lite-command 2.0.1 → 2.0.3

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: 71f2852f73f09542e278f594b692dd02c8e10f54fee85e1e9493d565520e5fc6
4
- data.tar.gz: 668b62c1be78ee8b18ad06469ddbabf703497777bc73536395c6608fe8e26614
3
+ metadata.gz: b21cf35a72b7a37760d250919ee052e3800bfe09083709e9d9f65593612d8826
4
+ data.tar.gz: b2b55e457b95ce878aab140537ba1f28aa5310c4e257d0e2b11948ed9ee7f9c2
5
5
  SHA512:
6
- metadata.gz: 18815326f8e22082e906c0142dd0b157a910a9d1755a56e67869b58cfe39ce4394beccb7c48565969ac291569005eb35d0a365ca9854bd9adf383def93ec8c8f
7
- data.tar.gz: 3cba4a2e8fa9f780e7546e5934b38a5c3d3aadc318bca455824a8058aa5855cf47026c7c7813cfca8c2f390702b3fdb8d260139613853936d8e59cf68d6e8437
6
+ metadata.gz: f8ab004280e1c00026dacc92a7d652dc2859c68f6648e31210ccfa1c16a1aba9ba31e57843910bf90d4b94677e8cd8c4c651989c2e2f1983556f33ff786e6514
7
+ data.tar.gz: aed6da43c95926071114ef9692b17c4fa2b5a3215629e473c8bd70a552fdd624f189095cfa1744da6aa427cbcf80cfb6adb6db81c5b754f4ff81bfee500d046d
data/CHANGELOG.md CHANGED
@@ -6,6 +6,24 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [2.0.3] - 2024-09-30
10
+ ### Changed
11
+ - Simplify error building
12
+ - Reduced recalling error since we can just throw it once
13
+ - Rename `fault_name` to `type`
14
+
15
+ ## [2.0.2] - 2024-09-29
16
+ ### Added
17
+ - faultable module
18
+ ### Changed
19
+ - Simplified status variable check
20
+ - Simplified context merge
21
+ - Fixed invalid looking at wrong variable
22
+ - Renamed `fault` and `thrower` to `caused_by` and `thrown_by` respectively
23
+ - Removed unused `additional_result_data` method
24
+ ### Removed
25
+ - Removed context init
26
+
9
27
  ## [2.0.1] - 2024-09-27
10
28
  ### Removed
11
29
  - Activemodel dependency
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lite-command (2.0.1)
4
+ lite-command (2.0.3)
5
5
  ostruct
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -94,7 +94,7 @@ command.context.result #=> 8
94
94
 
95
95
  #### States
96
96
  State represents the state of the executable code. Once `execute`
97
- is ran, it will always `complete` or `dnf` if a fault is thrown by a
97
+ is ran, it will always `complete` or `interrupted` if a fault is thrown by a
98
98
  child command.
99
99
 
100
100
  - `pending`
@@ -103,7 +103,7 @@ child command.
103
103
  - Command objects actively executing code.
104
104
  - `complete`
105
105
  - Command objects that executed to completion.
106
- - `dnf`
106
+ - `interrupted`
107
107
  - Command objects that could NOT be executed to completion.
108
108
  This could be as a result of a fault/exception on the
109
109
  object itself or one of its children.
@@ -9,22 +9,23 @@ module Lite
9
9
 
10
10
  base.include Lite::Command::Internals::Callable
11
11
  base.include Lite::Command::Internals::Executable
12
+ base.include Lite::Command::Internals::Faultable
12
13
  base.include Lite::Command::Internals::Resultable
13
14
 
14
15
  base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
15
- # eg: Users::ResetPassword::Fault
16
- class #{base}::Fault < Lite::Command::Fault; end
16
+ # eg: Users::ResetPassword::Fault < Lite::Command::Fault
17
+ #{base}::Fault = Class.new(Lite::Command::Fault)
18
+
19
+ # eg: Users::ResetPassword::Noop < Users::ResetPassword::Fault
20
+ #{base}::Noop = Class.new(#{base}::Fault)
21
+ #{base}::Invalid = Class.new(#{base}::Fault)
22
+ #{base}::Failure = Class.new(#{base}::Fault)
23
+ #{base}::Error = Class.new(#{base}::Fault)
17
24
  RUBY
18
-
19
- FAULTS.each do |f|
20
- base.class_eval <<-RUBY, __FILE__, __LINE__ + 1
21
- # eg: Users::ResetPassword::Noop < Users::ResetPassword::Fault
22
- class #{base}::#{f.capitalize} < #{base}::Fault; end
23
- RUBY
24
- end
25
25
  end
26
26
 
27
27
  attr_reader :context
28
+ alias ctx context
28
29
 
29
30
  def initialize(context = {})
30
31
  @context = Lite::Command::Context.build(context)
@@ -32,10 +33,6 @@ module Lite
32
33
 
33
34
  private
34
35
 
35
- def additional_result_data
36
- {} # Define in your class to add additional info to result hash
37
- end
38
-
39
36
  def on_before_execution
40
37
  # Define in your class to run code before execution
41
38
  end
@@ -6,25 +6,20 @@ module Lite
6
6
  module Command
7
7
  class Context < OpenStruct
8
8
 
9
- def self.init(attributes = {})
9
+ def self.build(attributes = {})
10
+ return attributes if attributes.is_a?(self) && !attributes.frozen?
11
+
10
12
  # To save memory and speed up the access to an attribute, the accessor methods
11
13
  # of an attribute are lazy loaded at certain points. This means that the methods
12
14
  # are defined only when a set of defined actions are triggered. This allows context
13
15
  # to only define the minimum amount of required methods to make your data structure work
14
- os = new(attributes)
16
+ os = new(attributes.to_h)
15
17
  os.methods(false)
16
18
  os
17
19
  end
18
20
 
19
- def self.build(attributes = {})
20
- return attributes if attributes.is_a?(self) && !attributes.frozen?
21
-
22
- init(attributes.to_h)
23
- end
24
-
25
21
  def merge!(attributes = {})
26
- attrs = attributes.is_a?(self.class) ? attributes.to_h : attributes
27
- attrs.each { |k, v| self[k] = v }
22
+ attributes.to_h.each { |k, v| self[k] = v }
28
23
  end
29
24
 
30
25
  end
@@ -3,51 +3,27 @@
3
3
  module Lite
4
4
  module Command
5
5
 
6
- # Fault represent a stoppage of a call execution. This error should
7
- # not be raised directly since it wont provide any context. Use
8
- # `Noop`, `Invalid`, `Failure`, and `Error` to signify severity.
9
6
  class Fault < StandardError
10
7
 
11
- attr_reader :faulter, :thrower, :reason
8
+ attr_reader :reason, :caused_by, :thrown_by
12
9
 
13
- def initialize(faulter, thrower, reason)
10
+ def initialize(reason, caused_by, thrown_by)
14
11
  super(reason)
15
12
 
16
- @faulter = faulter
17
- @thrower = thrower
18
13
  @reason = reason
14
+ @caused_by = caused_by
15
+ @thrown_by = thrown_by
19
16
  end
20
17
 
21
- def fault_klass
22
- @fault_klass ||= self.class.name.split("::").last
23
- end
24
-
25
- def fault_name
26
- @fault_name ||= fault_klass.downcase
18
+ def type
19
+ @type ||= self.class.name.split("::").last.downcase
27
20
  end
28
21
 
29
22
  end
30
23
 
31
- # Noop represents skipping completion of call execution early
32
- # an unsatisfied condition or logic check where there is no
33
- # point on proceeding.
34
- # eg: account is sample: skip since its a non-alterable record
35
24
  class Noop < Fault; end
36
-
37
- # Invalid represents a stoppage of call execution due to
38
- # missing, bad, or corrupt data.
39
- # eg: user not found: stop since rest of the call cant be executed
40
25
  class Invalid < Fault; end
41
-
42
- # Failure represents a stoppage of call execution due to
43
- # an unsatisfied condition or logic check where it blocks
44
- # proceeding any further.
45
- # eg: record not found: stop since there is nothing todo
46
26
  class Failure < Fault; end
