Reputation: 35
I'm obviously new to Ruby, and programming in general, and greatly appreciate any help.
Here is my code snippet:
class Player
attr_accessor :name, :hp
def initialize(name, hp)
@name = name
@hp = hp
end
def name
@name
end
def hp
@hp
end
end
def prompt
print "> "
end
prompt; pname = gets.chomp
player = Player.new(pname, rand(20..30))
puts "#{player.name} \:\: #{player.hp} HP"
def test
puts "#{player.name} \:\: #{player.hp} HP - IN METHOD"
end
test
When run, here are the results:
$ ruby wtf.rb
> Test Name
Test Name :: 20 HP
wtf.rb:24:in `test': undefined local variable or method `player' for main:Object (NameError) from wtf.rb:27:in `<main>'
Why does my call work in the first instance, but not the second? Is it because it is now looking for a new "player" variable within the "test" method? If so, how do I go about calling the one from the class instance created earlier?
Thanks!
Upvotes: 1
Views: 77
Reputation: 11935
Ruby doesn't have lexical scope for methods like Javascript for functions, so this (ruby):
player = Player.new(pname, rand(20..30))
def test
# error: undefined variable or method 'player',
# this happens because player was defined
# in an unrelated scope outside this method
puts "#{player.name} \:\: #{player.hp} HP - IN METHOD"
end
test
Is NOT equivalent to this (javascript)
var player = new Player(pname, ...);
var test = function() {
# works as expected, player is available because it was defined
# in the parent scope
console.log(player.name + "\:\:" + player.hp + " HP - IN METHOD");
};
test();
If you want something similar to lexical scope on ruby, maybe you should use lambda
player = Player.new(pname, rand(20..30))
test = lambda do
# works as expected, this block scope inherits from parent scope where the block
# was created, so, it can access player local variable
puts "#{player.name} \:\: #{player.hp} HP - IN METHOD"
end
test.call
Upvotes: 0
Reputation: 2254
player
is defined as a local variable outside the scope of the method test
,
change references of player
to @player
, making it an instance variable
Here is a quick reference on scope and variables, and also a similar question
As a side note you shouldn't use test
as a method name, because it is already defined on Kernel
irb(main):001:0> method(:test)
=> #<Method: Object(Kernel)#test>
Upvotes: 1
Reputation: 5205
def test
puts "#{player.name} \:\: #{player.hp} HP - IN METHOD"
end
You forgot to pass player
into the method:
def test(player)
puts "#{player.name} \:\: #{player.hp} HP - IN METHOD"
end
test(player) # => player = Player.new(pname, rand(20..30)) :: 22 HP - IN METHOD
Upvotes: 0