aspector 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -25,12 +25,12 @@ gem install aspector
25
25
 
26
26
  ##############################
27
27
 
28
- TestAspect = Aspector do
29
- target "
28
+ class TestAspect < Aspector::Base
29
+ target do
30
30
  def do_this
31
31
  puts 'do_this'
32
32
  end
33
- "
33
+ end
34
34
 
35
35
  before :test, :do_this
36
36
  before :test do
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.0
1
+ 0.6.0
data/aspector.gemspec ADDED
@@ -0,0 +1,117 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{aspector}
8
+ s.version = "0.6.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Guoliang Cao"]
12
+ s.date = %q{2011-11-18}
13
+ s.description = %q{}
14
+ s.email = %q{gcao99@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".irbrc",
22
+ ".rspec",
23
+ ".rvmrc",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "Guardfile",
27
+ "LICENSE.txt",
28
+ "README.rdoc",
29
+ "Rakefile",
30
+ "VERSION",
31
+ "aspector.gemspec",
32
+ "examples/activerecord_hooks.rb",
33
+ "examples/around_example.rb",
34
+ "examples/aspector_apply_example.rb",
35
+ "examples/aspector_example.rb",
36
+ "lib/aspector.rb",
37
+ "lib/aspector/advice.rb",
38
+ "lib/aspector/advice_metadata.rb",
39
+ "lib/aspector/aspects.rb",
40
+ "lib/aspector/base.rb",
41
+ "lib/aspector/deferred_logic.rb",
42
+ "lib/aspector/deferred_option.rb",
43
+ "lib/aspector/method_matcher.rb",
44
+ "lib/aspector/module_extension.rb",
45
+ "lib/aspector/object_extension.rb",
46
+ "lib/aspector/return_this.rb",
47
+ "spec/advices_on_private_methods_spec.rb",
48
+ "spec/aspect_on_eigen_class_spec.rb",
49
+ "spec/aspect_on_object_spec.rb",
50
+ "spec/aspector/after_spec.rb",
51
+ "spec/aspector/around_spec.rb",
52
+ "spec/aspector/aspect_spec.rb",
53
+ "spec/aspector/base_spec.rb",
54
+ "spec/aspector/before_spec.rb",
55
+ "spec/aspector_spec.rb",
56
+ "spec/aspects_combined_spec.rb",
57
+ "spec/execution_order_spec.rb",
58
+ "spec/spec_helper.rb"
59
+ ]
60
+ s.homepage = %q{http://github.com/gcao/aspector}
61
+ s.licenses = ["MIT"]
62
+ s.require_paths = ["lib"]
63
+ s.rubygems_version = %q{1.4.2}
64
+ s.summary = %q{Aspect Oriented Ruby Programming}
65
+
66
+ if s.respond_to? :specification_version then
67
+ s.specification_version = 3
68
+
69
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
70
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
71
+ s.add_development_dependency(%q<mocha>, ["~> 0.10.0"])
72
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
73
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
74
+ s.add_development_dependency(%q<rcov>, [">= 0"])
75
+ s.add_development_dependency(%q<reek>, ["~> 1.2.8"])
76
+ s.add_development_dependency(%q<roodi>, ["~> 2.1.0"])
77
+ s.add_development_dependency(%q<guard>, ["~> 0.8.4"])
78
+ s.add_development_dependency(%q<guard-bundler>, ["~> 0.1.3"])
79
+ s.add_development_dependency(%q<guard-rspec>, ["~> 0.5.2"])
80
+ s.add_development_dependency(%q<guard-shell>, ["~> 0.1.1"])
81
+ s.add_development_dependency(%q<rb-fsevent>, ["~> 0.4.3.1"])
82
+ s.add_development_dependency(%q<growl>, ["~> 1.0.3"])
83
+ s.add_development_dependency(%q<awesome_print>, [">= 0"])
84
+ else
85
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
86
+ s.add_dependency(%q<mocha>, ["~> 0.10.0"])
87
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
88
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
89
+ s.add_dependency(%q<rcov>, [">= 0"])
90
+ s.add_dependency(%q<reek>, ["~> 1.2.8"])
91
+ s.add_dependency(%q<roodi>, ["~> 2.1.0"])
92
+ s.add_dependency(%q<guard>, ["~> 0.8.4"])
93
+ s.add_dependency(%q<guard-bundler>, ["~> 0.1.3"])
94
+ s.add_dependency(%q<guard-rspec>, ["~> 0.5.2"])
95
+ s.add_dependency(%q<guard-shell>, ["~> 0.1.1"])
96
+ s.add_dependency(%q<rb-fsevent>, ["~> 0.4.3.1"])
97
+ s.add_dependency(%q<growl>, ["~> 1.0.3"])
98
+ s.add_dependency(%q<awesome_print>, [">= 0"])
99
+ end
100
+ else
101
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
102
+ s.add_dependency(%q<mocha>, ["~> 0.10.0"])
103
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
104
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
105
+ s.add_dependency(%q<rcov>, [">= 0"])
106
+ s.add_dependency(%q<reek>, ["~> 1.2.8"])
107
+ s.add_dependency(%q<roodi>, ["~> 2.1.0"])
108
+ s.add_dependency(%q<guard>, ["~> 0.8.4"])
109
+ s.add_dependency(%q<guard-bundler>, ["~> 0.1.3"])
110
+ s.add_dependency(%q<guard-rspec>, ["~> 0.5.2"])
111
+ s.add_dependency(%q<guard-shell>, ["~> 0.1.1"])
112
+ s.add_dependency(%q<rb-fsevent>, ["~> 0.4.3.1"])
113
+ s.add_dependency(%q<growl>, ["~> 1.0.3"])
114
+ s.add_dependency(%q<awesome_print>, [">= 0"])
115
+ end
116
+ end
117
+
@@ -0,0 +1,35 @@
1
+ class A
2
+ def initialize
3
+ end
4
+
5
+ def save
6
+ end
7
+ end
8
+
9
+ ##############################
10
+
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
12
+
13
+ require 'aspector'
14
+
15
+ class ActiveRecordHooks < Aspector::Base
16
+ aspect = self
17
+
18
+ default :private_methods => true
19
+
20
+ before :initialize do
21
+ puts "#{aspect}: before creating #{self.class.name} instance"
22
+ end
23
+
24
+ before :save do
25
+ puts "#{aspect}: before saving"
26
+ end
27
+ end
28
+
29
+ ActiveRecordHooks.apply(A)
30
+
31
+ ##############################
32
+
33
+ a = A.new
34
+ a.save
35
+
@@ -1,7 +1,3 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
- require 'aspector'
4
-
5
1
  class A
6
2
  def test
7
3
  puts 'test'
@@ -10,14 +6,18 @@ end
10
6
 
11
7
  ##############################
12
8
 
9
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
10
+
11
+ require 'aspector'
12
+
13
13
  aspector(A) do
14
- target "
14
+ target do
15
15
  def do_this &block
16
16
  puts 'before'
17
17
  block.call
18
18
  puts 'after'
19
19
  end
20
- "
20
+ end
21
21
 
22
22
  around :test, :do_this
23
23
  around :test do |&block|
@@ -32,8 +32,8 @@ end
32
32
  A.new.test
33
33
 
34
34
  # Expected output:
35
- # before(block)
36
35
  # before
36
+ # before(block)
37
37
  # test
38
- # after
39
38
  # after(block)
39
+ # after
@@ -1,7 +1,3 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
- require 'aspector'
4
-
5
1
  class A
6
2
  def test
7
3
  puts 'test'
@@ -10,12 +6,16 @@ end
10
6
 
11
7
  ##############################
12
8
 
9
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
10
+
11
+ require 'aspector'
12
+
13
13
  TestAspect = Aspector do
14
- target "
14
+ target do
15
15
  def do_this
16
16
  puts 'do_this'
17
17
  end
18
- "
18
+ end
19
19
 
20
20
  before :test, :do_this
21
21
  before :test do
@@ -1,7 +1,3 @@
1
- $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
- require 'aspector'
4
-
5
1
  class A
6
2
  def test
7
3
  puts 'test'
@@ -10,12 +6,16 @@ end
10
6
 
11
7
  ##############################
12
8
 
9
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
10
+
11
+ require 'aspector'
12
+
13
13
  aspector(A) do
14
- target "
14
+ target do
15
15
  def do_this
16
16
  puts 'do_this'
17
17
  end
18
- "
18
+ end
19
19
 
20
20
  before :test, :do_this
21
21
  before :test do
data/lib/aspector.rb CHANGED
@@ -1,13 +1,13 @@
1
1
  require 'aspector/object_extension'
2
2
  require 'aspector/module_extension'
3
3
 
4
- require 'aspector/aspect'
4
+ require 'aspector/base'
5
5
  require 'aspector/advice'
6
6
  require 'aspector/advice_metadata'
7
7
  require 'aspector/method_matcher'
8
8
  require 'aspector/deferred_logic'
9
+ require 'aspector/deferred_option'
9
10
 
10
- require 'aspector/aspect_instance'
11
- require 'aspector/aspect_instances'
11
+ require 'aspector/aspects'
12
12
 
13
13
  require 'aspector/return_this'
File without changes
@@ -1,5 +1,7 @@
1
+ require 'erb'
2
+
1
3
  module Aspector
2
- class AspectInstance
4
+ class Base
3
5
 
4
6
  METHOD_TEMPLATE = ERB.new <<-CODE
5
7
  wrapped_method = instance_method(:<%= method %>)
@@ -53,11 +55,11 @@ module Aspector
53
55
  end
54
56
  CODE
55
57
 
58
+ attr :options
56
59
 
57
- def initialize target, aspect, options = {}
60
+ def initialize target, options = {}
58
61
  @target = target
59
- @aspect = aspect
60
- @options = options.merge(aspect.options)
62
+ @options = options.merge(self.class.options)
61
63
  @context = get_context # Context is where advices will be applied (i.e. where methods are modified)
62
64
  end
63
65
 
@@ -77,13 +79,19 @@ module Aspector
77
79
  @context.instance_methods.each do |method|
78
80
  apply_to_method(method)
79
81
  end
82
+
83
+ if @options[:private_methods]
84
+ @context.private_instance_methods.each do |method|
85
+ apply_to_method(method, true)
86
+ end
87
+ end
80
88
  end
81
89
 
82
- def apply_to_method method
90
+ def apply_to_method method, is_private = false
83
91
  advices = advices_for_method method
84
92
  return if advices.empty?
85
93
 
86
- recreate_method method, advices
94
+ recreate_method method, advices, is_private
87
95
  end
88
96
 
89
97
  def to_hash
@@ -91,7 +99,7 @@ module Aspector
91
99
  "type" => self.class.name,
92
100
  "context" => @context.name,
93
101
  "options" => @options,
94
- "aspect" => @aspect.to_hash
102
+ "aspect" => self.class.to_hash
95
103
  }
