privados - programacion con objetos ruby
¿Es una práctica aceptable parchear las clases base de Ruby, como Fixnum? (4)
Creo que es así: si honestamente crees que la mayoría de los otros programadores estarían de acuerdo con tus parches, entonces está bien. Si no, ¿quizás debería implementar una biblioteca de códigos?
Todavía soy muy nuevo para Ruby (leyendo el Pico y pasando la mayor parte de mi tiempo en irb
), y ahora que sé que es posible parchar clases en Ruby, me pregunto cuándo es aceptable hacerlo, específicamente si es aceptable. parchear las clases base de Ruby. Por ejemplo: respondí otra pregunta de Ruby aquí donde el afiche quería saber cómo restar horas de un DateTime
. Dado que la clase DateTime
no parece proporcionar esta funcionalidad, Fixnum
una respuesta que Fixnum
clases DateTime
y Fixnum
como una posible solución. Este es el código que envié:
require ''date''
# A placeholder class for holding a set number of hours.
# Used so we can know when to change the behavior
# of DateTime#-() by recognizing when hours are explicitly passed in.
class Hours
attr_reader :value
def initialize(value)
@value = value
end
end
# Patch the #-() method to handle subtracting hours
# in addition to what it normally does
class DateTime
alias old_subtract -
def -(x)
case x
when Hours; return DateTime.new(year, month, day, hour-x.value, min, sec)
else; return self.old_subtract(x)
end
end
end
# Add an #hours attribute to Fixnum that returns an Hours object.
# This is for syntactic sugar, allowing you to write "someDate - 4.hours" for example
class Fixnum
def hours
Hours.new(self)
end
end
Repasé las clases porque pensé que en este caso se obtendría una sintaxis clara y concisa para restar un número fijo de horas de un DateTime
. Específicamente, podría hacer algo como esto como resultado del código anterior:
five_hours_ago = DateTime.now - 5.hours
Lo cual parece bastante agradable de ver y fácil de entender; sin embargo, no estoy seguro de si es una buena idea estar jugando con la funcionalidad del operador de DateTime
.
Las únicas alternativas que se me ocurren para esta situación serían:
1. Simplemente cree un nuevo objeto DateTime
sobre la marcha, calculando el nuevo valor de hora en la llamada a new
new_date = DateTime.new(old_date.year, old_date.year, old_date.month, old_date.year.day, old_date.hour - hours_to_subtract, date.min, date.sec)
2. Escriba un método de utilidad que acepte un DateTime
y la cantidad de horas para restarlo
Básicamente, solo un método de envoltura (1):
def subtract_hours(date, hours)
return DateTime.new(date.year, date.month, date.day, date.hour - hours, date.min, date.sec)
end
3. Agregue un nuevo método a DateTime
lugar de cambiar el comportamiento existente de #-()
Tal vez un nuevo método DateTime#less
que podría funcionar junto con el parche Fixnum#hours
, para permitir una sintaxis como esta:
date.less(5.hours)
Sin embargo, como ya mencioné, tomé el enfoque de parcheo porque pensé que resultaba en una sintaxis mucho más expresiva.
¿Hay algún problema con mi enfoque, o debería usar una de las 3 alternativas (u otra en la que no había pensado) para poder hacer esto? Tengo la sensación de que el parcheo se está convirtiendo en mi nuevo "martillo" para los problemas en Ruby, así que me gustaría obtener algunos comentarios sobre si estoy haciendo las cosas al estilo "Ruby" o no.
La forma más segura es definir tu propia clase que hereda de la incorporada, luego agrega tus cosas nuevas a tu nueva clase.
class MyDateTime < DateTime
alias...
def...
Pero obviamente ahora solo obtienes el nuevo comportamiento si declaras objetos de tu nueva clase.
Mi respuesta personal, en pocas palabras: el martillo de reparación de la clase central debe estar en la parte inferior de su caja de herramientas . Hay muchas otras técnicas disponibles para usted, y en casi todos los casos son suficientes, más limpias y más sostenibles .
Sin embargo, realmente depende del entorno en el que está codificando. Si se trata de un proyecto personal, seguro, parche para su corazón. Los problemas comienzan a surgir cuando trabajas en una gran base de código durante un largo período de tiempo con un gran grupo de programadores. En la organización para la que trabajo, que tiene bases de código Ruby de más de 100KLOC y una veintena de desarrolladores, hemos empezado a tomar medidas duras con los parches de los monos, porque hemos visto que esto lleva a un desgaste de la cabeza, a la hora de perder el comportamiento demasiado a menudo En este punto, prácticamente solo lo toleramos por el parche temporal de código de terceros que aún no ha incorporado o no incorporará nuestros parches de origen.
Personalmente, creo que es aceptable agregar métodos a las clases base, pero es inaceptable modificar la implementación de los métodos existentes.