47
-
48
- # Error represents a caught exception for a call execution
49
- # that could not complete.
50
- # eg: ApiServerError: stop since there was a 3rd party issue
51
27
  class Error < Fault; end
52
28
 
53
29
  end
@@ -3,28 +3,20 @@
3
3
  module Lite
4
4
  module Command
5
5
 
6
- # Status represents the state of the callable code. If no fault
7
- # is thrown then a status of SUCCESS is returned even if `call`
8
- # has not been executed.
9
- FAULTS = [
10
- NOOP = "noop",
6
+ STATUSES = [
7
+ SUCCESS = "success",
8
+ NOOP = "noop",
11
9
  INVALID = "invalid",
12
10
  FAILURE = "failure",
13
- ERROR = "error"
14
- ].freeze
15
- STATUSES = [
16
- *FAULTS,
17
- SUCCESS = "success"
11
+ ERROR = "error"
18
12
  ].freeze
13
+ FAULTS = (STATUSES - [SUCCESS]).freeze
19
14
 
20
15
  module Internals
21
16
  module Callable
22
17
 
23
18
  def self.included(base)
24
19
  base.extend ClassMethods
25
- base.class_eval do
26
- attr_reader :faulter, :thrower, :reason
27
- end
28
20
  end
29
21
 
30
22
  module ClassMethods
@@ -43,109 +35,44 @@ module Lite
43
35
  raise NotImplementedError, "call method not defined in #{self.class}"
44
36
  end
45
37
 
46
- def success?
47
- !fault?
48
- end
49
-
50
- def fault?(message = nil)
51
- FAULTS.any? { |f| send(:"#{f}?", message) }
52
- end
53
-
54
38
  def status
55
- STATUSES.find { |s| send(:"#{s}?") }
56
- end
57
-
58
- def faulter?
59
- faulter == self
39
+ @status || SUCCESS
60
40
  end
61
41
 
62
- def thrower?
63
- thrower == self
42
+ def success?
43
+ status == SUCCESS
64
44
  end
65
45
 
66
- def thrown_fault?
67
- fault? && !faulter?
46
+ def fault?(str = nil)
47
+ !success? && reason?(str)
68
48
  end
69
49
 
70
50
  FAULTS.each do |f|
71
- # eg: error?(message = nil)
72
- define_method(:"#{f}?") do |message = nil|
73
- fault_result = instance_variable_get(:"@#{f}") || false
74
- return fault_result if message.nil?
75
-
76
- reason == message
51
+ # eg: noop? or failure?("idk")
52
+ define_method(:"#{f}?") do |str = nil|
53
+ status == f && reason?(str)
77
54
  end
78
55
  end
79
56
 
80
57
  private
81
58
 
82
- def derive_faulter_from(object)
83
- (object.faulter if object.respond_to?(:faulter)) || self
84
- end
85
-
86
- def derive_thrower_from(object)
87
- if object.respond_to?(:executed?) && object.executed?
88
- object
89
- else
90
- (object.thrower if object.respond_to?(:thrower)) || faulter
91
- end
92
- end
93
-
94
- def derive_reason_from(object)
95
- if object.respond_to?(:reason)
96
- object.reason
97
- elsif object.respond_to?(:message)
98
- "[#{object.class.name}] #{object.message}".chomp(".")
99
- else
100
- object
101
- end
102
- end
103
-
104
- def fault(object)
105
- @faulter ||= derive_faulter_from(object)
106
- @thrower ||= derive_thrower_from(object)
107
- @reason ||= derive_reason_from(object)
108
- end
109
-
110
- # eg: Lite::Command::Noop.new(...)
111
- def raise_fault(klass, object)
112
- exception = klass.new(faulter, self, reason)
113
- exception.set_backtrace(object.backtrace) if object.respond_to?(:backtrace)
114
- raise(exception)
115
- end
116
-
117
- # eg: Users::ResetPassword::Noop.new(...)
118
- def raise_dynamic_fault(exception)
119
- fault_klass = self.class.const_get(exception.fault_klass)
120
- raise_fault(fault_klass, exception)
121
- end
122
-
123
- def raise_dynamic_faults?
124
- false
125
- end
126
-
127
- def throw!(command)
128
- return if command.success?
129
-
130
- send(:"#{command.status}!", command)
131
- end
132
-
133
59
  FAULTS.each do |f|
134
60
  # eg: error(object)
135
61
  define_method(:"#{f}") do |object|
136
- fault(object)
137
- instance_variable_set(:"@#{f}", true)
62
+ derive_fault_from(object)
63
+ @status = f
138
64
  end
139
65
 
140
66
  # eg: invalid!(object)
141
67
  define_method(:"#{f}!") do |object|
142
68
  send(:"#{f}", object)
143
- raise_fault(Lite::Command.const_get(f.capitalize), object)
69
+ raise fault(f.capitalize, object)
144
70
  end
145
71
 
146
72
  # eg: on_noop(exception)
147
73
  define_method(:"on_#{f}") do |_exception|
148
- # Define in your class to run code when a StandardError happens
74
+ # Define in your class to run code when a
75
+ # Lite::Command::Fault or StandardError happens
149
76
  end
150
77
  end
151
78
 
@@ -3,14 +3,11 @@
3
3
  module Lite
4
4
  module Command
5
5
 
6
- # State represents the state of the executable code. Once `execute`
7
- # is ran, it will always complete or dnf if a fault is thrown by a
8
- # child command.
9
6
  STATES = [
10
- PENDING = "pending",
11
- EXECUTING = "executing",
12
- COMPLETE = "complete",
13
- DNF = "dnf"
7
+ PENDING = "pending",
8
+ EXECUTING = "executing",
9
+ COMPLETE = "complete",
10
+ INTERRUPTED = "interrupted"
14
11
  ].freeze
15
12
 
16
13
  module Internals
@@ -19,21 +16,18 @@ module Lite
19
16
  def execute
20
17
  around_execution { call }
21
18
  rescue StandardError => e
22
- fn = e.respond_to?(:fault_name) ? e.fault_name : ERROR
19
+ f = e.respond_to?(:type) ? e.type : ERROR
23
20
 
24
- send(:"#{fn}", e)
21
+ send(:"#{f}", e)
25
22
  after_execution
26
- send(:"on_#{fn}", e)
23
+ send(:"on_#{f}", e)
27
24
  end
28
25
 
29
26
  def execute!
30
27
  around_execution { call }
31
28
  rescue StandardError => e
32
29
  after_execution
33
-
34
- raise(e) unless raise_dynamic_faults? && e.is_a?(Lite::Command::Fault)
35
-
36
- raise_dynamic_fault(e)
30
+ raise(e)
37
31
  end
38
32
 
39
33
  def state
@@ -41,14 +35,14 @@ module Lite
41
35
  end
42
36
 
43
37
  def executed?
44
- dnf? || complete?
38
+ complete? || interrupted?
45
39
  end
46
40
 
47
41
  STATES.each do |s|
48
- # eg: running?
42
+ # eg: executing?
49
43
  define_method(:"#{s}?") { state == s }
50
44
 
51
- # eg: dnf!
45
+ # eg: interrupted!
52
46
  define_method(:"#{s}!") { @state = s }
53
47
  end
54
48
 
@@ -63,7 +57,7 @@ module Lite
63
57
  end
64
58
 
65
59
  def after_execution
66
- fault? ? dnf! : complete!
60
+ fault? ? interrupted! : complete!
67
61
  on_after_execution
68
62
  stop_monotonic_time
69
63
  append_execution_result
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lite
4
+ module Command
5
+ module Internals
6
+ module Faultable
7
+
8
+ def self.included(base)
9
+ base.class_eval do
10
+ attr_reader :caused_by, :thrown_by, :reason
11
+ end
12
+ end
13
+
14
+ def reason?(str)
15
+ return true if str.nil?
16
+
17
+ reason == str
18
+ end
19
+
20
+ def caused_fault?
21
+ caused_by == self
22
+ end
23
+
24
+ def threw_fault?
25
+ thrown_by == self
26
+ end
27
+
28
+ def thrown?
29
+ fault? && !caused_fault?
30
+ end
31
+
32
+ private
33
+
34
+ def throw!(command)
35
+ return if command.success?
36
+
37
+ send(:"#{command.status}!", command)
38
+ end
39
+
40
+ def derive_caused_by_from(object)
41
+ (object.caused_by if object.respond_to?(:caused_by)) || self
42
+ end
43
+
44
+ def derive_thrown_by_from(object)
45
+ if object.respond_to?(:executed?) && object.executed?
46
+ object
47
+ else
48
+ (object.thrown_by if object.respond_to?(:thrown_by)) || caused_by
49
+ end
50
+ end
51
+
52
+ def derive_reason_from(object)
53
+ if object.respond_to?(:reason)
54
+ object.reason
55
+ elsif object.respond_to?(:message)
56
+ "[#{object.class.name}] #{object.message}".chomp(".")
57
+ else
58
+ object
59
+ end
60
+ end
61
+
62
+ def derive_fault_from(object)
63
+ @caused_by ||= derive_caused_by_from(object)
64
+ @thrown_by ||= derive_thrown_by_from(object)
65
+ @reason ||= derive_reason_from(object)
66
+ end
67
+
68
+ def raise_dynamic_faults?
69
+ false
70
+ end
71
+
72
+ # eg: Lite::Command::Noop.new(...) or Users::ResetPassword::Noop.new(...)
73
+ def fault(type, thrower)
74
+ klass = raise_dynamic_faults? ? self.class : Lite::Command
75
+ fault = klass.const_get(type.to_s).new(reason, caused_by, self)
76
+ fault.set_backtrace(thrower.backtrace) if thrower.respond_to?(:backtrace)
77
+ fault
78
+ end
79
+
80
+ end
81
+ end
82
+ end
83
+ end
@@ -16,7 +16,7 @@ module Lite
16
16
  end
17
17
 
18
18
  def outcome
19
- return state if pending? || thrown_fault?
19
+ return state if pending? || thrown?
20
20
 
21
21
  status
22
22
  end
@@ -34,8 +34,8 @@ module Lite
34
34
  state:,
35
35
  status:,
36
36
  reason:,
37
- fault: faulter&.index,
38
- throw: thrower&.index,
37
+ caused_by: caused_by&.index,
38
+ thrown_by: thrown_by&.index,
39
39
  runtime:
40
40
  }.compact