96
104
  end
97
105
 
@@ -106,16 +114,16 @@ module Aspector
106
114
  end
107
115
 
108
116
  def invoke_deferred_logics
109
- return unless @aspect.deferred_logics
117
+ return unless self.class.deferred_logics
110
118
 
111
119
  @deferred_logic_results ||= {}
112
- @aspect.deferred_logics.each do |logic|
113
- @deferred_logic_results[logic] = @context.class_eval(logic.code)
120
+ self.class.deferred_logics.each do |logic|
121
+ @deferred_logic_results[logic] = logic.apply @context
114
122
  end
115
123
  end
116
124
 
117
125
  def define_methods_for_advice_blocks
118
- @aspect.advices.each do |advice|
126
+ self.class.advices.each do |advice|
119
127
  next unless advice.advice_block
120
128
  @context.send :define_method, advice.with_method, advice.advice_block
121
129
  end
@@ -160,41 +168,128 @@ module Aspector
160
168
  end
161
169
 
162
170
  def advices_for_method method
163
- @aspect.advices.select do |advice|
171
+ self.class.advices.select do |advice|
164
172
  advice.match?(method, self)
165
173
  end
166
174
  end
167
175
 
168
- def recreate_method method, advices
176
+ def recreate_method method, advices, is_private
169
177
  @context.instance_variable_set(:@aspector_creating_method, true)
