Tim Scott
Tim Scott

Reputation: 15205

Properties don't change when values are assigned?

I'm a bit of Ruby, noob, and there's some basic thing I'm not getting. I have something like this:

def my_method
    attr1 = 'new 1 value'
    attr2 = 'new 2 value'
    puts "#{attr1} - #{attr2}"
    puts "Should be same? #{to_s}"
end

def to_s
    "#{attr1} - #{attr2}"
end

When I call my_method I get:

new 1 value - new 2 value 
Should be same? old 1 value - old 2 value

Huh?

Upvotes: 1

Views: 90

Answers (3)

user166390
user166390

Reputation:

This is because in Ruby

x = y

is always an assignment of the value resulting from y to the variable x while

obj.x = y

is always sending the x= message to the object obj (with the value resulting from y).

In Ruby attributes/properties are really just methods! Thus, try:

self.attr1 = 'new 1 value'
self.attr2 = 'new 2 value'

On the other hand, y may or may not be a method call (read: property fetch). It depends on if there is already a variable y in scope or not because variables shadow methods. This is why attr1 and attr2 work in to_s without needing to be prefixed.

Happy coding.

Upvotes: 1

Azolo
Azolo

Reputation: 4383

It's the scope attr1 and attr2 are local variables.

So when you're calling to_s it looking for attr_1 and attr_2 that you've declared (probably) in the class scope. Those won't get overwritten when you run my_method instead you just created a new variable in a smaller scope.

Try using @attr_1 and @attr_2 instead.

Check out Local Variable Gotchas

Upvotes: 1

Mark Thomas
Mark Thomas

Reputation: 37517

There are two ways to do it. One is to use class-scoped variables instead of local variables:

class MyClass

    def my_method
        @attr1 = 'new 1 value'
        @attr2 = 'new 2 value'
        puts "#{@attr1} - #{@attr2}"
        puts "Should be same? #{self.to_s}"
    end

    def to_s
        "#{@attr1} - #{@attr2}"
    end
end

m = MyClass.new
m.my_method

Output:

new 1 value - new 2 value
Should be same? new 1 value - new 2 value

The other way is to use attributes, which you have to specifically call as methods on self:

class MyClass
    attr_accessor :attr1,:attr2

    def my_method
        self.attr1 = 'new 1 value'
        self.attr2 = 'new 2 value'
        puts "#{attr1} - #{attr2}"
        puts "Should be same? #{self.to_s}"
    end

    def to_s
        "#{attr1} - #{attr2}"
    end
end

m = MyClass.new
m.my_method

This has the same output.

Upvotes: 1

Related Questions