I'm hoping to implement something like all of the great plugins out there for ruby, so that you can do this:
acts_as_commentable
has_attached_file :avatar
But I have one constraint:
That helper method can only include a module; it can't define any variables or methods.
The reason for this is because, I want the options hash to define something like type
, and that could be converted into one of say 20 different 'workhorse' modules, all of which I could sum up in a line like this:
def dynamic_method(options = {})
include ("My::Helpers::#{options[:type].to_s.camelize}").constantize(options)
end
Then those 'workhorses' would handle the options, doing things like:
has_many "#{options[:something]}"
Here's what the structure looks like, and I'm wondering if you know the missing piece in the puzzle:
# 1 - The workhorse, encapsuling all dynamic variables
module My::Module
def self.included(base)
base.extend ClassMethods
base.class_eval do
include InstanceMethods
end
end
module InstanceMethods
self.instance_eval %Q?
def #{options[:my_method]}
"world!"
end
?
end
module ClassMethods
end
end
# 2 - all this does is define that helper method
module HelperModule
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def dynamic_method(options = {})
# don't know how to get options through!
include My::Module(options)
end
end
end
# 3 - send it to active_record
ActiveRecord::Base.send(:include, HelperModule)
# 4 - what it looks like
class TestClass < ActiveRecord::Base
dynamic_method :my_method => "hello"
end
puts TestClass.new.hello #=> "world!"
That %Q?
I'm not totally sure how to use, but I'm basically just wanting to somehow be able to pass the options
hash from that helper method into the workhorse module. Is that possible? That way, the workhorse module could define all sorts of functionality, but I could name the variables whatever I wanted at runtime.
Method arguments These can be called as the default argument type. When you don't know which type of argument to use, use the required arguments. They are order dependent and as the name suggests, required. If you don't pass them during method invocation Ruby will throw an ArgumentError .
Actually, Ruby facilitates the use of composition by using the mixin facility. Indeed, a module can be included in another module or class by using the include , prepend and extend keywords.
I'm working on something similar, based on some clever ruby code I saw once but now can't find again. I have things almost working, but it messes up things like self.included and self.extended in your Module, for somewhat obvious reasons that could be worked around, but I don't like how complicated it would get. I think there's one trick I haven't thought of yet that would make this work more perfectly.
So this may or may not work for you, but what I'm trying is the idea of an anonymous module created dynamically based on your options. (I think 'type' may be a reserved word but I'm not sure, so let's say "options" instead). Check out this idea:
Module HelperModule
def[](options)
Module.new do
include HelperModule
define_method(:options) { options }
end
end
def options
raise TypeError.new("You need to instantiate this module with [], man!")
end
end
obj = Object.new
obj.extend(HelperModule)
obj.options => raises TypeError
obj = Object.new
obj.extend(HelperModule[ :my_option => "my_option" ]
obj.options => { my_option => "my_option }
Kind of neat, huh? But isn't quite good enough for me yet, because the actual Module you get from HelperModule[options] doesn't have the self.included and self.extended from the original HelperModule. I guess I could just define self.included and self.extended in the anon module, but I don't like the code confusion. I also don't like having to explicitly say "include HelperModule" in the anonymous module, I'd rather it be, like "self", except "self" doesn't mean the right thing there, so that doesn't work.
Ah, wait, guess what I just discovered: If this general approach seems like it should work for you, it can be supplied by the paramix gem: http://rubyworks.github.com/paramix/
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