aquarium 0.1.6 → 0.1.7

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.
Files changed (32) hide show
  1. data/CHANGES +18 -0
  2. data/README +68 -39
  3. data/RELEASE-PLAN +25 -1
  4. data/UPGRADE +4 -0
  5. data/examples/aspect_design_example.rb +9 -3
  6. data/examples/aspect_design_example_spec.rb +7 -2
  7. data/examples/method_tracing_example.rb +1 -1
  8. data/examples/method_tracing_example_spec.rb +2 -2
  9. data/lib/aquarium/aspects/aspect.rb +53 -60
  10. data/lib/aquarium/aspects/dsl/aspect_dsl.rb +0 -1
  11. data/lib/aquarium/aspects/pointcut.rb +72 -17
  12. data/lib/aquarium/aspects/pointcut_composition.rb +4 -1
  13. data/lib/aquarium/extensions/hash.rb +65 -28
  14. data/lib/aquarium/extensions/set.rb +2 -0
  15. data/lib/aquarium/finders/finder_result.rb +13 -2
  16. data/lib/aquarium/finders/method_finder.rb +54 -28
  17. data/lib/aquarium/finders/type_finder.rb +36 -19
  18. data/lib/aquarium/utils/method_utils.rb +3 -12
  19. data/lib/aquarium/utils/name_utils.rb +27 -1
  20. data/lib/aquarium/version.rb +1 -1
  21. data/spec/aquarium/aspects/aspect_invocation_spec.rb +182 -51
  22. data/spec/aquarium/aspects/aspect_spec.rb +43 -8
  23. data/spec/aquarium/aspects/pointcut_and_composition_spec.rb +32 -3
  24. data/spec/aquarium/aspects/pointcut_or_composition_spec.rb +36 -5
  25. data/spec/aquarium/aspects/pointcut_spec.rb +373 -99
  26. data/spec/aquarium/extensions/hash_spec.rb +129 -38
  27. data/spec/aquarium/finders/finder_result_spec.rb +73 -15
  28. data/spec/aquarium/finders/method_finder_spec.rb +156 -72
  29. data/spec/aquarium/finders/object_finder_spec.rb +1 -0
  30. data/spec/aquarium/finders/type_finder_spec.rb +43 -0
  31. data/spec/aquarium/utils/name_utils_spec.rb +79 -4
  32. metadata +3 -3
@@ -1,6 +1,7 @@
1
1
  require 'set'
2
2
  require File.dirname(__FILE__) + '/../utils/array_utils'
3
3
  require File.dirname(__FILE__) + '/../utils/invalid_options'
4
+ require File.dirname(__FILE__) + '/../extensions/hash'
4
5
  require File.dirname(__FILE__) + '/../extensions/regexp'
5
6
  require File.dirname(__FILE__) + '/../extensions/symbol'
6
7
  require File.dirname(__FILE__) + '/finder_result'
@@ -27,6 +28,13 @@ module Aquarium
27
28
  # <tt>:name => type_or_type_name_or_regexp</tt>::
28
29
  # Sugar for specifying one type name.
29
30
  #
31
+ # <tt>:exclude_type => type_or_type_name_or_regexp</tt>::
32
+ # <tt>:exclude_types => type_or_type_name_or_regexp</tt>::
33
+ # <tt>:exclude_name => type_or_type_name_or_regexp</tt>::
34
+ # <tt>:exclude_names => type_or_type_name_or_regexp</tt>::
35
+ # Exclude matching types from the list. These excluded types <b>won't</b> appear
36
+ # in the FinderResult#not_matched.
37
+ #
30
38
  # Actually, there is actually no difference between <tt>:types</tt>,
31
39
  # <tt>:type</tt>, <tt>:names</tt>, and <tt>:name</tt>. The extra forms are "sugar"...
32
40
  #
@@ -50,18 +58,23 @@ module Aquarium
50
58
  # the whole name between the "::" exactly.
51
59
  #
52
60
  def find options = {}
53
- result = Aquarium::Finders::FinderResult.new
61
+ result = Aquarium::Finders::FinderResult.new
62
+ excluded = Aquarium::Finders::FinderResult.new
54
63
  unknown_options = []
55
64
  options.each do |option, value|
56
- case option.to_s
57
- when "names", "types", "name", "type"
58
- result << find_all_by(value)
59
- else
65
+ unless TypeFinder.is_recognized_option option
60
66
  unknown_options << option
