Reputation: 3870
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
Upvotes: 5
Views: 1268
Reputation: 13014
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
Upvotes: 4
Reputation: 19221
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.
Upvotes: 2