aquarium 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
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