向 ruby 中的内置 class 添加方法的正确方法是什么?

What is the proper way to add a method to a built-in class in ruby?

exercism.io I have submitted a solution ot the Pangram ProblemRuby

为了解决这个问题,我为 String class 创建了一个名为 alpha? 的方法,它确定字符是否为字母('a'..'z').这个方法在 module 里面,然后我 include 在字符串 class.

这是我的代码:

module Str_Plus
  def alpha?
      self[/[a-zA-Z]+/] == self
  end
end

class Pangram
  String.include Str_Plus 
  ...
end

有人提到这不是向内置 class 添加功能的最佳方式。
我的问题是,正确的方法是什么

扩展核心时class我喜欢在lib目录下添加一个core_ext目录

创建并 initializer 用于加载自定义扩展(例如:config/initializers/core_exts.rb)。并在其中添加以下行:

Dir[File.join(Rails.root, "lib", "core_ext", "*.rb")].each {|file| require file }

并让您的扩展名像:

#lib/core_ext/string.rb
class String
  def alpha?
    self[/[a-zA-Z]+/] == self
  end
end

现在您可以从控制台执行

"ABCD".alpha? # true
"ABC1".alpha? # false
"1234".alpha? # false

希望对您有所帮助

tenebrousedge 可能暗示 refinements

或者,更确切地说,根本不修补 String。通常情况下,monkeypatching 产生的问题多于它解决的问题。如果 String 已经知道 alpha? 并且它做了一些不同的事情怎么办?

例如,ruby 的未来版本可能会添加 String#alpha? 以正确处理 unicode

'新幹線'.alpha? # => true

而您的代码实际上会用劣质版本覆盖此内置功能。现在您的应用程序在各种地方都出现问题,因为 stdlib/rails 假定了新行为。混乱!

这就是说:尽可能避免使用 monkeypatching。当你无法避免时,使用改进。

只想用一个具体的操作示例添加到@sergio 的答案中(写成答案以获得代码格式)。制作您自己的 class / 模块。像 alpha? 这样的方法不必在 String 本身上定义有用和可重用,将它放在那里,即使进行了改进,也会导致名称冲突。任何执行此操作的 gem 都会立即出现在我的垃圾列表中,因为只需要两个 gem 就可以为他们要添加的方法选择相同的名称,而且很混乱。

相反,最好将您的方法包含在您自己的 classes 中。我会选择一个比 MyStringIdentifier 更好的名字,但你不必

作为一个模块:

module MyStringIdentifier
  # allows you to use `MyStringIdentifer.any_module_method_name_here`
  extend self

  def alpha?(string)
    !!(/^[a-zA-Z]+$/ =~ string)
  end
end

MyStringIdentifier.alpha?("hello")

或者,作为 class:

class MyStringIdentifier
  attr_reader :string

  def initialize(string)
    @string = string.to_s
  end

  def alpha?
    !!(/^[a-zA-Z]+$/ =~ string)
  end
end

MyStringIdentifier.new("hello").alpha?