向 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 Problem
中 Ruby
。
为了解决这个问题,我为 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?
在 exercism.io I have submitted a solution ot the Pangram Problem
中 Ruby
。
为了解决这个问题,我为 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?