Sunday, August 19, 2012

Ruby Attribute Methods

I often get confused with these three concepts:
attr_accessor
attr_reader
attr_writer

After watching Ruby Essential Training from lynda.com, here's what I understand about them now. Let's address attr_writer first.

attr_writer

Use attr_writer when you want ruby to get your input to what this attribute (qualities of a particular object) will be. Here's an example.
j@ime:~$ irb
irb(main):001:0> class Car
irb(main):002:1> attr_writer :color
irb(main):003:1> def color
irb(main):004:2> @color
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> volks = Car.new
=> #
irb(main):008:0> volks.color = 'blue'
=> "blue"
irb(main):009:0> puts volks.color
blue
=> nil

In the example above, all Cars have colors, but different cars will have different colors, don't they? By not defining any specific color inside class Car, you then have a say as to what color your car is going to be.

If I did not create a method setter (irb(main):003:1> def color) for color, I get an error message, saying 'color' is undefined.
j@ime:~$ irb
irb(main):001:0> class Car
irb(main):002:1> attr_writer :color
irb(main):003:1> end
=> nil
irb(main):004:0> volkswagen = Car.new
=> #
irb(main):005:0> volkswagen.color = "blue"
=> "blue"
irb(main):006:0> puts volkswagen.color
NoMethodError: undefined method `color' for #
 from (irb):6
 from /usr/bin/irb:12:in `
'
In a way, input for attribute 'color' is coming from the user. You will have to assign the user's input into a "container"--an instance variable (@color), as this is something that def color is going to use.

attr_reader

On the other hand, if you want all cars (class Car) to be of one color, then you use attr_reader instead. I asked Ruby for a 'red' audi, but she gave me an error message instead...
irb(main):001:0> class Car
irb(main):002:1> attr_reader :color
irb(main):003:1> def color
irb(main):004:2> @color = 'blue'
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> audi = Car.new
=> #
irb(main):008:0> audi.color
=> "blue"
irb(main):009:0> puts audi.color
blue
=> nil
irb(main):010:0> audi.color = 'red'
NoMethodError: undefined method `color=' for #
 from (irb):10
 from /usr/bin/irb:12:in `
'

attr_accessor

attr_accessor on the other hand, is something else, and I don't quite get it. Take a look...
irb(main):001:0> class Car
irb(main):002:1> attr_accessor :color
irb(main):003:1> def color
irb(main):004:2> @color = "white"
irb(main):005:2> end
irb(main):006:1> end
=> nil
irb(main):007:0> ford = Car.new
=> #
irb(main):008:0> ford.color
=> "white"
irb(main):009:0> puts ford.color
white
=> nil
irb(main):010:0> ferrari = Car.new
=> #
irb(main):011:0> ferrari.color = "red"
=> "red"
irb(main):012:0> puts ferrari.color
white
=> nil

I think the reason ruby is insisting that ferrari's color is white (even if I say that it's red) is because I defined @color as white inside of class Car.

In a sense, the script is saying, "You can get any color you want, as long as it's white."

If we do not do a def color @color inside the class definition, you can get any color you want...
irb(main):001:0> class Car
irb(main):002:1> attr_accessor :color
irb(main):003:1> end
=> nil
irb(main):004:0> ford = Car.new
=> #
irb(main):005:0> ford.color = 'yellow'
=> "yellow"
irb(main):006:0> puts ford.color
yellow
=> nil
irb(main):007:0> porsche = Car.new
=> #
irb(main):008:0> porsche.color = 'silver'
=> "silver"
irb(main):009:0> puts porsche.color
silver
=> nil

No comments:

Post a Comment