aquarium 0.1.0 → 0.1.5
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 +53 -0
- data/README +20 -4
- data/Rakefile +19 -4
- data/UPGRADE +41 -1
- data/examples/aspect_design_example.rb +4 -1
- data/examples/aspect_design_example_spec.rb +41 -0
- data/examples/design_by_contract_example.rb +2 -3
- data/examples/design_by_contract_example_spec.rb +92 -0
- data/examples/method_missing_example.rb +1 -1
- data/examples/method_missing_example_spec.rb +59 -0
- data/examples/method_tracing_example.rb +4 -2
- data/examples/method_tracing_example_spec.rb +141 -0
- data/lib/aquarium/aspects/advice.rb +2 -2
- data/lib/aquarium/aspects/aspect.rb +20 -35
- data/lib/aquarium/aspects/dsl.rb +2 -1
- data/lib/aquarium/aspects/dsl/aspect_dsl.rb +12 -8
- data/lib/aquarium/aspects/dsl/object_dsl.rb +8 -0
- data/lib/aquarium/aspects/join_point.rb +16 -10
- data/lib/aquarium/aspects/pointcut.rb +3 -3
- data/lib/aquarium/extras/design_by_contract.rb +20 -11
- data/lib/aquarium/utils.rb +1 -0
- data/lib/aquarium/utils/method_utils.rb +41 -0
- data/lib/aquarium/utils/name_utils.rb +35 -0
- data/lib/aquarium/utils/type_utils.rb +9 -0
- data/lib/aquarium/version.rb +3 -5
- data/rake_tasks/examples.rake +1 -1
- data/spec/aquarium/aspects/aspect_invocation_spec.rb +30 -28
- data/spec/aquarium/aspects/aspect_spec.rb +90 -0
- data/spec/aquarium/aspects/concurrent_aspects_spec.rb +5 -3
- data/spec/aquarium/aspects/concurrent_aspects_with_objects_and_types_spec.rb +3 -1
- data/spec/aquarium/aspects/dsl/aspect_dsl_spec.rb +174 -110
- data/spec/aquarium/aspects/join_point_spec.rb +120 -19
- data/spec/aquarium/aspects/pointcut_spec.rb +24 -14
- data/spec/aquarium/extras/design_by_contract_spec.rb +3 -0
- data/spec/aquarium/finders/finder_result_spec.rb +1 -1
- data/spec/aquarium/finders/method_finder_spec.rb +3 -4
- data/spec/aquarium/spec_example_classes.rb +4 -0
- data/spec/aquarium/utils/method_utils_spec.rb +124 -1
- data/spec/aquarium/utils/name_utils_spec.rb +56 -0
- data/spec/aquarium/utils/type_utils_spec.rb +17 -0
- metadata +12 -4
- data/spec/aquarium/finders/method_sorting_spec.rb +0 -16
@@ -59,7 +59,7 @@ module Aquarium
|
|
59
59
|
# <tt>:attribute => attribute || [attribute_list]</tt>::
|
60
60
|
# One or an array of attribute names and/or regular expessions to match.
|
61
61
|
# This is syntactic sugar for the corresponding attribute readers and/or writers
|
62
|
-
# methods, as specified using the <tt>:attrbute_options
|
62
|
+
# methods, as specified using the <tt>:attrbute_options</tt>. Any matches will be
|
63
63
|
# joined with the matched :methods.</tt>.
|
64
64
|
#
|
65
65
|
# <tt>:attribute_options => [options]</tt>::
|
@@ -202,13 +202,13 @@ module Aquarium
|
|
202
202
|
end
|
203
203
|
|
204
204
|
def add_join_points which_join_points_list, results_hash, type_or_object_sym
|
205
|
-
|
205
|
+
instance_method = @specification[:method_options].include?(:class) ? false : true
|
206
206
|
results_hash.each_pair do |type_or_object, method_name_list|
|
207
207
|
method_name_list.each do |method_name|
|
208
208
|
which_join_points_list << Aquarium::Aspects::JoinPoint.new(
|
209
209
|
type_or_object_sym => type_or_object,
|
210
210
|
:method_name => method_name,
|
211
|
-
:
|
211
|
+
:instance_method => instance_method)
|
212
212
|
end
|
213
213
|
end
|
214
214
|
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
# A simple Design by Contract module. Adds advice to test that the contract, which is specified with
|
2
2
|
# a block passes. Note that it doesn't attempt to handle the correct behavior under contract
|
3
3
|
# inheritance (TODO).
|
4
|
-
|
4
|
+
# Warning: This module automatically includes Aquarium::Aspects::DSL::AspectDSL into the class with
|
5
|
+
# the contract and it adds the :precondition, :postcondition, and the :invariant methods to Object!
|
5
6
|
require 'aquarium'
|
6
7
|
|
7
8
|
module Aquarium
|
8
9
|
module Extras
|
9
10
|
module DesignByContract
|
10
|
-
|
11
|
+
include Aquarium::Aspects
|
12
|
+
|
11
13
|
class ContractError < Exception
|
12
14
|
def initialize(message)
|
13
15
|
super
|
@@ -15,21 +17,21 @@ module Aquarium
|
|
15
17
|
end
|
16
18
|
|
17
19
|
def precondition *args, &contract_block
|
18
|
-
message = handle_message_arg
|
20
|
+
message = handle_message_arg args
|
19
21
|
add_advice :before, "precondition", message, *args, &contract_block
|
20
22
|
end
|
21
23
|
|
22
24
|
def postcondition *args, &contract_block
|
23
|
-
message = handle_message_arg
|
25
|
+
message = handle_message_arg args
|
24
26
|
add_advice :after_returning, "postcondition", message, *args, &contract_block
|
25
27
|
end
|
26
28
|
|
27
29
|
def invariant *args, &contract_block
|
28
|
-
message = handle_message_arg
|
29
|
-
around *args do |jp, *
|
30
|
-
DesignByContract.test_condition "invariant failure (before invocation): #{message}", jp, *
|
30
|
+
message = handle_message_arg args
|
31
|
+
Aspect.new make_args(:around, *args) do |jp, *params|
|
32
|
+
DesignByContract.test_condition "invariant failure (before invocation): #{message}", jp, *params, &contract_block
|
31
33
|
jp.proceed
|
32
|
-
DesignByContract.test_condition "invariant failure (after invocation): #{message}", jp, *
|
34
|
+
DesignByContract.test_condition "invariant failure (after invocation): #{message}", jp, *params, &contract_block
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -42,12 +44,19 @@ module Aquarium
|
|
42
44
|
end
|
43
45
|
|
44
46
|
def add_advice kind, test_kind, message, *args, &contract_block
|
45
|
-
|
46
|
-
DesignByContract.test_condition "#{test_kind} failure: #{message}", jp, *
|
47
|
+
Aspect.new make_args(kind, *args) do |jp, *params|
|
48
|
+
DesignByContract.test_condition "#{test_kind} failure: #{message}", jp, *params, &contract_block
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
50
|
-
def
|
52
|
+
def make_args advice_kind, *args
|
53
|
+
args2 = args.dup.unshift advice_kind
|
54
|
+
args2 << {} unless args2.last.kind_of?(Hash)
|
55
|
+
args2.last[:type] = self.name
|
56
|
+
args2
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_message_arg args
|
51
60
|
options = args[-1]
|
52
61
|
return unless options.kind_of?(Hash)
|
53
62
|
message = options[:message]
|
data/lib/aquarium/utils.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
module Aquarium
|
2
2
|
module Utils
|
3
3
|
module MethodUtils
|
4
|
+
|
4
5
|
def self.method_args_to_hash *args
|
5
6
|
return {} if args.empty? || (args.size == 1 && args[0].nil?)
|
6
7
|
hash = (args[-1] and args[-1].kind_of? Hash) ? args.pop : {}
|
@@ -13,6 +14,46 @@ module Aquarium
|
|
13
14
|
end
|
14
15
|
hash
|
15
16
|
end
|
17
|
+
|
18
|
+
def self.visibility type_or_instance, method_sym, class_or_instance_only = nil
|
19
|
+
meta_method_suffixes = determine_meta_method_suffixes type_or_instance, class_or_instance_only
|
20
|
+
meta_method_suffixes.each do |suffix|
|
21
|
+
%w[public protected private].each do |protection|
|
22
|
+
meta_method = "#{protection}_#{suffix}"
|
23
|
+
if find_method(type_or_instance, method_sym, meta_method)
|
24
|
+
return protection.intern
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def self.determine_meta_method_suffixes2 type_or_instance, class_or_instance_only
|
33
|
+
["method_defined"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.determine_meta_method_suffixes type_or_instance, class_or_instance_only
|
37
|
+
limits = class_or_instance_only.nil? ? [:instance_method_only, :class_method_only] : [class_or_instance_only]
|
38
|
+
meta_method_suffixes = []
|
39
|
+
limits.each do |limit|
|
40
|
+
if (type_or_instance.kind_of?(Class) || type_or_instance.kind_of?(Module))
|
41
|
+
meta_method_suffixes << "instance_methods" if limit == :instance_method_only
|
42
|
+
meta_method_suffixes << "methods" if limit == :class_method_only
|
43
|
+
else
|
44
|
+
meta_method_suffixes << "methods" if limit == :instance_method_only
|
45
|
+
end
|
46
|
+
end
|
47
|
+
meta_method_suffixes
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.find_method2 type_or_instance, method_sym, meta_method
|
51
|
+
type_or_instance.send(meta_method, method_sym.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.find_method type_or_instance, method_sym, meta_method
|
55
|
+
type_or_instance.send(meta_method).include?(method_sym.to_s)
|
56
|
+
end
|
16
57
|
end
|
17
58
|
end
|
18
59
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'aquarium/utils/type_utils'
|
2
|
+
|
3
|
+
# Convert various strings, symbols, object ids, etc. into valid "names" that
|
4
|
+
# can be used as method names, etc.
|
5
|
+
module Aquarium
|
6
|
+
module Utils
|
7
|
+
module NameUtils
|
8
|
+
|
9
|
+
def self.make_type_or_object_key type_or_object
|
10
|
+
if Aquarium::Utils::TypeUtils.is_type?(type_or_object)
|
11
|
+
make_valid_type_name type_or_object
|
12
|
+
else
|
13
|
+
make_valid_object_name type_or_object
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.make_valid_type_name type
|
18
|
+
type.name.gsub(/:/, '_')
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.make_valid_object_name type_or_object
|
22
|
+
"#{make_valid_type_name(type_or_object.class)}_#{make_valid_object_id_name(type_or_object.object_id)}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# Fixes Tracker #13864.
|
26
|
+
def self.make_valid_object_id_name object_id
|
27
|
+
object_id.to_s.gsub(/^-/, "_neg_")
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.make_valid_attr_name_from_method_name method_name
|
31
|
+
method_name.to_s.gsub("=","_equalsign_").gsub("?", "_questionmark_").gsub("!", "_exclamationmark_").gsub("~", "_tilde_").intern
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/aquarium/version.rb
CHANGED
@@ -2,17 +2,15 @@ module Aquarium
|
|
2
2
|
module VERSION
|
3
3
|
def self.build_tag
|
4
4
|
tag = "REL_" + [MAJOR, MINOR, TINY].join('_')
|
5
|
-
|
6
|
-
tag << "_" << RELEASE_CANDIDATE
|
7
|
-
end
|
5
|
+
tag << "_" << RELEASE_CANDIDATE unless RELEASE_CANDIDATE.nil? or RELEASE_CANDIDATE.empty?
|
8
6
|
tag
|
9
7
|
end
|
10
8
|
|
11
9
|
unless defined? MAJOR
|
12
10
|
MAJOR = 0
|
13
11
|
MINOR = 1
|
14
|
-
TINY =
|
15
|
-
RELEASE_CANDIDATE =
|
12
|
+
TINY = 5
|
13
|
+
RELEASE_CANDIDATE = nil
|
16
14
|
|
17
15
|
# RANDOM_TOKEN: 0.598704893979657
|
18
16
|
REV = "$LastChangedRevision: 7 $".match(/LastChangedRevision: (\d+)/)[1]
|
data/rake_tasks/examples.rake
CHANGED
@@ -3,44 +3,46 @@ require File.dirname(__FILE__) + '/../spec_example_classes'
|
|
3
3
|
require 'aquarium/aspects/aspect'
|
4
4
|
require 'aquarium/aspects/dsl'
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
include Aquarium::Aspects
|
7
|
+
|
8
|
+
describe Aspect, "#new with invalid invocation parameter list" do
|
9
|
+
it "should have as the first parameter at least one of :around, :before, :after, :after_returning, and :after_raising." do
|
10
|
+
lambda { Aspect.new :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
9
11
|
end
|
10
12
|
|
11
13
|
it "should contain no other advice types if :around advice specified." do
|
12
|
-
lambda {
|
13
|
-
lambda {
|
14
|
-
lambda {
|
15
|
-
lambda {
|
14
|
+
lambda { Aspect.new :around, :before, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
15
|
+
lambda { Aspect.new :around, :after, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
16
|
+
lambda { Aspect.new :around, :after_returning, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
17
|
+
lambda { Aspect.new :around, :after_raising, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
16
18
|
end
|
17
19
|
|
18
20
|
it "should allow only one of :after, :after_returning, or :after_raising advice to be specified." do
|
19
|
-
lambda {
|
20
|
-
lambda {
|
21
|
-
lambda {
|
21
|
+
lambda { Aspect.new :after, :after_returning, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
22
|
+
lambda { Aspect.new :after, :after_raising, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
23
|
+
lambda { Aspect.new :after_returning, :after_raising, :pointcut => {:type => Watchful} }.should raise_error(Aquarium::Utils::InvalidOptions)
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
25
|
-
describe
|
27
|
+
describe Aspect, "#new, when the arguments contain more than one advice type," do
|
26
28
|
it "should allow :before to be specified with :after." do
|
27
|
-
lambda {
|
29
|
+
lambda { Aspect.new :before, :after, :pointcut => {:type => Watchful}, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
|
28
30
|
end
|
29
31
|
|
30
32
|
it "should allow :before to be specified with :after_returning." do
|
31
|
-
lambda {
|
33
|
+
lambda { Aspect.new :before, :after_returning, :pointcut => {:type => Watchful}, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
|
32
34
|
end
|
33
35
|
|
34
36
|
it "should allow :before to be specified with :after_raising." do
|
35
|
-
lambda {
|
37
|
+
lambda { Aspect.new :before, :after_raising, :pointcut => {:type => Watchful}, :noop => true }.should_not raise_error(Aquarium::Utils::InvalidOptions)
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
|
-
describe
|
41
|
+
describe Aspect, "#new arguments for specifying the types and methods" do
|
40
42
|
it "should advise equivalent join points when :type => T and :method => m is used or :pointcut =>{:type => T, :method => m} is used." do
|
41
43
|
advice = proc {|jp,*args| "advice"}
|
42
|
-
aspect1 =
|
43
|
-
aspect2 =
|
44
|
+
aspect1 = Aspect.new :after, :type => Watchful, :method => :public_watchful_method, &advice
|
45
|
+
aspect2 = Aspect.new :after, :pointcut => {:type => Watchful, :method => :public_watchful_method}, &advice
|
44
46
|
# We don't use aspect1.should eql(aspect2) because the "specifications" are different.
|
45
47
|
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
46
48
|
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
@@ -51,9 +53,9 @@ describe Object, "#advise arguments for specifying the types and methods" do
|
|
51
53
|
|
52
54
|
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
55
|
advice = proc {|jp,*args| "advice"}
|
54
|
-
aspect1 =
|
56
|
+
aspect1 = Aspect.new :after, :type => Watchful, :method => :public_watchful_method, &advice
|
55
57
|
pointcut = Aquarium::Aspects::Pointcut.new :type => Watchful, :method => :public_watchful_method
|
56
|
-
aspect2 =
|
58
|
+
aspect2 = Aspect.new :after, :pointcut => pointcut, &advice
|
57
59
|
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
58
60
|
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
59
61
|
aspect1.advice.should eql(aspect2.advice)
|
@@ -62,9 +64,9 @@ describe Object, "#advise arguments for specifying the types and methods" do
|
|
62
64
|
|
63
65
|
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
66
|
advice = proc {|jp,*args| "advice"}
|
65
|
-
aspect1 =
|
67
|
+
aspect1 = Aspect.new :after, :pointcut => {:type => Watchful, :method => :public_watchful_method}, &advice
|
66
68
|
pointcut = Aquarium::Aspects::Pointcut.new :type => Watchful, :method => :public_watchful_method
|
67
|
-
aspect2 =
|
69
|
+
aspect2 = Aspect.new :after, :pointcut => pointcut, &advice
|
68
70
|
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
69
71
|
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
70
72
|
aspect1.advice.should eql(aspect2.advice)
|
@@ -72,12 +74,12 @@ describe Object, "#advise arguments for specifying the types and methods" do
|
|
72
74
|
end
|
73
75
|
end
|
74
76
|
|
75
|
-
describe
|
77
|
+
describe Aspect, "#new arguments for specifying the objects and methods" do
|
76
78
|
it "should advise equivalent join points when :object => o and :method => m is used or :pointcut =>{:object => o, :method => m} is used." do
|
77
79
|
advice = proc {|jp,*args| "advice"}
|
78
80
|
watchful = Watchful.new
|
79
|
-
aspect1 =
|
80
|
-
aspect2 =
|
81
|
+
aspect1 = Aspect.new :after, :object => watchful, :method => :public_watchful_method, &advice
|
82
|
+
aspect2 = Aspect.new :after, :pointcut => {:object => watchful, :method => :public_watchful_method}, &advice
|
81
83
|
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
82
84
|
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
83
85
|
aspect1.advice.should eql(aspect2.advice)
|
@@ -87,9 +89,9 @@ describe Object, "#advise arguments for specifying the objects and methods" do
|
|
87
89
|
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
90
|
advice = proc {|jp,*args| "advice"}
|
89
91
|
watchful = Watchful.new
|
90
|
-
aspect1 =
|
92
|
+
aspect1 = Aspect.new :after, :object => watchful, :method => :public_watchful_method, &advice
|
91
93
|
pointcut = Aquarium::Aspects::Pointcut.new :object => watchful, :method => :public_watchful_method
|
92
|
-
aspect2 =
|
94
|
+
aspect2 = Aspect.new :after, :pointcut => pointcut, &advice
|
93
95
|
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
94
96
|
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
95
97
|
aspect1.advice.should eql(aspect2.advice)
|
@@ -99,9 +101,9 @@ describe Object, "#advise arguments for specifying the objects and methods" do
|
|
99
101
|
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
102
|
advice = proc {|jp,*args| "advice"}
|
101
103
|
watchful = Watchful.new
|
102
|
-
aspect1 =
|
104
|
+
aspect1 = Aspect.new :after, :pointcut => {:object => watchful, :method => :public_watchful_method}, &advice
|
103
105
|
pointcut = Aquarium::Aspects::Pointcut.new :object => watchful, :method => :public_watchful_method
|
104
|
-
aspect2 =
|
106
|
+
aspect2 = Aspect.new :after, :pointcut => pointcut, &advice
|
105
107
|
aspect1.pointcuts.should eql(aspect2.pointcuts)
|
106
108
|
aspect1.join_points_matched.should eql(aspect2.join_points_matched)
|
107
109
|
aspect1.advice.should eql(aspect2.advice)
|
@@ -512,6 +512,33 @@ describe Aspect, "#new with :after advice" do
|
|
512
512
|
end
|
513
513
|
do_watchful_public_protected_private
|
514
514
|
end
|
515
|
+
it "should ignore the value returned by the advice" do
|
516
|
+
class ReturningValue
|
517
|
+
def doit args
|
518
|
+
args + ["d"]
|
519
|
+
end
|
520
|
+
end
|
521
|
+
ary = %w[a b c]
|
522
|
+
ReturningValue.new.doit(ary).should == %w[a b c d]
|
523
|
+
@aspect = Aspect.new :after, :type => ReturningValue, :method => :doit do |jp, *args|
|
524
|
+
%w[aa] + jp.context.returned_value + %w[e]
|
525
|
+
end
|
526
|
+
ReturningValue.new.doit(ary).should == %w[a b c d]
|
527
|
+
end
|
528
|
+
|
529
|
+
it "should all the advice to assign a new return value" do
|
530
|
+
class ReturningValue
|
531
|
+
def doit args
|
532
|
+
args + ["d"]
|
533
|
+
end
|
534
|
+
end
|
535
|
+
ary = %w[a b c]
|
536
|
+
ReturningValue.new.doit(ary).should == %w[a b c d]
|
537
|
+
@aspect = Aspect.new :after, :type => ReturningValue, :method => :doit do |jp, *args|
|
538
|
+
jp.context.returned_value = %w[aa] + jp.context.returned_value + %w[e]
|
539
|
+
end
|
540
|
+
ReturningValue.new.doit(ary).should == %w[aa a b c d e]
|
541
|
+
end
|
515
542
|
end
|
516
543
|
|
517
544
|
describe Aspect, "#new with :after_returning advice" do
|
@@ -541,6 +568,34 @@ describe Aspect, "#new with :after_returning advice" do
|
|
541
568
|
end
|
542
569
|
do_watchful_public_protected_private
|
543
570
|
end
|
571
|
+
|
572
|
+
it "should ignore the value returned by the advice" do
|
573
|
+
class ReturningValue
|
574
|
+
def doit args
|
575
|
+
args + ["d"]
|
576
|
+
end
|
577
|
+
end
|
578
|
+
ary = %w[a b c]
|
579
|
+
ReturningValue.new.doit(ary).should == %w[a b c d]
|
580
|
+
@aspect = Aspect.new :after_returning, :type => ReturningValue, :method => :doit do |jp, *args|
|
581
|
+
%w[aa] + jp.context.returned_value + %w[e]
|
582
|
+
end
|
583
|
+
ReturningValue.new.doit(ary).should == %w[a b c d]
|
584
|
+
end
|
585
|
+
|
586
|
+
it "should all the advice to assign a new return value" do
|
587
|
+
class ReturningValue
|
588
|
+
def doit args
|
589
|
+
args + ["d"]
|
590
|
+
end
|
591
|
+
end
|
592
|
+
ary = %w[a b c]
|
593
|
+
ReturningValue.new.doit(ary).should == %w[a b c d]
|
594
|
+
@aspect = Aspect.new :after_returning, :type => ReturningValue, :method => :doit do |jp, *args|
|
595
|
+
jp.context.returned_value = %w[aa] + jp.context.returned_value + %w[e]
|
596
|
+
end
|
597
|
+
ReturningValue.new.doit(ary).should == %w[aa a b c d e]
|
598
|
+
end
|
544
599
|
end
|
545
600
|
|
546
601
|
describe Aspect, "#new with :after_raising advice" do
|
@@ -818,6 +873,20 @@ describe Aspect, "#new with :around advice" do
|
|
818
873
|
orig_block_called.should be_false
|
819
874
|
watchful.public_watchful_method_args.should == [:a4, :a5, :a6]
|
820
875
|
end
|
876
|
+
|
877
|
+
it "should return the value returned by the advice" do
|
878
|
+
class ReturningValue
|
879
|
+
def doit args
|
880
|
+
args + ["d"]
|
881
|
+
end
|
882
|
+
end
|
883
|
+
ary = %w[a b c]
|
884
|
+
ReturningValue.new.doit(ary).should == %w[a b c d]
|
885
|
+
@aspect = Aspect.new :around, :type => ReturningValue, :method => :doit do |jp, *args|
|
886
|
+
%w[aa] + jp.proceed + %w[e]
|
887
|
+
end
|
888
|
+
ReturningValue.new.doit(ary).should == %w[aa a b c d e]
|
889
|
+
end
|
821
890
|
|
822
891
|
def do_around_spec *args_passed_to_proceed
|
823
892
|
@aspect = Aspect.new :around, :pointcut => {:type => Watchful, :methods => :public_watchful_method} do |jp, *args|
|
@@ -886,6 +955,27 @@ describe Aspect, "#unadvise" do
|
|
886
955
|
end
|
887
956
|
end
|
888
957
|
|
958
|
+
describe "invariant protection level of methods under advising and unadvising", :shared => true do
|
959
|
+
it "should keep the protection level of an advised methods unchanged." do
|
960
|
+
%w[public protected private].each do |protection|
|
961
|
+
meta = "#{protection}_instance_methods"
|
962
|
+
method = "#{protection}_watchful_method"
|
963
|
+
Watchful.send(meta).should include(method)
|
964
|
+
aspect = Aspect.new(:after, :type => Watchful, :method => method.intern) {|jp, *args| true }
|
965
|
+
Watchful.send(meta).should include(method)
|
966
|
+
aspect.unadvise
|
967
|
+
Watchful.send(meta).should include(method)
|
968
|
+
end
|
969
|
+
end
|
970
|
+
end
|
971
|
+
|
972
|
+
describe Aspect, "Advising methods should keep the protection level of an advised methods unchanged." do
|
973
|
+
it_should_behave_like("invariant protection level of methods under advising and unadvising")
|
974
|
+
end
|
975
|
+
describe Aspect, "Unadvising methods should restore the original protection level of the methods." do
|
976
|
+
it_should_behave_like("invariant protection level of methods under advising and unadvising")
|
977
|
+
end
|
978
|
+
|
889
979
|
describe Aspect, "#eql?" do
|
890
980
|
before(:all) do
|
891
981
|
@advice = Proc.new {}
|