170
- grouped_advices = []
171
178
 
172
- advices.each do |advice|
173
- if advice.around? and not grouped_advices.empty?
174
- recreate_method_with_advices method, grouped_advices
179
+ before_advices = advices.select {|advice| advice.before? or advice.before_filter? }
180
+ after_advices = advices.select {|advice| advice.after? }
181
+ around_advices = advices.select {|advice| advice.around? }
175
182
 
176
- grouped_advices = []
183
+ if around_advices.size > 1
184
+ (around_advices.size - 1).downto(1) do |i|
185
+ advice = around_advices[i]
186
+ recreate_method_with_advices method, [], [], advice
177
187
  end
178
-
179
- grouped_advices << advice
180
188
  end
181
189
 
182
- # create wrap method for before/after advices which are not wrapped inside around advice.
183
- recreate_method_with_advices method, grouped_advices unless grouped_advices.empty?
190
+ recreate_method_with_advices method, before_advices, after_advices, around_advices.first
191
+
192
+ @context.send :private, method if is_private
184
193
  ensure
185
194
  @context.instance_variable_set(:@aspector_creating_method, nil)
186
195
  end
187
196
 
188
- def recreate_method_with_advices method, advices
189
- before_advices = advices.select {|advice| advice.before? or advice.before_filter? }
190
- after_advices = advices.select {|advice| advice.after? }
191
- around_advice = advices.first if advices.first.around?
192
-
197
+ def recreate_method_with_advices method, before_advices, after_advices, around_advice
193
198
  code = METHOD_TEMPLATE.result(binding)
