Ruby Metaprogramming

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
 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值