论坛首页 编程语言技术论坛

领略一下ruby的DSL能力

浏览 10932 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-05-05  
在rails里面,我们可以用很方便的声明方式来定义model之间的关联关系,例如:

class Topic < ActiveRecord::Base
  has_many :posts
  belongs_to :user
end


那has_many和belongs_to究竟是什么东西呢?其实他们是Topic类的class method,标准写法是:

class Topic < ActiveRecord::Base
  Topic.has_many(:posts)
  Topic.belongs_to(:user)
end


那么has_many可以给我们带来什么呢?类方法has_many在被执行的时候,给Topic的对象实例添加了一系列方法:posts, posts<<, orders.push......等等。所以当我们在model里面声明has_many,belongs_to等对象关系的时候,一系列相关的对象方法就被自动添加进来了。

既然明白了rails的小把戏,让我们来自己试试看吧:
module M
  def self.included(c)
    c.extend(G)
  end
  module G
    def generate_method(*args)
      args.each do |method_name|
        define_method(method_name) { puts method_name }
      end
    end
end
end

class C
  include M
  generate_method :method1, :method2
end

c = C.new
c.method1
c.method2



我们定义了一个声明generate_method,可以接受多个symbol,来动态的创建同名的方法。现在我们在类C里面使用这个声明:generate_method :method1, :method2,当然我们需要include模块M。为什么rails的model不需要include相关的模块呢?当然是因为Topic的父类ActiveRecord::Base已经include了模块Associations了。

类C通过include模块M,调用了模块M的一个included回调接口,让类C去extend模块G,换句话来说就是,通过include模块M,来给类C动态添加一个类方法generate_method。

这个generate_method被定义在模块G当中,它接受一系列参数,来动态创建相关的方法。于是我们就实现了这样的DSL功能:

通过在类C里面声明generate_method :method1, :method2,让类C动态的添加了两个实例方法method1,method2,是不是很有意思?

实际上rails的对象关联声明也是以同样的方式实现的。
   发表时间:2007-05-09  
看了以后很有帮助!
0 请登录后投票
   发表时间:2007-06-01  
请问robbin:
Topic.has_many(:posts)  
Topic.belongs_to(:user)
这两个类方法(以及其它类似的方法)是在什么地方定义的??
0 请登录后投票
   发表时间:2007-06-03  
看看rails的源代码,
其中大量用到了method_missing
然后将params传到一个method generator函数中

动态地分析是否可以添加/定义这个函数

很powerful

不过,也使得代码不好读,太动态了

浅见
0 请登录后投票
   发表时间:2007-06-05  
好像楼上的并没有回答我的问题咧?
0 请登录后投票
   发表时间:2007-06-14  
请问robbin先生,您用的是什么文本编辑器,我也想用:)
看着挺舒服的。
0 请登录后投票
   发表时间:2007-06-17  
lzqjj 写道
好像楼上的并没有回答我的问题咧?


To lzqjj:
這個嘛.. 事實上看看ActiveRecord的源代碼即可明瞭:)
0 请登录后投票
   发表时间:2007-06-25  
请Robbin解释一下,这两行方法在什么时候执行啊?搞不太懂耶。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics