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 +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
|
-
|