aspector 0.5.0 → 0.6.0

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