Our Point class uses two instance variables. As we've noted, however, the value of these variables are only accessible to other instance methods. If we want users of the Point class to be able to use the X and Y coordinates of a point, we've got to provide accessor methods that return the value of the variables:
class Point def initialize(x,y) @x, @y = x, y end def x # The accessor (or getter) method for @x @x end def y # The accessor method for @y @y end end
p = Point.new(1,2) q = Point.new(p.x*2, p.y*3)
class MutablePoint def initialize(x,y); @x, @y = x, y; end def x; @x; end # The getter method for @x def y; @y; end # The getter method for @y def x=(value) # The setter method for @x @x = value end def y=(value) # The setter method for @y @y = value end end
p = Point.new(1,1) p.x = 0 p.y = 0
This combination of instance variable with trivial getter and setter methods is so common that Ruby provides a way to automate it. The attr_reader
and attr_accessor
methods are defined by the Module class. All classes are modules, (the Class class is a subclass of Module) so you can invoke these method inside any class definition. Both methods take any number of symbols naming attributes. attr_reader
creates trivial getter methods for the instance variables with the same name. attr_accessor
creates getter and setter methods. Thus, if we were defining a mutable Point
class, we could write:
class Point attr_accessor :x, :y # Define accessor methods for our instance variables end
class Point attr_reader :x, :y # Define reader methods for our instance variables end
attr_reader "x", "y"
attr :x # Define a trivial getter method x for @x attr :y, true # Define getter and setter methods for @y. Optional boolean is Obsoleted
Theattr
,attr_reader
, andattr_accessor
methods create instance methods for us. This is an example of metaprogramming.
x=
podemos sentirnos tentados de utilizarlo
dentro de otro método de instancia de la clase.
That is, instead of writing @x=2
, you might write
x=2
, intending to invoke x=(2)
implicitly on self.
x=2
creates a new
local variable.
self.x=2
.
casiano@exthost:~/LPPsrc/221012$ cat -n setters.rb 1 class Tutu 2 attr_accessor :n 3 4 def initialize(n) 5 @n = n 6 end 7 8 def to_s 9 "#{n*2}" 10 end 11 12 def square 13 n = n * n # n here is a local variable! 14 end 15 16 def square2 17 self.n = n * n 18 end 19 end 20 21 if __FILE__ == $0 22 x = Tutu.new(ARGV.shift || 4) 23 puts x # to_s gets called: 8 24 begin 25 x.square 26 rescue 27 puts "Raised exception '#{$!.class}'. Message: <#{$!}>" 28 end 29 x.square2 # 32 = 16 *2 30 puts x 31 end
~/rubytesting/TheRubyProgrammingLanguage/Chapter7ClassesAndModules$ ruby setters.rb 8 Raised exception 'NoMethodError'. Message: <undefined method `*' for nil:NilClass> 32
attr_reader
et al. son proveídos por la clase Module.
ruby-1.9.2-head :004 > Class.class => Class ruby-1.9.2-head :005 > Class.superclass => Module ruby-1.9.2-head :006 > Class.superclass.superclass => Object ruby-1.9.2-head :007 > Class.superclass.superclass.superclass => BasicObject ruby-1.9.2-head :008 > Class.ancestors => [Class, Module, Object, InteractiveEditor::Editors, Wirble::Shortcuts, PP::ObjectMixin, Kernel, BasicObject]
attr_accessor
es un método de instancia o de clase?Casiano Rodriguez León 2015-01-07