1

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!

3 Answers 3

1

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>
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the reference and the note about using test as a method name!
0
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

1 Comment

Thank you very much, this makes perfect sense.
0

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

1 Comment

Thanks for the comment; being new to programming, I don't understand your response but it's given me something new to research.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.