cmdx 2.0.1 → 2.1.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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +53 -8
  3. data/lib/cmdx/callbacks.rb +31 -11
  4. data/lib/cmdx/chain.rb +29 -10
  5. data/lib/cmdx/coercions/big_decimal.rb +1 -1
  6. data/lib/cmdx/coercions/boolean.rb +3 -9
  7. data/lib/cmdx/coercions/coerce.rb +4 -1
  8. data/lib/cmdx/coercions/date_time.rb +1 -1
  9. data/lib/cmdx/coercions/integer.rb +11 -2
  10. data/lib/cmdx/coercions/symbol.rb +23 -4
  11. data/lib/cmdx/coercions.rb +25 -10
  12. data/lib/cmdx/configuration.rb +31 -16
  13. data/lib/cmdx/context.rb +36 -52
  14. data/lib/cmdx/deprecation.rb +4 -7
  15. data/lib/cmdx/deprecators/error.rb +4 -1
  16. data/lib/cmdx/deprecators.rb +17 -8
  17. data/lib/cmdx/errors.rb +11 -10
  18. data/lib/cmdx/executors/fiber.rb +16 -4
  19. data/lib/cmdx/executors/thread.rb +18 -4
  20. data/lib/cmdx/executors.rb +22 -7
  21. data/lib/cmdx/fault.rb +15 -3
  22. data/lib/cmdx/i18n_proxy.rb +9 -5
  23. data/lib/cmdx/input.rb +23 -21
  24. data/lib/cmdx/inputs.rb +14 -26
  25. data/lib/cmdx/log_formatters/json.rb +8 -1
  26. data/lib/cmdx/log_formatters/logstash.rb +7 -1
  27. data/lib/cmdx/mergers.rb +22 -7
  28. data/lib/cmdx/middlewares.rb +40 -24
  29. data/lib/cmdx/output.rb +5 -2
  30. data/lib/cmdx/pipeline.rb +18 -3
  31. data/lib/cmdx/railtie.rb +1 -0
  32. data/lib/cmdx/result.rb +22 -6
  33. data/lib/cmdx/retriers/decorrelated_jitter.rb +10 -5
  34. data/lib/cmdx/retriers/exponential.rb +10 -2
  35. data/lib/cmdx/retriers/fibonacci.rb +29 -12
  36. data/lib/cmdx/retriers.rb +17 -8
  37. data/lib/cmdx/retry.rb +20 -13
  38. data/lib/cmdx/runtime.rb +18 -17
  39. data/lib/cmdx/settings.rb +9 -9
  40. data/lib/cmdx/signal.rb +1 -1
  41. data/lib/cmdx/task.rb +90 -45
  42. data/lib/cmdx/telemetry.rb +37 -10
  43. data/lib/cmdx/util.rb +50 -4
  44. data/lib/cmdx/validators/absence.rb +1 -1
  45. data/lib/cmdx/validators/exclusion.rb +15 -15
  46. data/lib/cmdx/validators/format.rb +12 -4
  47. data/lib/cmdx/validators/inclusion.rb +15 -15
  48. data/lib/cmdx/validators/length.rb +5 -49
  49. data/lib/cmdx/validators/numeric.rb +5 -49
  50. data/lib/cmdx/validators/presence.rb +1 -1
  51. data/lib/cmdx/validators/validate.rb +7 -1
  52. data/lib/cmdx/validators.rb +21 -9
  53. data/lib/cmdx/version.rb +1 -1
  54. data/lib/cmdx/workflow.rb +28 -14
  55. data/lib/cmdx.rb +24 -0
  56. data/lib/generators/cmdx/templates/install.rb +80 -39
  57. data/mkdocs.yml +1 -0
  58. metadata +1 -1
@@ -1,40 +1,54 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  CMDx.configure do |config|
4
+ # Full configuration reference:
5
+ # https://drexed.github.io/cmdx/configuration
6
+
4
7
  # ===========================================================================
5
- # Locale
8
+ # Default locale
9
+ # https://drexed.github.io/cmdx/configuration/#default-locale
6
10
  # ===========================================================================