67
+ next
68
+ end
69
+
70
+ if option.to_s =~ /^exclude_/
71
+ excluded << find_all_by(value)
72
+ else
73
+ result << find_all_by(value)
61
74
  end
62
75
  end
63
76
  raise Aquarium::Utils::InvalidOptions.new("Unknown options: #{unknown_options.inspect}.") if unknown_options.size > 0
64
- result
77
+ result - excluded
65
78
  end
66
79
 
67
80
  # For a name (not a regular expression), return the corresponding type.
@@ -83,22 +96,11 @@ module Aquarium
83
96
 
84
97
  def find_all_by regexpes_or_names
85
98
  raise Aquarium::Utils::InvalidOptions.new("Input type(s) can't be nil!") if regexpes_or_names.nil?
86
- result = Aquarium::Finders::FinderResult.new
87
- expressions = make_array regexpes_or_names
88
- expressions.each do |expression|
89
- expr = strip expression
90
- next if empty expr
91
- if expr.kind_of? Regexp
92
- result << find_namespace_matched(expr)
93
- else
94
- result << find_by_name(expr)
95
- end
96
- end
97
- result
99
+ find_matching regexpes_or_names
98
100
  end
99
101
 
100
102
  def self.is_recognized_option option_or_symbol
101
- %w[name names type types].include? option_or_symbol.to_s
103
+ %w[name names type types exclude_type exclude_types exclude_name exclude_names].include? option_or_symbol.to_s
102
104
  end
103
105
 
104
106
  private
@@ -112,6 +114,21 @@ module Aquarium
112
114
  expression.nil? || (expression.respond_to?(:empty?) && expression.empty?)
113
115
  end
114
116
 
117
+ def find_matching regexpes_or_names
118
+ result = Aquarium::Finders::FinderResult.new
119
+ expressions = make_array regexpes_or_names
120
+ expressions.each do |expression|
121
+ expr = strip expression
122
+ next if empty expr
123
+ if expr.kind_of? Regexp
124
+ result << find_namespace_matched(expr)
125
+ else
126
+ result << find_by_name(expr)
127
+ end
128
+ end
129
+ result
130
+ end
131
+
115
132
  def find_namespace_matched expression
116
133
  expr = expression.kind_of?(Regexp) ? expression.source : expression.to_s
117
134
  return nil if expr.empty?
@@ -1,3 +1,5 @@
1
+ require 'aquarium/utils/type_utils'
2
+
1
3
  module Aquarium
2
4
  module Utils
3
5
  module MethodUtils
@@ -29,15 +31,12 @@ module Aquarium
29
31
  end
30
32
 
31
33
  private
32
- def self.determine_meta_method_suffixes2 type_or_instance, class_or_instance_only
33
- ["method_defined"]
34
- end
35
34
 
36
35
  def self.determine_meta_method_suffixes type_or_instance, class_or_instance_only
37
36
  limits = class_or_instance_only.nil? ? [:instance_method_only, :class_method_only] : [class_or_instance_only]
38
37
  meta_method_suffixes = []
39
38
  limits.each do |limit|
40
- if (is_type? type_or_instance)
39
+ if (Aquarium::Utils::TypeUtils.is_type? type_or_instance)
41
40
  meta_method_suffixes << "instance_methods" if limit == :instance_method_only
42
41
  meta_method_suffixes << "methods" if limit == :class_method_only
43
42
  else
@@ -47,14 +46,6 @@ module Aquarium
47
46
  meta_method_suffixes
48
47
  end
49
48
 
50
- def self.is_type? type_or_instance
51
- type_or_instance.kind_of?(Class) || type_or_instance.kind_of?(Module)
52
- end
53
-
54
- def self.find_method2 type_or_instance, method_sym, meta_method
55
- type_or_instance.send(meta_method, method_sym.to_s)
56
- end
57
-
58
49
  def self.find_method type_or_instance, method_sym, meta_method
59
50
  type_or_instance.send(meta_method).include?(method_sym.to_s)
60
51
  end
@@ -6,6 +6,28 @@ module Aquarium
6
6
  module Utils
7
7
  module NameUtils
8
8
 
9
+ @@char_map = {
10
+ '=' => '_equal_',
11
+ '?' => '_questionmark_',
12
+ '!' => '_exclamationmark_',
13
+ '~' => '_tilde_',
14
+ '-' => '_minus_',
15
+ '+' => '_plus_',
16
+ '/' => '_slash_',
17
+ '*' => '_star_',
18
+ '<' => '_lessthan_',
19
+ '>' => '_greaterthan_',
20
+ '<<' => '_leftshift_',
21
+ '>>' => '_rightshift_',
22
+ '=~' => '_matches_',
23
+ '%' => '_percent_',
24
+ '^' => '_caret_',
25
+ '[]' => '_brackets_',
26
+ '&' => '_ampersand_',
27
+ '|' => '_pipe_',
28
+ '`' => '_backtick_'
29
+ }
30
+
9
31
  def self.make_type_or_object_key type_or_object
