lite-command 3.1.5 → 3.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,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25949bea3778fbe660ae361819879bc36deb461fb37e9efa4ad11012529ae682
4
- data.tar.gz: 7f9df66b9027c3c7e3cb7b8efaad1508dec68c22b4b63ab27c4ffd123707519e
3
+ metadata.gz: ecfaebe941a3ed585e42a5a43b361d60de38076b6a4254125722b13d57294885
4
+ data.tar.gz: da15660c9410a9c8797d6c322ab79797f800f5233319a7a39d6476bba10504ec
5
5
  SHA512:
6
- metadata.gz: 9c2ee67da223708a63852d539ab82f7a893214c1016376fc0af4496d224ccdcfef3340b1267f6fec11348ae8d2ede2c87b605494aa2090a8f449c317a3d9613a
7
- data.tar.gz: 29ec28857fc0e8f29e1ba34a41cae8b44298a44c9477e73a237f5eb708965ba555a4b82edff984b20b61b4f1967ce93586ec74075a8421f6481c353865c0e275
6
+ metadata.gz: b91f356964b41577a7e274a5cc5cf46c74b60a088ffa781e7c5f3cbf0f7bd7713accf16ddf8bee16e99342e04a0040ea8dab2fb8c5ff7eb3132d7e3000596ca0
7
+ data.tar.gz: d905466a1fe16049f5af3877c2488120eb581070fe85a9bf20654cf09127bcccc8e6e9a79c436f16164e3104d5fc7d1bd6bbb7b839069250d29cc4b551e8c47e
data/CHANGELOG.md CHANGED
@@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [3.2.0] - 2024-10-29
10
+ ### Changed
11
+ - Move callbacks to hooks instead of try methods
12
+
9
13
  ## [3.1.5] - 2024-10-28
10
14
  ### Changed
11
15
  - Renamed private `delegate` method to `delegates` to prevent rails clash
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lite-command (3.1.5)
4
+ lite-command (3.2.0)
5
5
  activemodel
6
6
  ostruct
7
7
 