194
199
  #puts code
195
200
  # line no is the actual line no of METHOD_TEMPLATE + 5
196
- @context.class_eval code, __FILE__, 5
201
+ @context.class_eval code, __FILE__, 7
197
202
  end
198
203
 
204
+ class << self
205
+
206
+ def advices
207
+ @advices ||= []
208
+ end
209
+
210
+ def options
211
+ @options ||= {}
212
+ end
213
+
214
+ def deferred_logics
215
+ @deferred_logics ||= []
216
+ end
217
+
218
+ def apply target, options = {}
219
+ instances = target.instance_variable_get(:@aspector_instances)
220
+ return if instances and instances.detect {|instance| instance.is_a?(self) }
221
+
222
+ aspect_instance = new(target, options)
223
+ aspect_instance.apply
224
+ end
225
+
226
+ def default options
227
+ if @options
228
+ @options.merge! options
229
+ else
230
+ @options = options
231
+ end
232
+ end
233
+
234
+ def before *methods, &block
235
+ advices << create_advice(Aspector::AdviceMetadata::BEFORE, self, methods, &block)
236
+ end
237
+
238
+ def before_filter *methods, &block
239
+ advices << create_advice(Aspector::AdviceMetadata::BEFORE_FILTER, self, methods, &block)
240
+ end
241
+
242
+ def after *methods, &block
243
+ advices << create_advice(Aspector::AdviceMetadata::AFTER, self, methods, &block)
244
+ end
245
+
246
+ def around *methods, &block
247
+ advices << create_advice(Aspector::AdviceMetadata::AROUND, self, methods, &block)
248
+ end
249
+
250
+ def target code = nil, &block
251
+ logic = DeferredLogic.new(code || block)
252
+ deferred_logics << logic
253
+ logic
254
+ end
255
+
256
+ def deferred_option key
257
+ DeferredOption.new(key)
258
+ end
259
+
260
+ def to_hash
261
+ {
262
+ "type" => self.name,
263
+ "options" => options,
264
+ "advices" => advices.map {|advice| advice.to_s }
265
+ }
266
+ end
267
+
268
+ private
269
+
270
+ def create_advice meta_data, klass_or_module, *methods, &block
271
+ methods.flatten!
272
+
273
+ options = meta_data.default_options.clone
274
+ options.merge!(methods.pop) if methods.last.is_a? Hash
275
+ options.merge!(meta_data.mandatory_options)
276
+
277
+ # Convert symbols to strings to avoid inconsistencies
278
+ methods.size.times do |i|
279
+ methods[i] = methods[i].to_s if methods[i].is_a? Symbol
280
+ end
281
+
282
+ with_method = methods.pop unless block_given?
283
+
284
+ Aspector::Advice.new(self,
285
+ meta_data.advice_type,
286
+ Aspector::MethodMatcher.new(*methods),
287
+ with_method,
288
+ options,
289
+ &block)
290
+ end
291
+
292
+ end
199
293
  end
200
294
  end
295
+
@@ -8,7 +8,11 @@ module Aspector
8
8
  end
9
9
 
10
10
  def apply target
11
- @value = target.class_eval(@code)
11
+ if @code.is_a? String
12
+ @value = target.class_eval(@code)
13
+ else
14
+ @value = target.class_eval(&@code)
15
+ end
12
16
  end
