aquarium 0.1.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.
- data/CHANGES +4 -0
- data/EXAMPLES.rd +4 -0
- data/MIT-LICENSE +20 -0
- data/README +250 -0
- data/RELEASE-PLAN +1 -0
- data/Rakefile +236 -0
- data/UPGRADE +3 -0
- data/examples/aspect_design_example.rb +36 -0
- data/examples/design_by_contract_example.rb +88 -0
- data/examples/method_missing_example.rb +44 -0
- data/examples/method_tracing_example.rb +64 -0
- data/lib/aquarium.rb +7 -0
- data/lib/aquarium/aspects.rb +6 -0
- data/lib/aquarium/aspects/advice.rb +189 -0
- data/lib/aquarium/aspects/aspect.rb +577 -0
- data/lib/aquarium/aspects/default_object_handler.rb +27 -0
- data/lib/aquarium/aspects/dsl.rb +1 -0
- data/lib/aquarium/aspects/dsl/aspect_dsl.rb +61 -0
- data/lib/aquarium/aspects/join_point.rb +158 -0
- data/lib/aquarium/aspects/pointcut.rb +254 -0
- data/lib/aquarium/aspects/pointcut_composition.rb +36 -0
- data/lib/aquarium/extensions.rb +5 -0
- data/lib/aquarium/extensions/hash.rb +85 -0
- data/lib/aquarium/extensions/regexp.rb +20 -0
- data/lib/aquarium/extensions/set.rb +49 -0
- data/lib/aquarium/extensions/string.rb +13 -0
- data/lib/aquarium/extensions/symbol.rb +22 -0
- data/lib/aquarium/extras.rb +4 -0
- data/lib/aquarium/extras/design_by_contract.rb +64 -0
- data/lib/aquarium/finders.rb +4 -0
- data/lib/aquarium/finders/finder_result.rb +121 -0
- data/lib/aquarium/finders/method_finder.rb +228 -0
- data/lib/aquarium/finders/object_finder.rb +74 -0
- data/lib/aquarium/finders/type_finder.rb +127 -0
- data/lib/aquarium/utils.rb +9 -0
- data/lib/aquarium/utils/array_utils.rb +29 -0
- data/lib/aquarium/utils/hash_utils.rb +28 -0
- data/lib/aquarium/utils/html_escaper.rb +17 -0
- data/lib/aquarium/utils/invalid_options.rb +9 -0
- data/lib/aquarium/utils/method_utils.rb +18 -0
- data/lib/aquarium/utils/nil_object.rb +13 -0
- data/lib/aquarium/utils/set_utils.rb +32 -0
- data/lib/aquarium/version.rb +30 -0
- data/rake_tasks/examples.rake +7 -0
- data/rake_tasks/examples_specdoc.rake +8 -0
- data/rake_tasks/examples_with_rcov.rake +8 -0
- data/rake_tasks/verify_rcov.rake +7 -0
- data/spec/aquarium/aspects/advice_chain_node_spec.rb +34 -0
- data/spec/aquarium/aspects/advice_spec.rb +103 -0
- data/spec/aquarium/aspects/aspect_invocation_spec.rb +111 -0
- data/spec/aquarium/aspects/aspect_spec.rb +978 -0
- data/spec/aquarium/aspects/aspect_with_nested_types_spec.rb +129 -0
- data/spec/aquarium/aspects/concurrent_aspects_spec.rb +423 -0
- data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +103 -0
- data/spec/aquarium/aspects/concurrently_accessed.rb +21 -0
- data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +514 -0
- data/spec/aquarium/aspects/join_point_spec.rb +302 -0
- data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +131 -0
- data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +111 -0
- data/spec/aquarium/aspects/pointcut_spec.rb +800 -0
- data/spec/aquarium/extensions/hash_spec.rb +187 -0
- data/spec/aquarium/extensions/regex_spec.rb +40 -0
- data/spec/aquarium/extensions/set_spec.rb +105 -0
- data/spec/aquarium/extensions/string_spec.rb +25 -0
- data/spec/aquarium/extensions/symbol_spec.rb +37 -0
- data/spec/aquarium/extras/design_by_contract_spec.rb +68 -0
- data/spec/aquarium/finders/finder_result_spec.rb +359 -0
- data/spec/aquarium/finders/method_finder_spec.rb +878 -0
- data/spec/aquarium/finders/method_sorting_spec.rb +16 -0
- data/spec/aquarium/finders/object_finder_spec.rb +230 -0
- data/spec/aquarium/finders/type_finder_spec.rb +210 -0
- data/spec/aquarium/spec_example_classes.rb +117 -0
- data/spec/aquarium/spec_helper.rb +3 -0
- data/spec/aquarium/utils/array_utils_spec.rb +47 -0
- data/spec/aquarium/utils/hash_utils_spec.rb +48 -0
- data/spec/aquarium/utils/html_escaper_spec.rb +18 -0
- data/spec/aquarium/utils/method_utils_spec.rb +50 -0
- data/spec/aquarium/utils/nil_object_spec.rb +19 -0
- data/spec/aquarium/utils/set_utils_spec.rb +60 -0
- metadata +132 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
require File.dirname(__FILE__) + '/../spec_example_classes'
|
3
|
+
require 'aquarium/aspects/advice'
|
4
|
+
require 'aquarium/aspects/aspect'
|
5
|
+
include Aquarium::Aspects
|
6
|
+
|
7
|
+
describe Advice, "#sort_by_priority_order" do
|
8
|
+
it "should return an empty array for empty input" do
|
9
|
+
Aquarium::Aspects::Advice.sort_by_priority_order([]).should == []
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should return a properly-sorted array for arbitrary input of valid advice kind symbols" do
|
13
|
+
Aquarium::Aspects::Advice.sort_by_priority_order([:after_raising, :after_returning, :before, :after, :around]).should == [:around, :before, :after, :after_returning, :after_raising]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should accept strings for the advice kinds, but return sorted symbols" do
|
17
|
+
Aquarium::Aspects::Advice.sort_by_priority_order(["after_raising", "after_returning", "before", "after", "around"]).should == [:around, :before, :after, :after_returning, :after_raising]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Advice, "that raises an exception" do
|
22
|
+
it "should add the kind of advice to the exception message." do
|
23
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
24
|
+
raise SpecExceptionForTesting.new("advice called with args: #{args.inspect}")
|
25
|
+
end
|
26
|
+
begin
|
27
|
+
Watchful.new.public_watchful_method(:a1, :a2) || fail
|
28
|
+
rescue => e
|
29
|
+
e.message.should include("\"before\" advice")
|
30
|
+
end
|
31
|
+
aspect.unadvise
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should add the \"Class#method\" of the advised object's type and method to the exception message." do
|
35
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
36
|
+
raise "advice called with args: #{args.inspect}"
|
37
|
+
end
|
38
|
+
begin
|
39
|
+
Watchful.new.public_watchful_method(:a1, :a2) || fail
|
40
|
+
rescue => e
|
41
|
+
e.message.should include("Watchful#public_watchful_method")
|
42
|
+
end
|
43
|
+
aspect.unadvise
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should add the \"Class.method\" of the advised type's class method to the exception message." do
|
47
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_class_watchful_method, :method_options => [:class]} do |jp, *args|
|
48
|
+
raise "advice called with args: #{args.inspect}"
|
49
|
+
end
|
50
|
+
begin
|
51
|
+
Watchful.public_class_watchful_method(:a1, :a2) || fail
|
52
|
+
rescue => e
|
53
|
+
e.message.should include("Watchful.public_class_watchful_method")
|
54
|
+
end
|
55
|
+
aspect.unadvise
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should rethrow an exception of the same type as the original exception." do
|
59
|
+
class MyException < Exception; end
|
60
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_class_watchful_method, :method_options => [:class]} do |jp, *args|
|
61
|
+
raise MyException.new("advice called with args: #{args.inspect}")
|
62
|
+
end
|
63
|
+
lambda { Watchful.public_class_watchful_method :a1, :a2 }.should raise_error(MyException)
|
64
|
+
aspect.unadvise
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should rethrow an exception with the same backtrace as the original exception." do
|
68
|
+
class MyException < Exception; end
|
69
|
+
@backtrace = nil
|
70
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_class_watchful_method, :method_options => [:class]} do |jp, *args|
|
71
|
+
begin
|
72
|
+
exception = MyException.new("advice called with args: #{args.inspect}")
|
73
|
+
raise exception
|
74
|
+
rescue Exception => e
|
75
|
+
@backtrace = e.backtrace
|
76
|
+
raise e
|
77
|
+
end
|
78
|
+
end
|
79
|
+
begin
|
80
|
+
Watchful.public_class_watchful_method(:a1, :a2) || fail
|
81
|
+
rescue Exception => e
|
82
|
+
e.backtrace.should == @backtrace
|
83
|
+
end
|
84
|
+
aspect.unadvise
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe AdviceChainNodeFactory, "#make_node" do
|
89
|
+
it "should raise if an unknown advice kind is specified" do
|
90
|
+
lambda {Aquarium::Aspects::AdviceChainNodeFactory.make_node :advice_kind => :foo}.should raise_error(Aquarium::Utils::InvalidOptions)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return a node of the type corresponding to the input advice kind" do
|
94
|
+
Aquarium::Aspects::AdviceChainNodeFactory.make_node(:advice_kind => :no).kind_of?(Aquarium::Aspects::NoAdviceChainNode).should be_true
|
95
|
+
Aquarium::Aspects::AdviceChainNodeFactory.make_node(:advice_kind => :none).kind_of?(Aquarium::Aspects::NoAdviceChainNode).should be_true
|
96
|
+
Aquarium::Aspects::AdviceChainNodeFactory.make_node(:advice_kind => :before).kind_of?(Aquarium::Aspects::BeforeAdviceChainNode).should be_true
|
97
|
+
Aquarium::Aspects::AdviceChainNodeFactory.make_node(:advice_kind => :after).kind_of?(Aquarium::Aspects::AfterAdviceChainNode).should be_true
|
98
|
+
Aquarium::Aspects::AdviceChainNodeFactory.make_node(:advice_kind => :after_raising).kind_of?(Aquarium::Aspects::AfterRaisingAdviceChainNode).should be_true
|
99
|
+
Aquarium::Aspects::AdviceChainNodeFactory.make_node(:advice_kind => :after_returning).kind_of?(Aquarium::Aspects::AfterReturningAdviceChainNode).should be_true
|
100
|
+
Aquarium::Aspects::AdviceChainNodeFactory.make_node(:advice_kind => :around).kind_of?(Aquarium::Aspects::AroundAdviceChainNode).should be_true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
require File.dirname(__FILE__) + '/../spec_example_classes'
|
3
|
+
require 'aquarium/aspects/aspect'
|
4
|
+
require 'aquarium/aspects/dsl'
|
5
|
+
|
6
|
+
describe Object, "#advise with invalid invocation parameter list" do
|
7
|
+
it "should contain at least one of :around, :before, :after, :after_returning, and :after_raising." do
|
8
|
+
lambda { advise :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should contain no other advice types if :around advice specified." do
|
12
|
+
lambda { advise :around, :before, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
13
|
+
lambda { advise :around, :after, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
14
|
+
lambda { advise :around, :after_returning, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
15
|
+
lambda { advise :around, :after_raising, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should allow only one of :after, :after_returning, or :after_raising advice to be specified." do
|
19
|
+
lambda { advise :after, :after_returning, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
20
|
+
lambda { advise :after, :after_raising, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
21
|
+
lambda { advise :after_returning, :after_raising, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe Object, "#advise arguments can specify more than one advice types" do
|
26
|
+
it "should allow :before to be specified with :after." do
|
27
|
+
lambda { advise :before, :after, :pointcut => {:type => Watchful}, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should allow :before to be specified with :after_returning." do
|
31
|
+
lambda { advise :before, :after_returning, :pointcut => {:type => Watchful}, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow :before to be specified with :after_raising." do
|
35
|
+
lambda { advise :before, :after_raising, :pointcut => {:type => Watchful}, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe Object, "#advise arguments for specifying the types and methods" do
|
40
|
+
it "should advise equivalent join points when :type => T and :method => m is used or :pointcut =>{:type => T, :method => m} is used." do
|
41
|
+
advice = proc {|jp,*args| "advice"}
|
42
|
+
aspect1 = advise :after, :type => Watchful, :method => :public_watchful_method, &advice
|
43
|
+
aspect2 = advise :after, :pointcut => {:type => Watchful, :method => :public_watchful_method}, &advice
|
44
|
+
# We don't use aspect1.should eql(aspect2) because the "specifications" are different.
|
45
|
+
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
46
|
+
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
47
|
+
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
48
|
+
aspect1.advice.should eql(aspect2.advice)
|
49
|
+
aspect1.unadvise
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should advise equivalent join points when :type => T and :method => m is used or :pointcut => pointcut is used, where pointcut matches :type => T and :method => m." do
|
53
|
+
advice = proc {|jp,*args| "advice"}
|
54
|
+
aspect1 = advise :after, :type => Watchful, :method => :public_watchful_method, &advice
|
55
|
+
pointcut = Aquarium::Aspects::Pointcut.new :type => Watchful, :method => :public_watchful_method
|
56
|
+
aspect2 = advise :after, :pointcut => pointcut, &advice
|
57
|
+
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
58
|
+
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
59
|
+
aspect1.advice.should eql(aspect2.advice)
|
60
|
+
aspect1.unadvise
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should advise equivalent join points when :pointcut =>{:type => T, :method => m} is used or :pointcut => pointcut is used, where pointcut matches :type => T and :method => m." do
|
64
|
+
advice = proc {|jp,*args| "advice"}
|
65
|
+
aspect1 = advise :after, :pointcut => {:type => Watchful, :method => :public_watchful_method}, &advice
|
66
|
+
pointcut = Aquarium::Aspects::Pointcut.new :type => Watchful, :method => :public_watchful_method
|
67
|
+
aspect2 = advise :after, :pointcut => pointcut, &advice
|
68
|
+
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
69
|
+
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
70
|
+
aspect1.advice.should eql(aspect2.advice)
|
71
|
+
aspect1.unadvise
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe Object, "#advise arguments for specifying the objects and methods" do
|
76
|
+
it "should advise equivalent join points when :object => o and :method => m is used or :pointcut =>{:object => o, :method => m} is used." do
|
77
|
+
advice = proc {|jp,*args| "advice"}
|
78
|
+
watchful = Watchful.new
|
79
|
+
aspect1 = advise :after, :object => watchful, :method => :public_watchful_method, &advice
|
80
|
+
aspect2 = advise :after, :pointcut => {:object => watchful, :method => :public_watchful_method}, &advice
|
81
|
+
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
82
|
+
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
83
|
+
aspect1.advice.should eql(aspect2.advice)
|
84
|
+
aspect1.unadvise
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should advise equivalent join points when :object => o and :method => m is used or :pointcut => pointcut is used, where pointcut matches :object => o and :method => m." do
|
88
|
+
advice = proc {|jp,*args| "advice"}
|
89
|
+
watchful = Watchful.new
|
90
|
+
aspect1 = advise :after, :object => watchful, :method => :public_watchful_method, &advice
|
91
|
+
pointcut = Aquarium::Aspects::Pointcut.new :object => watchful, :method => :public_watchful_method
|
92
|
+
aspect2 = advise :after, :pointcut => pointcut, &advice
|
93
|
+
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
94
|
+
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
95
|
+
aspect1.advice.should eql(aspect2.advice)
|
96
|
+
aspect1.unadvise
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should advise equivalent join points when :pointcut =>{:object => o, :method => m} is used or :pointcut => pointcut is used, where pointcut matches :object => o and :method => m." do
|
100
|
+
advice = proc {|jp,*args| "advice"}
|
101
|
+
watchful = Watchful.new
|
102
|
+
aspect1 = advise :after, :pointcut => {:object => watchful, :method => :public_watchful_method}, &advice
|
103
|
+
pointcut = Aquarium::Aspects::Pointcut.new :object => watchful, :method => :public_watchful_method
|
104
|
+
aspect2 = advise :after, :pointcut => pointcut, &advice
|
105
|
+
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
106
|
+
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
107
|
+
aspect1.advice.should eql(aspect2.advice)
|
108
|
+
aspect1.unadvise
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
@@ -0,0 +1,978 @@
|
|
1
|
+
|
2
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
3
|
+
require File.dirname(__FILE__) + '/../spec_example_classes'
|
4
|
+
require 'aquarium/aspects'
|
5
|
+
|
6
|
+
include Aquarium::Aspects
|
7
|
+
|
8
|
+
# TODO Could refactor this whole file to use "behave_like", etc.
|
9
|
+
describe Aspect, "#new parameters that configure advice" do
|
10
|
+
it "should require the kind of advice as the first parameter." do
|
11
|
+
lambda {Aspect.new(:pointcuts => {:type => Watchful, :methods => :public_watchful_method}) {|jp, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should at least one of :method(s), :pointcut(s), :type(s), or :object(s)." do
|
15
|
+
lambda {Aspect.new(:after) {|jp, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should at least one of :pointcut(s), :type(s), or :object(s) unless :default_object => object is given." do
|
19
|
+
aspect = Aspect.new(:after, :default_object => Watchful.new, :methods => :public_watchful_method) {|jp, *args| true}
|
20
|
+
aspect.unadvise
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not contain :pointcut(s) and either :type(s) or :object(s)." do
|
24
|
+
lambda {Aspect.new(:after, :pointcuts => {:type => Watchful, :methods => :public_watchful_method}, :type => Watchful, :methods => :public_watchful_method) {|jp, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
|
25
|
+
lambda {Aspect.new(:after, :pointcuts => {:type => Watchful, :methods => :public_watchful_method}, :object => Watchful.new, :methods => :public_watchful_method) {|jp, *args| true}}.should raise_error(Aquarium::Utils::InvalidOptions)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should include an advice block or :advice => advice parameter." do
|
29
|
+
lambda {Aspect.new(:after, :type => Watchful, :methods => :public_watchful_method)}.should raise_error(Aquarium::Utils::InvalidOptions)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe Aspect, "#new :pointcut parameter with a hash of :type(s), :object(s), and/or :method(s)" do
|
34
|
+
it "should accept a {:type(s) => [T1, ...], :methods = [...]} hash, indicating the types and methods to advise." do
|
35
|
+
advice_called = false
|
36
|
+
aspect = Aspect.new :before, :pointcut => {:type => [Watchful], :methods => :public_watchful_method} do |jp, *args|
|
37
|
+
advice_called = true
|
38
|
+
jp.should_not == nil
|
39
|
+
args.size.should == 4
|
40
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
41
|
+
end
|
42
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
43
|
+
advice_called.should be_true
|
44
|
+
aspect.unadvise
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should accept a {:type(s) => T, :methods = [...]} hash, indicating the type and methods to advise." do
|
48
|
+
advice_called = false
|
49
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
50
|
+
advice_called = true
|
51
|
+
jp.should_not == nil
|
52
|
+
args.size.should == 4
|
53
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
54
|
+
end
|
55
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
56
|
+
advice_called.should be_true
|
57
|
+
aspect.unadvise
|
58
|
+
end
|
59
|
+
|
60
|
+
%w[public protected private].each do |protection|
|
61
|
+
it "should accept a {:type(s) => T, :methods = [...], :method_options =>[:instance, #{protection}]} hash, indicating the type and #{protection} instance methods to advise." do
|
62
|
+
advice_called = false
|
63
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => /watchful_method/, :method_options =>[:instance, protection.intern]} do |jp, *args|
|
64
|
+
advice_called = true
|
65
|
+
jp.should_not == nil
|
66
|
+
args.size.should == 4
|
67
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
68
|
+
end
|
69
|
+
Watchful.new.method("#{protection}_watchful_method".intern).call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
70
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
71
|
+
advice_called.should be_true
|
72
|
+
aspect.unadvise
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should accept a {:type(s) => T, :methods = [...], :method_options =>[:instance]} hash, indicating the type and (public) instance methods to advise." do
|
77
|
+
advice_called = false
|
78
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
79
|
+
advice_called = true
|
80
|
+
jp.should_not == nil
|
81
|
+
args.size.should == 4
|
82
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
83
|
+
end
|
84
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
85
|
+
advice_called.should be_true
|
86
|
+
aspect.unadvise
|
87
|
+
end
|
88
|
+
|
89
|
+
%w[public private].each do |protection|
|
90
|
+
it "should accept a {:type(s) => T, :methods = [...], :method_options =>[:class, :#{protection}]} hash, indicating the type and #{protection} class methods to advise." do
|
91
|
+
advice_called = false
|
92
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => /class_watchful_method$/, :method_options =>[:class, protection.intern]} do |jp, *args|
|
93
|
+
advice_called = true
|
94
|
+
jp.should_not == nil
|
95
|
+
args.size.should == 4
|
96
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
97
|
+
end
|
98
|
+
Watchful.method("#{protection}_class_watchful_method".intern).call :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
99
|
+
advice_called.should be_true
|
100
|
+
aspect.unadvise
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should accept a {:type(s) => T, :methods = [...], :method_options =>:class} hash, indicating the type and (public) class methods to advise." do
|
105
|
+
advice_called = false
|
106
|
+
aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_class_watchful_method, :method_options =>:class} do |jp, *args|
|
107
|
+
advice_called = true
|
108
|
+
jp.should_not == nil
|
109
|
+
args.size.should == 4
|
110
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
111
|
+
end
|
112
|
+
Watchful.public_class_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
113
|
+
advice_called.should be_true
|
114
|
+
aspect.unadvise
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should accept a {:objects(s) => [O1, ...], :methods = [...]} hash, indicating the objects and methods to advise." do
|
118
|
+
watchful1 = Watchful.new
|
119
|
+
watchful2 = Watchful.new
|
120
|
+
advice_called = false
|
121
|
+
aspect = Aspect.new :before, :pointcut => {:objects => [watchful1, watchful2], :methods => :public_watchful_method} do |jp, *args|
|
122
|
+
advice_called = true
|
123
|
+
jp.should_not == nil
|
124
|
+
args.size.should == 4
|
125
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
126
|
+
end
|
127
|
+
watchful1.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
128
|
+
watchful2.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
129
|
+
advice_called.should be_true
|
130
|
+
aspect.unadvise
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should accept a {:objects(s) => O, :methods = [...]} hash, indicating the objects and methods to advise." do
|
134
|
+
watchful = Watchful.new
|
135
|
+
advice_called = false
|
136
|
+
aspect = Aspect.new :before, :pointcut => {:objects => watchful, :methods => :public_watchful_method} do |jp, *args|
|
137
|
+
advice_called = true
|
138
|
+
jp.should_not == nil
|
139
|
+
args.size.should == 4
|
140
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
141
|
+
end
|
142
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
143
|
+
advice_called.should be_true
|
144
|
+
aspect.unadvise
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe Aspect, "#new :pointcut parameter with a PointCut object or an array of Pointcuts" do
|
149
|
+
it "should accept a single Pointcut object." do
|
150
|
+
advice_called = false
|
151
|
+
pointcut = Pointcut.new :type => [Watchful], :methods => :public_watchful_method
|
152
|
+
aspect = Aspect.new :before, :pointcut => pointcut do |jp, *args|
|
153
|
+
advice_called = true
|
154
|
+
jp.should_not == nil
|
155
|
+
args.size.should == 4
|
156
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
157
|
+
end
|
158
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
159
|
+
advice_called.should be_true
|
160
|
+
aspect.unadvise
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should accept an array of Pointcut objects." do
|
164
|
+
advice_called = 0
|
165
|
+
pointcut1 = Pointcut.new :type => [Watchful], :methods => :public_watchful_method
|
166
|
+
pointcut2 = Pointcut.new :type => [Watchful], :methods => :public_class_watchful_method, :method_options => [:class]
|
167
|
+
aspect = Aspect.new :before, :pointcut => [pointcut1, pointcut2] do |jp, *args|
|
168
|
+
advice_called += 1
|
169
|
+
jp.should_not == nil
|
170
|
+
args.size.should == 4
|
171
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
172
|
+
end
|
173
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
174
|
+
Watchful.public_class_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
175
|
+
advice_called.should == 2
|
176
|
+
aspect.unadvise
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should treat an array of Pointcuts as if they are one Pointcut \"or'ed\" together." do
|
180
|
+
advice_called = 0
|
181
|
+
advice = Proc.new {|jp, *args|
|
182
|
+
advice_called += 1
|
183
|
+
jp.should_not == nil
|
184
|
+
args.size.should == 4
|
185
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
186
|
+
}
|
187
|
+
pointcut1 = Pointcut.new :type => [Watchful], :methods => :public_watchful_method
|
188
|
+
pointcut2 = Pointcut.new :type => [Watchful], :methods => :public_class_watchful_method, :method_options => [:class]
|
189
|
+
pointcut12 = pointcut1.or pointcut2
|
190
|
+
aspect1 = Aspect.new :before, :pointcut => [pointcut1, pointcut2], :advice => advice
|
191
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
192
|
+
Watchful.public_class_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
193
|
+
advice_called.should == 2
|
194
|
+
aspect1.unadvise
|
195
|
+
advice_called = 0
|
196
|
+
aspect2 = Aspect.new :before, :pointcut => pointcut12, :advice => advice
|
197
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
198
|
+
Watchful.public_class_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
199
|
+
advice_called.should == 2
|
200
|
+
aspect2.unadvise
|
201
|
+
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe Aspect, "#new :type(s), :object(s), and :method(s) parameters" do
|
206
|
+
it "should accept :type(s) => [T1, ...] and :methods => [...] parameters indicating the types to advise." do
|
207
|
+
advice_called = false
|
208
|
+
aspect = Aspect.new :before, :types => [Watchful], :methods => :public_watchful_method do |jp, *args|
|
209
|
+
advice_called = true
|
210
|
+
jp.should_not == nil
|
211
|
+
args.size.should == 4
|
212
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
213
|
+
end
|
214
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
215
|
+
advice_called.should be_true
|
216
|
+
aspect.unadvise
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should accept :type(s) => T and :methods => [...] parameters indicating the types to advise." do
|
220
|
+
advice_called = false
|
221
|
+
aspect = Aspect.new :before, :type => Watchful, :methods => :public_watchful_method do |jp, *args|
|
222
|
+
advice_called = true
|
223
|
+
jp.should_not == nil
|
224
|
+
args.size.should == 4
|
225
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
226
|
+
end
|
227
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
228
|
+
advice_called.should be_true
|
229
|
+
aspect.unadvise
|
230
|
+
end
|
231
|
+
|
232
|
+
it "should accept :type(s) => /regexp/ and :methods => [...] parameters indicating the types to advise." do
|
233
|
+
advice_called = false
|
234
|
+
aspect = Aspect.new :before, :type => /^Watchful/, :methods => :public_watchful_method do |jp, *args|
|
235
|
+
advice_called = true
|
236
|
+
jp.should_not == nil
|
237
|
+
args.size.should == 4
|
238
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
239
|
+
end
|
240
|
+
Watchful.new.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
241
|
+
advice_called.should be_true
|
242
|
+
aspect.unadvise
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should accept :object(s) => [O1, ...] and :methods => [...] parameters indicating the objects to advise." do
|
246
|
+
watchful1 = Watchful.new
|
247
|
+
watchful2 = Watchful.new
|
248
|
+
advice_called = false
|
249
|
+
aspect = Aspect.new :before, :object => [watchful1, watchful2], :methods => :public_watchful_method do |jp, *args|
|
250
|
+
advice_called = true
|
251
|
+
jp.should_not == nil
|
252
|
+
args.size.should == 4
|
253
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
254
|
+
end
|
255
|
+
watchful1.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
256
|
+
watchful2.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
257
|
+
advice_called.should be_true
|
258
|
+
aspect.unadvise
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should accept :object(s) => O and :methods => [...] parameters indicating the objects to advise." do
|
262
|
+
watchful = Watchful.new
|
263
|
+
advice_called = false
|
264
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method do |jp, *args|
|
265
|
+
advice_called = true
|
266
|
+
jp.should_not == nil
|
267
|
+
args.size.should == 4
|
268
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
269
|
+
end
|
270
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
271
|
+
advice_called.should be_true
|
272
|
+
aspect.unadvise
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should accept :object(s) => O and :methods => [...] parameters indicating the objects to advise." do
|
276
|
+
watchful = Watchful.new
|
277
|
+
advice_called = false
|
278
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method do |jp, *args|
|
279
|
+
advice_called = true
|
280
|
+
jp.should_not == nil
|
281
|
+
args.size.should == 4
|
282
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
283
|
+
end
|
284
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
285
|
+
advice_called.should be_true
|
286
|
+
aspect.unadvise
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
describe Aspect, "#new block parameter" do
|
291
|
+
it "should accept a block as the advice to use." do
|
292
|
+
watchful = Watchful.new
|
293
|
+
advice_called = false
|
294
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method do |jp, *args|
|
295
|
+
advice_called = true
|
296
|
+
jp.should_not == nil
|
297
|
+
args.size.should == 4
|
298
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
299
|
+
end
|
300
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
301
|
+
advice_called.should be_true
|
302
|
+
aspect.unadvise
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should accept an :advice => Proc parameter indicating the advice to use." do
|
306
|
+
watchful = Watchful.new
|
307
|
+
advice_called = false
|
308
|
+
advice = Proc.new {|jp, *args|
|
309
|
+
advice_called = true
|
310
|
+
jp.should_not == nil
|
311
|
+
args.size.should == 4
|
312
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
313
|
+
}
|
314
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method, :advice => advice
|
315
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
316
|
+
advice_called.should be_true
|
317
|
+
aspect.unadvise
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should accept a :call => Proc parameter as a synonym for :advice." do
|
321
|
+
watchful = Watchful.new
|
322
|
+
advice_called = false
|
323
|
+
advice = Proc.new {|jp, *args|
|
324
|
+
advice_called = true
|
325
|
+
jp.should_not == nil
|
326
|
+
args.size.should == 4
|
327
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
328
|
+
}
|
329
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method, :call => advice
|
330
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
331
|
+
advice_called.should be_true
|
332
|
+
aspect.unadvise
|
333
|
+
end
|
334
|
+
|
335
|
+
it "should accept a :invoke => Proc parameter as a synonym for :advice." do
|
336
|
+
watchful = Watchful.new
|
337
|
+
advice_called = false
|
338
|
+
advice = Proc.new {|jp, *args|
|
339
|
+
advice_called = true
|
340
|
+
jp.should_not == nil
|
341
|
+
args.size.should == 4
|
342
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
343
|
+
}
|
344
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method, :invoke => advice
|
345
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
346
|
+
advice_called.should be_true
|
347
|
+
aspect.unadvise
|
348
|
+
end
|
349
|
+
|
350
|
+
it "should accept a :advise_with => Proc parameter as a synonym for :advice." do
|
351
|
+
watchful = Watchful.new
|
352
|
+
advice_called = false
|
353
|
+
advice = Proc.new {|jp, *args|
|
354
|
+
advice_called = true
|
355
|
+
jp.should_not == nil
|
356
|
+
args.size.should == 4
|
357
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
358
|
+
}
|
359
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method, :advise_with => advice
|
360
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
361
|
+
advice_called.should be_true
|
362
|
+
aspect.unadvise
|
363
|
+
end
|
364
|
+
|
365
|
+
it "should ignore all synonyms if there is an :advice => Proc parameter." do
|
366
|
+
watchful = Watchful.new
|
367
|
+
advice_called = false
|
368
|
+
advice = Proc.new {|jp, *args|
|
369
|
+
advice_called = true
|
370
|
+
jp.should_not == nil
|
371
|
+
args.size.should == 4
|
372
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
373
|
+
}
|
374
|
+
advice2 = Proc.new {|jp, *args| raise "should not be called"}
|
375
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method, :invoke => advice2, :advice => advice
|
376
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
377
|
+
advice_called.should be_true
|
378
|
+
aspect.unadvise
|
379
|
+
end
|
380
|
+
|
381
|
+
it "should ignore all but the last :advice => Proc parameter." do
|
382
|
+
watchful = Watchful.new
|
383
|
+
advice_called = false
|
384
|
+
advice = Proc.new {|jp, *args|
|
385
|
+
advice_called = true
|
386
|
+
jp.should_not == nil
|
387
|
+
args.size.should == 4
|
388
|
+
args.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
389
|
+
}
|
390
|
+
advice2 = Proc.new {|jp, *args| raise "should not be called"}
|
391
|
+
aspect = Aspect.new :before, :object => watchful, :methods => :public_watchful_method, :advice => advice2, :advice => advice
|
392
|
+
watchful.public_watchful_method :a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2'
|
393
|
+
advice_called.should be_true
|
394
|
+
aspect.unadvise
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
describe Aspect, "#new invoked for the private implementation methods inserted by other aspects" do
|
399
|
+
it "should have no affect." do
|
400
|
+
class WithAspectLikeMethod
|
401
|
+
def _aspect_foo; end
|
402
|
+
end
|
403
|
+
aspect = Aspect.new(:after, :pointcut => {:type => WithAspectLikeMethod, :methods => :_aspect_foo}) {|jp, *args| fail}
|
404
|
+
WithAspectLikeMethod.new._aspect_foo
|
405
|
+
aspect.unadvise
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
describe Aspect, "#new modifications to the list of methods for the advised object or type" do
|
410
|
+
before(:all) do
|
411
|
+
@advice = Proc.new {}
|
412
|
+
end
|
413
|
+
after(:each) do
|
414
|
+
@aspect.unadvise
|
415
|
+
end
|
416
|
+
|
417
|
+
it "should not include new public instance or class methods for the advised type." do
|
418
|
+
all_public_methods_before = all_public_methods_of_type Watchful
|
419
|
+
@aspect = Aspect.new :after, :pointcut => {:type => Watchful, :method_options => :suppress_ancestor_methods}, :advice => @advice
|
420
|
+
(all_public_methods_of_type(Watchful) - all_public_methods_before).should == []
|
421
|
+
end
|
422
|
+
|
423
|
+
it "should not include new protected instance or class methods for the advised type." do
|
424
|
+
all_protected_methods_before = all_protected_methods_of_type Watchful
|
425
|
+
@aspect = Aspect.new :after, :pointcut => {:type => Watchful, :method_options => :suppress_ancestor_methods}, :advice => @advice
|
426
|
+
(all_protected_methods_of_type(Watchful) - all_protected_methods_before).should == []
|
427
|
+
end
|
428
|
+
|
429
|
+
it "should not include new public methods for the advised object." do
|
430
|
+
watchful = Watchful.new
|
431
|
+
all_public_methods_before = all_public_methods_of_object Watchful
|
432
|
+
@aspect = Aspect.new :after, :pointcut => {:object => watchful, :method_options => :suppress_ancestor_methods}, :advice => @advice
|
433
|
+
(all_public_methods_of_object(Watchful) - all_public_methods_before).should == []
|
434
|
+
end
|
435
|
+
|
436
|
+
it "should not include new protected methods for the advised object." do
|
437
|
+
watchful = Watchful.new
|
438
|
+
all_protected_methods_before = all_protected_methods_of_object Watchful
|
439
|
+
@aspect = Aspect.new :after, :pointcut => {:object => watchful, :method_options => :suppress_ancestor_methods}, :advice => @advice
|
440
|
+
(all_protected_methods_of_object(Watchful) - all_protected_methods_before).should == []
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
describe Aspect, "#new with :before advice" do
|
445
|
+
after(:each) do
|
446
|
+
@aspect.unadvise if @aspect
|
447
|
+
end
|
448
|
+
|
449
|
+
it "should pass the context information to the advice, including self and the method parameters." do
|
450
|
+
watchful = Watchful.new
|
451
|
+
context = nil
|
452
|
+
@aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
453
|
+
context = jp.context
|
454
|
+
end
|
455
|
+
block_called = 0
|
456
|
+
watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
|
457
|
+
block_called.should == 1
|
458
|
+
context.advice_kind.should == :before
|
459
|
+
context.advised_object.should == watchful
|
460
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
461
|
+
context.returned_value.should == nil
|
462
|
+
context.raised_exception.should == nil
|
463
|
+
end
|
464
|
+
|
465
|
+
it "should evaluate the advice before the method body and its block (if any)." do
|
466
|
+
@aspect = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
467
|
+
@advice_called += 1
|
468
|
+
end
|
469
|
+
do_watchful_public_protected_private
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
describe Aspect, "#new with :after advice" do
|
474
|
+
after(:each) do
|
475
|
+
@aspect.unadvise if @aspect
|
476
|
+
end
|
477
|
+
|
478
|
+
it "should pass the context information to the advice, including self, the method parameters, and the return value when the method returns normally." do
|
479
|
+
watchful = Watchful.new
|
480
|
+
context = nil
|
481
|
+
@aspect = Aspect.new :after, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
482
|
+
context = jp.context
|
483
|
+
end
|
484
|
+
block_called = 0
|
485
|
+
watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
|
486
|
+
block_called.should == 1
|
487
|
+
context.advice_kind.should == :after
|
488
|
+
context.advised_object.should == watchful
|
489
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
490
|
+
context.returned_value.should == block_called
|
491
|
+
context.raised_exception.should == nil
|
492
|
+
end
|
493
|
+
|
494
|
+
it "should pass the context information to the advice, including self, the method parameters, and the rescued exception when an exception is raised." do
|
495
|
+
watchful = Watchful.new
|
496
|
+
context = nil
|
497
|
+
@aspect = Aspect.new :after, :pointcut => {:type => Watchful, :methods => /public_watchful_method/} do |jp, *args|
|
498
|
+
context = jp.context
|
499
|
+
end
|
500
|
+
block_called = 0
|
501
|
+
lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }}.should raise_error(Watchful::WatchfulError)
|
502
|
+
block_called.should == 1
|
503
|
+
context.advised_object.should == watchful
|
504
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
505
|
+
context.returned_value.should == nil
|
506
|
+
context.raised_exception.kind_of?(Watchful::WatchfulError).should be_true
|
507
|
+
end
|
508
|
+
|
509
|
+
it "should evaluate the advice after the method body and its block (if any)." do
|
510
|
+
@aspect = Aspect.new :after, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
511
|
+
@advice_called += 1
|
512
|
+
end
|
513
|
+
do_watchful_public_protected_private
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
describe Aspect, "#new with :after_returning advice" do
|
518
|
+
after(:each) do
|
519
|
+
@aspect.unadvise if @aspect
|
520
|
+
end
|
521
|
+
|
522
|
+
it "should pass the context information to the advice, including self, the method parameters, and the return value." do
|
523
|
+
watchful = Watchful.new
|
524
|
+
context = nil
|
525
|
+
@aspect = Aspect.new :after_returning, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
526
|
+
context = jp.context
|
527
|
+
end
|
528
|
+
block_called = 0
|
529
|
+
watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
|
530
|
+
block_called.should == 1
|
531
|
+
context.advice_kind.should == :after_returning
|
532
|
+
context.advised_object.should == watchful
|
533
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
534
|
+
context.returned_value.should == block_called
|
535
|
+
context.raised_exception.should == nil
|
536
|
+
end
|
537
|
+
|
538
|
+
it "should evaluate the advice after the method body and its block (if any)." do
|
539
|
+
@aspect = Aspect.new :after_returning, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
540
|
+
@advice_called += 1
|
541
|
+
end
|
542
|
+
do_watchful_public_protected_private
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
describe Aspect, "#new with :after_raising advice" do
|
547
|
+
after(:each) do
|
548
|
+
@aspect.unadvise if @aspect
|
549
|
+
end
|
550
|
+
|
551
|
+
it "should pass the context information to the advice, including self, the method parameters, and the rescued exception." do
|
552
|
+
watchful = Watchful.new
|
553
|
+
context = nil
|
554
|
+
@aspect = Aspect.new :after_raising, :pointcut => {:type => Watchful, :methods => /public_watchful_method/} do |jp, *args|
|
555
|
+
context = jp.context
|
556
|
+
end
|
557
|
+
block_called = 0
|
558
|
+
lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }}.should raise_error(Watchful::WatchfulError)
|
559
|
+
block_called.should == 1
|
560
|
+
context.advised_object.should == watchful
|
561
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
562
|
+
context.advice_kind.should == :after_raising
|
563
|
+
context.returned_value.should == nil
|
564
|
+
context.raised_exception.kind_of?(Watchful::WatchfulError).should be_true
|
565
|
+
end
|
566
|
+
|
567
|
+
it "should evaluate the advice after the method body and its block (if any)." do
|
568
|
+
@aspect = Aspect.new :after_raising, :pointcut => {:type => Watchful, :methods => /public_watchful_method/} do |jp, *args|
|
569
|
+
@advice_called += 1
|
570
|
+
end
|
571
|
+
do_watchful_public_protected_private true
|
572
|
+
end
|
573
|
+
|
574
|
+
it "should not advise rescue clauses for raised exceptions of types that don't match the specified exception" do
|
575
|
+
class MyError < StandardError; end
|
576
|
+
aspect_advice_invoked = false
|
577
|
+
@aspect = Aspect.new(:after_raising => MyError, :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, *args| aspect_advice_invoked = true}
|
578
|
+
block_invoked = false
|
579
|
+
watchful = Watchful.new
|
580
|
+
lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
|
581
|
+
aspect_advice_invoked.should be_false
|
582
|
+
block_invoked.should be_true
|
583
|
+
end
|
584
|
+
|
585
|
+
it "should not advise rescue clauses for raised exceptions of types that don't match the list of specified exceptions" do
|
586
|
+
class MyError1 < StandardError; end
|
587
|
+
class MyError2 < StandardError; end
|
588
|
+
aspect_advice_invoked = false
|
589
|
+
@aspect = Aspect.new(:after_raising => [MyError1, MyError2], :pointcut => {:type => Watchful, :methods => /public_watchful_method/}) {|jp, *args| aspect_advice_invoked = true}
|
590
|
+
block_invoked = false
|
591
|
+
watchful = Watchful.new
|
592
|
+
lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3) {|*args| block_invoked = true}}.should raise_error(Watchful::WatchfulError)
|
593
|
+
aspect_advice_invoked.should be_false
|
594
|
+
block_invoked.should be_true
|
595
|
+
end
|
596
|
+
|
597
|
+
it "should advise all rescue clauses in the matched methods, if no specific exceptions are specified" do
|
598
|
+
class ClassThatRaises
|
599
|
+
class CTRException < Exception; end
|
600
|
+
def raises
|
601
|
+
raise CTRException
|
602
|
+
end
|
603
|
+
end
|
604
|
+
aspect_advice_invoked = false
|
605
|
+
@aspect = Aspect.new :after_raising, :pointcut => {:type => ClassThatRaises, :methods => :raises} do |jp, *args|
|
606
|
+
aspect_advice_invoked = true
|
607
|
+
end
|
608
|
+
aspect_advice_invoked.should be_false
|
609
|
+
ctr = ClassThatRaises.new
|
610
|
+
lambda {ctr.raises}.should raise_error(ClassThatRaises::CTRException)
|
611
|
+
aspect_advice_invoked.should be_true
|
612
|
+
end
|
613
|
+
end
|
614
|
+
|
615
|
+
describe Aspect, "#new with :before and :after advice" do
|
616
|
+
after(:each) do
|
617
|
+
@aspect.unadvise if @aspect
|
618
|
+
end
|
619
|
+
|
620
|
+
it "should pass the context information to the advice, including self and the method parameters, plus the return value for the after-advice case." do
|
621
|
+
contexts = []
|
622
|
+
@aspect = Aspect.new :before, :after, :pointcut => {:type => Watchful, :methods => [:public_watchful_method]} do |jp, *args|
|
623
|
+
contexts << jp.context
|
624
|
+
end
|
625
|
+
watchful = Watchful.new
|
626
|
+
public_block_called = 0
|
627
|
+
watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| public_block_called += 1 }
|
628
|
+
public_block_called.should == 1
|
629
|
+
contexts.size.should == 2
|
630
|
+
contexts[0].advice_kind.should == :before
|
631
|
+
contexts[1].advice_kind.should == :after
|
632
|
+
contexts[0].returned_value.should == nil
|
633
|
+
contexts[1].returned_value.should == 1
|
634
|
+
contexts.each do |context|
|
635
|
+
context.advised_object.should == watchful
|
636
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
637
|
+
context.raised_exception.should == nil
|
638
|
+
end
|
639
|
+
|
640
|
+
%w[protected private].each do |protection|
|
641
|
+
block_called = 0
|
642
|
+
watchful.send("#{protection}_watchful_method", :b1, :b2, :b3) {|*args| block_called += 1}
|
643
|
+
block_called.should == 1
|
644
|
+
contexts.size.should == 2
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
it "should evaluate the advice before and after the method body and its block (if any)." do
|
649
|
+
@aspect = Aspect.new :before, :after, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
650
|
+
@advice_called += 1
|
651
|
+
end
|
652
|
+
do_watchful_public_protected_private false, 2
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
describe Aspect, "#new with :before and :after_returning advice" do
|
657
|
+
after(:each) do
|
658
|
+
@aspect.unadvise if @aspect
|
659
|
+
end
|
660
|
+
|
661
|
+
it "should pass the context information to the advice, including self and the method parameters, plus the return value for the after-advice case." do
|
662
|
+
watchful = Watchful.new
|
663
|
+
contexts = []
|
664
|
+
@aspect = Aspect.new :before, :after_returning, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
665
|
+
contexts << jp.context
|
666
|
+
end
|
667
|
+
block_called = 0
|
668
|
+
watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }
|
669
|
+
block_called.should == 1
|
670
|
+
contexts.size.should == 2
|
671
|
+
contexts[0].advice_kind.should == :before
|
672
|
+
contexts[1].advice_kind.should == :after_returning
|
673
|
+
contexts[0].returned_value.should == nil
|
674
|
+
contexts[1].returned_value.should == block_called
|
675
|
+
contexts.each do |context|
|
676
|
+
context.advised_object.should == watchful
|
677
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
678
|
+
context.raised_exception.should == nil
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
it "should evaluate the advice before and after the method body and its block (if any)." do
|
683
|
+
@aspect = Aspect.new :before, :after_returning, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
684
|
+
@advice_called += 1
|
685
|
+
end
|
686
|
+
do_watchful_public_protected_private false, 2
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
describe Aspect, "#new with :before and :after_raising advice" do
|
691
|
+
after(:each) do
|
692
|
+
@aspect.unadvise if @aspect
|
693
|
+
end
|
694
|
+
|
695
|
+
it "should pass the context information to the advice, including self and the method parameters, plus the raised exception for the after-advice case." do
|
696
|
+
watchful = Watchful.new
|
697
|
+
contexts = []
|
698
|
+
@aspect = Aspect.new :before, :after_raising, :pointcut => {:type => Watchful, :methods => :public_watchful_method_that_raises} do |jp, *args|
|
699
|
+
contexts << jp.context
|
700
|
+
end
|
701
|
+
block_called = 0
|
702
|
+
lambda {watchful.public_watchful_method_that_raises(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| block_called += 1 }}.should raise_error(Watchful::WatchfulError)
|
703
|
+
block_called.should == 1
|
704
|
+
contexts.size.should == 2
|
705
|
+
contexts[0].advice_kind.should == :before
|
706
|
+
contexts[1].advice_kind.should == :after_raising
|
707
|
+
contexts[0].raised_exception.should == nil
|
708
|
+
contexts[1].raised_exception.kind_of?(Watchful::WatchfulError).should be_true
|
709
|
+
contexts.each do |context|
|
710
|
+
context.advised_object.should == watchful
|
711
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
712
|
+
context.returned_value.should == nil
|
713
|
+
end
|
714
|
+
end
|
715
|
+
|
716
|
+
it "should evaluate the advice before and after the method body and its block (if any)." do
|
717
|
+
@aspect = Aspect.new :before, :after_raising, :pointcut => {:type => Watchful, :methods => :public_watchful_method_that_raises} do |jp, *args|
|
718
|
+
@advice_called += 1
|
719
|
+
end
|
720
|
+
do_watchful_public_protected_private true, 2
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
describe Aspect, "#new with :around advice" do
|
725
|
+
after(:each) do
|
726
|
+
@aspect.unadvise if @aspect
|
727
|
+
end
|
728
|
+
|
729
|
+
it "should pass the context information to the advice, including the object, advice kind, the method invocation parameters, etc." do
|
730
|
+
contexts = []
|
731
|
+
@aspect = Aspect.new :around, :pointcut => {:type => Watchful, :methods => [:public_watchful_method]} do |jp, *args|
|
732
|
+
contexts << jp.context
|
733
|
+
end
|
734
|
+
watchful = Watchful.new
|
735
|
+
public_block_called = false
|
736
|
+
protected_block_called = false
|
737
|
+
private_block_called = false
|
738
|
+
watchful.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| public_block_called = true }
|
739
|
+
watchful.send(:protected_watchful_method, :b1, :b2, :b3) {|*args| protected_block_called = true}
|
740
|
+
watchful.send(:private_watchful_method, :c1, :c2, :c3) {|*args| private_block_called = true}
|
741
|
+
public_block_called.should be_false # proceed is never called!
|
742
|
+
protected_block_called.should be_true
|
743
|
+
private_block_called.should be_true
|
744
|
+
contexts.size.should == 1
|
745
|
+
contexts[0].advised_object.should == watchful
|
746
|
+
contexts[0].advice_kind.should == :around
|
747
|
+
contexts[0].returned_value.should == nil
|
748
|
+
contexts[0].parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
749
|
+
contexts[0].raised_exception.should == nil
|
750
|
+
end
|
751
|
+
|
752
|
+
it "should advise subclass invocations of methods advised in the superclass." do
|
753
|
+
context = nil
|
754
|
+
@aspect = Aspect.new :around, :pointcut => {:type => Watchful, :methods => [:public_watchful_method]} do |jp, *args|
|
755
|
+
context = jp.context
|
756
|
+
end
|
757
|
+
child = WatchfulChild.new
|
758
|
+
public_block_called = false
|
759
|
+
protected_block_called = false
|
760
|
+
private_block_called = false
|
761
|
+
child.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| fail }
|
762
|
+
child.send(:protected_watchful_method, :b1, :b2, :b3) {|*args| protected_block_called = true}
|
763
|
+
child.send(:private_watchful_method, :c1, :c2, :c3) {|*args| private_block_called = true}
|
764
|
+
public_block_called.should be_false # proceed is never called!
|
765
|
+
protected_block_called.should be_true
|
766
|
+
private_block_called.should be_true
|
767
|
+
context.advised_object.should == child
|
768
|
+
context.advice_kind.should == :around
|
769
|
+
context.returned_value.should == nil
|
770
|
+
context.parameters.should == [:a1, :a2, :a3, {:h1 => 'h1', :h2 => 'h2'}]
|
771
|
+
context.raised_exception.should == nil
|
772
|
+
end
|
773
|
+
|
774
|
+
it "should not advise subclass overrides of superclass methods, when advising superclasses (but calls to superclass methods are advised)." do
|
775
|
+
class WatchfulChild2 < Watchful
|
776
|
+
def public_watchful_method *args
|
777
|
+
@override_called = true
|
778
|
+
yield(*args) if block_given?
|
779
|
+
end
|
780
|
+
attr_reader :override_called
|
781
|
+
def initialize
|
782
|
+
super
|
783
|
+
@override_called = false
|
784
|
+
end
|
785
|
+
end
|
786
|
+
@aspect = Aspect.new(:around, :pointcut => {:type => Watchful, :methods => [:public_watchful_method]}) {|jp, *args| fail}
|
787
|
+
child = WatchfulChild2.new
|
788
|
+
public_block_called = false
|
789
|
+
child.public_watchful_method(:a1, :a2, :a3, :h1 => 'h1', :h2 => 'h2') { |*args| public_block_called = true }
|
790
|
+
public_block_called.should be_true # advice never called
|
791
|
+
end
|
792
|
+
|
793
|
+
it "should evaluate the advice and only evaluate the method body and its block (if any) when JoinPoint#proceed is called." do
|
794
|
+
do_around_spec
|
795
|
+
end
|
796
|
+
|
797
|
+
it "should pass the block that was passed to the method by default if the block is not specified explicitly in the around advice in the call to JoinPoint#proceed." do
|
798
|
+
do_around_spec
|
799
|
+
end
|
800
|
+
|
801
|
+
it "should pass the parameters and block that were passed to the method by default if JoinPoint#proceed is invoked without parameters and a block." do
|
802
|
+
do_around_spec
|
803
|
+
end
|
804
|
+
|
805
|
+
it "should pass parameters passed explicitly to JoinPoint#proceed, rather than the original method parameters, but also pass the original block if a new block is not specified." do
|
806
|
+
do_around_spec :a4, :a5, :a6
|
807
|
+
end
|
808
|
+
|
809
|
+
it "should pass parameters and a block passed explicitly to JoinPoint#proceed, rather than the original method parameters and block." do
|
810
|
+
override_block_called = false
|
811
|
+
@aspect = Aspect.new :around, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
812
|
+
jp.proceed(:a4, :a5, :a6) {|*args| override_block_called = true}
|
813
|
+
end
|
814
|
+
watchful = Watchful.new
|
815
|
+
orig_block_called = false
|
816
|
+
watchful.public_watchful_method(:a1, :a2, :a3) {|*args| orig_block_called = true}
|
817
|
+
override_block_called.should be_true
|
818
|
+
orig_block_called.should be_false
|
819
|
+
watchful.public_watchful_method_args.should == [:a4, :a5, :a6]
|
820
|
+
end
|
821
|
+
|
822
|
+
def do_around_spec *args_passed_to_proceed
|
823
|
+
@aspect = Aspect.new :around, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
824
|
+
@advice_called += 1
|
825
|
+
returned_value = args_passed_to_proceed.empty? ? jp.proceed : jp.proceed(*args_passed_to_proceed)
|
826
|
+
@advice_called += 1
|
827
|
+
returned_value
|
828
|
+
end
|
829
|
+
do_watchful_public_protected_private false, 2, (args_passed_to_proceed.empty? ? nil : args_passed_to_proceed)
|
830
|
+
end
|
831
|
+
end
|
832
|
+
|
833
|
+
|
834
|
+
|
835
|
+
describe Aspect, "#unadvise" do
|
836
|
+
before(:all) do
|
837
|
+
@advice = Proc.new {}
|
838
|
+
end
|
839
|
+
it "should do nothing for unadvised types." do
|
840
|
+
expected_methods = Watchful.private_methods.sort
|
841
|
+
aspect = Aspect.new :around, :type => Watchful, :method => /does_not_exist/, :advice => @advice
|
842
|
+
(Watchful.private_methods.sort - expected_methods).should == []
|
843
|
+
aspect.unadvise
|
844
|
+
(Watchful.private_methods.sort - expected_methods).should == []
|
845
|
+
aspect.unadvise
|
846
|
+
(Watchful.private_methods.sort - expected_methods).should == []
|
847
|
+
end
|
848
|
+
|
849
|
+
it "should do nothing for unadvised objects." do
|
850
|
+
watchful = Watchful.new
|
851
|
+
expected_methods = Watchful.private_methods.sort
|
852
|
+
aspect = Aspect.new :around, :type => Watchful, :method => /does_not_exist/, :advice => @advice
|
853
|
+
(Watchful.private_methods.sort - expected_methods).should == []
|
854
|
+
aspect.unadvise
|
855
|
+
(Watchful.private_methods.sort - expected_methods).should == []
|
856
|
+
aspect.unadvise
|
857
|
+
(Watchful.private_methods.sort - expected_methods).should == []
|
858
|
+
end
|
859
|
+
|
860
|
+
it "should remove all advice added by the aspect." do
|
861
|
+
advice_called = false
|
862
|
+
aspect = Aspect.new(:after, :pointcut => {:type => Watchful, :method_options => :suppress_ancestor_methods}) {|jp, *args| advice_called = true}
|
863
|
+
aspect.unadvise
|
864
|
+
watchful = Watchful.new
|
865
|
+
|
866
|
+
%w[public protected private].each do |protection|
|
867
|
+
advice_called = false
|
868
|
+
block_called = false
|
869
|
+
watchful.send("#{protection}_watchful_method".intern, :a1, :a2, :a3) {|*args| block_called = true}
|
870
|
+
advice_called.should be_false
|
871
|
+
block_called.should be_true
|
872
|
+
end
|
873
|
+
end
|
874
|
+
|
875
|
+
it "should remove all advice overhead if all advices are removed." do
|
876
|
+
class Foo
|
877
|
+
def bar; end
|
878
|
+
end
|
879
|
+
before = Foo.private_instance_methods.sort
|
880
|
+
aspect = Aspect.new(:after, :pointcut => {:type => Foo, :method_options => :suppress_ancestor_methods}) {|jp, *args| true}
|
881
|
+
after = Foo.private_instance_methods
|
882
|
+
(after - before).should_not == []
|
883
|
+
aspect.unadvise
|
884
|
+
after = Foo.private_instance_methods
|
885
|
+
(after - before).should == []
|
886
|
+
end
|
887
|
+
end
|
888
|
+
|
889
|
+
describe Aspect, "#eql?" do
|
890
|
+
before(:all) do
|
891
|
+
@advice = Proc.new {}
|
892
|
+
end
|
893
|
+
after(:each) do
|
894
|
+
@aspect1.unadvise
|
895
|
+
@aspect2.unadvise
|
896
|
+
end
|
897
|
+
|
898
|
+
it "should return true if both aspects have the same specification and pointcuts." do
|
899
|
+
@aspect1 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, :advice => @advice
|
900
|
+
@aspect2 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, :advice => @advice
|
901
|
+
@aspect1.should eql(@aspect2)
|
902
|
+
end
|
903
|
+
|
904
|
+
it "should return true if both aspects have the same specification and pointcuts, even if the advice procs are not equal." do
|
905
|
+
@aspect1 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do true end
|
906
|
+
@aspect2 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do false end
|
907
|
+
@aspect1.should eql(@aspect2)
|
908
|
+
end
|
909
|
+
|
910
|
+
it "should return false if each aspect advises pointcuts in different objects, even if the the objects are equivalent." do
|
911
|
+
@aspect1 = Aspect.new :before, :pointcut => {:object => Watchful.new, :methods => :public_watchful_method} do true end
|
912
|
+
@aspect2 = Aspect.new :before, :pointcut => {:object => Watchful.new, :methods => :public_watchful_method} do false end
|
913
|
+
@aspect1.should_not eql(@aspect2)
|
914
|
+
end
|
915
|
+
end
|
916
|
+
|
917
|
+
describe Aspect, "#==" do
|
918
|
+
before(:all) do
|
919
|
+
@advice = Proc.new {}
|
920
|
+
end
|
921
|
+
after(:each) do
|
922
|
+
@aspect1.unadvise
|
923
|
+
@aspect2.unadvise
|
924
|
+
end
|
925
|
+
|
926
|
+
it "should be equivalent to #eql?." do
|
927
|
+
@aspect1 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, :advice => @advice
|
928
|
+
@aspect2 = Aspect.new :before, :pointcut => {:type => Watchful, :methods => :public_watchful_method}, :advice => @advice
|
929
|
+
@aspect1.specification.should == @aspect2.specification
|
930
|
+
@aspect1.pointcuts.should == @aspect2.pointcuts
|
931
|
+
@aspect1.should eql(@aspect2)
|
932
|
+
@aspect1.should == @aspect2
|
933
|
+
end
|
934
|
+
end
|
935
|
+
|
936
|
+
describe Aspect, "#advice_chain_inspect" do
|
937
|
+
it "should return the string '[nil]' if passed a nil advice chain" do
|
938
|
+
Aspect.advice_chain_inspect(nil).should == "[nil]"
|
939
|
+
chain = NoAdviceChainNode.new({:aspect => nil})
|
940
|
+
Aspect.advice_chain_inspect(chain).should include("NoAdviceChainNode")
|
941
|
+
end
|
942
|
+
end
|
943
|
+
|
944
|
+
def all_public_methods_of_type type
|
945
|
+
(type.public_methods + type.public_instance_methods).sort
|
946
|
+
end
|
947
|
+
def all_protected_methods_of_type type
|
948
|
+
(type.protected_methods + type.protected_instance_methods).sort
|
949
|
+
end
|
950
|
+
def all_public_methods_of_object object
|
951
|
+
object.public_methods.sort
|
952
|
+
end
|
953
|
+
def all_protected_methods_of_object object
|
954
|
+
object.protected_methods.sort
|
955
|
+
end
|
956
|
+
|
957
|
+
def do_watchful_public_protected_private raises = false, expected_advice_called_value = 1, args_passed_to_proceed = nil
|
958
|
+
%w[public protected private].each do |protection|
|
959
|
+
do_watchful_spec protection, raises, expected_advice_called_value, args_passed_to_proceed
|
960
|
+
end
|
961
|
+
end
|
962
|
+
|
963
|
+
def do_watchful_spec protection, raises, expected_advice_called_value, args_passed_to_proceed
|
964
|
+
suffix = raises ? "_that_raises" : ""
|
965
|
+
expected_advice_called = protection == "public" ? expected_advice_called_value : 0
|
966
|
+
watchful = Watchful.new
|
967
|
+
@advice_called = 0
|
968
|
+
block_called = 0
|
969
|
+
if raises
|
970
|
+
lambda {watchful.send("#{protection}_watchful_method#{suffix}".intern, :a1, :a2, :a3) {|*args| block_called += 1}}.should raise_error(Watchful::WatchfulError)
|
971
|
+
else
|
972
|
+
watchful.send("#{protection}_watchful_method#{suffix}".intern, :a1, :a2, :a3) {|*args| block_called += 1}
|
973
|
+
end
|
974
|
+
@advice_called.should == expected_advice_called
|
975
|
+
block_called.should == 1
|
976
|
+
expected_args = (protection == "public" && !args_passed_to_proceed.nil?) ? args_passed_to_proceed : [:a1, :a2, :a3]
|
977
|
+
watchful.instance_variable_get("@#{protection}_watchful_method#{suffix}_args".intern).should == expected_args
|
978
|
+
end
|