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.
Files changed (102) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rubocop.yml +26 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +8 -11
  7. data/Changelog.md +59 -0
  8. data/Gemfile +9 -14
  9. data/Gemfile.lock +84 -50
  10. data/README.md +118 -0
  11. data/Rakefile +6 -22
  12. data/aspector.gemspec +15 -127
  13. data/benchmarks/after_benchmark.rb +28 -0
  14. data/benchmarks/around_advice_benchmark.rb +35 -0
  15. data/benchmarks/around_benchmark.rb +32 -0
  16. data/benchmarks/before_benchmark.rb +28 -0
  17. data/benchmarks/benchmark_helper.rb +17 -0
  18. data/benchmarks/combined_benchmark.rb +36 -0
  19. data/benchmarks/method_invocation_benchmark.rb +30 -0
  20. data/benchmarks/raw_benchmark.rb +39 -0
  21. data/examples/activerecord_hooks.rb +10 -15
  22. data/examples/around_example.rb +20 -31
  23. data/examples/aspector_apply_example.rb +10 -17
  24. data/examples/aspector_example.rb +7 -16
  25. data/examples/cache_aspect.rb +20 -30
  26. data/examples/design_by_contract.rb +20 -44
  27. data/examples/exception_handler.rb +12 -20
  28. data/examples/exception_handler2.rb +16 -24
  29. data/examples/implicit_method_option_test.rb +8 -16
  30. data/examples/interception_options_example.rb +71 -0
  31. data/examples/logging_aspect.rb +16 -24
  32. data/examples/process_aspector.rb +13 -0
  33. data/examples/retry_aspect.rb +20 -20
  34. data/lib/aspector.rb +17 -15
  35. data/lib/aspector/advice.rb +44 -57
  36. data/lib/aspector/advice_metadata.rb +10 -11
  37. data/lib/aspector/aspect_instances.rb +2 -3
  38. data/lib/aspector/base.rb +6 -368
  39. data/lib/aspector/base_class_methods.rb +24 -55
  40. data/lib/aspector/deferred_logic.rb +3 -4
  41. data/lib/aspector/deferred_option.rb +5 -10
  42. data/lib/aspector/interception.rb +356 -0
  43. data/lib/aspector/logger.rb +18 -45
  44. data/lib/aspector/logging.rb +10 -29
  45. data/lib/aspector/method_matcher.rb +5 -6
  46. data/lib/aspector/object_extension.rb +4 -12
  47. data/lib/aspector/version.rb +3 -0
  48. data/spec/examples_spec.rb +59 -0
  49. data/spec/functionals/aspect_for_multiple_targets_spec.rb +54 -0
  50. data/spec/functionals/aspect_interception_options_accessing_spec.rb +112 -0
  51. data/spec/functionals/aspect_on_a_class_spec.rb +159 -0
  52. data/spec/functionals/aspect_on_an_instance_spec.rb +66 -0
  53. data/spec/functionals/aspector_spec.rb +138 -0
  54. data/spec/functionals/aspects_combined_spec.rb +37 -0
  55. data/spec/functionals/aspects_execution_order_spec.rb +61 -0
  56. data/spec/functionals/aspects_on_private_methods_spec.rb +82 -0
  57. data/spec/spec_helper.rb +20 -21
  58. data/spec/support/class_builder.rb +44 -0
  59. data/spec/units/advice_spec.rb +49 -0
  60. data/spec/units/advices/after_spec.rb +328 -0
  61. data/spec/units/advices/around_spec.rb +336 -0
  62. data/spec/units/advices/before_filter_spec.rb +287 -0
  63. data/spec/units/advices/before_spec.rb +237 -0
  64. data/spec/units/advices/raw_spec.rb +67 -0
  65. data/spec/units/base_class_methods_spec.rb +262 -0
  66. data/spec/units/base_spec.rb +133 -0
  67. data/spec/units/deferred_logic_spec.rb +35 -0
  68. data/spec/units/logger_spec.rb +20 -0
  69. data/spec/units/logging_spec.rb +85 -0
  70. data/spec/units/method_matcher_spec.rb +95 -0
  71. data/spec/units/object_extension_spec.rb +11 -0
  72. data/spec/units/special_chars_spec.rb +128 -0
  73. metadata +98 -246
  74. data/.document +0 -5
  75. data/.rvmrc +0 -8
  76. data/README.rdoc +0 -80
  77. data/VERSION +0 -1
  78. data/performance-tests/after_test.rb +0 -25
  79. data/performance-tests/around_advice_benchmark.rb +0 -66
  80. data/performance-tests/around_test.rb +0 -27
  81. data/performance-tests/before_test.rb +0 -25
  82. data/performance-tests/combined_test.rb +0 -33
  83. data/performance-tests/method_invocation_test.rb +0 -25
  84. data/performance-tests/raw_test.rb +0 -37
  85. data/performance-tests/test_helper.rb +0 -9
  86. data/run_all_examples.sh +0 -12
  87. data/spec/functional/advices_on_private_methods_spec.rb +0 -21
  88. data/spec/functional/aspect_on_eigen_class_spec.rb +0 -72
  89. data/spec/functional/aspect_on_object_spec.rb +0 -20
  90. data/spec/functional/aspector_spec.rb +0 -140
  91. data/spec/functional/aspects_combined_spec.rb +0 -48
  92. data/spec/functional/execution_order_spec.rb +0 -42
  93. data/spec/unit/advice_spec.rb +0 -4
  94. data/spec/unit/after_spec.rb +0 -88
  95. data/spec/unit/around_spec.rb +0 -76
  96. data/spec/unit/base_class_methods_spec.rb +0 -28
  97. data/spec/unit/base_spec.rb +0 -112
  98. data/spec/unit/before_spec.rb +0 -125
  99. data/spec/unit/deferred_logic_spec.rb +0 -23
  100. data/spec/unit/method_matcher_spec.rb +0 -43
  101. data/spec/unit/raw_spec.rb +0 -53
  102. data/spec/unit/special_chars_spec.rb +0 -122
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Raw advices' do
4
+ subject { klass.new }
5
+
6
+ context 'standard case' do
7
+ let(:klass) do
8
+ ClassBuilder.build do
9
+ def before_exec
10
+ values << 'before_exec'
11
+ end
12
+ end
13
+ end
14
+
15
+ before do
16
+ aspector(klass) do
17
+ raw :exec do
18
+ alias_method :exec_without_aspect, :exec
19
+
20
+ def exec
21
+ values << 'exec-result'
22
+ exec_without_aspect
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ it 'should execute exec_without_aspect' do
29
+ expect(subject)
30
+ .to receive(:exec_without_aspect)
31
+ .once
32
+
33
+ subject.exec
34
+ end
35
+
36
+ it 'should work' do
37
+ subject.exec
38
+ expect(subject.values).to eq %w( exec-result exec-result )
39
+ end
40
+ end
41
+
42
+ context 'when we want to use method that is defined after aspector binding' do
43
+ let(:klass) do
44
+ ClassBuilder.build do
45
+ aspector do
46
+ raw :exec do
47
+ alias_method :exec_without_aspect, :exec
48
+
49
+ def exec
50
+ after_defined_method
51
+ exec_without_aspect
52
+ end
53
+ end
54
+ end
55
+
56
+ def after_defined_method
57
+ values << 'after-defined'
58
+ end
59
+ end
60
+ end
61
+
62
+ it 'should be able to use it' do
63
+ subject.exec
64
+ expect(subject.values).to eq %w( after-defined exec-result )
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,262 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Aspector::Base class methods' do
4
+ subject { ClassBuilder.inherit(Aspector::Base) }
5
+
6
+ describe '.enable' do
7
+ pending
8
+ end
9
+
10
+ describe '.disable' do
11
+ pending
12
+ end
13
+
14
+ describe '.logger' do
15
+ pending
16
+ end
17
+
18
+ describe '.advices' do
19
+ pending
20
+ end
21
+
22
+ describe '.default_options' do
23
+ pending
24
+ end
25
+
26
+ describe '.apply' do
27
+ pending
28
+ end
29
+
30
+ describe '.default' do
31
+ context 'when there are no default options' do
32
+ let(:options) { { rand => rand } }
33
+
34
+ before do
35
+ subject.instance_variable_set(:'@default_options', nil)
36
+ end
37
+
38
+ it 'should assign provided options' do
39
+ subject.send(:default, options)
40
+
41
+ expect(subject.instance_variable_get(:'@default_options')).to eq options
42
+ end
43
+ end
44
+
45
+ context 'when there are default options' do
46
+ let(:options) { { rand => rand } }
47
+ let(:default_options) { { rand => rand } }
48
+
49
+ before do
50
+ subject.instance_variable_set(:'@default_options', default_options)
51
+ end
52
+
53
+ it 'should merge with existing options' do
54
+ subject.send(:default, options)
55
+
56
+ defaults = options.merge(default_options)
57
+ expect(subject.instance_variable_get(:'@default_options')).to eq defaults
58
+ end
59
+ end
60
+ end
61
+
62
+ describe '.before' do
63
+ subject do
64
+ ClassBuilder.inherit(Aspector::Base) do
65
+ before :test, :do_before
66
+ end
67
+ end
68
+
69
+ let(:advices) { subject.send(:advices) }
70
+ let(:advice) { advices.first }
71
+
72
+ it 'should create an advice' do
73
+ expect(subject.send(:advices).size).to eq 1
74
+ end
75
+
76
+ it 'created advice should be a before one' do
77
+ expect(advice.before?).to eq true
78
+ expect(advice.before_filter?).to eq false
79
+ expect(advice.after?).to eq false
80
+ expect(advice.around?).to eq false
81
+ expect(advice.raw?).to eq false
82
+ end
83
+
84
+ it 'skip_if_false for this advice should not be true' do
85
+ expect(advice.options[:skip_if_false]).not_to eq true
86
+ end
87
+
88
+ it 'should create a advice with a do_before method' do
89
+ expect(advice.with_method).to eq :do_before
90
+ end
91
+ end
92
+
93
+ describe '.before_filter' do
94
+ subject do
95
+ ClassBuilder.inherit(Aspector::Base) do
96
+ before_filter :test, :do_before
97
+ end
98
+ end
99
+
100
+ let(:advices) { subject.send(:advices) }
101
+ let(:advice) { advices.first }
102
+
103
+ it 'should create an advice' do
104
+ expect(subject.send(:advices).size).to eq 1
105
+ end
106
+
107
+ it 'created advice should be only a before one' do
108
+ expect(advice.before_filter?).to eq true
109
+ expect(advice.before?).to eq false
110
+ expect(advice.after?).to eq false
111
+ expect(advice.around?).to eq false
112
+ expect(advice.raw?).to eq false
113
+ end
114
+
115
+ it 'should create a advice with a do_before method' do
116
+ expect(advice.with_method).to eq :do_before
117
+ end
118
+ end
119
+
120
+ describe '.after' do
121
+ subject do
122
+ ClassBuilder.inherit(Aspector::Base) do
123
+ after :test, :do_after
124
+ end
125
+ end
126
+
127
+ let(:advices) { subject.send(:advices) }
128
+ let(:advice) { advices.first }
129
+
130
+ it 'should create an advice' do
131
+ expect(subject.send(:advices).size).to eq 1
132
+ end
133
+
134
+ it 'created advice should be a before one' do
135
+ expect(advice.after?).to eq true
136
+ expect(advice.before_filter?).to eq false
137
+ expect(advice.before?).to eq false
138
+ expect(advice.around?).to eq false
139
+ expect(advice.raw?).to eq false
140
+ end
141
+
142
+ it 'skip_if_false for this advice should not be true' do
143
+ expect(advice.options[:skip_if_false]).not_to eq true
144
+ end
145
+
146
+ it 'should create a advice with a do_after method' do
147
+ expect(advice.with_method).to eq :do_after
148
+ end
149
+ end
150
+
151
+ describe '.around' do
152
+ subject do
153
+ ClassBuilder.inherit(Aspector::Base) do
154
+ around :test, :do_around
155
+ end
156
+ end
157
+
158
+ let(:advices) { subject.send(:advices) }
159
+ let(:advice) { advices.first }
160
+
161
+ it 'should create an advice' do
162
+ expect(subject.send(:advices).size).to eq 1
163
+ end
164
+
165
+ it 'created advice should be a around one' do
166
+ expect(advice.after?).to eq false
167
+ expect(advice.before?).to eq false
168
+ expect(advice.around?).to eq true
169
+ expect(advice.raw?).to eq false
170
+ end
171
+
172
+ it 'skip_if_false for this advice should not be true' do
173
+ expect(advice.options[:skip_if_false]).not_to eq true
174
+ end
175
+
176
+ it 'should create a advice with a do_around method' do
177
+ expect(advice.with_method).to eq :do_around
178
+ end
179
+ end
180
+
181
+ describe '.raw' do
182
+ subject do
183
+ ClassBuilder.inherit(Aspector::Base) do
184
+ raw :test do
185
+ end
186
+ end
187
+ end
188
+
189
+ let(:advices) { subject.send(:advices) }
190
+ let(:advice) { advices.first }
191
+
192
+ it 'should create an advice' do
193
+ expect(subject.send(:advices).size).to eq 1
194
+ end
195
+
196
+ it 'created advice should be a around one' do
197
+ expect(advice.after?).to eq false
198
+ expect(advice.before_filter?).to eq false
199
+ expect(advice.before?).to eq false
200
+ expect(advice.around?).to eq false
201
+ expect(advice.raw?).to eq true
202
+ end
203
+
204
+ it 'skip_if_false for this advice should not be true' do
205
+ expect(advice.options[:skip_if_false]).not_to eq true
206
+ end
207
+ end
208
+
209
+ describe '.target' do
210
+ context 'when there is no code and no block' do
211
+ let(:code) { nil }
212
+
213
+ it 'should raise ArgumentError' do
214
+ expect { subject.send(:target, code) }.to raise_error(ArgumentError)
215
+ end
216
+ end
217
+
218
+ context 'when there is code and no block given' do
219
+ let(:code) { true }
220
+
221
+ it 'should not raise ArgumentError' do
222
+ expect { subject.send(:target, code) {} }.not_to raise_error
223
+ end
224
+ end
225
+
226
+ context 'when there is block given and no code' do
227
+ let(:code) { nil }
228
+
229
+ it 'should not raise ArgumentError' do
230
+ expect { subject.send(:target, code) {} }.not_to raise_error
231
+ end
232
+ end
233
+
234
+ context 'when there is code and block given' do
235
+ let(:code) { true }
236
+
237
+ it 'should not raise ArgumentError' do
238
+ expect { subject.send(:target, code) {} }.not_to raise_error
239
+ end
240
+ end
241
+ end
242
+
243
+ describe '.options' do
244
+ it 'should return DeferredOptions instance' do
245
+ expect(subject.send(:options)).to be_kind_of Aspector::DeferredOption
246
+ end
247
+ end
248
+
249
+ describe '._deferred_logics_' do
250
+ context 'when there is nothing in @deferred_logics' do
251
+ pending
252
+ end
253
+
254
+ context 'when there is value in @deferred_logics' do
255
+ pending
256
+ end
257
+ end
258
+
259
+ describe '._create_advice_' do
260
+ pending
261
+ end
262
+ end
@@ -0,0 +1,133 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Aspector::Base do
4
+ let(:klass) { ClassBuilder.build }
5
+ let(:aspect) do
6
+ Aspector do
7
+ before :exec do
8
+ values << 'do_before'
9
+ end
10
+ end
11
+ end
12
+
13
+ subject { klass.new }
14
+
15
+ describe 'default options' do
16
+ context 'when we create aspector with default options' do
17
+ subject do
18
+ Aspector do
19
+ default exec: 'value'
20
+ end
21
+ end
22
+
23
+ it 'should store them' do
24
+ expect(subject.send(:default_options)[:exec]).to eq 'value'
25
+ end
26
+ end
27
+ end
28
+
29
+ describe '#options' do
30
+ # They are used to access options set when aspect is applied
31
+ let(:method) { rand }
32
+ let(:aspect) do
33
+ Aspector do
34
+ before options[:methods] do
35
+ values << 'do_this'
36
+ end
37
+ end
38
+ end
39
+
40
+ before do
41
+ aspect.apply(klass, methods: :exec)
42
+ end
43
+
44
+ it 'should use methods block' do
45
+ subject.exec
46
+ expect(subject.values).to eq %w( do_this exec-result )
47
+ end
48
+ end
49
+
50
+ describe '#apply' do
51
+ context 'applying to a single target' do
52
+ it 'should apply a given code to the method' do
53
+ aspect.apply(klass)
54
+ subject.exec
55
+ expect(subject.values).to eq %w( do_before exec-result )
56
+ end
57
+ end
58
+
59
+ context 'applying to multiple targets at once' do
60
+ let(:klass1) { ClassBuilder.build }
61
+ let(:klass2) { ClassBuilder.build }
62
+
63
+ let(:instance1) { klass1.new }
64
+ let(:instance2) { klass2.new }
65
+
66
+ before { aspect.apply(klass1, klass2) }
67
+
68
+ it 'should apply to all the targets' do
69
+ instance1.exec
70
+ expect(instance1.values).to eq %w( do_before exec-result )
71
+
72
+ instance2.exec
73
+ expect(instance2.values).to eq %w( do_before exec-result )
74
+ end
75
+ end
76
+
77
+ context 'when we try to apply to nonexisting method' do
78
+ let(:aspect) do
79
+ Aspector do
80
+ before options[:methods] do
81
+ # dummy advice
82
+ end
83
+ end
84
+ end
85
+
86
+ it 'should not do anything (should not fail)' do
87
+ expect { aspect.apply(klass, methods: 'not_exist') }.not_to raise_error
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '#target' do
93
+ context 'adding method to targeted class/module' do
94
+ before do
95
+ aspector(klass) do
96
+ target do
97
+ def before_exec
98
+ values << 'before-exec'
99
+ end
100
+ end
101
+
102
+ before :exec, :before_exec
103
+ end
104
+ end
105
+
106
+ it 'should add to target' do
107
+ subject.exec
108
+ expect(subject.values).to eq %w( before-exec exec-result )
109
+ end
110
+ end
111
+
112
+ context 'when we provide an aspect as an argument to a #target method' do
113
+ let(:aspect_class) do
114
+ Class.new(Aspector::Base) do
115
+ target do |aspect|
116
+ define_method :before_exec do
117
+ values << "before_exec(#{aspect.class})"
118
+ end
119
+ end
120
+
121
+ before :exec, :before_exec
122
+ end
123
+ end
124
+
125
+ it 'should add it to target' do
126
+ aspect_class.apply(klass)
127
+
128
+ subject.exec
129
+ expect(subject.values).to eq ["before_exec(#{aspect_class})", 'exec-result']
130
+ end
131
+ end
132
+ end
133
+ end