Created
January 2, 2011 02:23
-
-
Save chischaschos/762214 to your computer and use it in GitHub Desktop.
A callbacks DSL creation example with ruby metaprogramming
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*.swp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require './wrappable-other' | |
class CallbackTest | |
extend Wrappable | |
def original | |
puts "Original method" | |
end | |
def before | |
puts "Before method" | |
end | |
wrap :original do | |
before_run :before | |
after_run lambda { puts "After with lambda" } | |
end | |
end | |
CallbackTest.new.original |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Wrappable | |
class WrapperOptions | |
attr_accessor :before, :after | |
def initialize(&block) | |
instance_eval(&block) | |
end | |
private | |
def before_run(before) | |
@before = before | |
end | |
def after_run(after) | |
@after = after | |
end | |
end | |
def wrap(original_method, &block) | |
wrapper_options = WrapperOptions.new(&block) | |
wrapper_options.before = normalize_call(wrapper_options.before) | |
wrapper_options.after = normalize_call(wrapper_options.after) | |
alias_method :old_method, original_method | |
define_method original_method do | |
send(wrapper_options.before) | |
send(:old_method) | |
send(wrapper_options.after) | |
end | |
end | |
private | |
def normalize_call(method) | |
class_eval do | |
if method.respond_to? :call | |
method_name = "_#{method}" | |
define_method(method_name , &method) | |
method_name | |
else | |
method | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Wrappable | |
def self.included(klass) | |
klass.extend ClassMethods | |
end | |
class Wrapper | |
def initialize(original_method, receiver, &block) | |
instance_eval &block | |
create(receiver, original_method) | |
end | |
def create(receiver, original_method) | |
receiver.send(:alias_method, :original_method, original_method) | |
before_method = receiver.instance_method(@before) | |
after_method = receiver.instance_method(@after) | |
receiver.send(:define_method, original_method) do | |
before_method.bind(self).call | |
send :original_method | |
after_method.bind(self).call | |
end | |
end | |
def before_run(method) | |
@before = method | |
end | |
def after_run(method) | |
@after = method | |
end | |
end | |
module ClassMethods | |
def wrap(original_method, &block) | |
Wrapper.new(original_method, self, &block) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment