【转】Ruby 中如何动态生成类

最近在研究Watir的自动化测试,有了成果写文章上来。先转一个帖子:

转自:http://www.coolcode.cn/show-303-1.html

 Ruby 中如何动态生成类

废话不多说,先看例子:

Ruby代码

  1. Object.module_eval("class Test1\nend")  
  2. x = Object.const_get("Test1".to_sym)  
  3. x.method(:attr_accessor).call("test1".to_sym)  
  4. x.method(:public).call("test1".to_sym)  
  5. x.method(:public).call("test1=".to_sym)  
  6. x.method(:attr_accessor).call("test2".to_sym)  
  7. x.method(:public).call("test2".to_sym)  
  8. x.method(:public).call("test2=".to_sym)  
  9. x.method(:attr_accessor).call("test3".to_sym)  
  10. x.method(:public).call("test3".to_sym)  
  11. x.method(:public).call("test3=".to_sym)  
  12. y = Test1.new  # also can use x.new  
  13. y.test1 = 'Hello'  
  14. y.test2 = 'Ruby'  
  15. y.test3 = 1.86  
  16. puts y.class  
  17. puts y.test1, y.test2, y.test3  

原理就是利用 module_eval 定义一个空类,然后利用 const_get 获取到该类的引用,最后利用反射机制调用 attr_accessor、public 等方法完成类的定义。

这样做有什么好处呢?好处是,只要我们知道类名及其属性名,就可以动态的创建一个类,这在反序列化未知类的对象时是非常有用的。

但是上面的方法看上去还是比较麻烦,下面定义一个通用的:

 

Ruby代码  

  1. class Object  
  2.   def self.attr_add(*symbols)  
  3.     symbols.each { |sym|  
  4.       self.send(:attr_accessor, sym)  
  5.       self.send(:public, sym, sym.to_s.concat('=').to_sym)  
  6.     }  
  7.     self  
  8.   end  
  9.   def self.define_class(name, *attrs)  
  10.     (name.split('::').inject(self) { |x, y| x.const_set(y, Class.new) }).attr_add(*attrs)  
  11.   end  
  12.   def self.class_get(name)  
  13.     name.split("::").inject(self) {|x,y| x.const_get(y) }  
  14.   end  
  15. end  

现在用 define_class 定义类,用 class_get 获取类就方便多了。

感谢您关注我的个人博客!
为了您的更好的阅读和留言,建议您注册用户,这样您可以获得更大的权限,以及更方便的留言。
注册只需要一分钟的时间。但是您需要提供您的邮箱。注册后,密码会自动发到您的邮箱,请在第一次登录时修改。
我承诺不会将您的Email泄露给他人,或者发送垃圾邮件。

用户登录

我的微博

feedsky
抓虾
google reader
my yahoo
newsgator
bloglines
鲜果
哪吒
有道
QQ邮箱
九点
帮看