2009-08-09 22 views
9

Este método:Cuándo utilizar 'yo' en Ruby

def format_stations_and_date 
    from_station.titelize! if from_station.respond_to?(:titleize!) 
    to_station.titleize! if to_station.respond_to?(:titleize!) 
    if date.respond_to?(:to_date) 
     date = date.to_date 
    end 
    end 

produce este error cuando date es nula:

NoMethodError (You have a nil object when you didn't expect it! 
The error occurred while evaluating nil.to_date): 
    app/models/schedule.rb:87:in `format_stations_and_date' 
    app/controllers/schedules_controller.rb:15:in `show' 

Sin embargo, si cambio date = date.to_date a self.date = self.date.to_date, el método funciona correctamente .

¿Qué está pasando? En general, ¿cuándo debo escribir self?

Editar: No se relaciona con la pregunta, pero tenga en cuenta que no hay "titleize!" método.

+0

posible duplicado de [¿Por qué los setters ruby ​​necesitan "self"? calificación dentro de la clase?] (http://stackoverflow.com/questions/44715/why-do-ruby-setters-need-self-qualification-within-the-class) –

Respuesta

42

Siempre que desee invocar un método setter en sí mismo, debe escribir self.foo = bar. Si simplemente escribe foo = bar, el analizador de ruby ​​lo reconoce como una asignación de variable y piensa en foo como una variable local a partir de ahora. Para que el analizador se dé cuenta de que desea invocar un método setter y no asignar una variable local, debe escribir obj.foo = bar, por lo que si el objeto es self, self.foo = bar

7

Usted desambigó entre el nombre del método de instancia y una variable local utilizando self (se permite tener ambos con el mismo nombre en el mismo ámbito). En otras palabras, habrá una resolución de nombre de método solo si no hay una variable local o de bloque del mismo nombre en el alcance. He aquí:

class Foo 
    attr_accessor :boo 
    def do_boo 
    boo = 123 
    puts "Locvar: #{boo} Method: #{self.boo}" 
    end 
end 
Foo.new.do_boo 

He aquí por qué: imagine que tiene un módulo que implementa un método. Este método asigna algo a su variable local interna "foo" que se usa para algunos cálculos. Si omite la parte "self", el método hará una llamada al método "foo =" en el objeto , cuya clase incluye el módulo, que no era la intención del autor y puede ser francamente desastrosa.

class Foo 
    def bar=(new_value_of_bar) 
    set_off_nukes(new_value_of_bar/3) 
    end 
end 

module InnocentModule # written by a different author elsewhere 
    def do_useful_stuff 
    ... 
    bar = Math.sin(something) # we're dead 
    end 
end 
Foo.send(:include, InnocentModule) 

Otra parte crucial en el que usted tiene que utilizar uno mismo es cuando se invoca el método de la clase Object #, porque simplemente diciendo "clase" significa una clase de palabras clave para Ruby.