`

Meta-Programming in Ruby: 动态生成class,并添加attribute和method。

阅读更多
Ruby的动态语言特性和强大的meta-programming模型一直是让我这种Java程序员唏嘘感慨。看着RoR可以实现那么多魔术般的事情而不费吹灰之力,我着实想好好学学Ruby的meta-programming。可惜这方面资料好像比较少(至少我是没有找到什么好的,JavaEye这里讨论的也不多),我只能硬着头皮自己慢慢摸索。这篇文章只能算是一个最简单的入门,给大家展示一下Ruby中的meta-programming大概是什么样子。

下面代码大概会做一下事情:
  1. 根据指定的txt文件动态创建一个class,例如“people.txt”会被创建为People。
  2. txt文件的第一行是以“,”分隔的字符串,我会把它们作为class的属性动态加入class。
  3. 动态声明class的initialize方法和to_s方法。
代码如下:
ruby 代码
 
  1. class MetaProgrammingTest  
  2.     
  3.   # class method,用来根据给定的文件动态创建一个新的class。  
  4.   def self.create_class(file_name)  
  5.     # 去掉文件的扩展名.txt,并令首字母大写。例如"people.txt" -> 'People'    
  6.     class_name = File.basename(file_name,".txt").capitalize  
  7.     # 动态创建一个class,并使用class_name对其命名。  
  8.     klass = Object.const_set(class_name,Class.new)  
  9.       
  10.     # 读取文件的第一行,并以","为分隔符把每个token放到数组names中。  
  11.     first_line = ''  
  12.     File.open(file_name) { |io| first_line = io.gets.chomp }  
  13.     names = first_line.split(",")  
  14.       
  15.     # class_eval会执行其closure中的代码。  
  16.     klass.class_eval do  
  17.       # 把names数组中所有的字符串声明为class的attribute。  
  18.       # 注意:这里做了2两件事情,声明了这些attribute,并创建了get和set这些attribute的方法。  
  19.       attr_accessor *names  
  20.         
  21.       # define_method用来定义class的instance method。
  22.       # 参数是方法名,后面的closure是方法体,closure的参数就是方法的参数。  
  23.       define_method(:initializedo |*values|  
  24.         # 对class的每个attribute,用传入的参数进行赋值。  
  25.         names.each_with_index do |name,i|   
  26.           instance_variable_set("@"+name, values[i])  
  27.         end  
  28.       end  
  29.         
  30.       # 定义to_s方法。  
  31.       # self.class返回当前对象的class(即"People")
  32.       # self.send()得到其参数代表的attribute的值。  
  33.       define_method(:to_sdo  
  34.         str = "[#{self.class}:"  
  35.         names.each {|name| str << " #{name}=#{self.send(name)}" }  
  36.         str + "]"  
  37.       end  
  38.         
  39.     end  
  40.       
  41.     # 返回这个动态创建的类。  
  42.     klass  
  43.   end  
  44.     
  45. end  
  46.   
  47. # 测试代码  
  48. klass = MetaProgrammingTest.create_class('people.txt') # "people.txt"的内容为"id,name,age"  
  49. klass_instance = klass.new('001', 'Allen Young', 23)  
  50. puts klass_instance.to_s    
  51. # 输出  
  52. puts klass_instance.inspect
  53. # 输出#  

怎么样?真的是非常强大吧。如果什么时候,Java也能有这么强大的meta-programming就好了。
分享到:
评论

相关推荐

    wsdl2h解析器和soapcpp2编译器

    - **-x**:不生成 `_XMLany/anyAttribute` 扩展性元素。 - **-y**:为结构体和枚举类型生成类型别名。 - **-z**:为了向后兼容性生成基于指针的数组 (`)。 ##### 输入源 - `infile.wsdl`:WSDL 文件输入。 - `in...

    hibernate配置详解

    &lt;meta attribute="class-description"&gt;这是一个Person类的描述。&lt;/meta&gt; &lt;meta attribute="class-scope"&gt;指定类作用域。&lt;/meta&gt; &lt;meta attribute="extends"&gt;指定父类名称。&lt;/meta&gt; ...

    Cxf常用命令

    它提供了丰富的命令行工具,使得开发人员能够方便地处理WSDL(Web服务描述语言)和XSD(XML Schema Definition)文件,以及生成Java代码。本文将详细介绍CXF中的两个主要命令:`xsd2wsdl` 和 `wsdl2java`。 ### `...

    twig模板手册

    - **自定义测试**:添加新的逻辑测试条件,如 `divisibleby`。 - **自定义节点**:创建新的节点类型以支持特定的语法结构。 - **自定义访问器**:允许模板直接访问对象的属性或方法。 - **自定义函数**:增加新的...

    import-html-entry:HTML输入原始码

    文章发布于,通过对比JS Entry,完整介绍了HTML Entry的原理,实际...-- mark the entry script with entry attribute --&gt; &lt; script src =" https://unpkg.com/mobx@5.0.3/lib/mobx.umd.js " entry &gt; &lt;/ sc

    TCT-Instagram-Feed:将JSON feed从JSON数据添加到页面-源码

    标记之前添加滑块JS 将[removed]和代码添加到functions.php或代码片段短代码[instafeed user="ATTRIBUTE_NAME"] 要使用grid = [instafeed user =“ feed-grid”],请使用滑块= [instafeed user =“ feed-slider”] ...

    2004-CAD快捷键.pdf

    - RECREATE: 重新生成图形(Recreate) - RECTANGLE: 画矩形(Rectangle) - DODONUT: 画圆环(Donut) - ELELLIPSE: 画椭圆(Ellipse) - REGREGION: 画区域(Region) - DIV: 分割(Divide) - DIVIDES: 点的分割...

    node-sequelize-starter:节点JS,Sequelize,Express和MySQL

    首先通过git克隆仓库并安装依赖项: git clone --depth 1 --single-branch https://github.com/shivammakwan/node-sequelize-starter.git your-project-name cd your-project-name npm install 关注自述文件 将.env...

    eslint-plugin-require-duplicate:ESLint插件可以发现重复的要求样式导入

    将require-duplicate添加到.eslintrc配置文件的plugins部分。 您可以省略eslint-plugin-前缀: { " plugins " : [ " require-duplicate " ] } 然后在“规则”部分下配置要使用的规则。 { " rules " : { " ...

    xslt元素使用说明

    - `&lt;xsl:attribute-set&gt;` 元素用于定义一组属性,并可以被其他模板重用。 - **语法**: - `&lt;xsl:attribute-set name="..."&gt;...&lt;/xsl:attribute-set&gt;` - **属性**: - `name`:必需属性,指定属性集的名称。 - **...

    FFMPEG移植s3c2440

    - **解决方法**:修改 `ffmpeg-0.5/libavcodec/arm/asm.S` 文件中的第 24 行和第 28 行,将 `.eabi_attribute` 替换为 `@.eabi_attribute`;同时修改 `ffmpeg-0.5/libavcodec/arm/dsputil_arm_s.S` 文件中的第 641 ...

    extjs 总结

    EXTJS TreePanel 和 Ext.data.Node 提供了丰富的功能,可以灵活地处理树形数据结构,支持动态加载、选择、事件监听等多种操作。在实际开发中,开发者可以根据需求自定义扩展这些组件,以满足复杂的应用场景。同时,...

    python类和函数教程-python基础教程:类.pdf

    我们可以访问或修改实例的属性,甚至可以动态地添加新的属性。实例方法通过`self`参数与实例关联,允许访问和修改实例的属性。 总结来说,Python中的类是一种强大的工具,它使得我们能够构建复杂的数据结构并封装...

    综合Python备忘单.zip

    - 属性和方法:类中的变量和函数,如`self.my_attribute`和`self.my_method()`。 - 继承:一个类继承自另一个类,如`class ChildClass(ParentClass):`。 - 多态:子类对象可以被视为父类对象,调用父类方法。 - ...

    求解报错:AttributeError:module ‘os’ has no attribute ‘exit’

    python3 server.py 127.0.0.1 8888 ...AttributeError: module ‘os’ has no attribute ‘exit’ 部分代码入下: from socket import * import sys,os #实现登录 def do_login(s,user,name,addr): for i in user: i

    php易框架cheatsheet

    - **activeCheckbox($model, $attribute)**:为指定的模型和属性生成一个复选框。 - **activeCheckboxList($model, $attribute, $data)**:为指定的模型和属性生成一个复选框列表。 - **activeDropDownList($model, ...

    ios7 UIKit 框架文档

    - `+ (NSLayoutConstraint *)constraintWithItem:(id)firstItem attribute:(NSLayoutAttribute)firstAttribute relatedBy:(NSLayoutRelation)relation toItem:(id)secondItem attribute:(NSLayoutAttribute)...

    gnucash-to-beancount:Gnucash转Beancount转换器

    Gnucash转Beancount转换器 将您的Gnucash Sqlite3文件转换为Beancount文本分类帐。 需要Python 3.3+ 安装 pip install gnucash-to-beancount ... 测试仍然是使用diff和黄金文件的原始方法。 如果test.sh没有

Global site tag (gtag.js) - Google Analytics