7
- # Fallback locale for built-in messages (validation, coercion, etc.) when
8
- # the I18n gem is not present. With I18n loaded, CMDx follows `I18n.locale`.
11
+ # The language CMDx uses for its built-in messages (validation errors,
12
+ # coercion errors, etc.) when the `I18n` gem isn't around. If `I18n` IS
13
+ # loaded, CMDx follows `I18n.locale` and ignores this setting.
9
14
  #
10
15
  # config.default_locale = "en"
11
16
 
12
17
  # ===========================================================================
13
18
  # Strict context
19
+ # https://drexed.github.io/cmdx/configuration/#strict-context
14
20
  # ===========================================================================
15
- # When true, dynamic reads on `context` raise `NoMethodError` for unknown
16
- # keys instead of returning `nil` (`[]`, `fetch`, `dig`, and `?` predicates
17
- # stay lenient). Override per-task via `settings(strict_context: true)`.
21
+ # Catches typos early. With strict mode on, `context.usr_id` (instead of
22
+ # `context.user_id`) raises `CMDx::UnknownAccessorError` instead of silently
23
+ # returning `nil`. Hash-style reads (`[]`, `fetch`, `dig`, `?` predicates)
24
+ # stay forgiving. Flip it per task with `settings(strict_context: true)`.
18
25
  #
19
26
  # config.strict_context = true
20
27
 
21
28
  # ===========================================================================
22
29
  # Correlation ID (xid)
30
+ # https://drexed.github.io/cmdx/configuration/#correlation-id-xid
23
31
  # ===========================================================================
24
- # Resolves an external correlation id (e.g. Rails `request_id`) once per
25
- # root execution. The value is stored on the Chain and surfaces on every
26
- # Result (`result.xid`, `result.to_h[:xid]`) and Telemetry::Event (`event.xid`),
27
- # so all tasks within the same request can be filtered together in logs.
32
+ # Stamps every task in a run with the same id so you can grep your logs by
33
+ # request. The callable runs ONCE per root execution; every nested task
34
+ # inherits the value. Surfaces as `result.xid`, `result.to_h[:xid]`, and
35
+ # `event.xid` on telemetry events.
28
36
  #
29
37
  # config.correlation_id = -> { Current.request_id }
30
38
 
31
39
  # ===========================================================================
32
40
  # Logging
41
+ # https://drexed.github.io/cmdx/configuration/#logging
33
42
  # ===========================================================================
34
- # In Rails, the Railtie already wires `config.logger = Rails.logger` and a
35
- # backtrace cleaner override here only if you need something different.
43
+ # Pick where logs go, how they look, and what to hide. In Rails, the Railtie
44
+ # already points `logger` at `Rails.logger` and wires a backtrace cleaner
45
+ # only override here if you want something different.
46
+ #
47
+ # Built-in formatters (under `CMDx::LogFormatters`):
48
+ # Line (default), JSON, KeyValue, Logstash, Raw
36
49
  #
37
- # Formatters: Line (default), Json, KeyValue, Logstash, Raw
50
+ # `log_exclusions` only strips keys from the LOG LINE — the in-memory
51
+ # `Result` and telemetry payloads stay complete.
38
52
  #
39
53
  # config.backtrace_cleaner = ->(bt) { Rails.backtrace_cleaner.clean(bt) }
40
54
  # config.log_exclusions = [:context]
@@ -44,8 +58,12 @@ CMDx.configure do |config|
44
58
 
45
59
  # ===========================================================================
46
60
  # Middlewares
61
+ # https://drexed.github.io/cmdx/configuration/#middlewares
47
62
  # ===========================================================================
48
- # Wrap every task's execution. Must respond to `call(task) { ... }`.
63
+ # Wrap every task with shared behavior (auth, locale, timing, you name it).
64
+ # A middleware is anything that responds to `call(task) { ... }` and MUST
65
+ # yield (or call `next_link.call` from a proc) — forgetting to do so raises
66
+ # `CMDx::MiddlewareError` so tasks never silently disappear.
49
67
  #
