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,49 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Aspector::Advice do
4
+ subject { described_class.new }
5
+
6
+ describe '.new' do
7
+ pending
8
+ end
9
+
10
+ describe '#name' do
11
+ pending
12
+ end
13
+
14
+ describe '#with_method' do
15
+ pending
16
+ end
17
+
18
+ describe '#match?' do
19
+ pending
20
+ end
21
+
22
+ describe '#raw?' do
23
+ pending
24
+ end
25
+
26
+ describe '#before?' do
27
+ pending
28
+ end
29
+
30
+ describe '#after?' do
31
+ pending
32
+ end
33
+
34
+ describe '#around?' do
35
+ pending
36
+ end
37
+
38
+ describe '#type_name' do
39
+ pending
40
+ end
41
+
42
+ describe '#use_deferred_logic?' do
43
+ pending
44
+ end
45
+
46
+ describe '#to_s' do
47
+ pending
48
+ end
49
+ end
@@ -0,0 +1,328 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'After advices' do
4
+ subject { klass.new }
5
+
6
+ context 'standard case' do
7
+ let(:klass) do
8
+ ClassBuilder.build do
9
+ def after_exec(result)
10
+ values << 'after-exec'
11
+ result
12
+ end
13
+ end
14
+ end
15
+
16
+ before do
17
+ aspector(klass) do
18
+ after :exec, :after_exec
19
+ end
20
+ end
21
+
22
+ it 'should execute after_exec' do
23
+ expect(subject)
24
+ .to receive(:after_exec)
25
+ .once
26
+
27
+ subject.exec
28
+ end
29
+
30
+ it 'should work' do
31
+ subject.exec
32
+ expect(subject.values).to eq %w( exec-result after-exec )
33
+ end
34
+ end
35
+
36
+ context 'logic in string' do
37
+ let(:klass) { ClassBuilder.build }
38
+
39
+ before do
40
+ aspector(klass) do
41
+ after :exec, <<-CODE
42
+ values << 'after-exec'
43
+ result
44
+ CODE
45
+ end
46
+ end
47
+
48
+ it 'should work' do
49
+ subject.exec
50
+ expect(subject.values).to eq %w( exec-result after-exec )
51
+ end
52
+ end
53
+
54
+ context 'logic in block' do
55
+ let(:klass) { ClassBuilder.build }
56
+
57
+ before do
58
+ aspector(klass) do
59
+ after :exec do |result|
60
+ values << 'after_value'
61
+ result
62
+ end
63
+ end
64
+ end
65
+
66
+ it 'should work' do
67
+ subject.exec
68
+ expect(subject.values).to eq %w( exec-result after_value )
69
+ end
70
+ end
71
+
72
+ context 'when we want to use method that is defined after aspector binding' do
73
+ let(:klass) do
74
+ ClassBuilder.build do
75
+ aspector do
76
+ after :exec, :after_exec
77
+ end
78
+
79
+ def after_exec(result)
80
+ values << 'after-exec'
81
+ result
82
+ end
83
+ end
84
+ end
85
+
86
+ it 'should be able to use it' do
87
+ subject.exec
88
+ expect(subject.values).to eq %w( exec-result after-exec )
89
+ end
90
+ end
91
+
92
+ context 'method with parameters' do
93
+ let(:klass) do
94
+ ClassBuilder.build do
95
+ def after_exec(method, result, *exec_params)
96
+ values << "after-exec(#{method})"
97
+ values << exec_params
98
+ values.flatten!
99
+ result
100
+ end
101
+ end
102
+ end
103
+
104
+ let(:exec_param) { rand }
105
+
106
+ before do
107
+ aspector(klass) do
108
+ after :exec, :after_exec, method_arg: true
109
+ end
110
+ end
111
+
112
+ it 'should execute after_exec with method args' do
113
+ expect(subject)
114
+ .to receive(:after_exec)
115
+ .with('exec', ['exec-result'], exec_param)
116
+ .once
117
+
118
+ subject.exec(exec_param)
119
+ end
120
+
121
+ it 'should work' do
122
+ subject.exec(exec_param)
123
+ expect(subject.values).to eq %w( exec-result after-exec(exec) ) << exec_param
124
+ end
125
+ end
126
+
127
+ context 'method with method_arg' do
128
+ let(:klass) do
129
+ ClassBuilder.build do
130
+ def after_exec(method, result)
131
+ values << "after_exec(#{method})"
132
+ result
133
+ end
134
+ end
135
+ end
136
+
137
+ before do
138
+ aspector(klass) do
139
+ after :exec, :after_exec, method_arg: true
140
+ end
141
+ end
142
+
143
+ it 'should execute after_exec with method args' do
144
+ expect(subject)
145
+ .to receive(:after_exec)
146
+ .with('exec', ['exec-result'])
147
+ .once
148
+
149
+ subject.exec
150
+ end
151
+
152
+ it 'should work' do
153
+ subject.exec
154
+ expect(subject.values).to eq %w( exec-result after_exec(exec) )
155
+ end
156
+ end
157
+
158
+ context 'new result from aspect block' do
159
+ let(:klass) { ClassBuilder.build }
160
+
161
+ before do
162
+ aspector(klass) do
163
+ after :exec do |_result|
164
+ values << 'after_value'
165
+ 'block-result'
166
+ end
167
+ end
168
+ end
169
+
170
+ it 'should return it by default' do
171
+ expect(subject.exec).to eq 'block-result'
172
+ expect(subject.values).to eq %w( exec-result after_value )
173
+ end
174
+ end
175
+
176
+ context 'when result_arg is set to false' do
177
+ let(:klass) do
178
+ ClassBuilder.build do
179
+ def exec
180
+ values << 'exec-result'
181
+ 'exec-result'
182
+ end
183
+ end
184
+ end
185
+
186
+ before do
187
+ aspector(klass) do
188
+ after :exec, result_arg: false do
189
+ values << 'do_after'
190
+ 'do_after'
191
+ end
192
+ end
193
+ end
194
+
195
+ it 'should return original method return value' do
196
+ expect(subject.exec).to eq 'exec-result'
197
+ end
198
+
199
+ it 'should still execute the after block' do
200
+ subject.exec
201
+ expect(subject.values).to eq %w( exec-result do_after )
202
+ end
203
+ end
204
+
205
+ describe 'implicit method option' do
206
+ context 'when we want to bind to a single method' do
207
+ let(:klass) do
208
+ ClassBuilder.build do
209
+ def after_method(result)
210
+ values << 'after-method'
211
+ result
212
+ end
213
+ end
214
+ end
215
+
216
+ before do
217
+ aspector klass, method: %i( exec ) do
218
+ after :after_method
219
+ end
220
+ end
221
+
222
+ it 'should work' do
223
+ subject.exec
224
+ expect(subject.values).to eq %w( exec-result after-method )
225
+ end
226
+ end
227
+
228
+ context 'when we want to bind to multiple methods' do
229
+ let(:klass) do
230
+ ClassBuilder.build do
231
+ def after_method(result)
232
+ values << 'after-method'
233
+ result
234
+ end
235
+
236
+ def exec_new
237
+ values << 'exec-new'
238
+ end
239
+ end
240
+ end
241
+
242
+ before do
243
+ aspector klass, methods: %i( exec exec_new ) do
244
+ after :after_method
245
+ end
246
+ end
247
+
248
+ it 'should work for method 1' do
249
+ subject.exec
250
+ expect(subject.values).to eq %w( exec-result after-method )
251
+ end
252
+
253
+ it 'should work for method 2' do
254
+ subject.exec_new
255
+ expect(subject.values).to eq %w( exec-new after-method )
256
+ end
257
+ end
258
+ end
259
+
260
+ describe 'disabling aspect' do
261
+ let(:klass) do
262
+ ClassBuilder.build do
263
+ def after_method(result)
264
+ values << 'after-method'
265
+ result
266
+ end
267
+ end
268
+ end
269
+
270
+ let(:aspect) do
271
+ aspector klass, method: %i( exec ) do
272
+ after :after_method
273
+ end
274
+ end
275
+
276
+ before do
277
+ aspect.disable
278
+ end
279
+
280
+ context 'when we define an aspect and we disable it' do
281
+ it 'should not work' do
282
+ subject.exec
283
+ expect(subject.values).to eq %w( exec-result )
284
+ end
285
+
286
+ context 'and we enable it back' do
287
+ it 'should work again' do
288
+ subject.exec
289
+ expect(subject.values).to eq %w( exec-result )
290
+ aspect.enable
291
+ subject.exec
292
+ expect(subject.values).to eq %w( exec-result exec-result after-method )
293
+ end
294
+ end
295
+ end
296
+ end
297
+
298
+ context 'all methods except' do
299
+ let(:klass) do
300
+ ClassBuilder.build do
301
+ def after_exec(result)
302
+ values << 'after-exec'
303
+ result
304
+ end
305
+
306
+ def except_exec
307
+ values << 'except-exec'
308
+ end
309
+ end
310
+ end
311
+
312
+ before do
313
+ aspector(klass) do
314
+ after(/^ex.*/, :after_exec, except: :except_exec)
315
+ end
316
+ end
317
+
318
+ it 'should work with exec' do
319
+ subject.exec
320
+ expect(subject.values).to eq %w( exec-result after-exec )
321
+ end
322
+
323
+ it 'should not work with except_exec' do
324
+ subject.except_exec
325
+ expect(subject.values).to eq %w( except-exec )
326
+ end
327
+ end
328
+ end
@@ -0,0 +1,336 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Around advices' do
4
+ subject { klass.new }
5
+
6
+ context 'standard case' do
7
+ let(:klass) do
8
+ ClassBuilder.build do
9
+ def around_exec(proxy, &block)
10
+ values << 'before-exec'
11
+ result = proxy.call(&block)
12
+ values << 'after-exec'
13
+ result
14
+ end
15
+ end
16
+ end
17
+
18
+ before do
19
+ aspector(klass) do
20
+ around :exec, :around_exec
21
+ end
22
+ end
23
+
24
+ it 'should wrap around the exec method and work' do
25
+ subject.exec
26
+ expect(subject.values).to eq %w( before-exec exec-result after-exec )
27
+ end
28
+ end
29
+
30
+ context 'logic in string' do
31
+ let(:klass) { ClassBuilder.build }
32
+
33
+ before do
34
+ aspector(klass) do
35
+ around :exec, <<-CODE
36
+ values << 'before-exec'
37
+ result = INVOKE_PROXY
38
+ values << 'after-exec'
39
+ result
40
+ CODE
41
+ end
42
+ end
43
+
44
+ it 'should wrap around the exec method and work' do
45
+ subject.exec
46
+ expect(subject.values).to eq %w( before-exec exec-result after-exec )
47
+ end
48
+ end
49
+
50
+ context 'logic in block' do
51
+ let(:klass) { ClassBuilder.build }
52
+
53
+ before do
54
+ aspector(klass) do
55
+ around :exec do |proxy, &block|
56
+ values << 'before-exec'
57
+ result = proxy.call(&block)
58
+ values << 'after-exec'
59
+ result
60
+ end
61
+ end
62
+ end
63
+
64
+ it 'should wrap around the exec method and work' do
65
+ subject.exec
66
+ expect(subject.values).to eq %w( before-exec exec-result after-exec )
67
+ end
68
+ end
69
+
70
+ context 'when we want to use method that is defined after aspector binding' do
71
+ let(:klass) do
72
+ ClassBuilder.build do
73
+ aspector do
74
+ around :exec, :around_exec
75
+ end
76
+
77
+ def around_exec(proxy, &block)
78
+ values << 'before-exec'
79
+ result = proxy.call(&block)
80
+ values << 'after-exec'
81
+ result
82
+ end
83
+ end
84
+ end
85
+
86
+ it 'should be able to use it' do
87
+ subject.exec
88
+ expect(subject.values).to eq %w( before-exec exec-result after-exec )
89
+ end
90
+ end
91
+
92
+ context 'method with parameters' do
93
+ let(:klass) do
94
+ ClassBuilder.build do
95
+ def around_exec(method, proxy, *exec_params, &block)
96
+ values << "before-exec(#{method})"
97
+ result = proxy.call(&block)
98
+ values << exec_params
99
+ values << "after-exec(#{method})"
100
+ values.flatten!
101
+ result
102
+ end
103
+ end
104
+ end
105
+
106
+ let(:exec_param) { rand }
107
+
108
+ before do
109
+ aspector(klass) do
110
+ around :exec, :around_exec, method_arg: true
111
+ end
112
+ end
113
+
114
+ it 'should work' do
115
+ subject.exec(exec_param)
116
+ expected = (%w( before-exec(exec) exec-result ) << exec_param) + %w( after-exec(exec) )
117
+ expect(subject.values).to eq expected
118
+ end
119
+ end
120
+
121
+ context 'method with method_arg' do
122
+ let(:klass) do
123
+ ClassBuilder.build do
124
+ def around_exec(method, proxy, &block)
125
+ values << "before-exec(#{method})"
126
+ result = proxy.call(&block)
127
+ values << "after-exec(#{method})"
128
+ result
129
+ end
130
+ end
131
+ end
132
+
133
+ before do
134
+ aspector(klass) do
135
+ around :exec, :around_exec, method_arg: true
136
+ end
137
+ end
138
+
139
+ it 'should work' do
140
+ subject.exec
141
+ expect(subject.values).to eq %w( before-exec(exec) exec-result after-exec(exec) )
142
+ end
143
+ end
144
+
145
+ context 'new result from aspect block' do
146
+ let(:klass) { ClassBuilder.build }
147
+
148
+ before do
149
+ aspector(klass) do
150
+ around :exec do |proxy, &block|
151
+ values << 'before-exec'
152
+ proxy.call(&block)
153
+ values << 'after-exec'
154
+ 'block-result'
155
+ end
156
+ end
157
+ end
158
+
159
+ it 'should return them by default' do
160
+ expect(subject.exec).to eq 'block-result'
161
+ expect(subject.values).to eq %w( before-exec exec-result after-exec )
162
+ end
163
+ end
164
+
165
+ describe 'implicit method option' do
166
+ context 'when we want to bind to a single method' do
167
+ let(:klass) do
168
+ ClassBuilder.build do
169
+ def around_method(proxy, &block)
170
+ values << 'before-method'
171
+ result = proxy.call(&block)
172
+ values << 'after-method'
173
+ result
174
+ end
175
+ end
176
+ end
177
+
178
+ before do
179
+ aspector klass, method: %i( exec ) do
180
+ around :around_method
181
+ end
182
+ end
183
+
184
+ it 'should work' do
185
+ subject.exec
186
+ expect(subject.values).to eq %w( before-method exec-result after-method )
187
+ end
188
+ end
189
+
190
+ context 'when we want to bind to multiple methods' do
191
+ let(:klass) do
192
+ ClassBuilder.build do
193
+ def around_method(proxy, &block)
194
+ values << 'before-method'
195
+ result = proxy.call(&block)
196
+ values << 'after-method'
197
+ result
198
+ end
199
+
200
+ def exec_new
201
+ values << 'exec-new'
202
+ end
203
+ end
204
+ end
205
+
206
+ before do
207
+ aspector klass, methods: %i( exec exec_new ) do
208
+ around :around_method
209
+ end
210
+ end
211
+
212
+ it 'should work for method 1' do
213
+ subject.exec
214
+ expect(subject.values).to eq %w( before-method exec-result after-method )
215
+ end
216
+
217
+ it 'should work for method 2' do
218
+ subject.exec_new
219
+ expect(subject.values).to eq %w( before-method exec-new after-method )
220
+ end
221
+ end
222
+ end
223
+
224
+ context 'disabling aspect' do
225
+ let(:klass) do
226
+ ClassBuilder.build do
227
+ def around_exec(proxy, &block)
228
+ values << 'before-exec'
229
+ result = proxy.call(&block)
230
+ values << 'after-exec'
231
+ result
232
+ end
233
+ end
234
+ end
235
+
236
+ let(:aspect) do
237
+ aspector(klass) do
238
+ around :exec, :around_exec
239
+ end
240
+ end
241
+
242
+ before do
243
+ aspect.disable
244
+ end
245
+
246
+ context 'when we define an aspect and we disable it' do
247
+ it 'should not work' do
248
+ subject.exec
249
+ expect(subject.values).to eq %w( exec-result )
250
+ end
251
+
252
+ context 'and we enable it back' do
253
+ it 'should work again' do
254
+ subject.exec
255
+ expect(subject.values).to eq %w( exec-result )
256
+ aspect.enable
257
+ subject.exec
258
+ expect(subject.values).to eq %w( exec-result before-exec exec-result after-exec )
259
+ end
260
+ end
261
+ end
262
+ end
263
+
264
+ context 'disabling aspect' do
265
+ let(:klass) do
266
+ ClassBuilder.build do
267
+ def around_exec(proxy, &block)
268
+ values << 'before-exec'
269
+ result = proxy.call(&block)
270
+ values << 'after-exec'
271
+ result
272
+ end
273
+ end
274
+ end
275
+
276
+ let(:aspect) do
277
+ aspector(klass) do
278
+ around :exec, :around_exec
279
+ end
280
+ end
281
+
282
+ before do
283
+ aspect.disable
284
+ end
285
+
286
+ context 'when we define an aspect and we disable it' do
287
+ it 'should not work' do
288
+ subject.exec
289
+ expect(subject.values).to eq %w( exec-result )
290
+ end
291
+ end
292
+
293
+ context 'and we enable it back' do
294
+ it 'should not work' do
295
+ subject.exec
296
+ expect(subject.values).to eq %w( exec-result )
297
+ aspect.enable
298
+ subject.exec
299
+ expect(subject.values).to eq %w( exec-result before-exec exec-result after-exec )
300
+ end
301
+ end
302
+ end
303
+
304
+ context 'all methods except' do
305
+ let(:klass) do
306
+ ClassBuilder.build do
307
+ def around_exec(proxy, &block)
308
+ values << 'before-exec'
309
+ result = proxy.call(&block)
310
+ values << 'after-exec'
311
+ result
312
+ end
313
+
314
+ def except_exec
315
+ values << 'except-exec'
316
+ end
317
+ end
318
+ end
319
+
320
+ before do
321
+ aspector(klass) do
322
+ around(/^ex.*/, :around_exec, except: :except_exec)
323
+ end
324
+ end
325
+
326
+ it 'should work with exec' do
327
+ subject.exec
328
+ expect(subject.values).to eq %w( before-exec exec-result after-exec )
329
+ end
330
+
331
+ it 'should not work with except_exec' do
332
+ subject.except_exec
333
+ expect(subject.values).to eq %w( except-exec )
334
+ end
335
+ end
336
+ end