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 获取类就方便多了。

 

 

 

标签: Ruby

« 上一篇 | 下一篇 »

只显示10条记录相关文章

发表评论

评论 (必须):