Где лучше всего добавить методы к целочисленному классу в Rails?
-
06-07-2019 - |
Вопрос
Где лучше всего добавить метод к целочисленному классу в 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 автоматически запустит их для вас.