Class: Module

Inherits:
Object
  • Object
show all
Defined in:
lib/mole/module.rb

Instance Method Summary collapse

Instance Method Details

#after_mole_filtersObject


Holds after filters



181
182
183
# File 'lib/mole/module.rb', line 181

def after_mole_filters #:nodoc:
  @after_mole_filters ||= Hash.new{ |h,k| h[k] = [] }
end

#apply_after_filters(filters, clazz, key, ret_val, *a, &b) ⇒ Object

:nodoc:



252
253
254
255
256
257
258
259
# File 'lib/mole/module.rb', line 252

def apply_after_filters( filters, clazz, key, ret_val, *a, &b )   #:nodoc:              
  begin  
    filters.each { |r,m| r.send( m, clazz, key, ret_val, b, *a ) }
  rescue => ca_boom    
    ::Mole.logger.error ">>> MOle Failure: After-Filter -- " + ca_boom
    ca_boom.backtrace.each { |l| ::Mole.logger.error l }           
  end    
end

#apply_before_filters(filters, clazz, key, *a, &b) ⇒ Object

:nodoc:



243
244
245
246
247
248
249
250
# File 'lib/mole/module.rb', line 243

def apply_before_filters( filters, clazz, key, *a, &b )          #:nodoc:              
  begin
    filters.each { |r,m| r.send( m, clazz, key, b, *a ) }
  rescue => ca_boom
    ::Mole.logger.error ">>> MOle Failure: Before-Filter -- " + ca_boom
    ca_boom.backtrace.each { |l| ::Mole.logger.error l }           
  end    
end

#apply_perf_filters(elapsed, filters, clazz, key, ret_val, *a, &b) ⇒ Object

:nodoc:



261
262
263
264
265
266
267
268
269
270
# File 'lib/mole/module.rb', line 261

def apply_perf_filters( elapsed, filters, clazz, key, ret_val, *a, &b )       #:nodoc:
  begin
    if ( elapsed >= Mole.perf_threshold  )
      filters.each { |r,m| r.send( m, clazz, key, elapsed, ret_val, b, *a ) }            
    end
  rescue => ca_boom
    ::Mole.logger.error ">>> MOle Failure: Perf-Filter -- " + ca_boom
    ca_boom.backtrace.each { |l| ::Mole.logger.error l }             
  end    
end

#apply_unchecked_filters(boom, filters, clazz, key, *a, &b) ⇒ Object

:nodoc:



272
273
274
275
276
277
278
279
# File 'lib/mole/module.rb', line 272

def apply_unchecked_filters( boom, filters, clazz, key, *a, &b ) #:nodoc:
  begin
    filters.each { |r,m| r.send( m, clazz, key, boom, b, *a ) }
  rescue => ca_boom                               
    ::Mole.logger.error ">>> MOle Failure: Unchecked-Filter -- " + ca_boom
    ca_boom.backtrace.each { |l| ::Mole.logger.error l }             
  end                                                                       
end

#before_mole_filtersObject


Holds before filters



175
176
177
# File 'lib/mole/module.rb', line 175

def before_mole_filters #:nodoc:    
  @before_mole_filters ||= Hash.new{ |h,k| h[k] = [] }
end

#mole_after(opts = {}, &interceptor) ⇒ Object

intercepts a feature after the feature is called. During the callback you will have access to the object ( context ) on which the call is intercepted, as well as the arguments/block and return values the feature was issued with.

Example:

MyClass.mole_after( :feature => :blee ) do |context, feature, ret_val, block, *args|
  Mole::Moler.mole_it( context, feature, context.session[:user_id], 
                      :args => args )
end

This will wrap the method blee with an after interceptor. After the blee call is issued on MyClass, control will be handed to the after interceptor.

Options:

:feature

The name of the feature to be intercepted

:interceptor

The class name of your interceptor class. If no interceptor block is specified

:method

The name of the method to callback the interceptor on once an exception condition has been trapped.



126
127
128
129
130
131
132
133
134
135
# File 'lib/mole/module.rb', line 126

