2012-01-28 13 views
6

Quiero crear una subclase de Fecha.¿Por qué Date.new no invoca initialize?

A, sana, joven Rubyist normal, unscarred por la idiosincrasia de aplicación de fecha sería ir sobre esto de la siguiente manera:

require 'date' 

class MyDate < Date 

    def initialize(year, month, day) 
    @original_month = month 
    @original_day = day 

    # Christmas comes early! 
    super(year, 12, 25) 
    end 

end 

y proceder a utilizarlo de la manera más esperado ...

require 'my_date' 

mdt = MyDate.new(2012, 1, 28) 

puts mdt.to_s 

... sólo para ser traicionado por el hecho de que el método de la fecha :: nueva es en realidad un alias a la fecha :: civiles, lo que no siempre initialize llamada. En este caso, la última pieza de código imprime "2012-01-28" en lugar de la esperada "2012-12-25".

Estimado Ruby-community, wtf es esto?

¿Hay alguna razón muy buena de aliasing nuevo, por lo que ignora inicializar, y como resultado, cualquier sentido común y respeto por la salud mental del programador del cliente?

+1

Por cuya definición de "bueno"? –

+0

¿Cuál es la alternativa? Si llama a civil desde la inicialización, ha asignado un objeto que no necesita. – pguardiario

+0

Bueno, parece semánticamente incorrecto asignar e inicializar un objeto en el mismo método. Quiero decir, si 'civil' es el 'nuevo' de facto, ¿por qué no hacer que llame' initialize' al final? Puede ser una formalidad pura en 'Fecha', pero permitirá ampliar la clase sin necesidad de profundizar en los detalles de su implementación. Por lo tanto, me preguntaba, ¿por qué la decisión de alias 'civil' a' new' podría haberse tomado? – jst

Respuesta

6

Define initialize, pero crea la nueva instancia con new. new devuelve una nueva instancia de la clase, no el resultado de initialize.

puede hacerlo:

require 'date' 

class MyDate < Date 

    def self.new(year, month, day) 
    @original_month = month 
    @original_day = day 

    # Christmas comes early! 
    super(year, 12, 25) 
    end 

end 

mdt = MyDate.new(2012, 1, 28) 

puts mdt.to_s 

Observación: @original_month y @original_day no están disponibles en esta solución. La siguiente solución extiende la fecha, por lo que puede acceder al mes y día originales. Para las fechas normales, los valores serán nulos.

require 'date' 

class Date 
    attr_accessor :original_month 
    attr_accessor :original_day 
end 

class MyDate < Date 

    def self.new(year, month, day) 

    # Christmas comes early! 
    date = super(year, 12, 25) 
    date.original_month = month 
    date.original_day = day 
    date 
    end 

end 

mdt = MyDate.new(2012, 1, 28) 

puts mdt.to_s 
puts mdt.original_month 

Pero yo recomendaría:

require 'date' 

class MyDate < Date 

    def self.create(year, month, day) 
    @original_month = month 
    @original_day = day 

    # Christmas comes early! 
    new(year, 12, 25) 
    end 

end 

mdt = MyDate.create(2012, 1, 28) 

puts mdt.to_s 

o

require 'date' 

class Date 

    def this_year_christmas 
    # Christmas comes early! 
    self.class.new(year, 12, 28) 
    end 

end 

mdt = Date.new(2012, 1, 28).this_year_christmas 

puts mdt.to_s 
+0

¡Gracias por la gran respuesta! Terminé sobrecargando el método 'nuevo'. Parece muy extraño que la asignación e inicialización del objeto ocurra en un método. – jst

+0

En su definición 'self.create', los vars de instancia se establecen en la clase, no en la instancia. El uso de 'instance_variable_set' en el resultado de' new' se encargará de eso; solo asegúrate de devolver la instancia. – Kelvin

Cuestiones relacionadas