50
68
  # Example — run each task under the current user's locale:
51
69
  #
@@ -59,9 +77,13 @@ CMDx.configure do |config|
59
77
 
60
78
  # ===========================================================================
61
79
  # Callbacks
80
+ # https://drexed.github.io/cmdx/configuration/#callbacks
62
81
  # ===========================================================================
63
- # Events:
64
- # :before_validation, :before_execution,
82
+ # Hook into a task's lifecycle. Each callback receives the task instance.
83
+ #
84
+ # Available events:
85
+ # :before_execution, :before_validation,
86
+ # :around_execution, :after_execution,
65
87
  # :on_complete, :on_interrupted,
66
88
  # :on_success, :on_skipped, :on_failed,
67
89
  # :on_ok, :on_ko
@@ -72,16 +94,20 @@ CMDx.configure do |config|
72
94
 
73
95
  # ===========================================================================
74
96
  # Telemetry
97
+ # https://drexed.github.io/cmdx/configuration/#telemetry
75
98
  # ===========================================================================
76
- # Events and payloads:
77
- # :task_started payload: {}
78
- # :task_deprecated payload: {}
79
- # :task_retried payload: { attempt: Integer }
80
- # :task_rolled_back payload: {}
81
- # :task_executed payload: { result: CMDx::Result }
99
+ # A tiny pub/sub bus for runtime events. Subscribe with a callable; nothing
100
+ # fires if nobody's listening, so unused events cost nothing.
101
+ #
102
+ # Events and their extra payload keys:
103
+ # :task_started {}
104
+ # :task_deprecated {}
105
+ # :task_retried { attempt: Integer }
106
+ # :task_rolled_back {}
107
+ # :task_executed { result: CMDx::Result }
82
108
  #
83
109
  # Every event also carries: event.cid, event.xid, event.tid, event.task,
84
- # event.type, event.root, event.timestamp.
110
+ # event.type, event.name, event.root, event.payload, event.timestamp.
85
111
  #
86
112
  # config.telemetry.subscribe(:task_executed, proc do |event|
87
113
  # StatsD.timing("cmdx.task", event.payload[:result].duration)
@@ -89,8 +115,11 @@ CMDx.configure do |config|
89
115
 
90
116
  # ===========================================================================
91
117
  # Coercions
118
+ # https://drexed.github.io/cmdx/configuration/#coercions
92
119
  # ===========================================================================
93
- # Register custom type coercions. Callable receives `(value, **options)`.
120
+ # Teach CMDx how to convert raw input into a custom type. The callable gets
121
+ # `(value, **options)` and returns the coerced value (or
122
+ # `CMDx::Coercions::Failure.new("message")` to signal a bad value).
94
123
  #
95
124
  # config.coercions.register(:currency, proc do |value, **|
96
125
  # BigDecimal(value.to_s.gsub(/[^\d.-]/, ""))
@@ -98,9 +127,11 @@ CMDx.configure do |config|
98
127
 
99
128
  # ===========================================================================
100
129
  # Validators
130
+ # https://drexed.github.io/cmdx/configuration/#validators
101
131
  # ===========================================================================
102
- # Register custom validators. Callable receives `(value, options)` and
103
- # returns a `CMDx::Validators::Failure.new(message)` on failure.
132
+ # Custom input validators. The callable gets `(value, options)` (options is
133
+ # a positional Hash). Return `CMDx::Validators::Failure.new(message)` to
134
+ # fail — anything else (even `nil`) means the value passed.
104
135
  #
105
136
  # config.validators.register(:uuid, proc do |value, _options|
106
137
  # unless value.to_s.match?(/\A[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\z/i)
@@ -110,11 +141,13 @@ CMDx.configure do |config|
110
141
 
111
142
  # ===========================================================================
112
143
  # Retriers
144
+ # https://drexed.github.io/cmdx/retries/
113
145
  # ===========================================================================