13
17
 
14
18
  end
@@ -0,0 +1,11 @@
1
+ module Aspector
2
+ class DeferredOption
3
+
4
+ attr_reader :key
5
+
6
+ def initialize key
7
+ @key = key
8
+ end
9
+
10
+ end
11
+ end
@@ -14,8 +14,17 @@ module Aspector
14
14
  when Symbol
15
15
  item.to_s == method
16
16
  when DeferredLogic
17
- new_matcher = MethodMatcher.new(context.deferred_logic_results[item])
18
- new_matcher.match?(item)
17
+ value = context.deferred_logic_results[item]
18
+ if value
19
+ new_matcher = MethodMatcher.new(*[value].flatten)
20
+ new_matcher.match?(method)
21
+ end
22
+ when DeferredOption
23
+ value = context.options[item.key]
24
+ if value
25
+ new_matcher = MethodMatcher.new(*[value].flatten)
26
+ new_matcher.match?(method)
27
+ end
19
28
  end
20
29
  end
21
30
  end
@@ -4,7 +4,7 @@ module Aspector
4
4
  def aspector *args, &block
5
5
  options = args.last.is_a?(Hash) ? args.pop : {}
6
6
 
7
- aspect = Aspector::Aspect.new(options, &block)
7
+ aspect = Aspector(options, &block)
8
8
 
9
9
  aspect.apply(self) if self.is_a? Module
10
10
  args.each {|target| aspect.apply(target) }
@@ -13,7 +13,10 @@ module Aspector
13
13
  end
14
14
 
15
15
  def Aspector options = {}, &block
16
- Aspector::Aspect.new(options, &block)
16
+ klass = Class.new(Aspector::Base)
17
+ klass.default options
18
+ klass.class_eval &block if block_given?
19
+ klass
17
20
  end
18
21
 
19
22
  end
@@ -0,0 +1,29 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Advices on private methods" do
4
+ it "should work" do
5
+ klass = Class.new do
6
+ def value
7
+ @value ||= []
8
+ end
9
+
10
+ private
11
+
12
+ def test
13
+ value << "test"
14
+ end
15
+
16
+ def do_before
17
+ value << "do_before"
18
+ end
19
+ end
20
+
21
+ aspector(klass, :private_methods => true) do
22
+ before :test, :do_before
23
+ end
24
+
25
+ obj = klass.new
26
+ obj.send :test
27
+ obj.value.should == %w"do_before test"
28
+ end
29
+ end
@@ -37,7 +37,7 @@ describe "Aspector for eigen class" do
37
37
  end
38
38
 
39
39
  klass.test
40
- klass.value.should == %w"do_around_before do_before test do_after do_around_after"
40
+ klass.value.should == %w"do_before do_around_before test do_around_after do_after"
41
41
  end
42
42
 
43
43
  it "new methods" do
@@ -80,7 +80,7 @@ describe "Aspector for eigen class" do
80
80
  end
81
81
 
82
82
  klass.test
83
- klass.value.should == %w"do_around_before do_before test do_after do_around_after"
83
+ klass.value.should == %w"do_before do_around_before test do_around_after do_after"
84
84
  end
85
85
 
86
86
  end
@@ -38,6 +38,34 @@ describe "Aspector::Aspect" do
38
38
  end
39
39
  end
40
40
 
41
+ aspect = Aspector do
42
+ target do
43
+ def do_this
44
+ value << "do_this"
45
+ end
46
+ end
47
+
48
+ before :test, :do_this
49
+ end
50
+
51
+ aspect.apply(klass)
52
+
53
+ obj = klass.new
54
+ obj.test
55
+ obj.value.should == %w"do_this test"
56
+ end
57
+
58
+ it "target takes String too" do
59
+ klass = Class.new do
60
+ def value
61
+ @value ||= []
62
+ end
63
+
64
+ def test
65
+ value << "test"
66
+ end
67
+ end
68
+
41
69
  aspect = Aspector do
42
70
  target '
43
71
  def do_this
@@ -54,4 +82,5 @@ describe "Aspector::Aspect" do
54
82
  obj.test
55
83
  obj.value.should == %w"do_this test"
56
84
  end
85
+
57
86
  end