10
32
  if Aquarium::Utils::TypeUtils.is_type?(type_or_object)
11
33
  make_valid_type_name type_or_object
@@ -28,7 +50,11 @@ module Aquarium
28
50
  end
29
51
 
30
52
  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
53
+ new_name = method_name.to_s
54
+ @@char_map.each do |char, substitute|
55
+ new_name.gsub! char, substitute
56
+ end
57
+ new_name.intern
32
58
  end
33
59
  end
34
60
  end
@@ -9,7 +9,7 @@ module Aquarium
9
9
  unless defined? MAJOR
10
10
  MAJOR = 0
11
11
  MINOR = 1
12
- TINY = 6
12
+ TINY = 7
13
13
  RELEASE_CANDIDATE = nil
14
14
 
15
15
  # RANDOM_TOKEN: 0.598704893979657
@@ -38,88 +38,219 @@ describe Aspect, "#new, when the arguments contain more than one advice type," d
38
38
  end
39
39
  end
40
40
 
41
+ def aspects_should_be_equal num_jps, aspect1, aspect2
42
+ # We don't use @aspect1.should eql(@aspect2) because the "specifications" are different.
43
+ aspect1.pointcuts.size.should == 1
44
+ aspect2.pointcuts.size.should == 1
45
+ aspect1.pointcuts.should eql(aspect2.pointcuts)
46
+ aspect1.advice.should eql(@advice)
47
+ aspect2.advice.should eql(@advice)
48
+ join_points_should_be_equal num_jps, aspect1, aspect2
49
+ end
50
+
51
+ def join_points_should_be_equal num_jps, aspect1, aspect2
52
+ aspect1.join_points_matched.size.should == num_jps
53
+ aspect2.join_points_matched.size.should == num_jps
54
+ aspect1.join_points_matched.each {|jp| @expected_methods.should include(jp.method_name)}
55
+ aspect2.join_points_matched.each {|jp| @expected_methods.should include(jp.method_name)}
56
+ aspect1.join_points_matched.should eql(aspect2.join_points_matched)
57
+ aspect1.join_points_not_matched.should eql(aspect2.join_points_not_matched)
58
+ end
59
+
41
60
  describe Aspect, "#new arguments for specifying the types and methods" do
61
+ before :each do
62
+ @advice = proc {|jp,*args| "advice"}
63
+ @expected_methods = [:public_watchful_method]
64
+ end
65
+ after :each do
66
+ @aspect1.unadvise
67
+ @aspect2.unadvise
68
+ end
69
+
42
70
  it "should advise equivalent join points when :type => T and :method => m is used or :pointcut =>{:type => T, :method => m} is used." do
43
- advice = proc {|jp,*args| "advice"}
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
46
- # We don't use aspect1.should eql(aspect2) because the "specifications" are different.
47
- aspect1.pointcuts.should eql(aspect2.pointcuts)
48
- aspect1.pointcuts.should eql(aspect2.pointcuts)
49
- aspect1.join_points_matched.should eql(aspect2.join_points_matched)
50
- aspect1.advice.should eql(aspect2.advice)
51
- aspect1.unadvise
71
+ @aspect1 = Aspect.new :after, :type => Watchful, :method => :public_watchful_method, &@advice
72
+ @aspect2 = Aspect.new :after, :pointcut => {:type => Watchful, :method => :public_watchful_method}, &@advice
73
+ aspects_should_be_equal 1, @aspect1, @aspect2
52
74
  end
53
75
 
54
76
  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
55
- advice = proc {|jp,*args| "advice"}
56
- aspect1 = Aspect.new :after, :type => Watchful, :method => :public_watchful_method, &advice
77
+ @aspect1 = Aspect.new :after, :type => Watchful, :method => :public_watchful_method, &@advice
57
78
  pointcut = Aquarium::Aspects::Pointcut.new :type => Watchful, :method => :public_watchful_method
