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

StackOverflow https://stackoverflow.com/questions/266819

Вопрос

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

Это было полезно?

Решение

Если ваше сердце настроено на смешивание с классом 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.

Другие советы

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

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

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

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

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

  

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

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

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

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

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

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

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

"Bob".createUser(); 

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

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

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

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

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

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

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

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

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

Обычно (и логически) целые числа не могут быть преобразованы в мили или метры.Похоже, вы можете захотеть создать новый класс типа "Feet" или "inches", который инициализируется целым числом, а затем содержит методы типа size_in_miles или size_in_meters.Для удобства эти методы могут возвращать десятичные или плавающие типы, но вы также можете захотеть написать класс miles или meters .

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

Float feetToMiles(integer I)

что вы могли бы назвать

miles = Feet.feetToMiles(5280);

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

Поймите, что вопрос старый, но я думаю, что самый простой способ - создать класс 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

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

config/initializers/add_methods_that_are_naughty_to_numeric.rb

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top