114
- # Registered retriers compute the sleep duration between `retry_on` attempts.
115
- # Built-ins: `:exponential` (default), `:linear`, `:fibonacci`, `:half_random`,
116
- # `:full_random`, `:bounded_random`, `:decorrelated_jitter`. A callable
117
- # receives `call(attempt, delay, prev_delay)` and returns seconds.
146
+ # Retriers decide how long to wait between `retry_on` attempts. A callable
147
+ # gets `(attempt, delay, prev_delay)` and returns the next sleep in seconds.
148
+ #
149
+ # Built-ins: :exponential (default), :linear, :fibonacci, :half_random,
150
+ # :full_random, :bounded_random, :decorrelated_jitter.
118
151
  #
119
152
  # config.retriers.register(:capped_exponential, proc do |attempt, delay, _prev|
120
153
  # [delay * (2**(attempt - 1)), 30.0].min
@@ -122,9 +155,13 @@ CMDx.configure do |config|
122
155
 
123
156
  # ===========================================================================
124
157
  # Deprecators
158
+ # https://drexed.github.io/cmdx/deprecation/
125
159
  # ===========================================================================
126
- # Registered deprecators dispatch a task class's `deprecation` declaration.
127
- # Built-ins: `:log`, `:warn`, `:error`. A callable receives `call(task)`.
160
+ # Decide what happens when a task with a `deprecation` declaration runs —
161
+ # log a warning, raise, ping your error tracker, whatever you like. The
162
+ # callable receives the task instance.
163
+ #
164
+ # Built-ins: :log, :warn, :error.
128
165
  #
129
166
  # config.deprecators.register(:notify, proc do |task|
130
167
  # Bugsnag.notify("Deprecated task invoked: #{task.class.name}")
@@ -132,11 +169,13 @@ CMDx.configure do |config|
132
169
 
133
170
  # ===========================================================================
134
171
  # Executors
172
+ # https://drexed.github.io/cmdx/workflows/#parallel-execution
135
173
  # ===========================================================================
136
- # Registered executors drive `:parallel` workflow groups. Built-ins:
137
- # `:threads` (default), `:fibers`. A callable receives
138
- # `call(jobs:, concurrency:, on_job:)` and must invoke `on_job.call(job)`
139
- # for each job, blocking until every job is done.
174
+ # Executors power `:parallel` workflow groups. The callable gets
175
+ # `(jobs:, concurrency:, on_job:)`, runs `on_job.call(job)` for every job,
176
+ # and blocks until every job is done.
177
+ #
178
+ # Built-ins: :threads (default), :fibers.
140
179
  #
141
180
  # config.executors.register(:ractors, proc do |jobs:, concurrency:, on_job:|
142
181
  # jobs.each_slice(concurrency) do |slice|
@@ -146,10 +185,12 @@ CMDx.configure do |config|
146
185
 
147
186
  # ===========================================================================
148
187
  # Mergers
188
+ # https://drexed.github.io/cmdx/workflows/#parallel-execution
149
189
  # ===========================================================================
150
- # Merge strategies fold successful parallel task contexts back into the
151
- # workflow context. Built-ins: `:last_write_wins` (default), `:deep_merge`,
152
- # `:no_merge`. A callable receives `call(workflow_context, result)`.
190
+ # After parallel branches succeed, a merger folds each branch's context back
191
+ # into the workflow context. The callable gets `(workflow_context, result)`.
192
+ #
193
+ # Built-ins: :last_write_wins (default), :deep_merge, :no_merge.
153
194
  #
154
195
  # config.mergers.register(:whitelist, proc do |workflow_context, result|
155
196
  # result.context.to_h.slice(:order_id, :total).each do |key, value|
data/mkdocs.yml CHANGED
@@ -189,6 +189,7 @@ nav:
189
189
  - Tips and Tricks: tips_and_tricks.md
190
190
  - Comparison: comparison.md
191
191
  - v1 → v2 Migration: v2-migration.md
192
+ - Examples: https://github.com/drexed/cmdx/blob/main/examples/index.md
192
193
  - References:
193
194
  - API Documentation: https://drexed.github.io/cmdx/api/index.html
194
195
  - llms.txt: https://drexed.github.io/cmdx/llms.txt
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmdx
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez