Подтвердить что ты не робот

Является ли приемлемой практикой исправление базовых классов Ruby, таких как Fixnum?

Я все еще очень новичок в Ruby (читаю через Pickaxe и трачу большую часть своего времени на irb), и теперь, когда я знаю, что можно патчировать классы в Ruby, мне интересно, когда это приемлемо для этого, в частности, приемлемо ли для исправления базовых классов Ruby. Например: я ответил на другой вопрос Ruby здесь, где плакат хотел узнать, как вычесть часы из DateTime. Поскольку класс DateTime, как представляется, не обеспечивает эту функциональность, я отправил ответ, который исправляет классы DateTime и Fixnum как возможное решение. Это код, который я представил:

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

Я закрепил классы, потому что я думал, что в этом случае это приведет к четкому, сжатому синтаксису для вычитания фиксированного количества часов из DateTime. В частности, вы можете сделать что-то подобное в результате приведенного выше кода:

five_hours_ago = DateTime.now - 5.hours

Что, кажется, довольно приятно смотреть и легко понять; однако я не уверен, что неплохо было бы возиться с функциональностью оператора DateTime -.

Единственными альтернативами, которые я могу придумать для этой ситуации, будет следующее:

1. Просто создайте новый объект DateTime "на лету", вычисляя новое значение часа в вызове 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. Напишите метод утилиты, который принимает DateTime и количество часов для вычитания из него

В принципе, просто обертка вокруг метода (1):

def subtract_hours(date, hours)
  return DateTime.new(date.year, date.month, date.day, date.hour - hours, date.min, date.sec)
end


3. Добавьте новый метод в DateTime вместо изменения существующего поведения #-()

Возможно, новый DateTime#less метод, который может работать вместе с патчем Fixnum#hours, чтобы разрешить синтаксис следующим образом:

date.less(5.hours)

Однако, как я уже упоминал, я взял подход к исправлению, потому что думал, что это привело к гораздо более выразительному синтаксису.

Что-то не так с моим подходом, или я должен использовать одну из трех альтернатив (или другую, о которой я не думал), чтобы сделать это? Я чувствую, что исправление становится моим новым "молотом" для проблем в Ruby, поэтому я хотел бы получить некоторую информацию о том, что я делаю "Ruby way" или нет.

4b9b3361

Ответ 1

Мой личный ответ, в двух словах: базовый патч-молот должен быть внизу вашего инструментария. Существует много других доступных вам методов, и почти во всех случаях они являются достаточными, более чистыми и более sustainable.

Это действительно зависит от среды, в которой вы кодируете. Если это персональный проект - обязательно, исправьте свое сердечное содержание! Проблемы возникают, когда вы работаете над большой кодовой базой в течение длительного периода времени с большой группой программистов. В организации, в которой я работаю, у которой есть кодовые базы Ruby более 100KLOC и двадцати или около того разработчиков, мы начали очень сильно расправляться с переделкой обезьян, потому что мы видели, что это привело к поцарапанию головы, слишком часто. На данный момент мы почти полностью терпим его для временного исправления стороннего кода, который либо еще не включил, либо не включит наши исходные исправления.

Ответ 2

Лично я считаю приемлемым добавлять методы к базовым классам, но неприемлемо модифицировать реализацию существующих методов.

Ответ 3

Самый безопасный способ - определить свой собственный класс, который наследуется от встроенного, а затем добавить новый материал в новый класс.

class MyDateTime < DateTime
  alias...
  def...

Но, очевидно, теперь вы получаете только новое поведение, если объявляете объекты своего нового класса.

Ответ 4

Я думаю, что это так: если вы честно считаете, что большинство других программистов согласятся с вашими исправлениями, то хорошо. Если нет, возможно, вам следует внедрять библиотеку кодов?