0

I'm trying to pass a variable to numerous classes but get an 'undefined local variable or method' error.

I've created a 'Player' class which has a method to initialise an object with two parameters, and have a 'Board' class where I want to use one of these parameters (I've just included a 'puts' statement for simplicity below) but this is where the error occurs. Outside of the 'Board' class, the same statement works (currently commented out).

How can I use the player1.name value inside of the 'Board' class please? Thanks

class Player
attr_accessor :name, :symbol

  def initialize(name, symbol)
    @name = name
    @symbol = symbol
  end

end 


class Board

puts player1.name

end

player1 = Player.new("Player1","X")
#puts player1.name
Turbo124
  • 3
  • 2

2 Answers2

0

It seems that you're trying to call the instance of player1 inside the Board class before it is created.

This means player1 does not exist in that context.

I guess you could either instantiate it inside the Board class or pass it as an option. Here's an example:

class Board
  def initialize(options={})
    # Uses the player passed to it.
    @player = options[:player]
  end

  # Not often seen since you can get it from the player class
  # but can be done here inside the Board class too if you want to.
  def player_name
    puts @player.name
  end

end

# Instantiate your player as usual.
player1 = Player.new("Player1","X")

# Adding it to an options hash
# this step is optional, you can add it directly to board
# like you did for adding the name and symbol to the player class.
options = {player: player1}

# Instantiate a board with the player you've created.
board = Board.new(options)

# To puts the player name run the method.
board.player_name # "Player1"

See Ruby Classes and Modules if you would like more examples and learn more.

csalmeida
  • 528
  • 7
  • 26
  • Note that `puts @player.name` will always result in `NoMethodError: undefined method \`name' for nil:NilClass`. `@player` in the `initialize` method is another variable than `@player` in class context. The former `@player` is the instance variable of an instance variable `Board`. While the latter `@player` is an instance variable of the class `Board`, which people also call a [class instance variable](https://stackoverflow.com/questions/15773552/ruby-class-instance-variable-vs-class-variable). – 3limin4t0r May 01 '20 at 15:02
  • That's correct but thought this would give @Turbo124 enough to go on as I'm not sure what is trying to be achieved here. However, I've edited the answer to expand on the example. Wrapped the `puts` statement in a method and added how to use it in the end. Hopefully this helps! Thanks @3limin4t0r – csalmeida May 01 '20 at 18:26
0

When you open a class with the class keyword you open a new scope and the current bindings are thrown out of the window. Furthermore your code would never work since you reference player1 before defining the variable.

To solve these two issues we have to move the player1 definition above the class. Then instead of using the class keyword to define Board class we can use the Class constructor which keeps the current bindings.

This results in:

player1 = Player.new("Player1","X")

Board = Class.new do
  puts player1.name
end

Although this might solve your problem, I doubt that this is the functionality you'll actually need. The question reeks of a XY-problem. The above will bind the class as a whole to what the player1 value is at the moment of class definition.

In turn this means that every instance of Board is in some way bound to player1. I assume that every instance of Board can have its own player(s), in which case the following would be a better fit:

class Board
  def initialize(player1)
    @player1 = player1
  end
end
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52