@@ -0,0 +1,35 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Aspector::Base" do
4
+ it "Default options" do
5
+ aspect = Aspector do
6
+ default :test => 'value'
7
+ end
8
+
9
+ aspect.options[:test].should == 'value'
10
+ end
11
+
12
+ it "deferred_option" do
13
+ klass = Class.new do
14
+ def value
15
+ @value ||= []
16
+ end
17
+
18
+ def test
19
+ value << "test"
20
+ end
21
+ end
22
+
23
+ aspect = Aspector do
24
+ before deferred_option(:methods) do
25
+ value << "do_this"
26
+ end
27
+ end
28
+
29
+ aspect.apply(klass, :methods => [:test])
30
+
31
+ obj = klass.new
32
+ obj.test
33
+ obj.value.should == %w"do_this test"
34
+ end
35
+ end
@@ -36,7 +36,7 @@ describe "Aspector" do
36
36
 
37
37
  obj = klass.new
38
38
  obj.test
39
- obj.value.should == %w"do_around_before do_before test do_after do_around_after"
39
+ obj.value.should == %w"do_before do_around_before test do_around_after do_after"
40
40
  end
41
41
 
42
42
  it "multiple aspects should work together" do
@@ -62,4 +62,50 @@ describe "Aspector" do
62
62
  obj.test
63
63
  obj.value.should == %w"second_aspect first_aspect test"
64
64
  end
65
+
66
+ it "treating Aspect as regular class should work" do
67
+ klass = Class.new do
68
+ def value
69
+ @value ||= []
70
+ end
71
+
72
+ def test
73
+ value << "test"
74
+ end
75
+ end
76
+
77
+ class TestAspect < Aspector::Base
78
+ before(:test) { value << 'before_test' }
79
+ end
80
+
81
+ TestAspect.apply(klass)
82
+
83
+ obj = klass.new
84
+ obj.test
85
+ obj.value.should == %w"before_test test"
86
+ end
87
+
88
+ it "should apply only once if called multiple times" do
89
+ klass = Class.new do
90
+ def value
91
+ @value ||= []
92
+ end
93
+
94
+ def test
95
+ value << "test"
96
+ end
97
+ end
98
+
99
+ aspect = Aspector do
100
+ before(:test) { value << 'before_test' }
101
+ end
102
+
103
+ aspect.apply(klass)
104
+ aspect.apply(klass)
105
+
106
+ obj = klass.new
107
+ obj.test
108
+ obj.value.should == %w"before_test test"
109
+ end
110
+
65
111
  end
@@ -50,6 +50,6 @@ describe "Aspects combined" do
50
50
 
51
51
  obj = klass.new
52
52
  obj.test
53
- obj.value.should == %w"do_before_block do_around_before do_before new_test do_after do_around_after"
53
+ obj.value.should == %w"do_before_block do_before do_around_before new_test do_around_after do_after"
54
54
  end
55
55
  end
@@ -0,0 +1,62 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Aspect execution order" do
4
+ it "should work" do
5
+ klass = Class.new do
6
+ def value
7
+ @value ||= []
8
+ end
9
+
10
+ def test
11
+ value << "test"
12
+ end
13
+
14
+ def do_before1
15
+ value << "do_before1"
16
+ end
17
+
18
+ def do_before2
19
+ value << "do_before2"
20
+ end
21
+
22
+ def do_after1 result
23
+ value << "do_after1"
24
+ result
25
+ end
26
+
27
+ def do_after2 result
28
+ value << "do_after2"
29
+ result
30
+ end
31
+
32
+ def do_around1 &block
33
+ value << "do_around_before1"
34
+ result = block.call
35
+ value << "do_around_after1"
36
+ result
37
+ end
38
+
39
+ def do_around2 &block
40
+ value << "do_around_before2"
41
+ result = block.call
42
+ value << "do_around_after2"
43
+ result
44
+ end
45
+
46
+ end
47
+
48
+ aspector(klass) do
49
+ before :test, :do_before1
50
+ after :test, :do_after1
51
+ around :test, :do_around1
52
+ before :test, :do_before2
53
+ after :test, :do_after2
54
+ around :test, :do_around2
55
+ end
56
+
57
+ obj = klass.new
58
+ obj.test
59
+ obj.value.should == %w"do_before1 do_before2 do_around_before1 do_around_before2 test
60
+ do_around_after2 do_around_after1 do_after1 do_after2"
61
+ end
62
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aspector
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 5
8
+ - 6
9
9
  - 0
