1

I'm trying to achieve something that is for sure possible but I'm not able to put it into to find it from the docuemntation.

In a nutshell, I would like to define methods dynamically:

Initial point:

class Foo < Bar
  def baz
    RecordLoader.for(Baz).load(object.baz_id)
  end

  def qux
    RecordLoader.for(Quz).load(object.qux_id)
  end
end

class Bar
end

I would like to be able to change it to

class Foo < Bar
  record_loader_for :baz
  record_loader_for :qux
end

class Bar
  def self.record_loader_for(attribute)
    define_method attribute.to_s do
      # What is missing here?
    end
  end
end

I'm trying to figure out how I can use the value of attribute to write something like

RecordLoader.for(attribute.to_s.classify.constantize). # <- attribute is local to the class
            .load(object.send("#{attribute.to_s}_id")) # <- object is local to the instance

1 Answer 1

1

You can go with class_eval and generate your method into string:

  def self.record_loader_for(attribute)
    class_eval <<~RUBY, __FILE__ , __LINE__ + 1
      def #{attribute}
        RecordLoader.for(#{attribute.to_s.classify}).load(#{attribute}_id)
      end
    RUBY
  end

but in fact, define_method should work too, ruby will save closure from the method call:

require 'active_support'
require 'active_support/core_ext'
require 'ostruct'

class RecordLoader
  def self.for(cls)
    new(cls)
  end

  def initialize(cls)
    @cls = cls
  end

  def load(id)
    puts "loading #{@cls} id #{id}"
  end
end

class Baz; end

class Bar
  def object
    OpenStruct.new(baz_id: 123, qux_id:321)
  end

  def self.record_loader_for(attribute)
    define_method attribute.to_s do
      RecordLoader.for(attribute.to_s.classify.constantize).
        load(object.send("#{attribute.to_s}_id"))
    end
  end
end

class Foo < Bar
  record_loader_for :baz
  record_loader_for :qux
end

Foo.new.baz

class_eval is slower to define method, but resulting method executes faster and does not keep references to original closure context, define_method is the opposite - defines faster, but method runs slower.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.