41
41
  end
@@ -3,7 +3,7 @@
3
3
  module Lite
4
4
  module Command
5
5
 
6
- VERSION = "2.0.1"
6
+ VERSION = "2.0.3"
7
7
 
8
8
  end
9
9
  end
data/lib/lite/command.rb CHANGED
@@ -5,6 +5,7 @@ require "generators/rails/command_generator" if defined?(Rails::Generators)
5
5
  require "lite/command/version"
6
6
  require "lite/command/internals/callable"
7
7
  require "lite/command/internals/executable"
8
+ require "lite/command/internals/faultable"
8
9
  require "lite/command/internals/resultable"
9
10
  require "lite/command/fault"
10
11
  require "lite/command/context"
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: 2.0.1
4
+ version: 2.0.3
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-09-27 00:00:00.000000000 Z
11
+ date: 2024-09-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ostruct
@@ -196,6 +196,7 @@ files:
196
196
  - lib/lite/command/fault.rb
197
197
  - lib/lite/command/internals/callable.rb
198
198
  - lib/lite/command/internals/executable.rb
199
+ - lib/lite/command/internals/faultable.rb
199
200
  - lib/lite/command/internals/resultable.rb
200
201
  - lib/lite/command/version.rb
201
202
  - lite-command.gemspec
@@ -219,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
220
  - !ruby/object:Gem::Version
220
221
  version: '0'
221
222
  requirements: []
222
- rubygems_version: 3.5.19
223
+ rubygems_version: 3.5.20
223
224
  signing_key:
224
225
  specification_version: 4
225
226
  summary: Ruby Command based framework (aka service objects)