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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NmIyODE2NzY1ZTAwZjA4YzZmY2NmYzYyNzFiZmVmOGJhMWE4MzNkYw==
4
+ MTgxYzgyOGI5NmQwYzE2MWM0NGI2NjZiMTIzM2U5NDk5ZGZiZjZkYw==
5
5
  data.tar.gz: !binary |-
6
- MWE4YzcxOWFkYmU2ZTQ5ZjllMDg0MWQ3NTdkZTVhNjZjYjFjZWUzMA==
6
+ ZGIyNGMyNDdmZGY1NjM0NmZmY2E5NTMwODU2MDJmMTU1YTYwYjM4OQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZTExN2U3Njg2MmM2OTQ0NTk0NDZmYjk2NDU4NmE1NjBmOTIwNDJlMzY3MGRk
10
- MTc5NmRiMjJhNTljMjc3Yzg2OGE2NmU1Y2IwMDQ1ZDlkYTA4MjI4N2QzODA0
11
- NzZlMGMyYWYzMzEyM2QyM2UyN2EzY2NlN2FjYjdlMjQyYWU0NjA=
9
+ N2FhODUwZmE3ZTM3NDJlMGM2N2JlM2YxNWExNDIxMDI0MzdlNmZlZGFmODFj
10
+ ZmM3NjY3ZWQ2M2FkMjFkMjI4NWY3MDFkNzJmYzc1MWY3YTMyN2VjZWZlYzky
11
+ MWIyZDlhMTA1MjY5YTQ2MDc1ZjhjMGM1OGU0ZGQyZThhZWJiMzc=
12
12
  data.tar.gz: !binary |-
13
- MzA2YjM3ZTRiOWRlNzJiZWNjZDRhZWE5NWU1MjI5OGQ0OWZhMDdlZmJkNjFi
14
- ZTE5YWRlNjljNDE4NTQ2ZWU3OTIzN2FhZTYyZGM2ODk0N2MyZjBkOGZhODRh
15
- NzJhNTk5NDUyYjk3MGE0NGZkYTM0OGViNDA4MTA4MmNhNzhjYjM=
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
@@ -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,
@@ -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
- errors.add(true, args)
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={})
@@ -1,3 +1,3 @@
1
1
  module Lev
2
- VERSION = "4.1.0"
2
+ VERSION = "4.2.0"
3
3
  end
@@ -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
@@ -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.1.0
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-16 00:00:00.000000000 Z
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