58
- aspect2 = Aspect.new :after, :pointcut => pointcut, &advice
59
- aspect1.pointcuts.should eql(aspect2.pointcuts)
60
- aspect1.join_points_matched.should eql(aspect2.join_points_matched)
61
- aspect1.advice.should eql(aspect2.advice)
62
- aspect1.unadvise
79
+ @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice
80
+ aspects_should_be_equal 1, @aspect1, @aspect2
63
81
  end
64
82
 
65
83
  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
66
- advice = proc {|jp,*args| "advice"}
67
- aspect1 = Aspect.new :after, :pointcut => {:type => Watchful, :method => :public_watchful_method}, &advice
84
+ @aspect1 = Aspect.new :after, :pointcut => {:type => Watchful, :method => :public_watchful_method}, &@advice
68
85
  pointcut = Aquarium::Aspects::Pointcut.new :type => Watchful, :method => :public_watchful_method
69
- aspect2 = Aspect.new :after, :pointcut => pointcut, &advice
70
- aspect1.pointcuts.should eql(aspect2.pointcuts)
71
- aspect1.join_points_matched.should eql(aspect2.join_points_matched)
72
- aspect1.advice.should eql(aspect2.advice)
73
- aspect1.unadvise
86
+ @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice
87
+ aspects_should_be_equal 1, @aspect1, @aspect2
74
88
  end
75
89
 
76
90
  it "should advise an equivalent join point when :type => T and :method => m is used or :pointcut => join_point is used, where join_point matches :type => T and :method => m." do
77
- # pending "working on Pointcut.new first."
78
- advice = proc {|jp,*args| "advice"}
79
- aspect1 = Aspect.new :after, :type => Watchful, :method => :public_watchful_method, &advice
91
+ @aspect1 = Aspect.new :after, :type => Watchful, :method => :public_watchful_method, &@advice
80
92
  join_point = Aquarium::Aspects::JoinPoint.new :type => Watchful, :method => :public_watchful_method
81
- aspect2 = Aspect.new :after, :pointcut => join_point, &advice
82
- aspect1.join_points_matched.should eql(aspect2.join_points_matched)
83
- aspect1.advice.should eql(aspect2.advice)
84
- aspect1.unadvise
93
+ @aspect2 = Aspect.new :after, :pointcut => join_point, &@advice
94
+ join_points_should_be_equal 1, @aspect1, @aspect2
85
95
  end
96
+ end
86
97
 
98
+ describe Aspect, "#new arguments for specifying the types and attributes" do
99
+ class ClassWithAttrib1
100
+ def initialize *args
101
+ @state = args
102
+ end
103
+ def dummy; end
104
+ attr_accessor :state
105
+ end
106
+
107
+ before :each do
108
+ @advice = proc {|jp,*args| "advice"}
109
+ @expected_methods = [:state, :state=]
110
+ end
111
+ after :each do
112
+ @aspect1.unadvise
113
+ @aspect2.unadvise
114
+ end
115
+
116
+ it "should not advise any method join points except those corresponding to attribute methods." do
117
+ @aspect1 = Aspect.new :after, :type => ClassWithAttrib1, :attribute => :state, &@advice
118
+ @aspect2 = Aspect.new :after, :pointcut => {:type => ClassWithAttrib1, :attribute => :state}, &@advice
119
+ aspects_should_be_equal 2, @aspect1, @aspect2
120
+ end
121
+
122
+ it "should advise equivalent join points when :type => T and :attribute => a is used or :pointcut =>{:type => T, :attribute => a} is used." do
123
+ @aspect1 = Aspect.new :after, :type => ClassWithAttrib1, :attribute => :state, &@advice
124
+ @aspect2 = Aspect.new :after, :pointcut => {:type => ClassWithAttrib1, :attribute => :state}, &@advice
125
+ aspects_should_be_equal 2, @aspect1, @aspect2
126
+ end
127
+
128
+ it "should advise equivalent join points when :type => T and :attribute => a is used or :pointcut => pointcut is used, where pointcut matches :type => T and :attribute => a." do
129
+ @aspect1 = Aspect.new :after, :type => ClassWithAttrib1, :attribute => :state, &@advice
130
+ pointcut = Aquarium::Aspects::Pointcut.new :type => ClassWithAttrib1, :attribute => :state
131
+ @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice
132
+ aspects_should_be_equal 2, @aspect1, @aspect2
133
+ end
134
+
135
+ it "should advise equivalent join points when :pointcut =>{:type => T, :attribute => a} is used or :pointcut => pointcut is used, where pointcut matches :type => T and :attribute => a." do
136
+ @aspect1 = Aspect.new :after, :pointcut => {:type => ClassWithAttrib1, :attribute => :state}, &@advice
137
+ pointcut = Aquarium::Aspects::Pointcut.new :type => ClassWithAttrib1, :attribute => :state
138
+ @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice
139
+ aspects_should_be_equal 2, @aspect1, @aspect2
140
+ end
141
+
142
+ it "should advise equivalent join points when :type => T and :attribute => a (the attribute's reader and writer) is used or :pointcut => [join_points] is used, where the join_points match :type => T and :method => :a and :method => :a=." do
143
+ # pending "working on Pointcut.new first."
144
+ @aspect1 = Aspect.new :after, :type => ClassWithAttrib1, :attribute => :state, &@advice
145
+ join_point1 = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttrib1, :method => :state
146
+ join_point2 = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttrib1, :method => :state=
147
+ @aspect2 = Aspect.new :after, :pointcut => Pointcut.new(:join_points => [join_point1, join_point2]), &@advice
148
+ join_points_should_be_equal 2, @aspect1, @aspect2
149
+ end
150
+
151
+ it "should advise an equivalent join point when :type => T and :method => :a= (the attribute's writer) is used or :pointcut => join_point is used, where join_point matches :type => T and :method => a=." do
152
+ # pending "working on Pointcut.new first."
153
+ @aspect1 = Aspect.new :after, :type => ClassWithAttrib1, :attribute => :state, :attribute_options => [:writer], &@advice
154
+ join_point = Aquarium::Aspects::JoinPoint.new :type => ClassWithAttrib1, :method => :state=
155
+ @aspect2 = Aspect.new :after, :pointcut => join_point, &@advice
156
+ join_points_should_be_equal 1, @aspect1, @aspect2
157
+ end
87
158
  end