def mole_after(opts = {}, &interceptor)
  raise "Missing :feature option" if opts[:feature].nil? or opts[:feature].to_s.empty?    
  opts[:interceptor] ||= interceptor
  opts[:method] ||= :call
  feature = opts[:feature].to_s
  if after_mole_filters[feature].empty?
    wrap feature 
    after_mole_filters[feature] << [opts[:interceptor], opts[:method]]
  end
end

#mole_before(opts = {}, &interceptor) ⇒ Object

intercepts a feature before the feature is called. During the callback you will have access to the object ( context ) on which the call is intercepted, as well as the arguments/block, the feature was issued with.

Example:

MyClass.mole_before( :feature => :blee ) do |context, feature, block, *args|
  Mole::Moler.mole_it( context, feature, context.session[:user_id], 
                      :args => args )
end

This will wrap the method blee with a before interceptor. Before the blee call is issued on MyClass, control will be handed to the before interceptor.

Options:

:feature

The name of the feature to be intercepted

If you elect not to use the block form of the call, you can pass in the following arguments to the option hash:

:interceptor

The class name of your interceptor class. If no interceptor block is specified

:method

The name of the method to callback the interceptor on once an exception condition has been trapped.



96
97
98
99
100
101
102
103
104
105
# File 'lib/mole/module.rb', line 96

def mole_before(opts={}, &interceptor)  
  raise "Missing :feature option" if opts[:feature].nil? or opts[:feature].to_s.empty?
  opts[:interceptor] ||= interceptor
  opts[:method] ||= :call
  feature = opts[:feature].to_s
  if before_mole_filters[feature].empty?
    wrap feature 
    before_mole_filters[feature] << [opts[:interceptor], opts[:method]]
  end
end

#mole_dump(msg = nil) ⇒ Object


Dumps moled feature info



139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/mole/module.rb', line 139

def mole_dump( msg=nil )
  puts "\n------------------------------------------------------------------"
  puts "From #{msg}" if msg
  puts "MOle Info for class <- #{self} ->"
  puts "\nBefore filters"
  before_mole_filters.keys.sort.each { |k| puts "\t#{k} --> #{before_mole_filters[k]}" }
  puts "\nAfter filters"
  after_mole_filters.keys.sort.each { |k| puts "\t#{k} --> #{after_mole_filters[k]}" }
  puts "\nUnchecked filters"
  unchecked_mole_filters.keys.sort.each { |k| puts "\t#{k} --> #{unchecked_mole_filters[k]}" }
  puts "\nPerf filters"
  perf_mole_filters.keys.sort.each { |k| puts "\t#{k} --> #{perf_mole_filters[k]}" }    
  puts "---------------------------------------------------------------------\n"    
end

#mole_perf(opts = {}, &interceptor) ⇒ Object

intercepts a collection of features and wrap performance check based on the specified :perf_threshold. The trigger defaults to 5 secs if not explicitly set.

Example:

MyClass.mole_perf do |context, action, elapsed_time, ret, block, *args|                            
  Mole::DbMole.perf_it( context.session[:user_id], 
                        :controller   => context.class.name,
                        :action       => action,                           
                        :elapsed_time => "%3.3f" % elapsed_time )
end

This will trap all public methods on the MyClass that takes more than :perf_threshold to complete. You can override this default by using the option :features => [m1,m2,…]. This is handy for controller moling rails and merb context.

If you elect not to use the block form of the call, you can pass in the following arguments to the option hash:

:interceptor

The class name of your interceptor class

:method

The name of the method to callback the interceptor on once a perf condition has been trapped.



30
31
32
33
34
35
36
37
38
# File 'lib/mole/module.rb', line 30

def mole_perf( opts={}, &interceptor )    
  opts[:interceptor] ||= interceptor
  opts[:method]      ||= :call             
  opts[:features]    ||= instance_methods( false )
  opts[:features].each do |feature|  
    wrap feature
    perf_mole_filters[feature.to_s] << [opts[:interceptor], opts[:method]]
  end    
