lev 4.1.0 → 4.2.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 +8 -8
- data/README.md +31 -0
- data/lib/lev.rb +2 -0
- data/lib/lev/object.rb +4 -0
- data/lib/lev/routine.rb +38 -1
- data/lib/lev/version.rb +1 -1
- data/spec/active_job_routines_spec.rb +27 -0
- data/spec/routine_spec.rb +88 -4
- data/spec/transaction_spec.rb +43 -0
- metadata +20 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MTgxYzgyOGI5NmQwYzE2MWM0NGI2NjZiMTIzM2U5NDk5ZGZiZjZkYw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZGIyNGMyNDdmZGY1NjM0NmZmY2E5NTMwODU2MDJmMTU1YTYwYjM4OQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
N2FhODUwZmE3ZTM3NDJlMGM2N2JlM2YxNWExNDIxMDI0MzdlNmZlZGFmODFj
|
10
|
+
ZmM3NjY3ZWQ2M2FkMjFkMjI4NWY3MDFkNzJmYzc1MWY3YTMyN2VjZWZlYzky
|
11
|
+
MWIyZDlhMTA1MjY5YTQ2MDc1ZjhjMGM1OGU0ZGQyZThhZWJiMzc=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
MmJkMjMwZDhhNjk1ZjRiYThiMzkzYjBkMmFlZmVjZGU1NGYyYjNlOGJhYjM4
|
14
|
+
MDU2YzI4NTg2OTQ0ZjdhYmM3OTkzZTU2Y2FjZTc0ZWRmYWVmZmMyZjdmNWNl
|
15
|
+
MTI0ODYwMDE1YzI0NWIzZGQzYTkxNDMzOTkzNGU3ZWZkOTdmMWQ=
|
data/README.md
CHANGED
@@ -63,6 +63,16 @@ Here's an example setting an error and an output:
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
+
If you'd like the `fatal_error` to raise a `StandardError` immediately instead of bubbling up to the `Lev::Routine#errors` object, you must configure it:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
Lev.configure do |config|
|
70
|
+
config.raise_fatal_errors = true
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
So if you `fatal_error(name: :is_blank)` it will raise `StandardError: "name is blank"`, or `fatal_error(thing: :is_broken, and: :messed_up)` it will raise `StandardError: "thing is broken - and messed up"`
|
75
|
+
|
66
76
|
Additionally, see below for a discussion on how to transfer errors from ActiveRecord models.
|
67
77
|
|
68
78
|
Any `StandardError` raised within a routine will be caught and transformed into a fatal error with `:kind` set to `:exception`. The caller of this routine can choose to reraise this exception by calling `reraise_exception!` on the returned errors object:
|
@@ -376,6 +386,27 @@ Routine class have access to a few other methods:
|
|
376
386
|
2. a `topmost_runner` accessor which points to the highest routine in the calling
|
377
387
|
hierarchy (that routine whose 'runner' is nil)
|
378
388
|
|
389
|
+
### Calling routines as ActiveJobs
|
390
|
+
|
391
|
+
If `ActiveJob` is included in your project, you can invoke a routine to be run in the background. E.g. instead of saying
|
392
|
+
|
393
|
+
```ruby
|
394
|
+
MyRoutine.call(arg1: 23, arg2: 'howdy')
|
395
|
+
```
|
396
|
+
|
397
|
+
You can say
|
398
|
+
|
399
|
+
```ruby
|
400
|
+
MyRoutine.perform_later(arg1: 23, arg2: 'howdy')
|
401
|
+
```
|
402
|
+
|
403
|
+
By default jobs are placed in the `:default` queue, but you can override this in the `lev_routine` call:
|
404
|
+
|
405
|
+
```ruby
|
406
|
+
class MyRoutine
|
407
|
+
lev_routine active_job_queue: :some_other_queue
|
408
|
+
end
|
409
|
+
```
|
379
410
|
|
380
411
|
## Handlers
|
381
412
|
|
data/lib/lev.rb
CHANGED
@@ -54,11 +54,13 @@ module Lev
|
|
54
54
|
attr_accessor :form_error_class
|
55
55
|
attr_accessor :security_transgression_error
|
56
56
|
attr_accessor :illegal_argument_error
|
57
|
+
attr_accessor :raise_fatal_errors
|
57
58
|
|
58
59
|
def initialize
|
59
60
|
@form_error_class = 'error'
|
60
61
|
@security_transgression_error = Lev::SecurityTransgression
|
61
62
|
@illegal_argument_error = Lev::IllegalArgument
|
63
|
+
@raise_fatal_errors = false
|
62
64
|
super
|
63
65
|
end
|
64
66
|
end
|
data/lib/lev/object.rb
CHANGED
@@ -8,6 +8,10 @@ class Object
|
|
8
8
|
options[:transaction] ||= Lev::TransactionIsolation.mysql_default.symbol
|
9
9
|
@transaction_isolation = Lev::TransactionIsolation.new(options[:transaction])
|
10
10
|
|
11
|
+
@active_job_queue = options[:active_job_queue]
|
12
|
+
|
13
|
+
@raise_fatal_errors = options[:raise_fatal_errors]
|
14
|
+
|
11
15
|
@delegates_to = options[:delegates_to]
|
12
16
|
if @delegates_to
|
13
17
|
uses_routine @delegates_to,
|
data/lib/lev/routine.rb
CHANGED
@@ -206,6 +206,34 @@ module Lev
|
|
206
206
|
result.outputs.send(@express_output)
|
207
207
|
end
|
208
208
|
|
209
|
+
if defined?(ActiveJob)
|
210
|
+
def active_job_class
|
211
|
+
@active_job_class ||= const_set("ActiveJob",
|
212
|
+
Class.new(ActiveJob::Base) do
|
213
|
+
queue_as do
|
214
|
+
parent_routine.active_job_queue
|
215
|
+
end
|
216
|
+
|
217
|
+
def parent_routine
|
218
|
+
self.class.parent
|
219
|
+
end
|
220
|
+
|
221
|
+
def perform(*args, &block)
|
222
|
+
parent_routine.call(*args, &block)
|
223
|
+
end
|
224
|
+
end
|
225
|
+
)
|
226
|
+
end
|
227
|
+
|
228
|
+
def perform_later(*args, &block)
|
229
|
+
active_job_class.perform_later(*args, &block)
|
230
|
+
end
|
231
|
+
|
232
|
+
def active_job_queue
|
233
|
+
@active_job_queue || :default
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
209
237
|
# Called at a routine's class level to foretell which other routines will
|
210
238
|
# be used when this routine executes. Helpful for figuring out ahead of
|
211
239
|
# time what kind of transaction isolation level should be used.
|
@@ -239,6 +267,11 @@ module Lev
|
|
239
267
|
@nested_routines ||= {}
|
240
268
|
end
|
241
269
|
|
270
|
+
def raise_fatal_errors?
|
271
|
+
@raise_fatal_errors ||
|
272
|
+
(Lev.configuration.raise_fatal_errors && @raise_fatal_errors.nil?)
|
273
|
+
end
|
274
|
+
|
242
275
|
def class_to_symbol(klass)
|
243
276
|
klass.name.underscore.gsub('/','_').to_sym
|
244
277
|
end
|
@@ -369,7 +402,11 @@ module Lev
|
|
369
402
|
end
|
370
403
|
|
371
404
|
def fatal_error(args={})
|
372
|
-
|
405
|
+
if topmost_runner.class.raise_fatal_errors?
|
406
|
+
raise StandardError, args.to_a.map { |i| i.join(' ') }.join(' - ')
|
407
|
+
else
|
408
|
+
errors.add(true, args)
|
409
|
+
end
|
373
410
|
end
|
374
411
|
|
375
412
|
def nonfatal_error(args={})
|
data/lib/lev/version.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_job'
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
ActiveJob::Base.queue_adapter = :test
|
5
|
+
ActiveJob::Base.logger = ::Logger.new(nil)
|
6
|
+
|
7
|
+
class LaterRoutine
|
8
|
+
lev_routine active_job_queue: :something_else
|
9
|
+
|
10
|
+
protected
|
11
|
+
def exec
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
RSpec.describe 'ActiveJob routines' do
|
16
|
+
it 'can perform routines later' do
|
17
|
+
expect {
|
18
|
+
LaterRoutine.perform_later
|
19
|
+
}.to change { ActiveJob::Base.queue_adapter.enqueued_jobs.count }.by(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'can have the default queue overridden' do
|
23
|
+
LaterRoutine.perform_later
|
24
|
+
queue_name = ActiveJob::Base.queue_adapter.enqueued_jobs.first[:queue]
|
25
|
+
expect(queue_name).to eq('something_else')
|
26
|
+
end
|
27
|
+
end
|
data/spec/routine_spec.rb
CHANGED
@@ -4,16 +4,16 @@ describe Lev::Routine do
|
|
4
4
|
|
5
5
|
before do
|
6
6
|
stub_const 'RaiseError', Class.new
|
7
|
-
RaiseError.class_eval {
|
8
|
-
lev_routine
|
7
|
+
RaiseError.class_eval {
|
8
|
+
lev_routine
|
9
9
|
def exec
|
10
10
|
raise 'error message'
|
11
11
|
end
|
12
12
|
}
|
13
13
|
|
14
14
|
stub_const 'RaiseStandardError', Class.new
|
15
|
-
RaiseStandardError.class_eval {
|
16
|
-
lev_routine
|
15
|
+
RaiseStandardError.class_eval {
|
16
|
+
lev_routine
|
17
17
|
def exec
|
18
18
|
unknown_method_call
|
19
19
|
end
|
@@ -32,4 +32,88 @@ describe Lev::Routine do
|
|
32
32
|
}.to raise_error(NameError)
|
33
33
|
end
|
34
34
|
|
35
|
+
it 'allows not raising fatal errors to be overridden' do
|
36
|
+
stub_const 'NestedFatalError', Class.new
|
37
|
+
NestedFatalError.class_eval {
|
38
|
+
lev_routine
|
39
|
+
|
40
|
+
def exec
|
41
|
+
fatal_error(code: :its_broken)
|
42
|
+
end
|
43
|
+
}
|
44
|
+
|
45
|
+
stub_const 'SpecialFatalErrorOption', Class.new
|
46
|
+
SpecialFatalErrorOption.class_eval {
|
47
|
+
lev_routine raise_fatal_errors: true, delegates_to: NestedFatalError
|
48
|
+
}
|
49
|
+
|
50
|
+
stub_const 'NoFatalErrorOption', Class.new
|
51
|
+
NoFatalErrorOption.class_eval {
|
52
|
+
lev_routine
|
53
|
+
def exec
|
54
|
+
fatal_error(code: :no_propagate)
|
55
|
+
end
|
56
|
+
}
|
57
|
+
|
58
|
+
Lev.configure { |c| c.raise_fatal_errors = false }
|
59
|
+
|
60
|
+
expect {
|
61
|
+
SpecialFatalErrorOption.call
|
62
|
+
}.to raise_error
|
63
|
+
|
64
|
+
expect {
|
65
|
+
NoFatalErrorOption.call
|
66
|
+
}.not_to raise_error
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'allows raising fatal errors config to be overridden' do
|
70
|
+
stub_const 'SpecialNoFatalErrorOption', Class.new
|
71
|
+
SpecialNoFatalErrorOption.class_eval {
|
72
|
+
lev_routine raise_fatal_errors: false
|
73
|
+
def exec
|
74
|
+
fatal_error(code: :its_broken)
|
75
|
+
end
|
76
|
+
}
|
77
|
+
|
78
|
+
Lev.configure { |c| c.raise_fatal_errors = true }
|
79
|
+
|
80
|
+
expect {
|
81
|
+
SpecialNoFatalErrorOption.call
|
82
|
+
}.not_to raise_error
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'when raise_fatal_errors is configured true' do
|
86
|
+
before do
|
87
|
+
Lev.configure do |config|
|
88
|
+
config.raise_fatal_errors = true
|
89
|
+
end
|
90
|
+
|
91
|
+
stub_const 'RaiseFatalError', Class.new
|
92
|
+
RaiseFatalError.class_eval {
|
93
|
+
lev_routine
|
94
|
+
def exec
|
95
|
+
fatal_error(code: :broken, such: :disaster)
|
96
|
+
end
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
after do
|
101
|
+
Lev.configure do |config|
|
102
|
+
config.raise_fatal_errors = false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'raises an exception on fatal_error if configured' do
|
107
|
+
expect {
|
108
|
+
RaiseFatalError.call
|
109
|
+
}.to raise_error
|
110
|
+
|
111
|
+
begin
|
112
|
+
RaiseFatalError.call
|
113
|
+
rescue => e
|
114
|
+
expect(e.message).to eq('code broken - such disaster')
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
35
119
|
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
unless ActiveRecord::Migration.table_exists?(:models)
|
4
|
+
ActiveRecord::Migration.create_table(:models)
|
5
|
+
end
|
6
|
+
|
7
|
+
class Model < ActiveRecord::Base; end
|
8
|
+
|
9
|
+
RSpec.describe 'Transactions' do
|
10
|
+
before do
|
11
|
+
stub_const 'RollBackTransactions', Class.new
|
12
|
+
stub_const 'NestedRoutine', Class.new
|
13
|
+
|
14
|
+
NestedRoutine.class_eval do
|
15
|
+
lev_routine
|
16
|
+
|
17
|
+
def exec
|
18
|
+
raise 'Rolled back'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
RollBackTransactions.class_eval do
|
23
|
+
lev_routine
|
24
|
+
|
25
|
+
uses_routine NestedRoutine
|
26
|
+
|
27
|
+
def exec
|
28
|
+
Model.create!
|
29
|
+
run(:nested_routine)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'in nested routines' do
|
35
|
+
it 'rolls back on exceptions' do
|
36
|
+
expect {
|
37
|
+
RollBackTransactions.call
|
38
|
+
}.to raise_error
|
39
|
+
|
40
|
+
expect(Model.count).to eq(0)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lev
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- JP Slavinsky
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04
|
11
|
+
date: 2015-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -178,6 +178,20 @@ dependencies:
|
|
178
178
|
- - ! '>='
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: activejob
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ! '>='
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ! '>='
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
name: rails
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -221,6 +235,7 @@ files:
|
|
221
235
|
- lib/lev/transaction_isolation.rb
|
222
236
|
- lib/lev/utilities.rb
|
223
237
|
- lib/lev/version.rb
|
238
|
+
- spec/active_job_routines_spec.rb
|
224
239
|
- spec/create_sprocket_spec.rb
|
225
240
|
- spec/deep_merge_spec.rb
|
226
241
|
- spec/delegates_to_spec.rb
|
@@ -238,6 +253,7 @@ files:
|
|
238
253
|
- spec/support/paramify_handler_b.rb
|
239
254
|
- spec/support/sprocket.rb
|
240
255
|
- spec/support/sprocket_handler.rb
|
256
|
+
- spec/transaction_spec.rb
|
241
257
|
homepage: http://github.com/lml/lev
|
242
258
|
licenses:
|
243
259
|
- MIT
|
@@ -263,6 +279,7 @@ signing_key:
|
|
263
279
|
specification_version: 4
|
264
280
|
summary: Ride the rails but don't touch them.
|
265
281
|
test_files:
|
282
|
+
- spec/active_job_routines_spec.rb
|
266
283
|
- spec/create_sprocket_spec.rb
|
267
284
|
- spec/deep_merge_spec.rb
|
268
285
|
- spec/delegates_to_spec.rb
|
@@ -280,3 +297,4 @@ test_files:
|
|
280
297
|
- spec/support/paramify_handler_b.rb
|
281
298
|
- spec/support/sprocket.rb
|
282
299
|
- spec/support/sprocket_handler.rb
|
300
|
+
- spec/transaction_spec.rb
|