10
- version: 0.5.0
10
+ version: 0.6.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Guoliang Cao
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-11-11 00:00:00 -05:00
18
+ date: 2011-11-18 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -260,28 +260,33 @@ files:
260
260
  - README.rdoc
261
261
  - Rakefile
262
262
  - VERSION
263
+ - aspector.gemspec
264
+ - examples/activerecord_hooks.rb
263
265
  - examples/around_example.rb
264
266
  - examples/aspector_apply_example.rb
265
267
  - examples/aspector_example.rb
266
268
  - lib/aspector.rb
267
269
  - lib/aspector/advice.rb
268
270
  - lib/aspector/advice_metadata.rb
269
- - lib/aspector/aspect.rb
270
- - lib/aspector/aspect_instance.rb
271
- - lib/aspector/aspect_instances.rb
271
+ - lib/aspector/aspects.rb
272
+ - lib/aspector/base.rb
272
273
  - lib/aspector/deferred_logic.rb
274
+ - lib/aspector/deferred_option.rb
273
275
  - lib/aspector/method_matcher.rb
274
276
  - lib/aspector/module_extension.rb
275
277
  - lib/aspector/object_extension.rb
276
278
  - lib/aspector/return_this.rb
279
+ - spec/advices_on_private_methods_spec.rb
277
280
  - spec/aspect_on_eigen_class_spec.rb
278
281
  - spec/aspect_on_object_spec.rb
279
282
  - spec/aspector/after_spec.rb
280
283
  - spec/aspector/around_spec.rb
281
284
  - spec/aspector/aspect_spec.rb
285
+ - spec/aspector/base_spec.rb
282
286
  - spec/aspector/before_spec.rb
283
287
  - spec/aspector_spec.rb
284
288
  - spec/aspects_combined_spec.rb
289
+ - spec/execution_order_spec.rb
285
290
  - spec/spec_helper.rb
286
291
  has_rdoc: true
287
292
  homepage: http://github.com/gcao/aspector
@@ -1,75 +0,0 @@
1
- require 'erb'
2
-
3
- module Aspector
4
- class Aspect
5
-
6
- attr_reader :advices, :options, :deferred_logics
7
-
8
- def initialize options = {}, &block
9
- @options = options
10
- @advices = []
11
- instance_eval &block
12
- end
13
-
14
- def apply target, options = {}
15
- aspect_instance = AspectInstance.new(target, self, options)
16
- aspect_instance.apply
17
- end
18
-
19
- def before *methods, &block
20
- @advices << create_advice(Aspector::AdviceMetadata::BEFORE, self, methods, &block)
21
- end
22
-
23
- def before_filter *methods, &block
24
- @advices << create_advice(Aspector::AdviceMetadata::BEFORE_FILTER, self, methods, &block)
25
- end
26
-
27
- def after *methods, &block
28
- @advices << create_advice(Aspector::AdviceMetadata::AFTER, self, methods, &block)
29
- end
30
-
31
- def around *methods, &block
32
- @advices << create_advice(Aspector::AdviceMetadata::AROUND, self, methods, &block)
33
- end
34
-
35
- def target code
36
- logic = DeferredLogic.new(code)
37
- @deferred_logics ||= []
38
- @deferred_logics << logic
39
- logic
40
- end
41
-
42
- def to_hash
43
- {
44
- "type" => self.class.name,
45
- "options" => @options,
46
- "advices" => @advices.map {|advice| advice.to_s }
47
- }
48
- end
49
-
50
- private
51
-
52
- def create_advice meta_data, klass_or_module, *methods, &block
53
- methods.flatten!
54
-
55
- options = meta_data.default_options.clone
56
- options.merge!(methods.pop) if methods.last.is_a? Hash
57
- options.merge!(meta_data.mandatory_options)
58
-
59
- # Convert symbols to strings to avoid inconsistencies
60
- methods.size.times do |i|
61
- methods[i] = methods[i].to_s if methods[i].is_a? Symbol
62
- end
63
-
64
- with_method = methods.pop unless block_given?
65
-
66
- Aspector::Advice.new(self,
67
- meta_data.advice_type,
68
- Aspector::MethodMatcher.new(*methods),
69
- with_method,
70
- options,
71
- &block)
72
- end
73
- end
74
- end
75
-