Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

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

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