修补 Ruby 的基类(例如 Fixnum)是否可以接受? [英] Is it acceptable practice to patch Ruby's base classes, such as Fixnum?

查看:44
本文介绍了修补 Ruby 的基类(例如 Fixnum)是否可以接受?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对 Ruby 还是很陌生(阅读 Pickaxe 并把大部分时间花在 irb 上),现在我知道可以在 Ruby 中修补类,我想知道什么时候这样做是可以接受的,特别是修补 Ruby 的基类是否可以接受.例如:我在此处回答了另一个 Ruby 问题,其中发帖人想知道如何从 DateTime 中减去小时数.由于 DateTime 类似乎没有提供此功能,我发布了一个答案,将 DateTimeFixnum 类修补为可能的解决方案.这是我提交的代码:

I am still very new to Ruby (reading through the Pickaxe and spending most of my time in irb), and now that I know it's possible to patch classes in Ruby, I'm wondering when it's acceptable to do so, specifically whether it's acceptable to patch Ruby's base classes. For example: I answered another Ruby question here where the poster wanted to know how to subtract hours from a DateTime. Since the DateTime class doesn't seem to provide this functionality, I posted an answer that patches the DateTime and Fixnum classes as a possible solution. This is the code I submitted:

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 中减去固定的小时数.具体来说,您可以根据上述代码执行以下操作:

I patched the classes because I thought in this instance it would result in a clear, concise syntax for subtracting a fixed number of hours from a DateTime. Specifically, you could do something like this as a result of the above code:

five_hours_ago = DateTime.now - 5.hours

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

Which seems to be fairly nice to look at and easy to understand; however, I'm not sure whether it's a good idea to be messing with the functionality of DateTime's - operator.

对于这种情况,我能想到的唯一替代方案是:

The only alternatives that I can think of for this situation would be:

1.只需即时创建一个新的 DateTime 对象,计算对 new 的调用中的新小时值

1. Simply create a new DateTime object on-the-fly, computing the new hour value in the call to 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.编写一个实用方法,它接受 DateTime 和从中减去的小时数


2. Write a utility method that accepts a DateTime and the number of hours to subtract from it

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

Basically, just a wrapper around method (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 添加一个新方法,而不是更改 #-()


3. Add a new method to DateTime instead of changing the existing behavior of #-()

也许是一个新的 DateTime#less 方法,它可以与 Fixnum#hours 补丁一起工作,以允许这样的语法:

Perhaps a new DateTime#less method that could work together with the Fixnum#hours patch, to allow syntax like this:

date.less(5.hours)


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


However, as I already mentioned, I took the patching approach because I thought it resulted in a much more expressive syntax.

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

Is there anything wrong with my approach, or should I be using one of the 3 alternatives (or another one I haven't thought of) in order to do this? I have the feeling that patching is becoming my new 'hammer' for problems in Ruby, so I'd like to get some feedback on whether I'm doing things the "Ruby way" or not.

推荐答案

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

My personal answer, in a nutshell: the core-class patching hammer should be at the bottom of your toolbox. There are a lot of other techniques available to you, and in almost all cases they are sufficient, cleaner, and more sustainable.

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

It really depends on the environment in which you are coding, though. If it's a personal project - sure, patch to your heart's content! The problems begin to arise when you are working on a large codebase over a long period of time with a large group of programmers. In the organization I work for, which has Ruby codebases of over 100KLOC and and twenty or so developers, we have started to crack down pretty hard on monkey patching, because we've seen it lead to head-scratching, man-hour wasting behavior far too often. At this point we pretty much only tolerate it for temporarily patching third-party code which either hasn't yet incorporated or won't incorporate our source patches.

这篇关于修补 Ruby 的基类(例如 Fixnum)是否可以接受?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