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.
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
find a subject via the subject class based on the id method parameter
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
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)?
Because I’m building these classes for another API, namely Resque. I’m
creating a DSL for building Resque jobs, which the documentation defines
thusly:
Resque jobs are Ruby classes (or modules) which respond to
the perform method. Here’s an example:
class Archive @queue = :file_serve
def self.perform(repo_id, branch = ‘master’)
repo = Repository.find(repo_id)
repo.create_archive(branch)
end
end
So unfortunately I can’t change the form of the classes I’m trying to
generate (with the possible exception of changing them into modules)
However, it seems that GitHub - defunkt/resque: Moved to resque/resque uses classes
in order to be able to distribute them to different machines. In that
case you would need to make sure the class has a name and is known at
all nodes. In that case it might be wise to also add a String
argument to the method call.
Btw, if my assumption is correct you might get away with simple
instances that implement important methods (#name for example) and are
assigned to constants which reflect their name.
Side note: code distribution is the Achilles heel of distributed job
systems. You either have to distribute code along with the request
which bloats queues and introduces security risks. Or you distribute
it via some other channel and then you can get typical versioning
issues…
Kind regards
robert
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.