class Module

Source from www.erikveen.dds.nl/monitorfunctions/index.html

Public Instance Methods

post_condition(*method_names, &block1) click to toggle source
# File lib/wrap_method.rb, line 135
def post_condition(*method_names, &block1)
  pre_and_post_condition(false, true, *method_names, &block1)
end
pre_and_post_condition(pre, post, *method_names, &block1) click to toggle source
# File lib/wrap_method.rb, line 139
def pre_and_post_condition(pre, post, *method_names, &block1)
  method_names.flatten.each do |method_name|
    wrap_method(method_name) do |org_method, args2, block2, obj2|
      block1.call(obj2, method_name, args2, block2)   if pre

      res     = org_method.call(*args2, &block2)      if org_method

      block1.call(obj2, method_name, args2, block2)   if post

      res
    end
  end
end
pre_condition(*method_names, &block1) click to toggle source

Since adding code at the beginning or at the end of an instance method is very common, we simplify this by providing the next methods. Althoug they're named *_condition, they're not checking anything. They should be named *_action. But pre_action is harder to remember than pre_condition. So I stick to the latter.

# File lib/wrap_method.rb, line 131
def pre_condition(*method_names, &block1)
  pre_and_post_condition(true, false, *method_names, &block1)
end
wrap_method(*method_names, &block1) click to toggle source

This wrap_method is low-level stuff. If you just want to add code to a method, scroll down to pre_condition and post_condition. They're much easier to use.

# File lib/wrap_method.rb, line 23
  def wrap_method(*method_names, &block1)
    raise ArgumentError, "method_name is missing"       if method_names.empty?
    raise ArgumentError, "block is missing"             unless block1

    Thread.exclusive do
      method_names.flatten.each do |method_name|
        count =
        Module.module_eval do
          @_wm_count_ ||= 0
          @_wm_count_ +=1
        end

        module_eval <<-EOF

          # Get the method which is to be wrapped.
          method = instance_method(:"#{method_name}")   rescue nil

          # But it shouldn't be defined in a super class...
          if method.to_s != "#<UnboundMethod: " + self.to_s + "##{method_name}>"
            method      = nil
          end

          if method.nil? and ($VERBOSE or $DEBUG)
            $stderr.puts \
              "Wrapping a non-existing method ["+self.to_s+"##{method_name}]."
          end

          # Store the method-to-be-wrapped and the wrapping block.
          define_method(:"_wm_previous_#{method_name}_#{count}_") do
            [method, block1]
          end

          # Avoid this stupid "warning: method redefined".
          unless :#{method_name} == :initialize
            undef_method(:"#{method_name}")     rescue nil
          end

            # Define __class__ and __kind_of__.

          define_method(:__class__) \
                    {Object.instance_method(:class).bind(self).call}

          define_method(:__kind_of__) \
                    {|s| Object.instance_method(:"kind_of?").bind(self).call(s)}

            # Define the new method.

          def #{method_name}(*args2, &block2)
            if self.__kind_of__(Module)
              context   = metaclass
            else
              context   = self.__class__
            end

            # Retrieve the previously stored method-to-be-wrapped (old),
            # as well as the wrapping block (new).
            # Note: An UnboundMethod of self.superclass.metaclass can't be
            # bound to self.metaclass, so we "walk up" the class hierarchy.
            previous    = context.instance_method(
                              :"_wm_previous_#{method_name}_#{count}_")

            begin
              previous  = previous.bind(zelf ||= self)
            rescue TypeError => e
              retry     if zelf = zelf.superclass
            end

            old, new    = previous.call

            # If there's no method-to-be-wrapped in the current class, we 
            # should look for it in the superclass.
            old ||=
              context.superclass.instance_method(:"#{method_name}") rescue nil

            # Since old is an unbound method, we should bind it.
            # Note: An UnboundMethod of self.superclass.metaclass can't be
            # bound to self.metaclass, so we "walk up" the class hierarchy.
            begin
              old &&= old.bind(zelf ||= self)
            rescue TypeError => e
              retry     if zelf = zelf.superclass
            end

              # Finally...

            new.call(old, args2, block2, self)
          end
        EOF
      end
    end
  end
wrap_module_method(*method_names, &block1) click to toggle source
# File lib/wrap_method.rb, line 115
def wrap_module_method(*method_names, &block1)        # Deprecated
  if $VERBOSE or $DEBUG
    $stderr.puts "Module#wrap_module_method is deprecated."
    $stderr.puts "Use aModule.metaclass.wrap_method instead."
  end

  metaclass.wrap_method(*method_names, &block1)
end