def install_hook(type, target_method, method_sym, scope, &block)
assert_kind_of 'target_method', target_method, Symbol
assert_kind_of 'method_sym', method_sym, Symbol unless method_sym.nil?
assert_kind_of 'scope', scope, Symbol
if !block_given? and method_sym.nil?
raise ArgumentError, "You need to pass 2 arguments to \"#{type}\"."
end
if method_sym.to_s[-1,1] == '='
raise ArgumentError, "Methods ending in = cannot be hooks"
end
unless [ :class, :instance ].include?(scope)
raise ArgumentError, 'You need to pass :class or :instance as scope'
end
if registered_as_hook?(target_method, scope)
hooks = hooks_with_scope(scope)
if !(hooks[target_method][:in] <=> self)
before_hook_name = hook_method_name(target_method, 'execute_before', 'hook_stack')
after_hook_name = hook_method_name(target_method, 'execute_after', 'hook_stack')
hooks[target_method][:in].class_eval "remove_method :\#{before_hook_name} if instance_methods(false).any? { |m| m.to_sym == :\#{before_hook_name} }\ndef \#{before_hook_name}(*args)\nsuper\nend\n\nremove_method :\#{after_hook_name} if instance_methods(false).any? { |m| m.to_sym == :\#{before_hook_name} }\ndef \#{after_hook_name}(*args)\nsuper\nend\n", __FILE__, __LINE__ + 1
while !(hooks[target_method][:in] <=> self) do
hooks[target_method][:in] = hooks[target_method][:in].superclass
end
define_hook_stack_execution_methods(target_method, scope)
hooks[target_method][:in].class_eval{define_advised_method(target_method, scope)}
end
else
register_hook(target_method, scope)
hooks = hooks_with_scope(scope)
end
if block
method_sym = "__hooks_#{type}_#{quote_method(target_method)}_#{hooks[target_method][type].length}".to_sym
if scope == :class
meta_class.instance_eval do
define_method(method_sym, &block)
end
else
define_method(method_sym, &block)
end
end
hooks[target_method][type] << { :name => method_sym, :from => self }
define_hook_stack_execution_methods(target_method, scope)
end