Ruby class << self 元编程问题

miclle · 2011年12月13日 · 最后由 scriptfans 回复于 2012年02月21日 · 6368 次阅读

User Model:

class User < ActiveRecord::Base
  has_one :profile, :dependent => :destroy
  delegate :gender, :to => :profile, :prefix=> false, :allow_nil => true
  delegate :bio, :to => :profile, :prefix=> false, :allow_nil => true
  ... ...
end

问题来了,如果 profile 里有很多方法我想通过 delegate 这样加到 user 中来,要写很多 delegate...造轮子了

看到过有人写过这样的代码

class Post < ActiveRecord::Base

  STATUSES = ['draft', 'published', 'spam']
  validate_inclusion_of :status, :in => STATUSES

  class <<self
    STATUSES.each do |status_name|
      define_method "all_#{status_name}" do
        find(:all, :conditions => { :status => status_name }
      end
    end
  end

end

想请教下,怎么通过这种方法解决写多个 delegate 的问题

delegate :gender, :bio, :a, :b, :c, :to => :profile, :prefix=> false, :allow_nil => true

从楼主的标题看来楼主不懂元编程 不懂元编程的人写出来的元编程往往更难维护... 建议楼主或者先把 Ruby 基础语法和先研究明白,或者系统学习一下元编程,或者干脆直接写几个 delegate

其实几次 delegate 虽然不 DRY,但是几乎木有什么额外的维护成本....

如果真的很多,可以 Extract model code to Module.去看看 ihower 的 slide 啦:-)

#2 楼 @hooopo 是的,我一直做前端,刚开始写 ROR,学习了,谢谢大家

#2 楼 @hooopo ihover 的哪个 slide?好像没见过

def delegate(*methods)
  options = methods.pop
  unless options.is_a?(Hash) && to = options[:to]
    raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)."
  end

  if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/
    raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
  end

  prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_"

  methods.each do |method|
    module_eval(<<-EOS, "(__DELEGATION__)", 1)
      def #{prefix}#{method}(*args, &block)
        #{to}.__send__(#{method.inspect}, *args, &block)
      end
    EOS
  end
end

看了源码就知道怎么写了吧

这是元编程问题吗?... 我可能会用 with_options(options) 方法来处理。

-_-#我感觉元编程核心就是eval。。。

楼上,非也非也,元编程的核心应该是对象模型⋯⋯ 详情可以参见《Metaprogramming Ruby》,中文版《Ruby 元编程》已经上架。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号