在Ruby中动态创建类和添加方法

时间:2012-03-05 20:44:10

标签: ruby metaprogramming datamapper

如何在不使用“eval”的情况下创建新类并添加一些方法?

这是我正在努力做的事情;我想改变这种结构:

obj = [
{
    :scope => 'account',
    :fields => [
        { :title => 'title', :length => 64, :required => true   },
        { :title => 'email', :length => 256, :required => true, :type => 'email'    }
    ],
    :before_save => Proc.new{
        #do something here
    },
},

{
    :scope => 'product',
    :fields => [
        { :title => 'title', :length => 64, :required => true   },
        { :title => 'description', :length => 256, :required => true    },
        { :title => 'cost', :required => true, :type => 'decimal'   }
    ]
    },
]

进入这个:

class Account
    include DataMapper::Resource

    property :id,       Serial
    property :title,    String, :length => 64, :required => true
    property :email,    String, :length => 256, :required => true

    def before_save
        #do something here
    end
end

...

谢谢!

2 个答案:

答案 0 :(得分:2)

正如安德鲁所说,动态创建类有不同的方法。这可能就是其中之一:

假设您从一个DM模型开始(没有使用DM,从文档中获取第一个):

class Post
  include DataMapper::Resource

  property :id,         Serial    # An auto-increment integer key
  property :title,      String    # A varchar type string, for short strings
  property :body,       Text      # A text block, for longer string data.
  property :created_at, DateTime  # A DateTime, for any date you might like.
end

并且您想要从表单

的散列中给出的元数据动态创建它
{:ClassName => {:field1 => :Type1, :field2 => :Type2 ...}}

你可以这样做:

require 'data_mapper'

models = {:Post => {
  :id => :Serial,
  :title => :String,
  :body => :Text
}}

models.each do |name, fields|
  klass = Class.new do
    include DataMapper::Resource

    fields.each do |field_name, field_type|
      property(field_name, const_get(field_type))
    end
  end
  Object.const_set(name, klass)
end

关键方法:

答案 1 :(得分:0)

如果您想查看一个真实示例,请参阅此库中的代码:https://github.com/apohllo/rod/blob/v0.7.x/lib/rod/model.rb#L410