-
-
Save ryanlecompte/1283413 to your computer and use it in GitHub Desktop.
# First the end result of what we want: | |
class Foo | |
before_hook :whoa | |
before_hook :amazing | |
def test | |
puts "This is kinda cool!" | |
end | |
def amazing | |
puts "Pretty amazing!" | |
end | |
def whoa | |
puts "Whoa!" | |
end | |
end | |
Foo.new.test | |
# OUTPUT BELOW | |
Whoa! | |
Pretty amazing! | |
This is kinda cool! | |
# And this is how I implemented it: | |
# Demonstrates how to provide ActiveRecord-like before_filter | |
# hooks for arbitrary classes. | |
module ExecutionHooks | |
# this method is invoked whenever a new instance method is added to a class | |
def method_added(method_name) | |
# do nothing if the method that was added was an actual hook method, or | |
# if it already had hooks added to it | |
return if hooks.include?(method_name) || hooked_methods.include?(method_name) | |
add_hooks_to(method_name) | |
end | |
# this is the DSL method that classes use to add before hooks | |
def before_hook(method_name) | |
hooks << method_name | |
end | |
# keeps track of all before hooks | |
def hooks | |
@hooks ||= [] | |
end | |
private | |
# keeps track of all currently hooked methods | |
def hooked_methods | |
@hooked_methods ||= [] | |
end | |
def add_hooks_to(method_name) | |
# add this method to known hook mappings to avoid infinite | |
# recursion when we redefine the method below | |
hooked_methods << method_name | |
# grab the original method definition | |
original_method = instance_method(method_name) | |
# re-define the method, but notice how we reference the original | |
# method definition | |
define_method(method_name) do |*args, &block| | |
# invoke the hook methods | |
self.class.hooks.each do |hook| | |
method(hook).call | |
end | |
# now invoke the original method | |
original_method.bind(self).call(*args, &block) | |
end | |
end | |
end | |
# Make it available to all classes. | |
Class.send(:include, ExecutionHooks) |
It works with ruby 2, maybe you missed the last line to include in all classes
Class.send(:include, ExecutionHooks)
Or for a single class just
extend ExecutionHooks
In the class file
Thanks for this. I created different solution with this
http://stackoverflow.com/questions/29785454/call-before-methods-in-model-on-ruby/29837450#29837450
Thanks for this!
Any suggestions on passing a variable to the before_hook
?
e.g.: before_hook :refresh_user_token(user)
Thanks a lot, it helps me track of execution order of methods call. Just modified line 72 to method(hook).call(method_name)
and set before_hook : print_executed_action
Thanks.. very inspiring
I have created a version for a simple around_action
like functionality:
Thanks for this solution.
Any idea on how can we extend this before_hook
for Superclass as well? This before_hook
works when hook is added to a method of any class and method is called directly but doesn't work when the hook is added to a method of its superclass.
Thanks in advance!
It doesn't work here with ruby 2
undefined method before_hook for Foo:Class (NoMethodError)