我正在使用Ruby 1.9.2和Ruby on Rails v3.2.2 gem。我正在尝试以“正确的方式”学习元编程,此时我在RoR ActiveSupport::Concern
模块提供的included do ... end
块中对实例方法进行别名处理:
module MyModule
extend ActiveSupport::Concern
included do
# Builds the instance method name.
my_method_name = build_method_name.to_sym # => :my_method
# Defines the :my_method instance method in the including class of MyModule.
define_singleton_method(my_method_name) do |*args|
# ...
end
# Aliases the :my_method instance method in the including class of MyModule.
singleton_class = class << self; self end
singleton_class.send(:alias_method, :my_new_method, my_method_name)
end
end
“Newbiely”说,通过在网上搜索,我想出了singleton_class = class << self; self end
语句,我用它(而不是class << self ... end
块)来范围 my_method_name
变量,动态生成别名。
我想完全理解为什么和 singleton_class
如何在上面的代码中工作,如果有更好的方法(也许,更易于维护)和performant one)实现相同(别名,定义单例方法等),但“正确的方法”因为我认为不是这样。
答案 0 :(得分:6)
我推荐Yehuda Katz的post on metaprogamming on Ruby's self。以下是我回答您问题的简单摘要:
在Ruby中,所有对象都有一个单例类(也称为元类)。对象首先从它们的单例类中隐藏,然后从它们的显式类继承。 Ruby类本身也有自己的单例类,因为类也是对象。 class <<
成语只是Ruby用于访问对象单例类范围的语法。
class Person
class << self
# self in this scope is Person's singleton class
end
end
person = Person.new
person_singleton_class = class << person; self; end
您的Rails版本实际上提供了singleton_class
作为快捷方式。由于singleton_class
是一种可用方法,因此您无需将其分配给表达式singleton_class = class << self; self end
中的变量:
Person.singleton_class
person = Person.new
person.singleton_class
由于类直接从其单例类继承,因此我们希望在元编程时动态添加类方法。 Ruby提供了一些方法来打开对象的范围,同时保持对周围范围的访问:class_eval
和instance_eval
。这些行为的方式存在细微差别(Yehuda的帖子解释了这一点),但是你可以使用任何一个来输入你的单例类的范围,将单例类的方法解析为self
并且仍然可以访问{{1来自周围的范围。
所有这一切,您可以对您的模块进行一些小的更改:
my_method_name