-
-
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 doesn't work here with ruby 2
undefined method before_hook for Foo:Class (NoMethodError)
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!
What I was looking for. Right on. Thanks!