5

在 Rails 中向整数类添加方法的最佳位置在哪里?我想添加一个to_metersto_miles方法。

4

7 回答 7

11

如果您一心想使用 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 中初始化它。

于 2008-11-07T09:32:18.443 回答
2

通常(并且在逻辑上),整数不能转换为英里或米。听起来您可能想要创建一个新类,如“英尺”或“英寸”,用整数初始化,然后包含 size_in_miles 或 size_in_meters 等方法。为方便起见,这些方法可以返回十进制或浮点类型,但您可能还想编写英里类或米类。

作为替代方法,您可能希望在新类中创建一个具有如下签名的静态方法:

Float feetToMiles(integer I)

你会打电话给

miles = Feet.feetToMiles(5280);

并得到miles = 1.0

于 2008-11-05T21:47:13.923 回答
2

创建您自己的模块/库,当您需要它来执行此任务时将其包含在范围内。

如“requre 'unitCoversions'”

如果你足够努力的话,很有可能已经有人这样做了:)

但是不要尝试修改本机核心类,这只会以苦难告终。

(此外,您要扩展的类是 'numeric' ,这将适用于整数和浮点数:))

不完全清楚为什么我不应该这样做……Rails 对字符串类这样做并取得了巨大的成功。

因为它可以做并不意味着它应该做。众所周知,“猴子修补”可能会产生各种奇怪的副作用,如果做错了,它们可能会成为史诗般的失败。

当没有好的选择时就去做。

因为如果你真的想做一些愚蠢的事情,你可以构建一个完整的框架,它所做的只是对核心类进行猴子补丁。

例如,翻转数据库。

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

等等等等。有多少不好的方法可以做到这一点是没有限制的。

"Bob".createUser(); 

杯中的苦难。

如果你想做一些实际的事情,有一个 Convert 类或函数,

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

至少您不会以这种方式污染全局命名空间和核心功能,而且它更具有连贯性。

于 2008-11-05T21:48:47.490 回答
2

为什么不只是:

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
于 2008-11-06T00:50:26.377 回答
2

我同意猴子补丁应该小心使用,但有时它只是有意义的。我真的很喜欢允许你输入 5.days.ago 的助手,它们是 active_support 库的一部分

因此,在这种情况下,其他一些答案可能会更好,但是如果您要扩展 ruby​​ 类,我们会将所有扩展保留在 lib/extensions/class_name.rb

这样,在处理项目时,可以快速轻松地找到和查看标准类可能不寻常的任何内容。

于 2008-11-06T20:25:51.823 回答
0

意识到这个问题很老,但我认为最清楚的方法是创建一个具有两个属性的距离类@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
于 2013-03-07T11:06:12.873 回答
-1

如果你打算这样做,你不应该这样做,那么你将把你的代码放入:

config/initializers/add_methods_that_are_naughty_to_numeric.rb

Rails 会自动为您运行这些。

于 2008-11-05T21:53:49.430 回答