data/README.md CHANGED
@@ -33,10 +33,9 @@ Or install it yourself as:
33
33
  * [States](#states)
34
34
  * [Statuses](#statuses)
35
35
  * [Hooks](#hooks)
36
- * [State Hooks](#status-hooks)
37
- * [Attribute Hooks](#attribute-hooks)
38
- * [Execution Hooks](#execution-hooks)
36
+ * [Lifecycle Hooks](#lifecycle-hooks)
39
37
  * [Status Hooks](#status-hooks)
38
+ * [State Hooks](#state-hooks)
40
39
  * [Children](#children)
41
40
  * [Throwing Faults](#throwing-faults)
42
41
  * [Sequences](#sequences)
@@ -143,6 +142,10 @@ cmd.raise!(original: true) #=> raises Lite::Command::Fault
143
142
  # On exception:
144
143
  cmd.raise!(original: false) #=> raises Lite::Command::Error
145
144
  cmd.raise!(original: true) #=> raises StandardError
145
+
146
+ # Access the exception objects directly
147
+ cmd.original_exception #=> <StandardError ...>
148
+ cmd.command_exception #=> <Lite::Command::Error ...>
146
149
  ```
147
150
 
148
151
  ### Dynamic Faults
@@ -361,9 +364,6 @@ cmd.status #=> "invalid"
361
364
  cmd.reason #=> "Invalid message start value"
362
365
  cmd.metadata #=> { i18n: "gb.invalid_start_value" }
363
366
 
364
- cmd.original_exception #=> <RuntimeError ...>
365
- cmd.command_exception #=> <DecryptSecretMessage::Error ...>
366
-
367
367
  cmd.success? #=> false
368
368
  cmd.noop? #=> false
369
369
  cmd.invalid? #=> true
@@ -387,140 +387,91 @@ cmd.bad?("Other reason") #=> false
387
387
  ## Hooks
388
388
 
389
389
  Use hooks to run arbituary code at transition points and on finalized internals.
390
- The following is an example of the hooks called for a failed command with a
391
- successful child command.
390
+ All hooks are ran in the order they are defined. Hooks types can be defined
391
+ multiple times. The following is an example of the hooks called for a failed
392
+ command with a successful child command.
392
393
 
393
394
  ```ruby
394
- -> 1. FooCommand.on_pending
395
- -> 2. FooCommand.on_before_execution
396
- -> 3. FooCommand.on_executing
397
- ---> 3a. BarCommand.on_pending
398
- ---> 3b. BarCommand.on_before_execution
399
- ---> 3c. BarCommand.on_executing
400
- ---> 3d. BarCommand.on_after_execution
401
- ---> 3e. BarCommand.on_success
402
- ---> 3f. BarCommand.on_complete
403
- -> 4. FooCommand.on_after_execution
404
- -> 5. FooCommand.on_failure
405
- -> 6. FooCommand.on_interrupted
395
+ -> 1. FooCommand.after_initialize
396
+ -> 2. FooCommand.on_pending
397
+ -> 3. FooCommand.before_validation
398
+ -> 4. FooCommand.after_validation
399
+ -> 5. FooCommand.before_execution
400
+ -> 6. FooCommand.on_executing
401
+ ---> 6a. BarCommand.after_initialize
402
+ ---> 6b. BarCommand.on_pending
403
+ ---> 6c. BarCommand.before_validation
404
+ ---> 6d. BarCommand.after_validation
405
+ ---> 6e. BarCommand.before_execution
406
+ ---> 6f. BarCommand.on_executing
407
+ ---> 6g. BarCommand.after_execution
408
+ ---> 6h. BarCommand.on_failure
409
+ ---> 6i. BarCommand.on_interrupted
410
+ -> 7. FooCommand.after_execution
411
+ -> 8. FooCommand.on_failure
412
+ -> 9. FooCommand.on_interrupted
406
413
  ```
407
414
 
408
- ### Status Hooks
415
+ ### Lifecycle Hooks
409
416
 
410
- Define one or more callbacks that are called during transitions between states.
417
+ Define before and after callbacks to call around execution.
411
418
 
412
419
  ```ruby
413
420
  class DecryptSecretMessage < Lite::Command::Base
414
421
 
415
- def call
416
- # ...
417
- end
418
-
419
- private
420
-
421
- def on_pending
422
- # eg: Append additional contextual data
423
- end
424
-
425
- def on_executing
426
- # eg: Insert inspection debugger
427
- end
428
-
429
- def on_complete
430
- # eg: Log message for posterity
431
- end
432
-
433
- def on_interrupted
434
- # eg: Report to APM with tags and metadata
435
- end
436
-
437
- end
438
- ```
439
-
440
- ### Attribute Hooks
441
-
442
- Define before attribtue validation callbacks.
443
-
444
- ```ruby
445
- class DecryptSecretMessage < Lite::Command::Base
422
+ after_initialize :some_method
423
+ before_validation :some_method
424
+ after_validation :some_method
425
+ before_execution :some_method
426
+ after_execution :some_method
446
427
 
447
428
  def call
448
429
  # ...
449
430
  end
450
431
 
451
- private
452
-
453
- def on_before_validation
454
- # eg: Normalize context data
455
- end
456
-
457
432
  end
458
433
  ```
459
434
 
460
- ### Execution Hooks
435
+ ### Status Hooks
461
436
 
462
- Define before and after callbacks to call around execution.
437
+ Define one or more callbacks that are called after execution for
438
+ specific statuses.
463
439
 
464
440
  ```ruby
465
441
  class DecryptSecretMessage < Lite::Command::Base
466
442
 
443
+ on_success :some_method
444
+ on_noop :some_method
445
+ on_invalid :some_method
446
+ on_failure :some_method
447
+ on_error :some_method
448
+
467
449
  def call
468
450
  # ...
469
451
  end
470
452
 
471
- private
472
-
473
- def on_before_execution
474
- # eg: Append additional contextual data
475
- end
476
-
477
- def on_after_execution
478
- # eg: Store results to database
479
- end
480
-
481
453
  end
482
454
  ```
483
455
 
484
- ### Status Hooks
456
+ ### State Hooks
485
457
 
486
- Define one or more callbacks that are called after execution for
487
- specific statuses.
458
+ Define one or more callbacks that are called during transitions between states.
488
459
 
489
460
  ```ruby
490
461
  class DecryptSecretMessage < Lite::Command::Base
491
462
 
463
+ on_pending :some_method
464
+ on_executing :some_method
465
+ on_complete :some_method
466
+ on_interrupted :some_method
467
+
492
468
  def call
493
469
  # ...
494
470
  end
495
471
 
496
- private
497
-
498
- def on_success
499
- # eg: Increment KPI counter
500
- end
501
-
502
- def on_noop(fault)
503
- # eg: Log message for posterity
504
- end
505
-
506
- def on_invalid(fault)
507
- # eg: Send metadata errors to frontend
508
- end
509
-
510
- def on_failure(fault)
511
- # eg: Rollback record changes
512
- end
513
-
514
- def on_error(fault_or_exception)
515
- # eg: Report to APM with tags and metadata
516
- end
517
-
518
472
  end
519
473
  ```
520
474
 
521
- > [!NOTE]
522
- > The `on_success` callback does **NOT** take any arguments.
523
-
524
475
  ## Children
525
476
 
526
477
  When building complex commands, its best that you pass the parents context to the
@@ -16,6 +16,7 @@ module Lite
16
16
  base.include Internals::Faults
17
17
  base.include Internals::Calls
18
18
  base.include Internals::Executions
19
+ base.include Internals::Hooks
19
20
  base.include Internals::Results
20
21
 
21
22
  if Lite::Command.configuration.raise_dynamic_faults # rubocop:disable Style/GuardClause
@@ -34,7 +35,7 @@ module Lite
34
35
 
35
36
  def initialize(context = {})
36
37
  @context = Context.build(context)
37
- Utils.try(self, :on_pending)
38
+ run_hooks(:after_initialize)
38
39
  end
39
40
 
40
41
  end
@@ -52,9 +52,9 @@ module Lite
52
52
  private
53
53
 
54
54
  def validate_context_attributes
55
- return if errors.empty?
56
-
57
- invalid!(errors.full_messages.join(". "), metadata: errors.messages)
55
+ run_hooks(:before_validation)
56
+ invalid!(errors.full_messages.join(". "), metadata: errors.messages) unless valid?
57
+ run_hooks(:after_validation)
58
58
  end
59
59
 
60
60
  end
@@ -24,14 +24,12 @@ module Lite
24
24
 
25
25
  def call(context = {})
26
26
  instance = send(:new, context)
27
- instance.validate
28
27
  instance.send(:execute)
29
28
  instance
30
29
  end
31
30
 
32
31
  def call!(context = {})
33
32
  instance = send(:new, context)
34
- instance.validate
35
33
  instance.send(:execute!)
36
34
  instance
37
35
  end
@@ -50,16 +50,18 @@ module Lite
50
50
  increment_execution_index
51
51
  assign_execution_cmd_id
52
52
  start_monotonic_time
53
- Utils.try(self, :on_before_validation)
53
+ run_hooks(:on_pending)
54
54
  validate_context_attributes
55
- Utils.try(self, :on_before_execution)
55
+ run_hooks(:before_execution)
56
56
  executing!
57
- Utils.try(self, :on_executing)
57
+ run_hooks(:on_executing)
58
58
  end
59
59
 
60
60
  def after_execution
61
61
  send(:"#{success? ? COMPLETE : INTERRUPTED}!")
62
- Utils.try(self, :on_after_execution)
62
+ run_hooks(:after_execution)
63
+ run_hooks(:"on_#{status}")
64
+ run_hooks(:"on_#{state}")
63
65
  stop_monotonic_time
64
66
  append_execution_result
65
67
  freeze_execution_objects
@@ -72,26 +74,17 @@ module Lite
72
74
  end
73
75
 
74
76
  def execute
75
- around_execution { call }
76
- Utils.try(self, :on_success)
77
- rescue StandardError => e
78
- fault(e, Utils.try(e, :type) || ERROR, metadata, exception: e)
79
- after_execution
80
- Utils.try(self, :"on_#{status}", e)
81
- ensure
82
- Utils.try(self, :"on_#{state}")
77
+ execute!
78
+ rescue StandardError
79
+ # Do nothing
83
80
  end
84
81
 
85
82
  def execute!
86
83
  around_execution { call }
87
- Utils.try(self, :on_success)
88
84
  rescue StandardError => e
89
85
  fault(e, Utils.try(e, :type) || ERROR, metadata, exception: e)
90
86
  after_execution
91
- Utils.try(self, :"on_#{status}", e)
92
87
  raise(e)
93
- else
94
- Utils.try(self, :"on_#{state}")
95
88
  end
96
89
 
97
90
  end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Command
5
+
6
+ HOOKS = [
7
+ :after_initialize,
8
+ :before_validation,
9
+ :after_validation,
10
+ :before_execution,
11
+ :after_execution,
12
+ *STATUSES.map { |s| :"on_#{s}" },
13
+ *STATES.map { |s| :"on_#{s}" }
14
+ ].freeze
15
+
16
+ module Internals
17
+ module Hooks
18
+
19
+ def self.included(base)
20
+ base.extend ClassMethods
21
+ end
22
+
23
+ module ClassMethods
24
+
25
+ def hooks
26
+ @hooks ||= Utils.try(superclass, :hooks).dup || {}
27
+ end
28
+
29
+ HOOKS.each do |h|
30
+ define_method(h) do |*method_names, &block|
31
+ method_names << block if block_given?
32
+ method_names.each { |mn| (hooks[h] ||= []) << mn }
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ private
39
+
40
+ def run_hooks(hook)
41
+ hooks = self.class.hooks[hook]
42
+ return if hooks.nil?
43
+
44
+ hooks.each { |h| Utils.call(self, h) }
45
+ end
46
+
47
+ end
48
+ end
49
+
50
+ end
51
+ end
@@ -3,7 +3,7 @@
3
3
  module Lite
4
4
  module Command
5
5
 
6
- VERSION = "3.1.5"
6
+ VERSION = "3.2.0"
7
7
 
8
8
  end
9
9
  end
data/lib/lite/command.rb CHANGED
@@ -16,6 +16,7 @@ require "lite/command/internals/attributes"
16
16
  require "lite/command/internals/faults"
17
17
  require "lite/command/internals/calls"
18
18
  require "lite/command/internals/executions"
19
+ require "lite/command/internals/hooks"
19
20
  require "lite/command/internals/results"
20
21
  require "lite/command/base"
21
22
  require "lite/command/step"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lite-command
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.5
4
+ version: 3.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-10-28 00:00:00.000000000 Z
11
+ date: 2024-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -201,6 +201,7 @@ files:
201
201
  - lib/lite/command/internals/calls.rb
202
202
  - lib/lite/command/internals/executions.rb
203
203
  - lib/lite/command/internals/faults.rb
204
+ - lib/lite/command/internals/hooks.rb
204
205
  - lib/lite/command/internals/results.rb
205
206
  - lib/lite/command/internals/runtimes.rb
206
207
  - lib/lite/command/sequence.rb