Last active
August 29, 2015 14:02
-
-
Save dsalahutdinov/21a7260657ea4f4fe5dd to your computer and use it in GitHub Desktop.
Wrapper оборачивает вызовы методов вызовами before- и after-методов
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
# wrap_method оборачивает вызовы методов вызовами before- и after-методов | |
# Возможно множественная обертка, в ходе которой образуется method-chain | |
module Wrappable | |
class WrapperOptions | |
attr_reader :before_callback, :after_callback | |
def initialize(&block) | |
instance_eval(&block) | |
end | |
def before(method_name) | |
@before_callback = method_name | |
end | |
def after(method_name) | |
@after_callback = method_name | |
end | |
end | |
def wrap_method(method_name, &block) | |
@wrap_count = @wrap_count.nil? ? 0 : @wrap_count + 1 | |
old_method_name = "#{method_name}_wrappable_#{@wrap_count}" | |
wrapper_options_hash = instance_variable_get("@wrapper_options") | |
instance_variable_set("@wrapper_options", wrapper_options_hash = {}) if (wrapper_options_hash.nil?) | |
wrapper_options_hash[old_method_name] = WrapperOptions.new(&block) | |
alias_method old_method_name, method_name | |
define_method(method_name) do | |
wrapper_options = self.class.instance_variable_get("@wrapper_options")[old_method_name] | |
send(wrapper_options.before_callback) unless wrapper_options.before_callback.nil? | |
send(old_method_name) | |
send(wrapper_options.after_callback) unless wrapper_options.after_callback.nil? | |
end | |
end | |
end | |
class My | |
extend(Wrappable) | |
def target_method | |
puts "puts target_method" | |
end | |
def before1 | |
puts "before1" | |
end | |
def before2 | |
puts "before2" | |
end | |
def after1 | |
puts "after1" | |
end | |
def after2 | |
puts "after2" | |
end | |
wrap_method :target_method do | |
before :before1 | |
after :after1 | |
end | |
wrap_method :target_method do | |
before :before2 | |
after :after2 | |
end | |
end | |
My.new.target_method | |
# => before2 | |
# => before1 | |
# => puts target_method | |
# => after1 | |
# => after2 | |
# злоумышленники случайно или нет перезаписали локальную переменную | |
My.instance_variable_set("@wrapper_options", nil) | |
My.new.target_method | |
# NoMethodError: undefined method `[]' for nil:NilClass |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Реализовано на без статьи http://blog.crowdint.com/2011/01/14/building-a-basic-dsl-to-create-callbacks-in-ruby.html