From: Robert Klemme Date: 2011-01-25T23:19:07+09:00 Subject: Re: Surely there's a better way to do this... (implementing a DSL) On Tue, Jan 25, 2011 at 4:10 AM, Tony Arcieri wrote: > I'm trying to write a method that builds a class and takes arguments from > the outer scope when doing so: > >    def awesome_mcjobify(state, options = {}, &action) >      subject_class = @subject_class > >      job = Class.new do >        metaclass = class << self; self; end > >        metaclass.send :define_method, :perform do |id| >          subject = subject_class.find(id) >          action subject >        end > >        metaclass.send :define_method, :action, &action >      end > >      subject_class.const_set "#{state.to_s.camelize}Job", job >    end > > This is trying to do a lot of things at once and feels icky. It's building a > class that responds to a couple of methods, encapsulates a bit of state > (into the class itself, I guess?), then sticks that class namespaced > underneath another given class. > > Refactor me? :) I know there's supposed to be define_singleton_method in > 1.9, but using define_*method at all (not to mention send :define_method) > seems a lot messier than it could potentially be. > > Any suggestions? First thing that strikes me odd is that you define methods on the singleton class, i.e. instance methods of the newly created class. What do you need a class for then - especially since your new class inherits Object (which means, it does not inherit particular instance functionality)? From what I see you need something that responds to "perform" by doing two things 1. find a subject via the subject class based on the id method parameter 2. invoke the block passed with the subject found Wouldn't this do what you need? Proxy = Struct.new :subject_class, :action do def perform(id) subject = subject_class.find id action[subject] end end def awesome_mcjobify(state, options = {}, &action) Proxy[@subject_class, action] end It does not even need metaprogramming... Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/