在 Rails 中向整数类添加方法的最佳位置在哪里?我想添加一个to_meters
和to_miles
方法。
7 回答
如果您一心想使用 Numeric(或整数等)类来进行单位转换,那么至少要在逻辑上进行并具有一些实际价值。
首先,创建一个 Unit 类来存储单位类型(米、英尺、肘等)和创建时的值。然后向 Numeric 添加一堆方法,这些方法对应于 unit 可以具有的有效值:这些方法将返回一个 Unit 对象,其类型记录为方法名称。Unit 类将支持一堆 to_* 方法,这些方法将转换为具有相应单位值的另一种单位类型。这样,您可以执行以下命令:
>> x = 47.feet.to_meters
=> 14.3256
>> x.inspect
=> #<Unit 0xb795efb8 @value=14.3256, @type=:meter>
处理它的最佳方法可能是 Unit 类中的转换类型和表达式的矩阵,然后使用 method_missing 检查给定类型是否可以转换为另一种类型。在 numeric 类中,使用 method_missing 询问 Unit 是否支持给定的方法作为单元类型,如果支持,则返回使用 numeric 作为其值的请求类型的单元对象。然后,您可以通过向 Unit 添加一个扩展转换矩阵的 register_type 和 register_conversion 类方法来支持在运行时添加单位和转换,并且 Numeric 将“自动”获取该功能。
至于放在哪里,创建一个 lib/units.rb 文件,该文件还包含 Numeric 的 monkey_patch,然后在需要 lib/units.rb 文件的 config/environment.rb 中初始化它。
通常(并且在逻辑上),整数不能转换为英里或米。听起来您可能想要创建一个新类,如“英尺”或“英寸”,用整数初始化,然后包含 size_in_miles 或 size_in_meters 等方法。为方便起见,这些方法可以返回十进制或浮点类型,但您可能还想编写英里类或米类。
作为替代方法,您可能希望在新类中创建一个具有如下签名的静态方法:
Float feetToMiles(integer I)
你会打电话给
miles = Feet.feetToMiles(5280);
并得到miles = 1.0
创建您自己的模块/库,当您需要它来执行此任务时将其包含在范围内。
如“requre 'unitCoversions'”
如果你足够努力的话,很有可能已经有人这样做了:)
但是不要尝试修改本机核心类,这只会以苦难告终。
(此外,您要扩展的类是 'numeric' ,这将适用于整数和浮点数:))
不完全清楚为什么我不应该这样做……Rails 对字符串类这样做并取得了巨大的成功。
因为它可以做并不意味着它应该做。众所周知,“猴子修补”可能会产生各种奇怪的副作用,如果做错了,它们可能会成为史诗般的失败。
当没有好的选择时就去做。
因为如果你真的想做一些愚蠢的事情,你可以构建一个完整的框架,它所做的只是对核心类进行猴子补丁。
例如,翻转数据库。
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
这样,在处理项目时,可以快速轻松地找到和查看标准类可能不寻常的任何内容。
意识到这个问题很老,但我认为最清楚的方法是创建一个具有两个属性的距离类@length
和@unit
.
您只需要一个转换哈希,可能作为距离的类变量:
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 会自动为您运行这些。