Aliasing activerecord methods inside a plugin
I am trying to write a plugin that pseudonizes some methods in ActiveRecord like this:
class Foo < ActiveRecord::Base
include MyOwnPlugin
acts_as_my_own_plugin :methods => [:bar]
def bar
puts 'do something'
end
end
Inside the plugin:
module MyOwnPlugin
def self.included(base)
base.class_eval do
extend ClassMethods
end
end
module ClassMethods
def acts_as_my_own_plugin(options)
options[:methods].each do |m|
self.class_eval <<-END
alias_method :origin_#{m}, :#{m}
END
end
end
end
end
This approach will not work because when #acts_as_my_own_plugin is run, Foo # bar is not yet defined as it has not been started.
put actions_as_my_own_plugin: methods => [: bar] AFTER declaring the bar function will work. However, it is not.
I want action_as_my_own_plugin to sit on top of the class definition like most plugins do.
Is there an alternative approach to fulfill this condition?
source to share
Always remember: Ruby has a callback for almost everything.
Try the following:
module MyOwnPlugin
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
# gets called from within the models
def acts_as_my_own_plugin(options)
# store the list of methods in a class variable and symbolize them
@@methods = []
options[:methods].each { |method| @@methods << method.to_sym }
end
# callback method. gets called by ruby if a new method is added.
def method_added(name_of_method)
if @@methods.include?(name_of_method)
# delete the current method from our @@methods array
# in order to avoid infinite loops
@@methods.delete(name_of_method)
#puts "DEBUG: #{name_of_method.to_s} has been added!"
# code from your original plugin
self.class_eval <<-END
alias_method :origin_#{name_of_method}, :#{name_of_method}
def #{name_of_method}
puts "Called #{name_of_method}"
origin_#{name_of_method}
end
END
end
end
end
end
# include the plugin module in ActiveRecord::Base
# in order to make acts_as_my_own_plugin available in all models
ActiveRecord::Base.class_eval do
include MyOwnPlugin
end
# just call acts_as_my_own_plugin and define your methods afterwards
class Foo < ActiveRecord::Base
acts_as_my_own_plugin :methods => [:bar]
def bar
puts 'do something'
end
end
Hope this is helpful. The crazy things you can do with Ruby are just so cool;)
If you want to allow the definition of methods before and after the call acts_as_my_own_plugin
, you need to change the code again to allow this. However, the tricky part is done.
Disclaimer: This has been tested with Ruby 1.8.7. May not work with Ruby 1.9. *.
source to share