88
159
 
89
160
  describe Aspect, "#new arguments for specifying the objects and methods" do
161
+ before :each do
162
+ @advice = proc {|jp,*args| "advice"}
163
+ @expected_methods = [:public_watchful_method]
164
+ end
165
+ after :each do
166
+ @aspect1.unadvise
167
+ @aspect2.unadvise
168
+ end
169
+
90
170
  it "should advise equivalent join points when :object => o and :method => m is used or :pointcut =>{:object => o, :method => m} is used." do
91
- advice = proc {|jp,*args| "advice"}
92
171
  watchful = Watchful.new
93
- aspect1 = Aspect.new :after, :object => watchful, :method => :public_watchful_method, &advice
94
- aspect2 = Aspect.new :after, :pointcut => {:object => watchful, :method => :public_watchful_method}, &advice
95
- aspect1.pointcuts.should eql(aspect2.pointcuts)
96
- aspect1.join_points_matched.should eql(aspect2.join_points_matched)
97
- aspect1.advice.should eql(aspect2.advice)
98
- aspect1.unadvise
172
+ @aspect1 = Aspect.new :after, :object => watchful, :method => :public_watchful_method, &@advice
173
+ @aspect2 = Aspect.new :after, :pointcut => {:object => watchful, :method => :public_watchful_method}, &@advice
174
+ aspects_should_be_equal 1, @aspect1, @aspect2
99
175
  end
100
176
 
101
177
  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
102
- advice = proc {|jp,*args| "advice"}
103
178
  watchful = Watchful.new
104
- aspect1 = Aspect.new :after, :object => watchful, :method => :public_watchful_method, &advice
179
+ @aspect1 = Aspect.new :after, :object => watchful, :method => :public_watchful_method, &@advice
105
180
  pointcut = Aquarium::Aspects::Pointcut.new :object => watchful, :method => :public_watchful_method
106
- aspect2 = Aspect.new :after, :pointcut => pointcut, &advice
107
- aspect1.pointcuts.should eql(aspect2.pointcuts)
108
- aspect1.join_points_matched.should eql(aspect2.join_points_matched)
109
- aspect1.advice.should eql(aspect2.advice)
110
- aspect1.unadvise
181
+ @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice
182
+ aspects_should_be_equal 1, @aspect1, @aspect2
111
183
  end
112
184
 
113
185
  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
114
- advice = proc {|jp,*args| "advice"}
115
186
  watchful = Watchful.new
116
- aspect1 = Aspect.new :after, :pointcut => {:object => watchful, :method => :public_watchful_method}, &advice
187
+ @aspect1 = Aspect.new :after, :pointcut => {:object => watchful, :method => :public_watchful_method}, &@advice
117
188
  pointcut = Aquarium::Aspects::Pointcut.new :object => watchful, :method => :public_watchful_method
