Subsecciones


Acceso a los Atributos

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

The attr, attr_reader, and attr_accessor methods create instance methods for us. This is an example of metaprogramming.

Utilización de los Setters Dentro de una Clase

Una vez que se ha definido un setter como 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.

  1. It doesn’t work; x=2 creates a new local variable.
  2. The rule is that assignment expressions will only invoke a setter method when invoked through an object
  3. If you want to use a setter from within the class that defines it, invoke it explicitly through self.
  4. For example: 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

Los Accessors como attr_accessor se Invocan Fuera de las Definiciones de Métodos

attr_reader et al. son proveídos por la clase Module.

Todas las clases son módulos

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]

Ejercicio 14.1.1   ¿attr_accessor es un método de instancia o de clase?

Casiano Rodriguez León 2015-01-07