ruby 的类和模块是开放的,这是 ruby 的重要特征之一
ruby 核心类的扩展是非常容易的
总结了一下修改 ruby 核心类的一些常用方法以及可能面临的风险
最常见的方法就是添加一个新的不存在的方法
好处是不会和其他函数冲突,坏处是你无法判断是否会和 ruby 的下一本版本的同名函数冲突
比较经典的有 active support 对 ruby 核心类的扩展
比如这个函数返回单词的复数形式
# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/string/inflections.rb#L33
class String
def pluralize(count = nil, locale = :en)
locale = count if count.is_a?(Symbol)
if count == 1
dup
else
ActiveSupport::Inflector.pluralize(self, locale)
end
end
end
比如添加日志,调试信息等等
下面演示了在 ruby 的方法中添加一个输出
class String
alias _ruby_chars chars
def chars
puts 'char method done'
_ruby_chars
end
end
'test'.chars
# 输出
=> char method done
感觉这种相对安全,但是实际中用的不太多
比如 ActiveSupport 对 Time 的 to_s 方法的扩展
通过传递不同的参数来进行扩展
# 一部分源代码
# https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/time/conversions.rb#L6
DATE_FORMATS = {
db: "%Y-%m-%d %H:%M:%S",
number: "%Y%m%d%H%M%S",
}
def to_formatted_s(format = :default)
if formatter = DATE_FORMATS[format]
formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
else
to_default_s
end
end
alias_method :to_default_s, :to_s
alias_method :to_s, :to_formatted_s
# 得到扩展后的结果
Time.now.to_s(:db)
=> "2018-09-29 12:47:10"
## 得到ruby默认的结果
Time.now.to_s
=> "2018-09-29 12:47:36 +0000"
这种扩展也是有风险的,你无法知道 ruby 的下个版本是否也有相同的扩展导致其中一个被覆盖
这可以说是比较安全的扩展的方法,影响的范围也要小很多
比如要添加一个移除空格的方法到 string 对象,注意不是扩展到 String 类
可以通过 extend 方法来实现
module StringExtension
def remove_space
gsub(' ', '').gsub(' ', '')
end
end
str = 'hello world'
str.extend(StringExtension)
str.remove_space
=> "helloworld"
有时候我们需要覆盖 Gem 已经存在的方法,也可以使用这个方法来不破坏 Gem 并且实现我们的目的
如果你使用 devise 的话,在重设密码之后会默认发送邮件
可以对 user 对象覆盖它默认的方法,进行单独处理
def user.send_reset_password_instructions_notification(token)
# do something
end
扩展核心类最大的风险在于影响范围非常大
如果我们可以减小范围那么风险就小了很多
ruby2.1 开始提供了 refinement 来解决这个问题
module StringExtension
refine String do
def remove_space
gsub(' ', '').gsub(' ', '')
end
end
end
# 直接使用的话会出现一个error
'hello world'.remove_space
=> NoMethodError: undefined method `remove_space' for "hello world":String
# 使用using在指定的类里面使用
class Sample
using StringExtension
'hello world'.remove_space
end
=> "helloworld"
总结了修改 rubu core 的一些方法和其中的风险
比较经典的要数 Active Support 对 ruby 的扩展,可以看到很多例子
https://github.com/rails/rails/tree/master/activesupport/lib/active_support/core_ext
Active Support 因为非常有名,所以在一定程度上降低了风险
在自己项目里面进行修改的话应该慎重考虑风险以后在进行