Class: Module

Inherits:
Object show all
Defined in:
lib/wrap_method.rb

Overview

Instance Method Summary collapse

Instance Method Details

#post_condition(*method_names, &block1) ⇒ Object



135
136
137
# 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) ⇒ Object



139
140
141
142
143
144
145
146
147
148
149
150
151
# 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) ⇒ Object

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.



131
132
133
# 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) ⇒ Object

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.

Raises:

  • (ArgumentError)


23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# 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) ⇒ Object

Deprecated



115
116
117
118
119
120
121
122
# 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