I'm creating a presenter base class which is supposed to wrap an ActiveRecord object.
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
For each child class, I would like to be able to dynamically define a method based on a child attribute at initialization, so a ListPresenter like:
class ListPresenter < BasePresenter
end
should respond to list_id with the wrapped List object's id.
How would I do that short of defining it on every child class? I've tried the following in def initialize(object), both of which do not work.
Would prefer to avoid eval based approaches if possible as I hear it's a code smell.
Class approach (adds the method to BasePresenter, not the child classes)
self.class.send(:define_method, "#{object.class.name.underscore}_id") do
  @object.id
end
Metaclass approach (unable to access instance variables object or @object):
class << self
  define_method "#{@object.class.name.underscore}_id" do
    @object.id
  end
end
                Use Class#inherited hook to dynamically add a method whenever sub-class inherits BasePresenter.
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
                        I recommend you have a look at Class#inherited.
You can define this method in your base class and it irate over the inheriting classes' methods...
I'll probably edit this once I'm sitting at my computer, but it's quite straightforward.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With