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 +3 -3
- data/VERSION +1 -1
- data/aspector.gemspec +117 -0
- data/examples/activerecord_hooks.rb +35 -0
- data/examples/around_example.rb +8 -8
- data/examples/aspector_apply_example.rb +6 -6
- data/examples/aspector_example.rb +6 -6
- data/lib/aspector.rb +3 -3
- data/lib/aspector/{aspect_instances.rb → aspects.rb} +0 -0
- data/lib/aspector/{aspect_instance.rb → base.rb} +123 -28
- data/lib/aspector/deferred_logic.rb +5 -1
- data/lib/aspector/deferred_option.rb +11 -0
- data/lib/aspector/method_matcher.rb +11 -2
- data/lib/aspector/object_extension.rb +5 -2
- data/spec/advices_on_private_methods_spec.rb +29 -0
- data/spec/aspect_on_eigen_class_spec.rb +2 -2
- data/spec/aspector/aspect_spec.rb +29 -0
- data/spec/aspector/base_spec.rb +35 -0
- data/spec/aspector_spec.rb +47 -1
- data/spec/aspects_combined_spec.rb +1 -1
- data/spec/execution_order_spec.rb +62 -0
- metadata +12 -7
- data/lib/aspector/aspect.rb +0 -75
data/README.rdoc
CHANGED
@@ -25,12 +25,12 @@ gem install aspector
|
|
25
25
|
|
26
26
|
##############################
|
27
27
|
|
28
|
-
TestAspect
|
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.
|
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
|
+
|
data/examples/around_example.rb
CHANGED
@@ -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/
|
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/
|
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
|
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,
|
60
|
+
def initialize target, options = {}
|
58
61
|
@target = target
|
59
|
-
@
|
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" =>
|
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
|
117
|
+
return unless self.class.deferred_logics
|
110
118
|
|
111
119
|
@deferred_logic_results ||= {}
|
112
|
-
|
113
|
-
@deferred_logic_results[logic] = @context
|
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
|
-
|
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
|
-
|
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.
|
173
|
-
|
174
|
-
|
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
|
-
|
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
|
-
|
183
|
-
|
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,
|
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__,
|
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
|
+
|
@@ -14,8 +14,17 @@ module Aspector
|
|
14
14
|
when Symbol
|
15
15
|
item.to_s == method
|
16
16
|
when DeferredLogic
|
17
|
-
|
18
|
-
|
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
|
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
|
-
|
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
|
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
|
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
|
data/spec/aspector_spec.rb
CHANGED
@@ -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
|
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
|
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:
|
4
|
+
hash: 7
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
8
|
+
- 6
|
9
9
|
- 0
|
10
|
-
version: 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-
|
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/
|
270
|
-
- lib/aspector/
|
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
|
data/lib/aspector/aspect.rb
DELETED
@@ -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
|
-
|