118
- aspect2 = Aspect.new :after, :pointcut => pointcut, &advice
119
- aspect1.pointcuts.should eql(aspect2.pointcuts)
120
- aspect1.join_points_matched.should eql(aspect2.join_points_matched)
121
- aspect1.advice.should eql(aspect2.advice)
122
- aspect1.unadvise
189
+ @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice
190
+ aspects_should_be_equal 1, @aspect1, @aspect2
191
+ end
192
+ end
193
+
194
+ describe Aspect, "#new arguments for specifying the objects and attributes" do
195
+ class ClassWithAttrib2
196
+ def initialize *args
197
+ @state = args
198
+ end
199
+ def dummy; end
200
+ attr_accessor :state
201
+ end
202
+
203
+ before :each do
204
+ @advice = proc {|jp,*args| "advice"}
205
+ @object = ClassWithAttrib2.new
206
+ @expected_methods = [:state, :state=]
207
+ end
208
+ after :each do
209
+ @aspect1.unadvise
210
+ @aspect2.unadvise
211
+ end
212
+
213
+ it "should not advise any method join points except those corresponding to attribute methods." do
214
+ @aspect1 = Aspect.new :after, :object => @object, :attribute => :state, &@advice
215
+ @aspect2 = Aspect.new :after, :pointcut => {:object => @object, :attribute => :state}, &@advice
216
+ aspects_should_be_equal 2, @aspect1, @aspect2
217
+ end
218
+
219
+ it "should advise equivalent join points when :type => T and :attribute => a is used or :pointcut =>{:type => T, :attribute => a} is used." do
220
+ @aspect1 = Aspect.new :after, :object => @object, :attribute => :state, &@advice
221
+ @aspect2 = Aspect.new :after, :pointcut => {:object => @object, :attribute => :state}, &@advice
222
+ aspects_should_be_equal 2, @aspect1, @aspect2
223
+ end
224
+
225
+ it "should advise equivalent join points when :type => T and :attribute => a is used or :pointcut => pointcut is used, where pointcut matches :type => T and :attribute => a." do
226
+ @aspect1 = Aspect.new :after, :object => @object, :attribute => :state, &@advice
227
+ pointcut = Aquarium::Aspects::Pointcut.new :object => @object, :attribute => :state
228
+ @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice
229
+ aspects_should_be_equal 2, @aspect1, @aspect2
230
+ end
231
+
232
+ it "should advise equivalent join points when :pointcut =>{:type => T, :attribute => a} is used or :pointcut => pointcut is used, where pointcut matches :type => T and :attribute => a." do
233
+ @aspect1 = Aspect.new :after, :pointcut => {:object => @object, :attribute => :state}, &@advice
234
+ pointcut = Aquarium::Aspects::Pointcut.new :object => @object, :attribute => :state
235
+ @aspect2 = Aspect.new :after, :pointcut => pointcut, &@advice
236
+ aspects_should_be_equal 2, @aspect1, @aspect2
237
+ end
238
+
239
+ it "should advise equivalent join points when :type => T and :attribute => a (the attribute's reader and writer) is used or :pointcut => [join_points] is used, where the join_points match :type => T and :method => :a and :method => :a=." do
240
+ # pending "working on Pointcut.new first."
241
+ @aspect1 = Aspect.new :after, :object => @object, :attribute => :state, &@advice
242
+ join_point1 = Aquarium::Aspects::JoinPoint.new :object => @object, :method => :state
243
+ join_point2 = Aquarium::Aspects::JoinPoint.new :object => @object, :method => :state=
244
+ @aspect2 = Aspect.new :after, :pointcut => Pointcut.new(:join_points => [join_point1, join_point2]), &@advice
245
+ join_points_should_be_equal 2, @aspect1, @aspect2
246
+ end
247
+
248
+ it "should advise an equivalent join point when :type => T and :method => :a= (the attribute's writer) is used or :pointcut => join_point is used, where join_point matches :type => T and :method => a=." do
249
+ # pending "working on Pointcut.new first."
250
+ @aspect1 = Aspect.new :after, :object => @object, :attribute => :state, :attribute_options => [:writer], &@advice
251
+ join_point = Aquarium::Aspects::JoinPoint.new :object => @object, :method => :state=
252
+ @aspect2 = Aspect.new :after, :pointcut => join_point, &@advice
253
+ join_points_should_be_equal 1, @aspect1, @aspect2
123
254
  end
124
255
  end
125
256