Где лучшее место для добавления методов в класс Integer в Rails? - PullRequest
5 голосов
/ 06 ноября 2008

Где лучше всего добавить метод к целочисленному классу в Rails? Я хотел бы добавить to_meters и to_miles методы.

Ответы [ 7 ]

11 голосов
/ 07 ноября 2008

Если ваше сердце настроено на смешивание с классом Numeric (или integer и т. Д.), Чтобы получить преобразование единиц, то, по крайней мере, сделайте это логически и с некоторым реальным значением.

Сначала создайте класс Unit, в котором будут храниться тип единицы измерения (метры, футы, локти и т. Д.) И значение при создании. Затем добавьте в Numeric набор методов, соответствующих допустимым единицам значений: эти методы будут возвращать объект Unit с его типом, записанным в качестве имени метода. Класс Unit будет поддерживать набор методов to_ *, которые преобразуются в другой тип модуля с соответствующим значением модуля. Таким образом, вы можете выполнить следующую команду:

>> x = 47.feet.to_meters
=> 14.3256
>> x.inspect
=> #<Unit 0xb795efb8 @value=14.3256, @type=:meter>

Лучшим способом справиться с этим, вероятно, была бы матрица типов преобразования и выражений в классе Unit, а затем использовать method_missing, чтобы проверить, можно ли преобразовать данный тип в другой тип. В числовом классе используйте method_missing, чтобы спросить Unit, поддерживает ли он данный метод как тип модуля, и, если это так, вернуть объект модуля запрошенного типа, используя числовое значение в качестве его значения. Затем вы можете поддержать добавление модулей и преобразований во время выполнения, добавив метод класса register_type и register_conversion в Unit, который расширил матрицу преобразования, и Numeric «автоматически» подхватит возможность.

Что касается того, где его разместить, создайте файл lib / units.rb, который также будет содержать monkey_patch для Numeric, а затем инициализируйте его в config / environment.rb bu, требуя файл lib / units.rb.

2 голосов
/ 06 ноября 2008

Я согласен, что исправление обезьян следует использовать с осторожностью, но иногда это просто имеет смысл. Мне очень нравятся помощники, которые позволяют вам печатать 5.days.ago, которые являются частью библиотеки active_support

Так что некоторые другие ответы могут быть лучше в этом случае, но если вы расширяете классы ruby, мы сохраняем все наши расширения в lib / extensions / class_name.rb

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

2 голосов
/ 06 ноября 2008

Почему бы просто:

class Feet
  def self.in_miles(feet)
    feet/5280
  end
end

использование:

Feet.in_miles 2313

Или, может быть, посмотрите на это по-другому:

class Miles
  def self.from_feet(feet)
    feet/5280
  end
end

Miles.from_feet 2313
2 голосов
/ 06 ноября 2008

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

Например, "requre 'unitCoversions'"

И есть вероятность, что кто-то уже сделал это, если вы посмотрите достаточно усердно:)

Однако НЕ попробуйте изменить собственный базовый класс, который закончится только Misery.

(Кроме того, класс, который вы хотите расширить, это «числовой», который будет применяться как к целым числам, так и к числам с плавающей точкой :))

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

Поскольку это может быть сделано, это не значит, что должно быть сделано. «Обезьянье исправление», как известно, может иметь всевозможные странные побочные эффекты, и может быть эпическим провалом, если сделано неправильно.

Делайте это, когда нет хорошей альтернативы.

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

Например, переверните базу данных по голове.

5.getArtist(); 
10.getEvent(); 
100.getTrack(); 

и т. Д. И т. Д. Нет предела тому, как много плохих способов сделать это.

"Bob".createUser(); 

несчастье в чашке.

Если вы хотите сделать что-то практичное, иметь класс или функцию Convert,

convert( 3 , { :from=>:miles, :to=>:meters }); 

по крайней мере, вы не загрязняете глобальное пространство имен и основные функции таким образом, и это имеет более логичный смысл.

2 голосов
/ 06 ноября 2008

Обычно (и логически) целые числа не могут быть преобразованы в мили или метры. Звучит так, как будто вы можете захотеть создать новый класс, например «Ноги» или «дюймы», который инициализируется целым числом, а затем содержит методы, такие как size_in_miles или size_in_meters. Для удобства эти методы могут возвращать десятичные числа или типы с плавающей запятой, но вы также можете написать класс миль или класс метров.

В качестве альтернативного метода вы можете захотеть создать статический метод в вашем новом классе, который будет иметь такую ​​подпись:

Float feetToMiles(integer I)

что бы вы назвали

miles = Feet.feetToMiles(5280);

и получите miles = 1.0

0 голосов
/ 07 марта 2013

Понимаю, что вопрос старый, но я думаю, что самый ясный способ - создать класс Distance с двумя атрибутами @length и @unit.

Вам просто понадобится хеш преобразования, вероятно, как переменная класса Distance:

class Distance

  @@conversion_rates = {
    meters: {
      feet: 3.28084,
      meters: 1.0
    }
  }

  def to(new_unit)
    new_length = @length * @@conversion_rates[@unit][new_unit]
    Distance.new( new_length, new_unit ) 
  end

end

И это будет выглядеть примерно так:

Distance.new(3, :meters).to(:feet)

который, честно говоря, выглядит лучше, чем

3.meters.to_feet
0 голосов
/ 06 ноября 2008

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

config/initializers/add_methods_that_are_naughty_to_numeric.rb

Rails автоматически запустит их для вас.

...