Ruby Metaprogramming _Ruby_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > Ruby > Ruby Metaprogramming

Ruby Metaprogramming

 2011/9/29 8:03:58  Goldice  http://jdoc.iteye.com  我要评论(0)
  • 摘要:Ruby使用者对attr_accessor一定不会陌生。classAattr_accessor:numend等效于:classAdefnum@numenddef=(value)@num=valueendend在类的定义中,attr_accessor定义了num的读写方法,只用了一行代码就生成了两个实例方法,很cool,不是嘛?。这就是Metaprogramming,用程序来编写程序。Ruby中到底是用了什么trick能实现Metaprogramming这样cool的功能呢
  • 标签:

Ruby使用者对attr_accessor一定不会陌生。

?

class A
         attr_accessor :num
end

等效于:

class A
         def num
               @num
         end

         def =(value)
               @num = value
         end
end

在类的定义中,attr_accessor定义了num的读写方法,只用了一行代码就生成了两个实例方法,很cool,不是嘛?。这就是Metaprogramming,用程序来编写程序。

?

Ruby中到底是用了什么trick能实现Metaprogramming这样cool的功能呢?

我们把attr_accessor当做一个method,那么调用attr_accessor的是self,这个self是class A,也就是说,attr_accessor是一个类方法。按照这个思路,我们可以这样写:

?

?

class A
        def self.log s
                attr_reader s
                define_method("#{s}=") do |val|
                        instance_variable_set("@#{s}",val)
                end 
        end 


        log "num"
end

a=A.new
a.num = 10
puts a.num

在这里,使用attr_reader来定义实例变量的读方法,define_method来定义实例变量的写方法。

?

使用attr_reader或者自定义的log可以用于扩展代码,我们可以将它们称为macros.

?

使用上面这段代码,并没有体现出Metaprogramming的威力,因为在class A中直接定义方法,要比你定义一个类方法简单明了。但是如果是这样:

?

?

class B < A
     log "bnum"
end

b = B.new
b.bnum = 11
puts b.bnum # => 11

?我们就可以从A中直接继承log方法,来轻松构建B中的实例读写方法的了!这里的log,是不是很类似attr_accessor呢?

?

?

到目前为止,我们通过定义类方法,来实现继承类的Metaprogramming的方法。可是,有些时候,我们并不想通过继承的方式来获得元编程的能力,如果所有类想获得某种元编程的方法只能通过继承类的方式来实现,那太麻烦了吧!这个时候,module出现了。

?

?

module A
        def log s
                attr_reader s
                define_method("#{s}=") do |val|
                        instance_variable_set("@#{s}",val)
                end 
        end 
end

class B 
         extend A
         log "bnum"
end

b=B.new
b.bnum = 11
puts b.bnum

体会一下module和extend的作用,easy,不是嘛?

?

如果对于一个module,级想包含其中的instance method,又想包含其中的class method,肿么办?这个时候,就要来一点trick了。

?

module A
        module ClassMethod
                def log s
                        attr_reader s
                        define_method("#{s}=") do |val|
                                instance_variable_set("@#{s}",val)
                        end 
                end 
        end 

        def log
                puts "Just a instance method"
        end 

        def self.included(hostclass)
                hostclass.extend ClassMethod
        end 
end

class B 
         include A
         log "bnum"
end

b = B.new
b.log
b.bnum = 10
puts b.bnum
?

?

?

?

  • 相关文章
发表评论
用户名: 匿名