【问题标题】:Ruby Metaprogramming: Dynamically defining method based on child instance attributeRuby 元编程:基于子实例属性动态定义方法
【发布时间】:2015-04-26 08:24:27
【问题描述】:

我正在创建一个应该包装 ActiveRecord 对象的演示者基类。

class BasePresenter
  def initialize object
    @object = object
  end

  def method_missing(*args, &block)
    @object.send(*args, &block)
  end

  def self.wrap collection
    collection.map { |item| new item }
  end
end

对于每个子类,我希望能够在初始化时根据子属性动态定义一个方法,所以 ListPresenter 就像:

class ListPresenter < BasePresenter
end

应该使用包装的 List 对象的 id 响应 list_id

如果不在每个子类上定义它,我该怎么做?我在def initialize(object) 中尝试了以下方法,但都不起作用。 如果可能的话,宁愿避免使用基于eval 的方法,因为我听说这是一种代码味道。

类方法(将方法添加到 BasePresenter,而不是子类)

self.class.send(:define_method, "#{object.class.name.underscore}_id") do
  @object.id
end

元类方法(无法访问实例变量object@object):

class << self
  define_method "#{@object.class.name.underscore}_id" do
    @object.id
  end
end

【问题讨论】:

  • 当你说这些不起作用时,会发生什么?
  • @FrederickCheung:添加了对以前方法发生的情况的说明。
  • @fylooi:为什么要在id 前面加上模型名称(即list_id),而不是仅仅将id 委托给模型?
  • 你把这些调用放在哪里定义_method?
  • @Drenmi:不是一个具体的用例,而是按照重新定义模型属性同时保持原始属性可用的思路进行思考。还认为有条件地装饰某些类型的子模型可能会派上用场。 @FrederickCheung:在def initialize object对象赋值后

标签: ruby-on-rails ruby


【解决方案1】:

每当子类继承 BasePresenter 时,使用 Class#inherited 挂钩动态添加方法。

class BasePresenter
  def self.inherited(sub_klass)
    sub_klass.send(:define_method, "#{sub_klass.name.underscore.split("_")[0...-1].join("_")}_id") do
      instance_variable_get("@object").id
    end
  end
end


class ListPresenter < BasePresenter
end

# Sending a rails model object below
l = ListPresenter.new(User.first)
l.list_id #=> 1

【讨论】:

  • 为什么需要.split("_")[0...-1].join("_")
  • "ListPresenter".underscore #=> "list_presenter"。我只提取“列表”。同样"FooBarPresenter".underscore #=> "foo_bar_presenter" 你想要 "foo_bar_id"。因此.split("_")[0...-1].join("_") 。假设所有 sub_klasses 的名称中都有 Presenter 后缀。
  • 啊。我实际上想要@objects 课程。没问题,这将是微不足道的,因为这使我可以访问@object
  • 哦。是的,您可以轻松地在该方法中检索它并执行必要的操作
【解决方案2】:

我建议你看看Class#inherited

你可以在你的基类中定义这个方法,它会激怒继承类的方法......

我可能会在我坐在电脑前进行编辑,但这很简单。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-01
    • 2011-10-08
    • 2012-07-04
    • 2013-11-17
    • 2013-05-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多