aquarium 0.1.0 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- 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 {}
|