这个标题比较怪,实际上很简单,看下列代码
ruby 代码
- class Test
- class <<self
- def add_method_a
- module_eval %{
- def method_a
- end
- }
- end
- end
-
- add_method_a
- end
-
- puts Test.new.respond_to?(:method_a)
运行结果是打印出 true, 不知道会不会有人和我有一样的疑问,为什么在singleton方法add_method_a中调用module_eval 定义动态方法的结果是为Test类增加了一个instance method而不是一个singleton method。
其实,解释很简单,原因就在于,ruby解释过程中instance method和singleton method处理方式的一点不同:
cpp 代码
-
- case NODE_DEFS:
- VALUE klass;
-
- klass = rb_singleton_class(recv);
-
- rb_add_method(klass, node->nd_mid, defn,
- NOEX_PUBLIC|(body?body->nd_noex&NOEX_UNDEF:0));
cpp 代码
-
- VALUE ruby_class;
-
-
- case NODE_DEFN:
-
- rb_add_method(ruby_class, node->nd_mid, defn, noex);
虽然,两者同样使用rb_add_method添加method,但前者使用局部变量klass,而后者使用的是全局变量ruby_class。
ruby_class 是ruby解释过程中栈信息的一部分,用来记录当前语句(Node)所在的类范围,很明显,例子中module_eval执行时,ruby_class指向的仍然是Test类,因此,运行的结果是我们为Test添加了一个instance method。
对此,我们可以略微加以证明,在上面两处调用rb_add_method的地方加上一条打印信息:
cpp 代码
- printf("curren class: %s method: %s\n", rb_class2name(ruby_class), rb_id2name(node->nd_mid));
编译ruby,再次运行样例代码, 结果很清楚的告诉我们,此时ruby_class指向的都是Test类。
写倒这里,我们也顺带证明了一下一个我们常用的小技巧:
ruby 代码
- // 例如我们自己的"attr_accessor"
- module MyAttribute
- def add_attribute name
- module_eval %{
- def
- @
- end
-
- def
- @
- end
- }
- end
- end
-
- class TestModule
- extend MyAttribute //增加singleton method add_attribute
- add_attribute :my_attr
- end
-
- require 'date'
- t = TestModule.new
- t.my_attr = Date.today
- puts t.my_attr
可以方便为我们的类添加一些简单实用的小方法 :)
分享到:
相关推荐
def self.method_missing(name, *args) puts "Called method: #{name}" end my_object = MyClass.new my_object.some_method # 输出: "Called method: some_method" ``` ##### 2. eval `eval`函数可以用来执行一...
Ruby的元编程能力,如`class_eval`、`instance_eval`和`define_method`等方法,使得动态修改类和对象的行为变得容易,这在实现某些设计模式时特别有用。例如,元编程可以用来在运行时添加方法,实现动态代理或者创建...
在Ruby中,可以通过模块的extend方法和instance_eval方法实现单例模式,比如: ```ruby class Singleton class attr_accessor :instance end def initialize @state = "I'm the only one!" end def self....
10. `Module#define_method` 和 `Module#method_missing`: `define_method`用于在运行时定义实例方法,而`method_missing`是一个回调方法,当尝试调用不存在的方法时会被触发,这可以用来实现自定义错误处理或动态...
在Ruby中,可以使用`singleton_class`方法或`Module#class_eval`配合`instance`来实现单例模式。 2. **工厂模式(Factory)**:创建对象时,隐藏具体创建过程,提高灵活性。Ruby没有像Java那样的静态方法限制,因此...