Ruby Ruby Blocks Blocks Practice Build a Monster Class: Part 1

Immo Struchholz
Immo Struchholz
10,515 Points

Why do I have to use @ here?

Hi,

I played around a little with the class from the video and added a hit method. It takes an argument(amount) and substracts that from the health of the monster. Here is my code:

class Monster
    attr_accessor :name, :health
    def initialize(name)
        @name = name
        @health = 100
    end
    def hit(amount)
        health -= amount
    end

end

dragon = Monster.new("Smaug")
dragon.hit(25)
puts dragon.inspect

This code doesn't run, I get this error:

monster.rb:8:in `hit': undefined method `-' for nil:NilClass (NoMethodError)
    from scripts/ruby/monster.rb:14:in `<main>'

If I change health to @health inside the hit method however it works just fine. Why is that? I should be able to access it without the @, shouldn't I?

Patrick Shushereba
Patrick Shushereba
10,911 Points

Not exactly. The reason you define an instance variable to use is so that it can be accessed by any method in the class. If you don't use the @ in your hit method, Ruby doesn't know what you're talking about. Using @health lets Ruby know that you're using the variable that you defined with attr_accessor.

1 Answer

Andrew Stelmach
Andrew Stelmach
12,374 Points

It's better with some spacing and, yes, you need to use @health here:

class Monster
    attr_accessor :name, :health

    def initialize(name)
        @name = name
        @health = 100
    end

    def hit(amount)
        @health -= amount
    end
end

Check this out: http://stackoverflow.com/questions/4370960/what-is-attr-accessor-in-ruby

health returns @health.

health IS A METHOD. This is the critical piece of understanding and this is why your original code doesn't work.

A convenient Rubyism is that you can do health = something if you have attr_writer in your code (which is provided by attr_accessor).

So, this also works:

class Monster
    #This provides attr_reader and attr_writer for health
    attr_accessor :name, :health

    def initialize(name)
        @name = name
        @health = 100
    end

    def hit(amount)
        #This line uses attr_reader
        new_health = health - amount

        #This line uses attr_writer
        health = new_health
    end
end