17

我对 Ruby 还是很陌生(通读 Pickaxe 并且大部分时间都花在irb了修补 Ruby 的基类。例如:我在这里回答了另一个 Ruby 问题,发帖人想知道如何从DateTime. 由于DateTime该类似乎没有提供此功能,因此我发布了一个答案,该答案将修补DateTimeFixnum类作为可能的解决方案。这是我提交的代码:

require 'date'

# A placeholder class for holding a set number of hours.
# Used so we can know when to change the behavior
# of DateTime#-() by recognizing when hours are explicitly passed in.

class Hours
   attr_reader :value

   def initialize(value)
      @value = value
   end
end

# Patch the #-() method to handle subtracting hours
# in addition to what it normally does

class DateTime

   alias old_subtract -

   def -(x) 
      case x
        when Hours; return DateTime.new(year, month, day, hour-x.value, min, sec)
        else;       return self.old_subtract(x)
      end
   end

end

# Add an #hours attribute to Fixnum that returns an Hours object. 
# This is for syntactic sugar, allowing you to write "someDate - 4.hours" for example

class Fixnum
   def hours
      Hours.new(self)
   end
end

我修补了这些类,因为我认为在这种情况下,它会产生一种清晰、简洁的语法,用于从DateTime. 具体来说,由于上述代码,您可以执行以下操作:

five_hours_ago = DateTime.now - 5.hours

看起来很漂亮,也很容易理解;但是,我不确定弄乱DateTime'-运算符的功能是否是个好主意。

对于这种情况,我能想到的唯一选择是:

DateTime1. 简单地即时创建一个新对象,在调用中计算新的小时值new

new_date = DateTime.new(old_date.year, old_date.year, old_date.month, old_date.year.day, old_date.hour - hours_to_subtract, date.min, date.sec)


2. 编写一个实用方法,接受 aDateTime和要从中减去的小时数

基本上,只是方法(1)的包装:

def subtract_hours(date, hours)
  return DateTime.new(date.year, date.month, date.day, date.hour - hours, date.min, date.sec)
end


3.添加一个新的方法来DateTime代替改变现有的行为#-()

也许是DateTime#less一种可以与Fixnum#hours补丁一起使用的新方法,以允许这样的语法:

date.less(5.hours)

然而,正如我已经提到的,我采用了修补方法,因为我认为它会产生更具表现力的语法。

我的方法有什么问题吗,或者我应该使用 3 种替代方法中的一种(或我没有想到的另一种)来做到这一点?我感觉打补丁正在成为我解决 Ruby 问题的新“锤子”,所以我想就我是否以“Ruby 方式”做事得到一些反馈。

4

4 回答 4

18

我个人的回答,简而言之:核心级修补锤应该在工具箱的底部。您可以使用许多其他技术,并且几乎在所有情况下它们都足够、更清洁、更可持续

不过,这实际上取决于您编码的环境。如果这是一个个人项目——当然,随心所欲!当您与一大群程序员长时间处理大型代码库时,问题就开始出现了。在我工作的组织中,拥有超过 100KLOC 的 Ruby 代码库和大约 20 名开发人员,我们已经开始严厉打击猴子补丁,因为我们已经看到它会导致令人头疼、浪费工时的行为太频繁了。在这一点上,我们几乎只能容忍它临时修补尚未合并或不会合并我们的源补丁的第三方代码。

于 2008-10-27T02:03:39.547 回答
6

个人认为,在基类中添加方法是可以接受的,但是修改现有方法的实现是不能接受的。

于 2008-10-27T01:06:42.407 回答
5

安全的方法是定义你自己的继承自内置类的类,然后将你的新东西添加到你的新类中。

class MyDateTime < DateTime
  alias...
  def...

但显然,现在只有声明新类的对象才能获得新行为。

于 2008-10-27T01:56:37.063 回答
0

我认为它是这样的:如果你真的觉得大多数其他程序员会同意你的补丁,那很好。如果没有,也许您应该改为实现代码库?

于 2008-10-27T01:14:26.960 回答