在Rails中向Integer类添加方法的最佳位置在哪里?

时间:2008-11-05 21:42:41

标签: ruby-on-rails ruby monkeypatching

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

7 个答案:

答案 0 :(得分:11)

如果你的心脏被设置为使用数字(或整数等)类进行单位转换,那么至少要逻辑地并且具有一些实际价值。

首先,创建一个Unit类,用于存储单位类型(米,英尺,立方等)和创建时的值。然后向Numeric添加一组与单元可以具有的有效值对应的方法:这些方法将返回一个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文件,该文件还包含Monkey_patch到Numeric,然后在config / environment.rb中初始化它,需要lib / units.rb文件。

答案 1 :(得分:2)

通常(和逻辑上),整数不能转换为里程或米。听起来你可能想要创建一个新的类,如“Feet”或“inches”,用一个整数初始化,然后包含size_in_miles或size_in_meters等方法。为方便起见,这些方法可以返回decimal或float类型,但您可能还想写一个里程类或米类。

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

Float feetToMiles(integer I)

你打电话给

miles = Feet.feetToMiles(5280);

并获取miles = 1.0

答案 2 :(得分:2)

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

例如“requre'unitCoversions'”

而且很有可能,如果你看起来很努力,有人已经这样做了。)

然而 DONT 尝试修改本机核心类,这只会以Misery结束。

(另外,你要扩展的类是'numeric',它将适用于Integers和Floats :))

  

不完全清楚为什么我不应该这样做... Rails对字符串类做了很大的成功。

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

当没有好的替代方案时这样做。

因为如果你真的想做一些愚蠢的事情,你可以建立一个完整的框架 ALL 它所做的就是猴子修补核心类。

例如,在其头部翻转数据库。

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

等等,对于有多少糟糕的方法没有限制。

"Bob".createUser(); 
一杯苦难。

如果你想做一些实际的事情,请使用转换类或函数,

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

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

答案 3 :(得分: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

答案 4 :(得分:2)

我同意猴子补丁应该小心使用,但偶尔它才有意义。我非常喜欢帮助你输入5.days.ago的助手,它们是active_support库的一部分

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

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

答案 5 :(得分:0)

意识到问题已经过时了,但我认为最明确的方法是制作一个具有两个属性@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

答案 6 :(得分:-1)

如果您打算这样做,那么您不应该这样做,那么您可以将代码放入:

config/initializers/add_methods_that_are_naughty_to_numeric.rb

Rails会自动为你运行这些。