组织猴子补丁
Organizing monkey patches
我读到 blog post 建议为您的猴子补丁命名空间,以便可以轻松查看和包含它们。
例如:
module CoreExtensions
module DateTime
module BusinessDays
def weekday?
!sunday? && !saturday?
end
end
end
end
将进入:lib/core_extensions/class_name/group.rb
文件。
它可以通过 Module#include
实例方法包含在 DateTime class 中(class 继承,因为 Class
是 Module
)
# Actually monkey-patch DateTime
DateTime.include CoreExtensions::DateTime::BusinessDays
我的问题是 include 语句去哪里了?有约定吗?
例如:
我有以下猴子补丁:
# http://www.justinweiss.com/articles/3-ways-to-monkey-patch-without-making-a-mess/
module CoreExtensions
module String
module Cases
def snakecase
return self if self !~ /[A-Z]+.*/
# http://rubular.com/r/afGWPWLRBB
underscored = gsub(/(.)([A-Z])/, '_')
underscored.downcase
end
def camelcase
return self if self !~ /_/ && self =~ /[A-Z]+.*/
split('_').map{ |e| e.capitalize }.join
end
end
end
end
存在于 lib/core_extensions/string/cases.rb
文件中。
我应该把我的 String.include CoreExtensions::String::Cases
声明放在哪里?
还要说明的是,这只是一个 ruby 项目,这有什么不同吗?
我试过把它放在里面 lib/devify.rb
require 'devify/version'
require 'devify/some_dir'
require 'devify/scaffold'
require 'devify/tree_cloner'
require 'devify/renderer'
require 'devify/project'
require 'devify/tasks/some_task'
require 'devify/tasks/bootstrap'
require 'core_extensions/string/cases'
module Devify
String.include CoreExtensions::String::Cases
end
这行得通,而且行之有效。这是因为我的整个应用程序都位于 Devify
模块或命名空间中。
这种方式也很好,因为我没有污染全局命名空间,对吗?因为我只是猴子修补住在 Devify
?
里面的 String
s
只是不确定这是否是正确的方法。
虽然 ruby 提供了多种动态更改 class 内容或方法的方法,但猴子修补会导致大问题和奇怪的错误。我读了这个 post (http://www.virtuouscode.com/2008/02/23/why-monkeypatching-is-destroying-ruby/) 关于为什么使用 monkey-patching 是个坏主意。
综上所述,他说的很多话都是有道理的。当你创建一个猴子补丁时,你假设它只适用于那个项目,而且,当更多具有相似目的的库放在一起时,你可能会产生冲突和不可预见的副作用。
在某些情况下,猴子修补的好处非常棒,例如 ActiveSupport 通过使用 ago
或 [=11= 猴子修补 Fixnum class 来处理日期操纵的方式] 方法,或作为方法 to_json
。但是,应避免使用猴子补丁。
要点是:Ruby 是一种面向对象的语言,您可以使用对象组合或任何其他模式来实现您的目标。 Monkey-patching 在某种程度上将您引向面向对象哲学的相反方向,因为您向预先存在的 class 添加了更多职责并增加了它的 public 接口以提供新的功能。
此外,class 和可用的 public 方法的行为并不明确。通过查看 class 定义,您无法了解它在系统中的作用和作用,以及它如何与其他对象交互。它使一个简单的任务最终变得更加困难。
显然,Monkey 补丁使一切变得更小、更简单,但避免它会使您的代码更易于维护、更易于调试、阅读和测试,并且更优雅,因为它符合 "OOP" 模式。
将 include
调用放在哪里并不重要。
调用 String.include
将始终猴子修补整个对象 space 中所有字符串使用的 String
class。所以最好把指令放在顶层,以免误导代码的读者。
猴子补丁总是全局的。
这是一个强大的功能,可以永久使用。
如果您正在创作 gem 请注意您正在与他人共享一个全局名称space。对于顶级模块甚至 gem 名称也是如此。共享名称space只是共享代码的现实。
如果您正在寻找词法范围的猴子补丁,请查看 Ruby 2 中引入的新优化功能。
改进是从 Smalltalk 的 class 盒子中提取的想法。不过,改进也有其自身的问题,例如,它们缺乏对内省和反思的支持。因此基本上使它们隐身并且不适合生产使用。
如果您希望将猴子补丁仅限于某些字符串对象,请考虑子classing String
或在实例上调用 extend
。
我读到 blog post 建议为您的猴子补丁命名空间,以便可以轻松查看和包含它们。
例如:
module CoreExtensions
module DateTime
module BusinessDays
def weekday?
!sunday? && !saturday?
end
end
end
end
将进入:lib/core_extensions/class_name/group.rb
文件。
它可以通过 Module#include
实例方法包含在 DateTime class 中(class 继承,因为 Class
是 Module
)
# Actually monkey-patch DateTime
DateTime.include CoreExtensions::DateTime::BusinessDays
我的问题是 include 语句去哪里了?有约定吗?
例如:
我有以下猴子补丁:
# http://www.justinweiss.com/articles/3-ways-to-monkey-patch-without-making-a-mess/
module CoreExtensions
module String
module Cases
def snakecase
return self if self !~ /[A-Z]+.*/
# http://rubular.com/r/afGWPWLRBB
underscored = gsub(/(.)([A-Z])/, '_')
underscored.downcase
end
def camelcase
return self if self !~ /_/ && self =~ /[A-Z]+.*/
split('_').map{ |e| e.capitalize }.join
end
end
end
end
存在于 lib/core_extensions/string/cases.rb
文件中。
我应该把我的 String.include CoreExtensions::String::Cases
声明放在哪里?
还要说明的是,这只是一个 ruby 项目,这有什么不同吗?
我试过把它放在里面 lib/devify.rb
require 'devify/version'
require 'devify/some_dir'
require 'devify/scaffold'
require 'devify/tree_cloner'
require 'devify/renderer'
require 'devify/project'
require 'devify/tasks/some_task'
require 'devify/tasks/bootstrap'
require 'core_extensions/string/cases'
module Devify
String.include CoreExtensions::String::Cases
end
这行得通,而且行之有效。这是因为我的整个应用程序都位于 Devify
模块或命名空间中。
这种方式也很好,因为我没有污染全局命名空间,对吗?因为我只是猴子修补住在 Devify
?
String
s
只是不确定这是否是正确的方法。
虽然 ruby 提供了多种动态更改 class 内容或方法的方法,但猴子修补会导致大问题和奇怪的错误。我读了这个 post (http://www.virtuouscode.com/2008/02/23/why-monkeypatching-is-destroying-ruby/) 关于为什么使用 monkey-patching 是个坏主意。
综上所述,他说的很多话都是有道理的。当你创建一个猴子补丁时,你假设它只适用于那个项目,而且,当更多具有相似目的的库放在一起时,你可能会产生冲突和不可预见的副作用。
在某些情况下,猴子修补的好处非常棒,例如 ActiveSupport 通过使用 ago
或 [=11= 猴子修补 Fixnum class 来处理日期操纵的方式] 方法,或作为方法 to_json
。但是,应避免使用猴子补丁。
要点是:Ruby 是一种面向对象的语言,您可以使用对象组合或任何其他模式来实现您的目标。 Monkey-patching 在某种程度上将您引向面向对象哲学的相反方向,因为您向预先存在的 class 添加了更多职责并增加了它的 public 接口以提供新的功能。
此外,class 和可用的 public 方法的行为并不明确。通过查看 class 定义,您无法了解它在系统中的作用和作用,以及它如何与其他对象交互。它使一个简单的任务最终变得更加困难。
显然,Monkey 补丁使一切变得更小、更简单,但避免它会使您的代码更易于维护、更易于调试、阅读和测试,并且更优雅,因为它符合 "OOP" 模式。
将 include
调用放在哪里并不重要。
调用 String.include
将始终猴子修补整个对象 space 中所有字符串使用的 String
class。所以最好把指令放在顶层,以免误导代码的读者。
猴子补丁总是全局的。
这是一个强大的功能,可以永久使用。
如果您正在创作 gem 请注意您正在与他人共享一个全局名称space。对于顶级模块甚至 gem 名称也是如此。共享名称space只是共享代码的现实。
如果您正在寻找词法范围的猴子补丁,请查看 Ruby 2 中引入的新优化功能。
改进是从 Smalltalk 的 class 盒子中提取的想法。不过,改进也有其自身的问题,例如,它们缺乏对内省和反思的支持。因此基本上使它们隐身并且不适合生产使用。
如果您希望将猴子补丁仅限于某些字符串对象,请考虑子classing String
或在实例上调用 extend
。