Class: CheapAdvice

Inherits:
Object
  • Object
show all
Includes:
Options
Defined in:
lib/cheap_advice.rb,
lib/cheap_advice/trace.rb,
lib/cheap_advice/configuration.rb

Overview

Provides cheap advice mechanism for Ruby. kurt dot ruby at kurtstephens dot com

Defined Under Namespace

Modules: Options, Trace Classes: ActivationRecord, Advised, Configuration, Error

Constant Summary

EMPTY_Hash =
{ }.freeze
EMPTY_Array =
[ ].freeze
NULL_PROC =
lambda { | ar | }
NULL_AROUND_PROC =
lambda { | ar, result | result.call }

Instance Attribute Summary (collapse)

Instance Method Summary (collapse)

Methods included from Options

#[], #[]=

Constructor Details

- (CheapAdvice) initialize(*opts, &blk)

options:

:before
:after
:around


45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/cheap_advice.rb', line 45

def initialize *opts, &blk
  super()

  @advised = [ ]
  @advised_for = { }

  opts_hash = Hash === opts[-1] ? opts.pop : { }
  opts_key = opts.shift
  @options = opts_hash

  @before = (opts_key == :before ? blk : opts_hash[:before]) || 
    NULL_PROC
  @after  = (opts_key == :after  ? blk : opts_hash[:after])  || 
    NULL_PROC
  @around = (opts_key == :around ? blk : opts_hash[:around]) || 
    NULL_AROUND_PROC

  @blk = blk
end

Instance Attribute Details

- (Object) advised

Returns the value of attribute advised



33
34
35
# File 'lib/cheap_advice.rb', line 33

def advised
  @advised
end

- (Object) advised_extend

Module to extend new Advised objects with.



36
37
38
# File 'lib/cheap_advice.rb', line 36

def advised_extend
  @advised_extend
end

- (Object) after

Returns the value of attribute after



33
34
35
# File 'lib/cheap_advice.rb', line 33

def after
  @after
end

- (Object) around

Returns the value of attribute around



33
34
35
# File 'lib/cheap_advice.rb', line 33

def around
  @around
end

- (Object) before

Returns the value of attribute before



33
34
35
# File 'lib/cheap_advice.rb', line 33

def before
  @before
end

- (Object) options

Returns the value of attribute options



33
34
35
# File 'lib/cheap_advice.rb', line 33

def options
  @options
end

Instance Method Details

- (Object) advise!(mod, method, *opts)

Apply advice a method.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/cheap_advice.rb', line 68

def advise! mod, method, *opts
  return mod.map { | x | advise! x, method, *opts } if 
    Array === mod
  return method.map { | x | advise! mod, x, *opts } if 
    Array === method

  opts_hash = Hash === opts[-1] ? opts.pop : { }
  kind = opts.shift
  kind ||= :instance

  method = method.to_sym

  @mutex.synchronize do
    advised = advised_for mod, method, kind, opts_hash
    
    advised.enable! # Should this really be automatically enabled??
    
    advised
  end
end

- (Object) advised_for(mod, method, kind, opts)



97
98
99
100
# File 'lib/cheap_advice.rb', line 97

def advised_for mod, method, kind, opts
  (@advised_for[[ mod, method, kind ]] ||=
    construct_advised_for(mod, method, kind)).set_options!(opts)
end

- (Object) advised_select(mod, method, kind)



89
90
91
92
93
94
95
# File 'lib/cheap_advice.rb', line 89

def advised_select mod, method, kind
  @advised.select do | ad |
    (mod ? mod == ad.mod : true) &&
      (method ? method == ad.method : true) &&
      (kind ? kind == ad.kind : true)
  end
end

- (Object) construct_advised_for(mod, method, kind)



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/cheap_advice.rb', line 102

def construct_advised_for mod, method, kind
  advice = self
  
  advised = Advised.new(advice, mod, method, kind)
  
  advised.register_advice_methods!
  
  advised.mod_target.instance_eval do
    define_method advised.new_method do | *args, &block |
      ar = ActivationRecord.new(advised, self, args, block)
      
      do_result = Proc.new do
        self.__send__(advised.before_method, ar)
        begin
          ar.result = self.__send__(advised.old_method, *ar.args, &ar.block)
        rescue Exception => err
          ar.error = err
        ensure
          self.__send__(advised.after_method, ar)
        end
        
        ar.result
      end
      
      self.__send__(advised.around_method, ar, do_result)
      
      raise ar.error if ar.error
      
      ar.result
    end
  end

  advised.extend(@advised_extend) if @advised_extend

  @advised << advised
    
  advised
end

- (Object) disable! Also known as: unadvise!



142
143
144
145
146
147
# File 'lib/cheap_advice.rb', line 142

def disable!
  @mutex.synchronize do
    @advised.each { | x | x.disable! }
  end
  self
end

- (Object) enable! Also known as: readvise!



151
152
153
154
155
156
# File 'lib/cheap_advice.rb', line 151

def enable!
  @mutex.synchronize do
    @advised.each { | x | x.enable! }
  end
  self
end