end

#mole_unchecked(opts = {}, &interceptor) ⇒ Object

monitors a collections of features and wrap rescue logic to trap unchecked exceptions. You can handle to trap differently by either logging the event in the db or sending out email/IM notification.

Example:

MyClass.mole_unchecked do |context, action, boom, block, *args|
  Mole::Moler.check_it( context.session[:user_id], 
                       :controller => context.class.name,  
                       :action     => action,
                       :boom       => boom )    
end

This will wrap all public instance methods on MyClass. If any of these methods raises an unchecked exception, the MOle will surface the condition. This call also takes in a :features option to specify a list of methods if the default instance methods is not suitable, you can pass in a collection of methods that you wish to mole. This is handy in the case of Rails/Merb where conveniences are provided to gather controller actions

If you elect not to use the block form of the call, you can pass in the following arguments to the option hash:

:interceptor

The class name of your interceptor class

:method

The name of the method to callback the interceptor on once an exception condition has been trapped.



65
66
67
68
69
70
71
72
73
# File 'lib/mole/module.rb', line 65

def mole_unchecked( opts={}, &interceptor )    
  opts[:interceptor] ||= interceptor
  opts[:method]      ||= :call             
  opts[:features]    ||= instance_methods( false )
  opts[:features].each do |feature|  
    wrap feature
    unchecked_mole_filters[feature.to_s] << [opts[:interceptor], opts[:method]]
  end
end

#perf_mole_filtersObject


Holds perf around filters



187
188
189
# File 'lib/mole/module.rb', line 187

def perf_mole_filters #:nodoc:
  @perf_mole_filters ||= Hash.new{ |h,k| h[k] = []} 
end

#unchecked_mole_filtersObject


Holds unchecked exception filters



193
194
195
# File 'lib/mole/module.rb', line 193

def unchecked_mole_filters #:nodoc:
  @unchecked_mole_filters ||= Hash.new{ |h,k| h[k] = []} 
end

#wrap(method) ⇒ Object


Wrap method call

TODO Add support for wrapping class methods ??



208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/mole/module.rb', line 208

def wrap( method ) #:nodoc:
  return if wrapped?( method )  
  begin
    between = instance_method( method )
  rescue
    # between = find_public_class_method( method )
    raise "Unable to find moled feature `#{method}" unless(between)
  end
  method_name, punctuation = clean_method_name( method )
  code = <<-code
    def #{method_name}_with_mole#{punctuation} (*a, &b)
      key                 = '#{method}'
      klass               = self.class
      between             = klass.wrapped[key]
      ret_val             = nil
      klass.apply_before_filters( klass.before_mole_filters[key], self, key, *a, &b ) if klass.before_mole_filters[key]
      begin                                          
        elapsed = Benchmark::realtime do 
          ret_val = between.bind(self).call( *a, &b ) 
        end   
        klass.apply_perf_filters( elapsed, klass.perf_mole_filters[key], self, key, ret_val, *a, &b ) if klass.perf_mole_filters[key]
      rescue => boom   
        klass.apply_unchecked_filters( boom, klass.unchecked_mole_filters[key], self, key, *a, &b ) if klass.unchecked_mole_filters[key]
        raise boom            
      end                                                                 
      klass.apply_after_filters( klass.after_mole_filters[key], self, key, ret_val, *a, &b ) if klass.after_mole_filters[key]
      ret_val
    end
  code
   
  module_eval                code               
  alias_method_chain method, "mole" 
  wrapped[method.to_s]       = between
end

#wrappedObject


Log wrapped class



283
284
285
# File 'lib/mole/module.rb', line 283

def wrapped #:nodoc:
  @wrapped ||= {}
end

#wrapped?(which) ⇒ Boolean


Check if method has been wrapped

Returns:

  • (Boolean)


289
290
291
# File 'lib/mole/module.rb', line 289

def wrapped?(which) #:nodoc:
  wrapped.has_key?(which.to_s)
end