aspector 0.13.1 → 0.14.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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +26 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -11
- data/Changelog.md +59 -0
- data/Gemfile +9 -14
- data/Gemfile.lock +84 -50
- data/README.md +118 -0
- data/Rakefile +6 -22
- data/aspector.gemspec +15 -127
- data/benchmarks/after_benchmark.rb +28 -0
- data/benchmarks/around_advice_benchmark.rb +35 -0
- data/benchmarks/around_benchmark.rb +32 -0
- data/benchmarks/before_benchmark.rb +28 -0
- data/benchmarks/benchmark_helper.rb +17 -0
- data/benchmarks/combined_benchmark.rb +36 -0
- data/benchmarks/method_invocation_benchmark.rb +30 -0
- data/benchmarks/raw_benchmark.rb +39 -0
- data/examples/activerecord_hooks.rb +10 -15
- data/examples/around_example.rb +20 -31
- data/examples/aspector_apply_example.rb +10 -17
- data/examples/aspector_example.rb +7 -16
- data/examples/cache_aspect.rb +20 -30
- data/examples/design_by_contract.rb +20 -44
- data/examples/exception_handler.rb +12 -20
- data/examples/exception_handler2.rb +16 -24
- data/examples/implicit_method_option_test.rb +8 -16
- data/examples/interception_options_example.rb +71 -0
- data/examples/logging_aspect.rb +16 -24
- data/examples/process_aspector.rb +13 -0
- data/examples/retry_aspect.rb +20 -20
- data/lib/aspector.rb +17 -15
- data/lib/aspector/advice.rb +44 -57
- data/lib/aspector/advice_metadata.rb +10 -11
- data/lib/aspector/aspect_instances.rb +2 -3
- data/lib/aspector/base.rb +6 -368
- data/lib/aspector/base_class_methods.rb +24 -55
- data/lib/aspector/deferred_logic.rb +3 -4
- data/lib/aspector/deferred_option.rb +5 -10
- data/lib/aspector/interception.rb +356 -0
- data/lib/aspector/logger.rb +18 -45
- data/lib/aspector/logging.rb +10 -29
- data/lib/aspector/method_matcher.rb +5 -6
- data/lib/aspector/object_extension.rb +4 -12
- data/lib/aspector/version.rb +3 -0
- data/spec/examples_spec.rb +59 -0
- data/spec/functionals/aspect_for_multiple_targets_spec.rb +54 -0
- data/spec/functionals/aspect_interception_options_accessing_spec.rb +112 -0
- data/spec/functionals/aspect_on_a_class_spec.rb +159 -0
- data/spec/functionals/aspect_on_an_instance_spec.rb +66 -0
- data/spec/functionals/aspector_spec.rb +138 -0
- data/spec/functionals/aspects_combined_spec.rb +37 -0
- data/spec/functionals/aspects_execution_order_spec.rb +61 -0
- data/spec/functionals/aspects_on_private_methods_spec.rb +82 -0
- data/spec/spec_helper.rb +20 -21
- data/spec/support/class_builder.rb +44 -0
- data/spec/units/advice_spec.rb +49 -0
- data/spec/units/advices/after_spec.rb +328 -0
- data/spec/units/advices/around_spec.rb +336 -0
- data/spec/units/advices/before_filter_spec.rb +287 -0
- data/spec/units/advices/before_spec.rb +237 -0
- data/spec/units/advices/raw_spec.rb +67 -0
- data/spec/units/base_class_methods_spec.rb +262 -0
- data/spec/units/base_spec.rb +133 -0
- data/spec/units/deferred_logic_spec.rb +35 -0
- data/spec/units/logger_spec.rb +20 -0
- data/spec/units/logging_spec.rb +85 -0
- data/spec/units/method_matcher_spec.rb +95 -0
- data/spec/units/object_extension_spec.rb +11 -0
- data/spec/units/special_chars_spec.rb +128 -0
- metadata +98 -246
- data/.document +0 -5
- data/.rvmrc +0 -8
- data/README.rdoc +0 -80
- data/VERSION +0 -1
- data/performance-tests/after_test.rb +0 -25
- data/performance-tests/around_advice_benchmark.rb +0 -66
- data/performance-tests/around_test.rb +0 -27
- data/performance-tests/before_test.rb +0 -25
- data/performance-tests/combined_test.rb +0 -33
- data/performance-tests/method_invocation_test.rb +0 -25
- data/performance-tests/raw_test.rb +0 -37
- data/performance-tests/test_helper.rb +0 -9
- data/run_all_examples.sh +0 -12
- data/spec/functional/advices_on_private_methods_spec.rb +0 -21
- data/spec/functional/aspect_on_eigen_class_spec.rb +0 -72
- data/spec/functional/aspect_on_object_spec.rb +0 -20
- data/spec/functional/aspector_spec.rb +0 -140
- data/spec/functional/aspects_combined_spec.rb +0 -48
- data/spec/functional/execution_order_spec.rb +0 -42
- data/spec/unit/advice_spec.rb +0 -4
- data/spec/unit/after_spec.rb +0 -88
- data/spec/unit/around_spec.rb +0 -76
- data/spec/unit/base_class_methods_spec.rb +0 -28
- data/spec/unit/base_spec.rb +0 -112
- data/spec/unit/before_spec.rb +0 -125
- data/spec/unit/deferred_logic_spec.rb +0 -23
- data/spec/unit/method_matcher_spec.rb +0 -43
- data/spec/unit/raw_spec.rb +0 -53
- data/spec/unit/special_chars_spec.rb +0 -122
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Advices on private methods' do
|
4
|
+
subject { klass.new }
|
5
|
+
|
6
|
+
let(:klass) do
|
7
|
+
ClassBuilder.build
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:instance1) { klass.new }
|
11
|
+
let(:instance2) { klass.new }
|
12
|
+
|
13
|
+
context 'before aspect' do
|
14
|
+
before do
|
15
|
+
aspector(instance1) do
|
16
|
+
before :exec do
|
17
|
+
values << 'exec-before'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should bind only to one instance to which we want to bind' do
|
23
|
+
instance1.exec
|
24
|
+
instance2.exec
|
25
|
+
expect(instance1.values).to eq %w( exec-before exec-result )
|
26
|
+
expect(instance2.values).to eq %w( exec-result )
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'around aspect' do
|
31
|
+
before do
|
32
|
+
aspector(instance1) do
|
33
|
+
around :exec do |proxy, &block|
|
34
|
+
values << 'exec-around-before'
|
35
|
+
result = proxy.call(&block)
|
36
|
+
values << 'exec-around-after'
|
37
|
+
result
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should bind only to one instance to which we want to bind' do
|
43
|
+
instance1.exec
|
44
|
+
instance2.exec
|
45
|
+
expect(instance1.values).to eq %w( exec-around-before exec-result exec-around-after )
|
46
|
+
expect(instance2.values).to eq %w( exec-result )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'after aspect' do
|
51
|
+
before do
|
52
|
+
aspector(instance1) do
|
53
|
+
after :exec do |_result|
|
54
|
+
values << 'exec-after'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'should bind only the aspect that binds to private methods' do
|
60
|
+
instance1.exec
|
61
|
+
instance2.exec
|
62
|
+
expect(instance1.values).to eq %w( exec-result exec-after )
|
63
|
+
expect(instance2.values).to eq %w( exec-result )
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Aspector do
|
4
|
+
let(:klass) { ClassBuilder.build }
|
5
|
+
subject { klass.new }
|
6
|
+
|
7
|
+
context 'binding multiple aspects in a single place' do
|
8
|
+
before do
|
9
|
+
aspector(klass) do
|
10
|
+
before(:exec) { values << 'first-aspect' }
|
11
|
+
end
|
12
|
+
|
13
|
+
aspector(klass) do
|
14
|
+
before(:exec) { values << 'second-aspect' }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should work' do
|
19
|
+
subject.exec
|
20
|
+
expect(subject.values).to eq %w( second-aspect first-aspect exec-result )
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when we try to treat Aspect as a regular class' do
|
25
|
+
let(:aspect_klass) do
|
26
|
+
ClassBuilder.inherit(Aspector::Base) do
|
27
|
+
before(:exec) { values << 'before-exec' }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
before do
|
32
|
+
aspect_klass.apply(klass)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should work' do
|
36
|
+
subject.exec
|
37
|
+
expect(subject.values).to eq %w( before-exec exec-result )
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'when we want to apply aspect multiple times' do
|
42
|
+
let(:aspect_klass) do
|
43
|
+
Aspector do
|
44
|
+
before(:exec) { values << 'before-exec' }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
before do
|
49
|
+
aspect_klass.apply(klass)
|
50
|
+
aspect_klass.apply(klass)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should apply aspect multiple times' do
|
54
|
+
subject.exec
|
55
|
+
expect(subject.values).to eq %w( before-exec before-exec exec-result )
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when we set new_methods_only to true' do
|
60
|
+
let(:aspect_klass) do
|
61
|
+
Aspector do
|
62
|
+
before(:exec) { values << 'before-exec' }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
before do
|
67
|
+
aspect_klass.apply(klass, new_methods_only: true)
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'and we try to apply it to already existing method' do
|
71
|
+
it 'should not apply to existing methods' do
|
72
|
+
subject.exec
|
73
|
+
expect(subject.values).to eq %w( exec-result )
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'and we try to apply it to a new method' do
|
78
|
+
let(:klass) do
|
79
|
+
ClassBuilder.raw do
|
80
|
+
def values
|
81
|
+
@values ||= []
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
before do
|
87
|
+
klass.send :define_method, :exec do
|
88
|
+
values << 'exec-result'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should apply to new methods' do
|
93
|
+
subject.exec
|
94
|
+
expect(subject.values).to eq %w( before-exec exec-result )
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'when we set existing_methods_only to true' do
|
100
|
+
let(:aspect_klass) do
|
101
|
+
Aspector do
|
102
|
+
before(:exec) { values << 'before-exec' }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
before do
|
107
|
+
aspect_klass.apply(klass, existing_methods_only: true)
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'and we try to apply it to already existing method' do
|
111
|
+
it 'should apply to existing methods' do
|
112
|
+
subject.exec
|
113
|
+
expect(subject.values).to eq %w( before-exec exec-result )
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'and we try to apply it to a new method' do
|
118
|
+
let(:klass) do
|
119
|
+
ClassBuilder.raw do
|
120
|
+
def values
|
121
|
+
@values ||= []
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
before do
|
127
|
+
klass.send :define_method, :exec do
|
128
|
+
values << 'exec-result'
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'should not apply to new methods' do
|
133
|
+
subject.exec
|
134
|
+
expect(subject.values).to eq %w( exec-result )
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Aspects combined' do
|
4
|
+
let(:klass) { ClassBuilder.build }
|
5
|
+
subject { klass.new }
|
6
|
+
|
7
|
+
context 'when we want to combine multiple different aspects' do
|
8
|
+
before do
|
9
|
+
aspector(klass) do
|
10
|
+
before :exec do
|
11
|
+
values << 'exec-before'
|
12
|
+
end
|
13
|
+
|
14
|
+
after :exec do |result|
|
15
|
+
values << 'exec-after'
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
around :exec do |proxy, &block|
|
20
|
+
values << 'exec-around-before'
|
21
|
+
result = proxy.call(&block)
|
22
|
+
values << 'exec-around-after'
|
23
|
+
result
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should work' do
|
29
|
+
expected = %w(
|
30
|
+
exec-before exec-around-before exec-result exec-around-after exec-after
|
31
|
+
)
|
32
|
+
|
33
|
+
subject.exec
|
34
|
+
expect(subject.values).to eq expected
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Aspect execution order' do
|
4
|
+
let(:klass) { ClassBuilder.build }
|
5
|
+
subject { klass.new }
|
6
|
+
|
7
|
+
context 'when we apply aspects in certain order' do
|
8
|
+
before do
|
9
|
+
aspector(klass) do
|
10
|
+
before :exec do
|
11
|
+
values << 'exec-before1'
|
12
|
+
end
|
13
|
+
|
14
|
+
after :exec do |result|
|
15
|
+
values << 'exec-after1'
|
16
|
+
result
|
17
|
+
end
|
18
|
+
|
19
|
+
around :exec do |proxy, &block|
|
20
|
+
values << 'exec-around-before1'
|
21
|
+
result = proxy.call(&block)
|
22
|
+
values << 'exec-around-after1'
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
before :exec do
|
27
|
+
values << 'exec-before2'
|
28
|
+
end
|
29
|
+
|
30
|
+
after :exec do |result|
|
31
|
+
values << 'exec-after2'
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
around :exec do |proxy, &block|
|
36
|
+
values << 'exec-around-before2'
|
37
|
+
result = proxy.call(&block)
|
38
|
+
values << 'exec-around-after2'
|
39
|
+
result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should use this order' do
|
45
|
+
expected = %w(
|
46
|
+
exec-before1
|
47
|
+
exec-before2
|
48
|
+
exec-around-before1
|
49
|
+
exec-around-before2
|
50
|
+
exec-result
|
51
|
+
exec-around-after2
|
52
|
+
exec-around-after1
|
53
|
+
exec-after1
|
54
|
+
exec-after2
|
55
|
+
)
|
56
|
+
|
57
|
+
subject.exec
|
58
|
+
expect(subject.values).to eq expected
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe 'Aspects on private methods' do
|
4
|
+
subject { klass.new }
|
5
|
+
|
6
|
+
let(:klass) do
|
7
|
+
ClassBuilder.build do
|
8
|
+
private :exec
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'before aspect' do
|
13
|
+
before do
|
14
|
+
aspector(klass) do
|
15
|
+
before :exec do
|
16
|
+
values << 'exec-before(public_methods_only)'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
aspector(klass, private_methods: true) do
|
21
|
+
before :exec do
|
22
|
+
values << 'exec-before'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should bind only the aspect that binds to private methods' do
|
28
|
+
subject.send :exec
|
29
|
+
expect(subject.values).to eq %w( exec-before exec-result )
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'around aspect' do
|
34
|
+
before do
|
35
|
+
aspector(klass) do
|
36
|
+
around :exec do |proxy, &block|
|
37
|
+
values << 'exec-around-before(public_methods_only)'
|
38
|
+
result = proxy.call(&block)
|
39
|
+
values << 'exec-around-after(public_methods_only)'
|
40
|
+
result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
aspector(klass, private_methods: true) do
|
45
|
+
around :exec do |proxy, &block|
|
46
|
+
values << 'exec-around-before'
|
47
|
+
result = proxy.call(&block)
|
48
|
+
values << 'exec-around-after'
|
49
|
+
result
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should bind only the aspect that binds to private methods' do
|
55
|
+
subject.send :exec
|
56
|
+
expect(subject.values).to eq %w( exec-around-before exec-result exec-around-after )
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'after aspect' do
|
61
|
+
before do
|
62
|
+
aspector(klass) do
|
63
|
+
after :exec do |result|
|
64
|
+
values << 'exec-after(public_methods_only)'
|
65
|
+
result
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
aspector(klass, private_methods: true) do
|
70
|
+
after :exec do |result|
|
71
|
+
values << 'exec-after'
|
72
|
+
result
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should bind only the aspect that binds to private methods' do
|
78
|
+
subject.send :exec
|
79
|
+
expect(subject.values).to eq %w( exec-result exec-after )
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,31 +1,30 @@
|
|
1
|
-
ENV["ASPECTOR_LOG_LEVEL"] ||= "warn"
|
2
|
-
|
3
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
5
1
|
require 'rubygems'
|
6
2
|
require 'rspec'
|
7
|
-
require '
|
8
|
-
require '
|
3
|
+
require 'simplecov'
|
4
|
+
require 'pry'
|
9
5
|
|
10
|
-
|
11
|
-
|
12
|
-
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
13
8
|
|
14
|
-
|
9
|
+
# Don't include unnecessary stuff into rcov
|
10
|
+
SimpleCov.start do
|
11
|
+
add_filter '/vendor/'
|
12
|
+
add_filter '/gems/'
|
13
|
+
add_filter '/.bundle/'
|
14
|
+
add_filter '/spec/'
|
15
|
+
merge_timeout 600
|
15
16
|
end
|
16
17
|
|
17
|
-
|
18
|
-
klass = Class.new do
|
19
|
-
def value
|
20
|
-
@value ||= []
|
21
|
-
end
|
18
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
20
|
+
RSpec.configure do |config|
|
21
|
+
config.disable_monkey_patching!
|
27
22
|
|
28
|
-
|
29
|
-
|
23
|
+
config.expect_with :rspec do |expectations|
|
24
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
25
|
+
end
|
30
26
|
end
|
31
27
|
|
28
|
+
require 'aspector'
|
29
|
+
|
30
|
+
ENV['ASPECTOR_LOG_LEVEL'] ||= ::Logger::WARN.to_s
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# rubocop:disable NestedMethodDefinition
|
2
|
+
# Class builder helps creating anonymous classes that we can use to spec our aspector
|
3
|
+
# We need co create new class instances to have an "empty" and "clear" class for each spec
|
4
|
+
# This module acts as an interface to create classes
|
5
|
+
module ClassBuilder
|
6
|
+
class << self
|
7
|
+
# Builds a new anonymous class with a predefined methods
|
8
|
+
# @param block [Proc, nil] block that should be evaluated (if given)
|
9
|
+
# @return [Class] created anonymous class
|
10
|
+
def build(&block)
|
11
|
+
klass = raw do
|
12
|
+
def values
|
13
|
+
@values ||= []
|
14
|
+
end
|
15
|
+
|
16
|
+
# This is a method that we use as a place to bind to
|
17
|
+
# @note This method accepts dummy not used parameter but we keep it
|
18
|
+
# so we can exec with parameter if we need
|
19
|
+
def exec(_param = nil)
|
20
|
+
values << 'exec-result'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
klass.class_eval(&block) if block_given?
|
25
|
+
klass
|
26
|
+
end
|
27
|
+
|
28
|
+
# Creates an empty class without any predefined methods
|
29
|
+
# @param block [Proc, nil] block that should be evaluated (if given)
|
30
|
+
# @return [Class] created anonymous class
|
31
|
+
def raw(&block)
|
32
|
+
Class.new(&block)
|
33
|
+
end
|
34
|
+
|
35
|
+
# This method allows us to create a class that inherits from any other
|
36
|
+
# @param klass [Class] any class from which we want to inherit in our anonymous class
|
37
|
+
# @param block [Proc] a block of code that should be evaluated in a new anonymous class body
|
38
|
+
# @return [Class] new anonymous class
|
39
|
+
def inherit(klass, &block)
|
40
|
+
Class.new(klass, &block)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
# rubocop:enable NestedMethodDefinition
|