aspector 0.13.1 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +26 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -11
- data/Changelog.md +59 -0
- data/Gemfile +9 -14
- data/Gemfile.lock +84 -50
- data/README.md +118 -0
- data/Rakefile +6 -22
- data/aspector.gemspec +15 -127
- data/benchmarks/after_benchmark.rb +28 -0
- data/benchmarks/around_advice_benchmark.rb +35 -0
- data/benchmarks/around_benchmark.rb +32 -0
- data/benchmarks/before_benchmark.rb +28 -0
- data/benchmarks/benchmark_helper.rb +17 -0
- data/benchmarks/combined_benchmark.rb +36 -0
- data/benchmarks/method_invocation_benchmark.rb +30 -0
- data/benchmarks/raw_benchmark.rb +39 -0
- data/examples/activerecord_hooks.rb +10 -15
- data/examples/around_example.rb +20 -31
- data/examples/aspector_apply_example.rb +10 -17
- data/examples/aspector_example.rb +7 -16
- data/examples/cache_aspect.rb +20 -30
- data/examples/design_by_contract.rb +20 -44
- data/examples/exception_handler.rb +12 -20
- data/examples/exception_handler2.rb +16 -24
- data/examples/implicit_method_option_test.rb +8 -16
- data/examples/interception_options_example.rb +71 -0
- data/examples/logging_aspect.rb +16 -24
- data/examples/process_aspector.rb +13 -0
- data/examples/retry_aspect.rb +20 -20
- data/lib/aspector.rb +17 -15
- data/lib/aspector/advice.rb +44 -57
- data/lib/aspector/advice_metadata.rb +10 -11
- data/lib/aspector/aspect_instances.rb +2 -3
- data/lib/aspector/base.rb +6 -368
- data/lib/aspector/base_class_methods.rb +24 -55
- data/lib/aspector/deferred_logic.rb +3 -4
- data/lib/aspector/deferred_option.rb +5 -10
- data/lib/aspector/interception.rb +356 -0
- data/lib/aspector/logger.rb +18 -45
- data/lib/aspector/logging.rb +10 -29
- data/lib/aspector/method_matcher.rb +5 -6
- data/lib/aspector/object_extension.rb +4 -12
- data/lib/aspector/version.rb +3 -0
- data/spec/examples_spec.rb +59 -0
- data/spec/functionals/aspect_for_multiple_targets_spec.rb +54 -0
- data/spec/functionals/aspect_interception_options_accessing_spec.rb +112 -0
- data/spec/functionals/aspect_on_a_class_spec.rb +159 -0
- data/spec/functionals/aspect_on_an_instance_spec.rb +66 -0
- data/spec/functionals/aspector_spec.rb +138 -0
- data/spec/functionals/aspects_combined_spec.rb +37 -0
- data/spec/functionals/aspects_execution_order_spec.rb +61 -0
- data/spec/functionals/aspects_on_private_methods_spec.rb +82 -0
- data/spec/spec_helper.rb +20 -21
- data/spec/support/class_builder.rb +44 -0
- data/spec/units/advice_spec.rb +49 -0
- data/spec/units/advices/after_spec.rb +328 -0
- data/spec/units/advices/around_spec.rb +336 -0
- data/spec/units/advices/before_filter_spec.rb +287 -0
- data/spec/units/advices/before_spec.rb +237 -0
- data/spec/units/advices/raw_spec.rb +67 -0
- data/spec/units/base_class_methods_spec.rb +262 -0
- data/spec/units/base_spec.rb +133 -0
- data/spec/units/deferred_logic_spec.rb +35 -0
- data/spec/units/logger_spec.rb +20 -0
- data/spec/units/logging_spec.rb +85 -0
- data/spec/units/method_matcher_spec.rb +95 -0
- data/spec/units/object_extension_spec.rb +11 -0
- data/spec/units/special_chars_spec.rb +128 -0
- metadata +98 -246
- data/.document +0 -5
- data/.rvmrc +0 -8
- data/README.rdoc +0 -80
- data/VERSION +0 -1
- data/performance-tests/after_test.rb +0 -25
- data/performance-tests/around_advice_benchmark.rb +0 -66
- data/performance-tests/around_test.rb +0 -27
- data/performance-tests/before_test.rb +0 -25
- data/performance-tests/combined_test.rb +0 -33
- data/performance-tests/method_invocation_test.rb +0 -25
- data/performance-tests/raw_test.rb +0 -37
- data/performance-tests/test_helper.rb +0 -9
- data/run_all_examples.sh +0 -12
- data/spec/functional/advices_on_private_methods_spec.rb +0 -21
- data/spec/functional/aspect_on_eigen_class_spec.rb +0 -72
- data/spec/functional/aspect_on_object_spec.rb +0 -20
- data/spec/functional/aspector_spec.rb +0 -140
- data/spec/functional/aspects_combined_spec.rb +0 -48
- data/spec/functional/execution_order_spec.rb +0 -42
- data/spec/unit/advice_spec.rb +0 -4
- data/spec/unit/after_spec.rb +0 -88
- data/spec/unit/around_spec.rb +0 -76
- data/spec/unit/base_class_methods_spec.rb +0 -28
- data/spec/unit/base_spec.rb +0 -112
- data/spec/unit/before_spec.rb +0 -125
- data/spec/unit/deferred_logic_spec.rb +0 -23
- data/spec/unit/method_matcher_spec.rb +0 -43
- data/spec/unit/raw_spec.rb +0 -53
- data/spec/unit/special_chars_spec.rb +0 -122
data/examples/logging_aspect.rb
CHANGED
@@ -1,44 +1,36 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'aspector'
|
2
3
|
|
3
|
-
|
4
|
+
# Example class to which we will apply our aspects
|
5
|
+
class ExampleClass
|
6
|
+
def test(input)
|
4
7
|
input.upcase
|
5
8
|
end
|
6
|
-
|
7
9
|
end
|
8
10
|
|
9
|
-
|
10
|
-
|
11
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
12
|
-
|
13
|
-
require 'aspector'
|
14
|
-
|
11
|
+
# Aspect used as a logging hookup
|
15
12
|
class LoggingAspect < Aspector::Base
|
16
|
-
|
17
13
|
ALL_METHODS = /.*/
|
18
14
|
|
19
|
-
around ALL_METHODS, :
|
15
|
+
around ALL_METHODS, except: :class, method_arg: true do |method, proxy, *args, &block|
|
20
16
|
class_method = "#{self.class}.#{method}"
|
21
17
|
puts "Entering #{class_method}: #{args.join(',')}"
|
22
|
-
result = proxy.call
|
18
|
+
result = proxy.call(*args, &block)
|
23
19
|
puts "Exiting #{class_method}: #{result}"
|
24
20
|
result
|
25
21
|
end
|
26
|
-
|
27
22
|
end
|
28
23
|
|
29
|
-
|
30
|
-
|
31
|
-
LoggingAspect.apply(A)
|
32
|
-
puts "LoggingAspect is applied"
|
24
|
+
LoggingAspect.apply(ExampleClass)
|
25
|
+
puts 'LoggingAspect is applied'
|
33
26
|
|
34
|
-
|
35
|
-
|
27
|
+
instance = ExampleClass.new
|
28
|
+
instance.test 'input'
|
36
29
|
|
37
30
|
LoggingAspect.disable
|
38
|
-
puts
|
39
|
-
|
31
|
+
puts 'LoggingAspect is disabled'
|
32
|
+
instance.test 'input'
|
40
33
|
|
41
34
|
LoggingAspect.enable
|
42
|
-
puts
|
43
|
-
|
44
|
-
|
35
|
+
puts 'LoggingAspect is enabled'
|
36
|
+
instance.test 'input'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'aspector'
|
3
|
+
|
4
|
+
# Aspect used to provide process logging
|
5
|
+
class ProcessLogging < Aspector::Base
|
6
|
+
after :spawn do |return_value, *args|
|
7
|
+
$stderr.puts args[0].inspect
|
8
|
+
return_value
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
ProcessLogging.apply(Process, class_methods: true)
|
13
|
+
Process.spawn('pwd')
|
data/examples/retry_aspect.rb
CHANGED
@@ -1,41 +1,41 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
require 'aspector'
|
2
3
|
|
4
|
+
# Example class to which we will apply our aspects
|
5
|
+
class ExampleClass
|
3
6
|
def test
|
4
7
|
puts 'test'
|
5
|
-
|
8
|
+
fail
|
6
9
|
end
|
7
|
-
|
8
10
|
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
13
|
-
|
14
|
-
require 'aspector'
|
15
|
-
|
12
|
+
# Aspect that will be used as a retry with counting
|
16
13
|
class RetryAspect < Aspector::Base
|
17
|
-
|
18
14
|
target do
|
19
|
-
def retry_this
|
20
|
-
proxy.call
|
21
|
-
rescue
|
15
|
+
def retry_this(proxy, &block)
|
16
|
+
proxy.call(&block)
|
17
|
+
rescue
|
22
18
|
@retry_count ||= 3
|
23
19
|
@retry_count -= 1
|
24
20
|
|
25
|
-
|
21
|
+
if @retry_count == 0
|
22
|
+
@retry_count = nil
|
23
|
+
raise
|
24
|
+
end
|
26
25
|
|
27
26
|
retry
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
30
|
around :retry_this
|
32
|
-
|
33
31
|
end
|
34
32
|
|
35
|
-
|
36
|
-
|
37
|
-
RetryAspect.apply A, :method => "test"
|
33
|
+
RetryAspect.apply(ExampleClass, method: :test)
|
38
34
|
|
39
|
-
|
40
|
-
a.test
|
35
|
+
instance = ExampleClass.new
|
41
36
|
|
37
|
+
begin
|
38
|
+
instance.test
|
39
|
+
rescue
|
40
|
+
puts 'Fails after 3 retries'
|
41
|
+
end
|
data/lib/aspector.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
-
require '
|
2
|
-
require 'aspector/logger'
|
3
|
-
|
4
|
-
require 'aspector/object_extension'
|
5
|
-
require 'aspector/module_extension'
|
6
|
-
|
7
|
-
require 'aspector/base'
|
8
|
-
require 'aspector/base_class_methods'
|
9
|
-
require 'aspector/advice'
|
10
|
-
require 'aspector/advice_metadata'
|
11
|
-
require 'aspector/method_matcher'
|
12
|
-
require 'aspector/deferred_logic'
|
13
|
-
require 'aspector/deferred_option'
|
14
|
-
|
15
|
-
require 'aspector/aspect_instances'
|
1
|
+
require 'logger'
|
16
2
|
|
3
|
+
%w(
|
4
|
+
version
|
5
|
+
logging
|
6
|
+
logger
|
7
|
+
object_extension
|
8
|
+
module_extension
|
9
|
+
advice
|
10
|
+
advice_metadata
|
11
|
+
interception
|
12
|
+
base
|
13
|
+
base_class_methods
|
14
|
+
method_matcher
|
15
|
+
deferred_logic
|
16
|
+
deferred_option
|
17
|
+
aspect_instances
|
18
|
+
).each { |scope| require "aspector/#{scope}" }
|
data/lib/aspector/advice.rb
CHANGED
@@ -1,92 +1,79 @@
|
|
1
1
|
module Aspector
|
2
|
+
# A single aspect advice representation
|
2
3
|
class Advice
|
4
|
+
# All available advices types that we support
|
5
|
+
TYPES = %i(
|
6
|
+
before
|
7
|
+
before_filter
|
8
|
+
after
|
9
|
+
around
|
10
|
+
raw
|
11
|
+
)
|
12
|
+
|
13
|
+
# Defines methods that allow us to check if an advice is of a given type
|
14
|
+
TYPES.each do |type_name|
|
15
|
+
# Defines constants like BEFORE, AFTER,etc
|
16
|
+
const_set(type_name.to_s.upcase, type_name)
|
17
|
+
|
18
|
+
# @return [Boolean] is advice of a given type?
|
19
|
+
# @example Check if advice is an after
|
20
|
+
# advice.after? #=> true
|
21
|
+
define_method :"#{type_name}?" do
|
22
|
+
type == type_name
|
23
|
+
end
|
24
|
+
end
|
3
25
|
|
4
|
-
|
5
|
-
AFTER = 2
|
6
|
-
AROUND = 3
|
7
|
-
RAW = 4
|
8
|
-
|
9
|
-
attr_reader :type, :method_matcher, :options, :advice_code, :advice_block
|
26
|
+
attr_reader :type, :method_matcher, :options, :advice_code, :advice_block, :name
|
10
27
|
attr_accessor :index
|
11
28
|
|
12
|
-
def initialize
|
13
|
-
@
|
14
|
-
@
|
29
|
+
def initialize(parent, type, method_matcher, with_method, options = {}, &block)
|
30
|
+
@type = type
|
31
|
+
@parent = parent
|
32
|
+
@options = options
|
33
|
+
@advice_block = block
|
15
34
|
@method_matcher = method_matcher
|
35
|
+
@name = @options[:name] || "advice_#{index}"
|
16
36
|
|
17
37
|
if with_method.is_a? Symbol
|
18
|
-
@with_method
|
38
|
+
@with_method = with_method
|
19
39
|
else
|
20
|
-
@advice_code
|
40
|
+
@advice_code = with_method
|
21
41
|
end
|
22
|
-
|
23
|
-
@options = options
|
24
|
-
@advice_block = block
|
25
|
-
end
|
26
|
-
|
27
|
-
def name
|
28
|
-
@options[:name] || "advice #{index}"
|
29
42
|
end
|
30
43
|
|
31
44
|
def with_method
|
32
|
-
|
33
|
-
|
34
|
-
|
45
|
+
return nil if @advice_code
|
46
|
+
|
47
|
+
@with_method ||= "aop_#{hash.abs}"
|
35
48
|
end
|
36
49
|
|
37
|
-
def match?
|
38
|
-
return if method == with_method
|
39
|
-
return unless @method_matcher.match?(method, context)
|
50
|
+
def match?(method, context = nil)
|
51
|
+
return false if method == with_method
|
52
|
+
return false unless @method_matcher.match?(method, context)
|
40
53
|
|
41
54
|
return true unless @options[:except]
|
42
55
|
|
43
56
|
@except ||= MethodMatcher.new(@options[:except])
|
44
57
|
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
def raw?
|
49
|
-
type == RAW
|
58
|
+
!@except.match?(method)
|
50
59
|
end
|
51
60
|
|
52
|
-
def
|
53
|
-
type == BEFORE
|
54
|
-
end
|
55
|
-
|
56
|
-
def after?
|
57
|
-
type == AFTER
|
58
|
-
end
|
59
|
-
|
60
|
-
def around?
|
61
|
-
type == AROUND
|
62
|
-
end
|
63
|
-
|
64
|
-
def type_name
|
65
|
-
case @type
|
66
|
-
when BEFORE then @options[:skip_if_false] ? "BEFORE_FILTER" : "BEFORE"
|
67
|
-
when AFTER then "AFTER"
|
68
|
-
when AROUND then "AROUND"
|
69
|
-
when RAW then "RAW"
|
70
|
-
else "UNKNOWN?!"
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def use_deferred_logic? logic
|
61
|
+
def use_deferred_logic?(logic)
|
75
62
|
method_matcher.use_deferred_logic? logic
|
76
63
|
end
|
77
64
|
|
78
65
|
def to_s
|
79
66
|
s = "#{name}: "
|
80
|
-
s <<
|
81
|
-
s <<
|
67
|
+
s << type.to_s.upcase
|
68
|
+
s << ' [' << @method_matcher.to_s << '] DO '
|
69
|
+
|
82
70
|
if @with_method
|
83
71
|
s << @with_method.to_s
|
84
72
|
else
|
85
|
-
s <<
|
73
|
+
s << 'stuff in block'
|
86
74
|
end
|
87
|
-
s <<
|
75
|
+
s << ' WITH OPTIONS ' << @options.inspect
|
88
76
|
s
|
89
77
|
end
|
90
|
-
|
91
78
|
end
|
92
79
|
end
|
@@ -1,18 +1,17 @@
|
|
1
1
|
module Aspector
|
2
|
+
# Metadata for Advice model
|
2
3
|
class AdviceMetadata
|
3
|
-
attr_reader :advice_type, :default_options
|
4
|
+
attr_reader :advice_type, :default_options
|
4
5
|
|
5
|
-
def initialize
|
6
|
-
@advice_type
|
7
|
-
@default_options
|
8
|
-
@mandatory_options = mandatory_options || {}
|
6
|
+
def initialize(advice_type, default_options = {})
|
7
|
+
@advice_type = advice_type
|
8
|
+
@default_options = default_options
|
9
9
|
end
|
10
10
|
|
11
|
-
BEFORE = new Aspector::Advice::BEFORE
|
12
|
-
BEFORE_FILTER = new Aspector::Advice::
|
13
|
-
AFTER = new Aspector::Advice::AFTER,
|
14
|
-
AROUND = new Aspector::Advice::AROUND
|
15
|
-
RAW = new Aspector::Advice::RAW
|
11
|
+
BEFORE = new Aspector::Advice::BEFORE
|
12
|
+
BEFORE_FILTER = new Aspector::Advice::BEFORE_FILTER
|
13
|
+
AFTER = new Aspector::Advice::AFTER, result_arg: true
|
14
|
+
AROUND = new Aspector::Advice::AROUND
|
15
|
+
RAW = new Aspector::Advice::RAW
|
16
16
|
end
|
17
17
|
end
|
18
|
-
|
@@ -1,12 +1,11 @@
|
|
1
1
|
module Aspector
|
2
2
|
class AspectInstances < Array
|
3
|
-
|
4
3
|
def apply_to_method method
|
5
4
|
each do |aspect_instance|
|
6
|
-
next if aspect_instance.options[:
|
5
|
+
next if aspect_instance.options[:existing_methods_only]
|
6
|
+
|
7
7
|
aspect_instance.apply_to_method method
|
8
8
|
end
|
9
9
|
end
|
10
|
-
|
11
10
|
end
|
12
11
|
end
|
data/lib/aspector/base.rb
CHANGED
@@ -2,379 +2,17 @@ require 'erb'
|
|
2
2
|
|
3
3
|
module Aspector
|
4
4
|
class Base
|
5
|
-
|
6
|
-
attr :target
|
7
|
-
attr :options
|
8
|
-
|
9
|
-
def initialize target, options = {}
|
10
|
-
@target = target
|
11
|
-
|
12
|
-
default_options = self.class.default_options
|
13
|
-
if default_options and not default_options.empty?
|
14
|
-
@options = default_options.merge(options)
|
15
|
-
else
|
16
|
-
@options = options
|
17
|
-
end
|
18
|
-
|
19
|
-
@wrapped_methods = {}
|
20
|
-
end
|
21
|
-
|
22
5
|
def disabled?
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
def logger
|
27
|
-
return @logger if @logger
|
28
|
-
|
29
|
-
@logger = Logging.get_logger(self)
|
30
|
-
@logger.level = self.class.logger.level
|
31
|
-
@logger
|
32
|
-
end
|
33
|
-
|
34
|
-
def advices
|
35
|
-
self.class.advices
|
36
|
-
end
|
37
|
-
|
38
|
-
def apply
|
39
|
-
include_extension_module
|
40
|
-
invoke_deferred_logics
|
41
|
-
define_methods_for_advice_blocks
|
42
|
-
add_to_instances unless @options[:old_methods_only]
|
43
|
-
apply_to_methods unless @options[:new_methods_only]
|
44
|
-
add_method_hooks unless @options[:old_methods_only]
|
45
|
-
# TODO: clear deferred logic results if they are not used in any advice
|
6
|
+
false
|
46
7
|
end
|
47
8
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
# iterating through all methods
|
53
|
-
methods = [@options[:method] || @options[:methods]]
|
54
|
-
methods.compact!
|
55
|
-
methods.flatten!
|
56
|
-
|
57
|
-
if not methods.empty? and methods.all?{|method| method.is_a? String or method.is_a? Symbol }
|
58
|
-
methods.each do |method|
|
59
|
-
apply_to_method(method.to_s)
|
60
|
-
end
|
61
|
-
|
62
|
-
return
|
63
|
-
end
|
64
|
-
|
65
|
-
context.public_instance_methods.each do |method|
|
66
|
-
apply_to_method(method.to_s, :public)
|
67
|
-
end
|
68
|
-
|
69
|
-
context.protected_instance_methods.each do |method|
|
70
|
-
apply_to_method(method.to_s, :protected)
|
71
|
-
end
|
72
|
-
|
73
|
-
if @options[:private_methods]
|
74
|
-
context.private_instance_methods.each do |method|
|
75
|
-
apply_to_method(method.to_s, :private)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def apply_to_method method, scope = nil
|
81
|
-
filtered_advices = filter_advices advices, method
|
82
|
-
return if filtered_advices.empty?
|
83
|
-
|
84
|
-
logger.log Logging::DEBUG, 'apply-to-method', method
|
85
|
-
|
86
|
-
scope ||=
|
87
|
-
if context.private_instance_methods.include?(RUBY_VERSION.index('1.9') ? method.to_sym : method.to_s)
|
88
|
-
:private
|
89
|
-
elsif context.protected_instance_methods.include?(RUBY_VERSION.index('1.9') ? method.to_sym : method.to_s)
|
90
|
-
:protected
|
91
|
-
else
|
92
|
-
:public
|
93
|
-
end
|
94
|
-
|
95
|
-
recreate_method method, filtered_advices, scope
|
96
|
-
end
|
97
|
-
|
98
|
-
private
|
99
|
-
|
100
|
-
def include_extension_module
|
101
|
-
if self.class.const_defined?(:ToBeIncluded)
|
102
|
-
context.send(:include, self.class.const_get(:ToBeIncluded))
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def deferred_logic_results logic
|
107
|
-
@deferred_logic_results[logic]
|
108
|
-
end
|
109
|
-
|
110
|
-
def get_wrapped_method_of method
|
111
|
-
@wrapped_methods[method]
|
112
|
-
end
|
113
|
-
|
114
|
-
# context is where advices will be applied (i.e. where methods are modified), can be different from target
|
115
|
-
def context
|
116
|
-
return @target if @target.is_a?(Module) and not @options[:class_methods]
|
117
|
-
|
118
|
-
class << @target
|
119
|
-
self
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def invoke_deferred_logics
|
124
|
-
return unless (logics = self.class.send :_deferred_logics_)
|
125
|
-
|
126
|
-
logics.each do |logic|
|
127
|
-
result = logic.apply context, self
|
128
|
-
if advices.detect {|advice| advice.use_deferred_logic? logic }
|
129
|
-
@deferred_logic_results ||= {}
|
130
|
-
@deferred_logic_results[logic] = result
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def define_methods_for_advice_blocks
|
136
|
-
advices.each do |advice|
|
137
|
-
next if advice.raw?
|
138
|
-
next unless advice.advice_block
|
139
|
-
context.send :define_method, advice.with_method, advice.advice_block
|
140
|
-
context.send :private, advice.with_method
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
def add_to_instances
|
145
|
-
return if advices.empty?
|
146
|
-
|
147
|
-
aspect_instances = context.instance_variable_get(:@aop_instances)
|
148
|
-
unless aspect_instances
|
149
|
-
aspect_instances = AspectInstances.new
|
150
|
-
context.instance_variable_set(:@aop_instances, aspect_instances)
|
151
|
-
end
|
152
|
-
aspect_instances << self
|
153
|
-
end
|
154
|
-
|
155
|
-
def add_method_hooks
|
156
|
-
return if advices.empty?
|
157
|
-
|
158
|
-
if @options[:class_methods]
|
159
|
-
return unless @target.is_a?(Module)
|
160
|
-
|
161
|
-
eigen_class = class << @target; self; end
|
162
|
-
orig_singleton_method_added = @target.method(:singleton_method_added)
|
163
|
-
|
164
|
-
eigen_class.send :define_method, :singleton_method_added do |method|
|
165
|
-
aop_singleton_method_added(method) do
|
166
|
-
orig_singleton_method_added.call(method)
|
167
|
-
end
|
168
|
-
end
|
169
|
-
else
|
170
|
-
eigen_class = class << @target; self; end
|
171
|
-
|
172
|
-
if @target.is_a? Module
|
173
|
-
orig_method_added = @target.method(:method_added)
|
174
|
-
else
|
175
|
-
orig_method_added = eigen_class.method(:method_added)
|
176
|
-
end
|
177
|
-
|
178
|
-
eigen_class.send :define_method, :method_added do |method|
|
179
|
-
aop_method_added(method) do
|
180
|
-
orig_method_added.call(method)
|
181
|
-
end
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def filter_advices advices, method
|
187
|
-
advices.select do |advice|
|
188
|
-
advice.match?(method, self)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
def recreate_method method, advices, scope
|
193
|
-
context.instance_variable_set(:@aop_creating_method, true)
|
194
|
-
|
195
|
-
raw_advices = advices.select {|advice| advice.raw? }
|
196
|
-
|
197
|
-
if raw_advices.size > 0
|
198
|
-
raw_advices.each do |advice|
|
199
|
-
if @target.is_a? Module and not @options[:class_methods]
|
200
|
-
@target.class_exec method, self, &advice.advice_block
|
201
|
-
else
|
202
|
-
@target.instance_exec method, self, &advice.advice_block
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
return if raw_advices.size == advices.size
|
207
|
-
end
|
208
|
-
|
209
|
-
begin
|
210
|
-
@wrapped_methods[method] = context.instance_method(method)
|
211
|
-
rescue
|
212
|
-
# ignore undefined method error
|
213
|
-
if @options[:old_methods_only]
|
214
|
-
logger.log Logging::WARN, 'method-not-found', method
|
215
|
-
end
|
216
|
-
|
217
|
-
return
|
218
|
-
end
|
219
|
-
|
220
|
-
before_advices = advices.select {|advice| advice.before? }
|
221
|
-
after_advices = advices.select {|advice| advice.after? }
|
222
|
-
around_advices = advices.select {|advice| advice.around? }
|
223
|
-
|
224
|
-
(around_advices.size - 1).downto(1) do |i|
|
225
|
-
advice = around_advices[i]
|
226
|
-
recreate_method_with_advices method, [], [], advice
|
9
|
+
def apply target, options = {}
|
10
|
+
default_options = self.class.default_options
|
11
|
+
if default_options and not default_options.empty?
|
12
|
+
options = default_options.merge(options)
|
227
13
|
end
|
228
14
|
|
229
|
-
|
230
|
-
|
231
|
-
context.send scope, method if scope != :public
|
232
|
-
ensure
|
233
|
-
context.send :remove_instance_variable, :@aop_creating_method
|
15
|
+
Interception.new(self, target, options).apply
|
234
16
|
end
|
235
|
-
|
236
|
-
def recreate_method_with_advices method, before_advices, after_advices, around_advice, is_outermost = false
|
237
|
-
aspect = self
|
238
|
-
|
239
|
-
code = METHOD_TEMPLATE.result(binding)
|
240
|
-
aspect.logger.log Logging::DEBUG, 'generate-code', method, code
|
241
|
-
context.class_eval code, __FILE__, __LINE__ + 4
|
242
|
-
end
|
243
|
-
|
244
|
-
METHOD_TEMPLATE = ERB.new <<-CODE, nil, "%<>"
|
245
|
-
|
246
|
-
orig_method = aspect.send :get_wrapped_method_of, '<%= method %>'
|
247
|
-
% if around_advice
|
248
|
-
wrapped_method = instance_method(:<%= method %>)
|
249
|
-
% end
|
250
|
-
|
251
|
-
define_method :<%= method %> do |*args, &block|
|
252
|
-
% if logger.visible?(Logging::TRACE)
|
253
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'enter-generated-method'
|
254
|
-
% end
|
255
|
-
|
256
|
-
if aspect.disabled?
|
257
|
-
% if logger.visible?(Logging::TRACE)
|
258
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'exit--generated-method'
|
259
|
-
% end
|
260
|
-
return orig_method.bind(self).call(*args, &block)
|
261
|
-
end
|
262
|
-
|
263
|
-
% if is_outermost
|
264
|
-
result = catch(:returns) do
|
265
|
-
% end
|
266
|
-
|
267
|
-
% before_advices.each do |advice|
|
268
|
-
# Before advice: <%= advice.name %>
|
269
|
-
% if logger.visible?(Logging::TRACE)
|
270
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'before-invoke-advice', '<%= advice.name %>'
|
271
|
-
% end
|
272
|
-
% if advice.advice_code
|
273
|
-
result = (<%= advice.advice_code %>)
|
274
|
-
% else
|
275
|
-
result = <%= advice.with_method %> <%
|
276
|
-
if advice.options[:aspect_arg] %>aspect, <% end %><%
|
277
|
-
if advice.options[:method_arg] %>'<%= method %>', <% end
|
278
|
-
%>*args
|
279
|
-
% end
|
280
|
-
% if logger.visible?(Logging::TRACE)
|
281
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'after--invoke-advice', '<%= advice.name %>'
|
282
|
-
% end
|
283
|
-
% if advice.options[:skip_if_false]
|
284
|
-
unless result
|
285
|
-
% if logger.visible?(Logging::TRACE)
|
286
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'exit-method-due-to-before-filter', '<%= advice.name %>'
|
287
|
-
% end
|
288
|
-
return
|
289
|
-
end
|
290
|
-
% end
|
291
|
-
% end
|
292
|
-
|
293
|
-
% if around_advice
|
294
|
-
# Around advice: <%= around_advice.name %>
|
295
|
-
% if logger.visible?(Logging::TRACE)
|
296
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'before-invoke-advice', '<%= around_advice.name %>'
|
297
|
-
% end
|
298
|
-
% if around_advice.advice_code
|
299
|
-
result = (<%= around_advice.advice_code.gsub('INVOKE_PROXY', 'wrapped_method.bind(self).call(*args, &block)') %>)
|
300
|
-
|
301
|
-
% else
|
302
|
-
% if logger.visible?(Logging::TRACE)
|
303
|
-
proxy = lambda do |*args, &block|
|
304
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'before-invoke-proxy'
|
305
|
-
res = wrapped_method.bind(self).call *args, &block
|
306
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'after--invoke-proxy'
|
307
|
-
res
|
308
|
-
end
|
309
|
-
result = <%= around_advice.with_method %> <%
|
310
|
-
if around_advice.options[:aspect_arg] %>aspect, <% end %><%
|
311
|
-
if around_advice.options[:method_arg] %>'<%= method %>', <% end
|
312
|
-
%>proxy, *args, &block
|
313
|
-
% else
|
314
|
-
result = <%= around_advice.with_method %> <%
|
315
|
-
if around_advice.options[:aspect_arg] %>aspect, <% end %><%
|
316
|
-
if around_advice.options[:method_arg] %>'<%= method %>', <% end
|
317
|
-
%>wrapped_method.bind(self), *args, &block
|
318
|
-
% end
|
319
|
-
% end
|
320
|
-
% if logger.visible?(Logging::TRACE)
|
321
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'after--invoke-advice', '<%= around_advice.name %>'
|
322
|
-
% end
|
323
|
-
|
324
|
-
% else
|
325
|
-
|
326
|
-
# Invoke original method
|
327
|
-
% if logger.visible?(Logging::TRACE)
|
328
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'before-wrapped-method'
|
329
|
-
% end
|
330
|
-
result = orig_method.bind(self).call *args, &block
|
331
|
-
% if logger.visible?(Logging::TRACE)
|
332
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'after--wrapped-method'
|
333
|
-
% end
|
334
|
-
|
335
|
-
% end
|
336
|
-
|
337
|
-
% unless after_advices.empty?
|
338
|
-
% after_advices.each do |advice|
|
339
|
-
# After advice: <%= advice.name %>
|
340
|
-
% if logger.visible?(Logging::TRACE)
|
341
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'before-invoke-advice', '<%= advice.name %>'
|
342
|
-
% end
|
343
|
-
% if advice.advice_code
|
344
|
-
result = (<%= advice.advice_code %>)
|
345
|
-
% else
|
346
|
-
% if advice.options[:result_arg]
|
347
|
-
result = <%= advice.with_method %> <%
|
348
|
-
if advice.options[:aspect_arg] %>aspect, <% end %><%
|
349
|
-
if advice.options[:method_arg] %>'<%= method %>', <% end %><%
|
350
|
-
if advice.options[:result_arg] %>result, <% end
|
351
|
-
%>*args
|
352
|
-
% else
|
353
|
-
<%= advice.with_method %> <%
|
354
|
-
if advice.options[:aspect_arg] %>aspect, <% end %><%
|
355
|
-
if advice.options[:method_arg] %>'<%= method %>', <% end
|
356
|
-
%>*args
|
357
|
-
% end
|
358
|
-
% end
|
359
|
-
% if logger.visible?(Logging::TRACE)
|
360
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'after--invoke-advice', '<%= advice.name %>'
|
361
|
-
% end
|
362
|
-
% end
|
363
|
-
% end
|
364
|
-
|
365
|
-
% if is_outermost
|
366
|
-
result
|
367
|
-
|
368
|
-
end # end of catch
|
369
|
-
% end
|
370
|
-
|
371
|
-
% if logger.visible?(Logging::TRACE)
|
372
|
-
aspect.logger.log <%= Logging::TRACE %>, '<%= method %>', 'exit--generated-method'
|
373
|
-
% end
|
374
|
-
result
|
375
|
-
end
|
376
|
-
CODE
|
377
|
-
|
378
17
|
end
|
379
18
|
end
|
380
|
-
|