cmdx 1.20.0 → 2.0.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 (195) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +131 -1
  3. data/README.md +37 -24
  4. data/lib/cmdx/.DS_Store +0 -0
  5. data/lib/cmdx/callbacks.rb +179 -0
  6. data/lib/cmdx/chain.rb +78 -175
  7. data/lib/cmdx/coercions/array.rb +19 -33
  8. data/lib/cmdx/coercions/big_decimal.rb +12 -29
  9. data/lib/cmdx/coercions/boolean.rb +25 -45
  10. data/lib/cmdx/coercions/coerce.rb +32 -0
  11. data/lib/cmdx/coercions/complex.rb +12 -27
  12. data/lib/cmdx/coercions/date.rb +29 -33
  13. data/lib/cmdx/coercions/date_time.rb +29 -33
  14. data/lib/cmdx/coercions/float.rb +8 -29
  15. data/lib/cmdx/coercions/hash.rb +17 -43
  16. data/lib/cmdx/coercions/integer.rb +8 -32
  17. data/lib/cmdx/coercions/rational.rb +12 -33
  18. data/lib/cmdx/coercions/string.rb +6 -24
  19. data/lib/cmdx/coercions/symbol.rb +12 -26
  20. data/lib/cmdx/coercions/time.rb +31 -35
  21. data/lib/cmdx/coercions.rb +174 -0
  22. data/lib/cmdx/configuration.rb +45 -225
  23. data/lib/cmdx/context.rb +263 -242
  24. data/lib/cmdx/deprecation.rb +67 -0
  25. data/lib/cmdx/deprecators/error.rb +22 -0
  26. data/lib/cmdx/deprecators/log.rb +22 -0
  27. data/lib/cmdx/deprecators/warn.rb +21 -0
  28. data/lib/cmdx/deprecators.rb +101 -0
  29. data/lib/cmdx/errors.rb +145 -79
  30. data/lib/cmdx/executors/fiber.rb +42 -0
  31. data/lib/cmdx/executors/thread.rb +36 -0
  32. data/lib/cmdx/executors.rb +95 -0
  33. data/lib/cmdx/fault.rb +85 -78
  34. data/lib/cmdx/i18n_proxy.rb +104 -0
  35. data/lib/cmdx/input.rb +294 -0
  36. data/lib/cmdx/inputs.rb +218 -0
  37. data/lib/cmdx/log_formatters/json.rb +9 -20
  38. data/lib/cmdx/log_formatters/key_value.rb +10 -21
  39. data/lib/cmdx/log_formatters/line.rb +7 -19
  40. data/lib/cmdx/log_formatters/logstash.rb +8 -21
  41. data/lib/cmdx/log_formatters/raw.rb +8 -20
  42. data/lib/cmdx/logger_proxy.rb +30 -0
  43. data/lib/cmdx/mergers/deep_merge.rb +23 -0
  44. data/lib/cmdx/mergers/last_write_wins.rb +23 -0
  45. data/lib/cmdx/mergers/no_merge.rb +20 -0
  46. data/lib/cmdx/mergers.rb +95 -0
  47. data/lib/cmdx/middlewares.rb +128 -0
  48. data/lib/cmdx/output.rb +115 -0
  49. data/lib/cmdx/outputs.rb +66 -0
  50. data/lib/cmdx/pipeline.rb +144 -131
  51. data/lib/cmdx/railtie.rb +10 -36
  52. data/lib/cmdx/result.rb +252 -473
  53. data/lib/cmdx/retriers/bounded_random.rb +24 -0
  54. data/lib/cmdx/retriers/decorrelated_jitter.rb +28 -0
  55. data/lib/cmdx/retriers/exponential.rb +23 -0
  56. data/lib/cmdx/retriers/fibonacci.rb +39 -0
  57. data/lib/cmdx/retriers/full_random.rb +23 -0
  58. data/lib/cmdx/retriers/half_random.rb +24 -0
  59. data/lib/cmdx/retriers/linear.rb +23 -0
  60. data/lib/cmdx/retriers.rb +106 -0
  61. data/lib/cmdx/retry.rb +117 -138
  62. data/lib/cmdx/runtime.rb +251 -0
  63. data/lib/cmdx/settings.rb +68 -196
  64. data/lib/cmdx/signal.rb +165 -0
  65. data/lib/cmdx/task.rb +443 -336
  66. data/lib/cmdx/telemetry.rb +108 -0
  67. data/lib/cmdx/util.rb +73 -0
  68. data/lib/cmdx/validators/absence.rb +10 -39
  69. data/lib/cmdx/validators/exclusion.rb +33 -52
  70. data/lib/cmdx/validators/format.rb +19 -49
  71. data/lib/cmdx/validators/inclusion.rb +33 -54
  72. data/lib/cmdx/validators/length.rb +125 -127
  73. data/lib/cmdx/validators/numeric.rb +123 -123
  74. data/lib/cmdx/validators/presence.rb +10 -39
  75. data/lib/cmdx/validators/validate.rb +31 -0
  76. data/lib/cmdx/validators.rb +161 -0
  77. data/lib/cmdx/version.rb +2 -4
  78. data/lib/cmdx/workflow.rb +74 -82
  79. data/lib/cmdx.rb +111 -42
  80. data/lib/generators/cmdx/install_generator.rb +7 -17
  81. data/lib/generators/cmdx/task_generator.rb +12 -29
  82. data/lib/generators/cmdx/templates/install.rb +128 -52
  83. data/lib/generators/cmdx/templates/task.rb.tt +1 -1
  84. data/lib/generators/cmdx/templates/workflow.rb.tt +1 -2
  85. data/lib/generators/cmdx/workflow_generator.rb +12 -29
  86. data/lib/locales/en.yml +9 -6
  87. data/mkdocs.yml +25 -23
  88. metadata +39 -138
  89. data/lib/cmdx/attribute.rb +0 -440
  90. data/lib/cmdx/attribute_registry.rb +0 -185
  91. data/lib/cmdx/attribute_value.rb +0 -252
  92. data/lib/cmdx/callback_registry.rb +0 -169
  93. data/lib/cmdx/coercion_registry.rb +0 -138
  94. data/lib/cmdx/deprecator.rb +0 -77
  95. data/lib/cmdx/exception.rb +0 -46
  96. data/lib/cmdx/executor.rb +0 -374
  97. data/lib/cmdx/identifier.rb +0 -30
  98. data/lib/cmdx/locale.rb +0 -78
  99. data/lib/cmdx/middleware_registry.rb +0 -148
  100. data/lib/cmdx/middlewares/correlate.rb +0 -140
  101. data/lib/cmdx/middlewares/runtime.rb +0 -62
  102. data/lib/cmdx/middlewares/timeout.rb +0 -78
  103. data/lib/cmdx/parallelizer.rb +0 -100
  104. data/lib/cmdx/utils/call.rb +0 -53
  105. data/lib/cmdx/utils/condition.rb +0 -71
  106. data/lib/cmdx/utils/format.rb +0 -82
  107. data/lib/cmdx/utils/normalize.rb +0 -52
  108. data/lib/cmdx/utils/wrap.rb +0 -38
  109. data/lib/cmdx/validator_registry.rb +0 -143
  110. data/lib/generators/cmdx/locale_generator.rb +0 -39
  111. data/lib/locales/af.yml +0 -53
  112. data/lib/locales/ar.yml +0 -53
  113. data/lib/locales/az.yml +0 -53
  114. data/lib/locales/be.yml +0 -53
  115. data/lib/locales/bg.yml +0 -53
  116. data/lib/locales/bn.yml +0 -53
  117. data/lib/locales/bs.yml +0 -53
  118. data/lib/locales/ca.yml +0 -53
  119. data/lib/locales/cnr.yml +0 -53
  120. data/lib/locales/cs.yml +0 -53
  121. data/lib/locales/cy.yml +0 -53
  122. data/lib/locales/da.yml +0 -53
  123. data/lib/locales/de.yml +0 -53
  124. data/lib/locales/dz.yml +0 -53
  125. data/lib/locales/el.yml +0 -53
  126. data/lib/locales/eo.yml +0 -53
  127. data/lib/locales/es.yml +0 -53
  128. data/lib/locales/et.yml +0 -53
  129. data/lib/locales/eu.yml +0 -53
  130. data/lib/locales/fa.yml +0 -53
  131. data/lib/locales/fi.yml +0 -53
  132. data/lib/locales/fr.yml +0 -53
  133. data/lib/locales/fy.yml +0 -53
  134. data/lib/locales/gd.yml +0 -53
  135. data/lib/locales/gl.yml +0 -53
  136. data/lib/locales/he.yml +0 -53
  137. data/lib/locales/hi.yml +0 -53
  138. data/lib/locales/hr.yml +0 -53
  139. data/lib/locales/hu.yml +0 -53
  140. data/lib/locales/hy.yml +0 -53
  141. data/lib/locales/id.yml +0 -53
  142. data/lib/locales/is.yml +0 -53
  143. data/lib/locales/it.yml +0 -53
  144. data/lib/locales/ja.yml +0 -53
  145. data/lib/locales/ka.yml +0 -53
  146. data/lib/locales/kk.yml +0 -53
  147. data/lib/locales/km.yml +0 -53
  148. data/lib/locales/kn.yml +0 -53
  149. data/lib/locales/ko.yml +0 -53
  150. data/lib/locales/lb.yml +0 -53
  151. data/lib/locales/lo.yml +0 -53
  152. data/lib/locales/lt.yml +0 -53
  153. data/lib/locales/lv.yml +0 -53
  154. data/lib/locales/mg.yml +0 -53
  155. data/lib/locales/mk.yml +0 -53
  156. data/lib/locales/ml.yml +0 -53
  157. data/lib/locales/mn.yml +0 -53
  158. data/lib/locales/mr-IN.yml +0 -53
  159. data/lib/locales/ms.yml +0 -53
  160. data/lib/locales/nb.yml +0 -53
  161. data/lib/locales/ne.yml +0 -53
  162. data/lib/locales/nl.yml +0 -53
  163. data/lib/locales/nn.yml +0 -53
  164. data/lib/locales/oc.yml +0 -53
  165. data/lib/locales/or.yml +0 -53
  166. data/lib/locales/pa.yml +0 -53
  167. data/lib/locales/pl.yml +0 -53
  168. data/lib/locales/pt.yml +0 -53
  169. data/lib/locales/rm.yml +0 -53
  170. data/lib/locales/ro.yml +0 -53
  171. data/lib/locales/ru.yml +0 -53
  172. data/lib/locales/sc.yml +0 -53
  173. data/lib/locales/sk.yml +0 -53
  174. data/lib/locales/sl.yml +0 -53
  175. data/lib/locales/sq.yml +0 -53
  176. data/lib/locales/sr.yml +0 -53
  177. data/lib/locales/st.yml +0 -53
  178. data/lib/locales/sv.yml +0 -53
  179. data/lib/locales/sw.yml +0 -53
  180. data/lib/locales/ta.yml +0 -53
  181. data/lib/locales/te.yml +0 -53
  182. data/lib/locales/th.yml +0 -53
  183. data/lib/locales/tl.yml +0 -53
  184. data/lib/locales/tr.yml +0 -53
  185. data/lib/locales/tt.yml +0 -53
  186. data/lib/locales/ug.yml +0 -53
  187. data/lib/locales/uk.yml +0 -53
  188. data/lib/locales/ur.yml +0 -53
  189. data/lib/locales/uz.yml +0 -53
  190. data/lib/locales/vi.yml +0 -53
  191. data/lib/locales/wo.yml +0 -53
  192. data/lib/locales/zh-CN.yml +0 -53
  193. data/lib/locales/zh-HK.yml +0 -53
  194. data/lib/locales/zh-TW.yml +0 -53
  195. data/lib/locales/zh-YUE.yml +0 -53
@@ -1,32 +1,22 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cmdx
4
- # Generates CMDx initializer file for Rails applications
4
+ # Rails generator that scaffolds the CMDx initializer at
5
+ # `config/initializers/cmdx.rb`. The initializer template seeds global
6
+ # {CMDx.configuration} defaults (middlewares, callbacks, coercions,
7
+ # validators, telemetry) that all tasks inherit from.
5
8
  #
6
- # This generator creates a configuration initializer that sets up global
7
- # CMDx settings for the Rails application. It copies a pre-configured
8
- # initializer template to the standard Rails initializers directory.
9
+ # Invoked via `rails generate cmdx:install`.
9
10
  class InstallGenerator < Rails::Generators::Base
10
11
 
11
12
  source_root File.expand_path("templates", __dir__)
12
13
 
13
14
  desc "Creates CMDx initializer with global configuration settings"
14
15
 
15
- # Copies the CMDx initializer template to the Rails application
16
- #
17
- # Creates a new initializer file at `config/initializers/cmdx.rb` containing
18
- # the default CMDx configuration settings. This allows applications to
19
- # customize global CMDx behavior through the standard Rails configuration
20
- # pattern.
16
+ # Copies the initializer template into the host application's
17
+ # `config/initializers` directory.
21
18
  #
22
19
  # @return [void]
23
- #
24
- # @example Basic usage
25
- # rails generate cmdx:install
26
- #
27
- # @example Custom initializer location
28
- # generator.copy_initializer_file
29
- # # => Creates config/initializers/cmdx.rb
30
20
  def copy_initializer_file
31
21
  copy_file("install.rb", "config/initializers/cmdx.rb")
32
22
  end
@@ -1,32 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cmdx
4
- # Generates CMDx task files for Rails applications
4
+ # Rails generator that scaffolds a new {CMDx::Task} subclass under
5
+ # `app/tasks`, honoring nested module paths supplied through the NAME
6
+ # argument (e.g. `Billing::ChargeCard` writes to
7
+ # `app/tasks/billing/charge_card.rb`).
5
8
  #
6
- # This generator creates task classes that inherit from either ApplicationTask
7
- # (if defined) or CMDx::Task. It generates the task file in the standard
8
- # Rails tasks directory structure.
9
+ # Invoked via `rails generate cmdx:task NAME`.
10
+ #
11
+ # @see CMDx::Task
9
12
  class TaskGenerator < Rails::Generators::NamedBase
10
13
 
11
14
  source_root File.expand_path("templates", __dir__)
12
15
 
13
16
  desc "Creates a task with the given NAME"
14
17
 
15
- # Copies the task template to the Rails application
16
- #
17
- # Creates a new task file at `app/tasks/[class_path]/[file_name].rb` using
18
- # the task template. The file is placed in the standard Rails tasks directory
19
- # structure, maintaining proper namespacing if the task is nested.
18
+ # Renders `task.rb.tt` into `app/tasks/<class_path>/<file_name>.rb`.
20
19
  #
21
20
  # @return [void]
22
- #
23
- # @example Basic usage
24
- # rails generate cmdx:task UserRegistration
25
- # # => Creates app/tasks/user_registration.rb
26
- #
27
- # @example Nested task
28
- # rails generate cmdx:task Admin::UserManagement
29
- # # => Creates app/tasks/admin/user_management.rb
30
21
  def copy_files
31
22
  path = File.join("app/tasks", class_path, "#{file_name}.rb")
32
23
  template("task.rb.tt", path)
@@ -34,19 +25,11 @@ module Cmdx
34
25
 
35
26
  private
36
27
 
37
- # Determines the appropriate parent class name for the generated task
38
- #
39
- # Attempts to use ApplicationTask if it exists in the application, otherwise
40
- # falls back to CMDx::Task. This allows applications to define their own
41
- # base task class while maintaining compatibility.
42
- #
43
- # @return [Class] The parent class for the generated task
44
- #
45
- # @example
46
- # parent_class_name # => ApplicationTask
28
+ # Selects the parent class for the generated task: prefers the host
29
+ # application's `ApplicationTask` when defined, falling back to
30
+ # {CMDx::Task} otherwise. Consumed by the ERB template via `<%= %>`.
47
31
  #
48
- # @example Fallback behavior
49
- # parent_class_name # => CMDx::Task
32
+ # @return [Class] either `ApplicationTask` or {CMDx::Task}
50
33
  def parent_class_name
51
34
  ApplicationTask
52
35
  rescue NameError
@@ -1,61 +1,137 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  CMDx.configure do |config|
4
- # Task breakpoint configuration - controls when execute! raises faults
5
- # See https://github.com/drexed/cmdx/blob/main/docs/outcomes/statuses.md for more details
6
- #
7
- # Available statuses: "success", "skipped", "failed"
8
- # If set to an empty array, task will never halt
9
- config.task_breakpoints = %w[failed]
10
-
11
- # Workflow breakpoint configuration - controls when workflows stop execution
12
- # When a task returns these statuses, subsequent workflow tasks won't execute
13
- # See https://github.com/drexed/cmdx/blob/main/docs/workflow.md for more details
14
- #
15
- # Available statuses: "success", "skipped", "failed"
16
- # If set to an empty array, workflow will never halt
17
- config.workflow_breakpoints = %w[failed]
18
-
19
- # Logger configuration - choose from multiple formatters
20
- # See https://github.com/drexed/cmdx/blob/main/docs/logging.md for more details
21
- #
22
- # Available formatters:
23
- # - CMDx::LogFormatters::Json
24
- # - CMDx::LogFormatters::KeyValue
25
- # - CMDx::LogFormatters::Line
26
- # - CMDx::LogFormatters::Logstash
27
- # - CMDx::LogFormatters::Raw
28
- config.logger = Logger.new(
29
- $stdout,
30
- progname: "cmdx",
31
- formatter: CMDx::LogFormatters::Line.new,
32
- level: Logger::INFO
33
- )
34
-
35
- # Rollback configuration - controls which statuses trigger task rollback
36
- # See https://github.com/drexed/cmdx/blob/main/docs/outcomes/statuses.md for more details
37
- #
38
- # Available statuses: "success", "skipped", "failed"
39
- # If set to an empty array, task will never rollback
40
- config.rollback_on = %w[failed]
41
-
42
- # Default locale configuration - used for built-in translation lookups
43
- # Must match the basename of a YAML file in lib/locales/ (e.g. "en", "es", "ja")
4
+ # ===========================================================================
5
+ # Locale
6
+ # ===========================================================================
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`.
9
+ #
44
10
  # config.default_locale = "en"
45
11
 
46
- # Backtrace configuration - controls whether to log backtraces on faults and exceptions
47
- # https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#backtraces
48
- # config.backtrace = false
49
- # config.backtrace_cleaner = nil
12
+ # ===========================================================================
13
+ # Strict context
14
+ # ===========================================================================
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)`.
18
+ #
19
+ # config.strict_context = true
20
+
21
+ # ===========================================================================
22
+ # Correlation ID (xid)
23
+ # ===========================================================================
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.
28
+ #
29
+ # config.correlation_id = -> { Current.request_id }
30
+
31
+ # ===========================================================================
32
+ # Logging
33
+ # ===========================================================================
34
+ # In Rails, the Railtie already wires `config.logger = Rails.logger` and a
35
+ # backtrace cleaner — override here only if you need something different.
36
+ #
37
+ # Formatters: Line (default), Json, KeyValue, Logstash, Raw
38
+ #
39
+ # config.backtrace_cleaner = ->(bt) { Rails.backtrace_cleaner.clean(bt) }
40
+ # config.log_exclusions = [:context]
41
+ # config.log_formatter = CMDx::LogFormatters::Line.new
42
+ # config.log_level = Logger::INFO
43
+ # config.logger = Logger.new($stdout, progname: "cmdx")
44
+
45
+ # ===========================================================================
46
+ # Middlewares
47
+ # ===========================================================================
48
+ # Wrap every task's execution. Must respond to `call(task) { ... }`.
49
+ #
50
+ # Example — run each task under the current user's locale:
51
+ #
52
+ # config.middlewares.register(proc do |task, &next_link|
53
+ # locale = Current.user.locale || I18n.default_locale
54
+ # I18n.with_locale(locale) do
55
+ # task.metadata[:locale] = locale
56
+ # next_link.call
57
+ # end
58
+ # end)
59
+
60
+ # ===========================================================================
61
+ # Callbacks
62
+ # ===========================================================================
63
+ # Events:
64
+ # :before_validation, :before_execution,
65
+ # :on_complete, :on_interrupted,
66
+ # :on_success, :on_skipped, :on_failed,
67
+ # :on_ok, :on_ko
68
+ #
69
+ # config.callbacks.register(:on_failed, proc do |task|
70
+ # Rails.logger.error("[cmdx] #{task.class.name} failed: #{task.metadata[:reason]}")
71
+ # end)
72
+
73
+ # ===========================================================================
74
+ # Telemetry
75
+ # ===========================================================================
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 }
82
+ #
83
+ # Every event also carries: event.cid, event.xid, event.tid, event.task,
84
+ # event.type, event.root, event.timestamp.
85
+ #
86
+ # config.telemetry.subscribe(:task_executed, proc do |event|
87
+ # StatsD.timing("cmdx.task", event.payload[:result].duration)
88
+ # end)
89
+
90
+ # ===========================================================================
91
+ # Coercions
92
+ # ===========================================================================
93
+ # Register custom type coercions. Callable receives `(value, **options)`.
94
+ #
95
+ # config.coercions.register(:currency, proc do |value, **|
96
+ # BigDecimal(value.to_s.gsub(/[^\d.-]/, ""))
97
+ # end)
50
98
 
51
- # Exception handler configuration - called when non-fault exceptions are raised
52
- # https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#exception-handler
53
- # config.exception_handler = nil
99
+ # ===========================================================================
100
+ # Validators
101
+ # ===========================================================================
102
+ # Register custom validators. Callable receives `(value, options)` and
103
+ # returns a `CMDx::Validators::Failure.new(message)` on failure.
104
+ #
105
+ # config.validators.register(:uuid, proc do |value, _options|
106
+ # unless value.to_s.match?(/\A[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}\z/i)
107
+ # CMDx::Validators::Failure.new("is not a valid UUID")
108
+ # end
109
+ # end)
110
+
111
+ # ===========================================================================
112
+ # Executors
113
+ # ===========================================================================
114
+ # Registered executors drive `:parallel` workflow groups. Built-ins:
115
+ # `:threads` (default), `:fibers`. A callable receives
116
+ # `call(jobs:, concurrency:, on_job:)` and must invoke `on_job.call(job)`
117
+ # for each job, blocking until every job is done.
118
+ #
119
+ # config.executors.register(:ractors, proc do |jobs:, concurrency:, on_job:|
120
+ # jobs.each_slice(concurrency) do |slice|
121
+ # slice.map { |job| Ractor.new(job) { |j| on_job.call(j) } }.each(&:take)
122
+ # end
123
+ # end)
54
124
 
55
- # Additional global configurations - automatically applied to all tasks
125
+ # ===========================================================================
126
+ # Mergers
127
+ # ===========================================================================
128
+ # Merge strategies fold successful parallel task contexts back into the
129
+ # workflow context. Built-ins: `:last_write_wins` (default), `:deep_merge`,
130
+ # `:no_merge`. A callable receives `call(workflow_context, result)`.
56
131
  #
57
- # Middlewares - https://github.com/drexed/cmdx/blob/main/docs/middlewares.md
58
- # Callbacks - https://github.com/drexed/cmdx/blob/main/docs/callbacks.md
59
- # Coercions - https://github.com/drexed/cmdx/blob/main/docs/coercions.md
60
- # Validations - https://github.com/drexed/cmdx/blob/main/docs/validations.md
132
+ # config.mergers.register(:whitelist, proc do |workflow_context, result|
133
+ # result.context.to_h.slice(:order_id, :total).each do |key, value|
134
+ # workflow_context[key] = value
135
+ # end
136
+ # end)
61
137
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  def work
5
5
  # Your logic here...
6
- # Docs: https://github.com/drexed/cmdx
6
+ # Docs: https://drexed.github.io/cmdx/getting_started
7
7
  end
8
8
 
9
9
  end
@@ -2,7 +2,6 @@
2
2
  class <%= class_name %> < <%= parent_class_name %>
3
3
  include CMDx::Workflow
4
4
 
5
- tasks Task1, Task2
6
- # Docs: https://github.com/drexed/cmdx/docs/workflows.md
5
+ # Docs: https://drexed.github.io/cmdx/workflows
7
6
  end
8
7
  <% end -%>
@@ -1,32 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Cmdx
4
- # Generates CMDx workflow files for Rails applications
4
+ # Rails generator that scaffolds a new {CMDx::Workflow} subclass under
5
+ # `app/tasks`, honoring nested module paths supplied through the NAME
6
+ # argument (e.g. `Billing::Checkout` writes to
7
+ # `app/tasks/billing/checkout.rb`).
5
8
  #
6
- # This generator creates task classes that inherit from either ApplicationTask
7
- # (if defined) or CMDx::Task. It generates the task file in the standard
8
- # Rails tasks directory structure.
9
+ # Invoked via `rails generate cmdx:workflow NAME`.
10
+ #
11
+ # @see CMDx::Workflow
9
12
  class WorkflowGenerator < Rails::Generators::NamedBase
10
13
 
11
14
  source_root File.expand_path("templates", __dir__)
12
15
 
13
16
  desc "Creates a workflow with the given NAME"
14
17
 
15
- # Copies the task template to the Rails application
16
- #
17
- # Creates a new task file at `app/tasks/[class_path]/[file_name].rb` using
18
- # the task template. The file is placed in the standard Rails tasks directory
19
- # structure, maintaining proper namespacing if the task is nested.
18
+ # Renders `workflow.rb.tt` into `app/tasks/<class_path>/<file_name>.rb`.
20
19
  #
21
20
  # @return [void]
22
- #
23
- # @example Basic usage
24
- # rails generate cmdx:workflow SendNotifications
25
- # # => Creates app/tasks/send_notifications.rb
26
- #
27
- # @example Nested task
28
- # rails generate cmdx:workflow Admin::SendNotifications
29
- # # => Creates app/tasks/admin/send_notifications.rb
30
21
  def copy_files
31
22
  path = File.join("app/tasks", class_path, "#{file_name}.rb")
32
23
  template("workflow.rb.tt", path)
@@ -34,19 +25,11 @@ module Cmdx
34
25
 
35
26
  private
36
27
 
37
- # Determines the appropriate parent class name for the generated task
38
- #
39
- # Attempts to use ApplicationTask if it exists in the application, otherwise
40
- # falls back to CMDx::Task. This allows applications to define their own
41
- # base task class while maintaining compatibility.
42
- #
43
- # @return [Class] The parent class for the generated task
44
- #
45
- # @example
46
- # parent_class_name # => ApplicationTask
28
+ # Selects the parent class for the generated workflow: prefers the host
29
+ # application's `ApplicationTask` when defined, falling back to
30
+ # {CMDx::Task} otherwise. Consumed by the ERB template via `<%= %>`.
47
31
  #
48
- # @example Fallback behavior
49
- # parent_class_name # => CMDx::Task
32
+ # @return [Class] either `ApplicationTask` or {CMDx::Task}
50
33
  def parent_class_name
51
34
  ApplicationTask
52
35
  rescue NameError
data/lib/locales/en.yml CHANGED
@@ -1,17 +1,14 @@
1
1
  en:
2
2
  cmdx:
3
3
  attributes:
4
- required: "must be accessible via the %{method} source method"
5
- undefined: "delegates to undefined method %{method}"
4
+ required: "is required"
6
5
  coercions:
7
6
  into_a: "could not coerce into a %{type}"
8
7
  into_an: "could not coerce into an %{type}"
9
8
  into_any: "could not coerce into one of: %{types}"
10
- unknown: "unknown %{type} coercion type"
11
- faults:
12
- invalid: "Invalid"
9
+ reasons:
13
10
  unspecified: "Unspecified"
14
- returns:
11
+ outputs:
15
12
  missing: "must be set in the context"
16
13
  types:
17
14
  array: "array"
@@ -41,6 +38,9 @@ en:
41
38
  is_not: "length must not be %{is_not}"
42
39
  min: "length must be at least %{min}"
43
40
  max: "length must be at most %{max}"
41
+ gt: "length must be greater than %{gt}"
42
+ lt: "length must be less than %{lt}"
43
+ nil_value: "must have a length"
44
44
  not_within: "length must not be within %{min} and %{max}"
45
45
  within: "length must be within %{min} and %{max}"
46
46
  numeric:
@@ -48,6 +48,9 @@ en:
48
48
  is_not: "must not be %{is_not}"
49
49
  min: "must be at least %{min}"
50
50
  max: "must be at most %{max}"
51
+ gt: "must be greater than %{gt}"
52
+ lt: "must be less than %{lt}"
53
+ nil_value: "must be numeric"
51
54
  not_within: "must not be within %{min} and %{max}"
52
55
  within: "must be within %{min} and %{max}"
53
56
  presence: "cannot be empty"
data/mkdocs.yml CHANGED
@@ -17,8 +17,8 @@ theme:
17
17
  icon:
18
18
  repo: fontawesome/brands/github
19
19
  font:
20
- text: Inter
21
- code: IBM Plex Mono
20
+ text: DM Sans
21
+ code: DM Mono
22
22
  palette:
23
23
  # Palette toggle for automatic mode
24
24
  - media: "(prefers-color-scheme)"
@@ -120,20 +120,21 @@ plugins:
120
120
  - basics/context.md: Context object for data sharing, input/output management, and attribute access
121
121
  - basics/chain.md: Execution chain tracking for related tasks within threads
122
122
  Interruptions:
123
- - interruptions/halt.md: Intentional task interruption using skip! and fail! methods
124
- - interruptions/faults.md: Fault exceptions (SkipFault, FailFault) raised by execute! with rich context
125
- - interruptions/exceptions.md: Exception handling differences between execute and execute! methods
123
+ - interruptions/signals.md: Intentional task interruption using skip! and fail! methods
124
+ - interruptions/faults.md: CMDx::Fault raised by execute! with task class, signal, and cleaned backtrace
125
+ - interruptions/exceptions.md: Complete exception hierarchy (Error, DeprecationError, ImplementationError, MiddlewareError, Fault) and execute vs execute! semantics
126
126
  Outcomes:
127
127
  - outcomes/result.md: Result objects exposing execution state, status, context, and metadata
128
128
  - outcomes/states.md: Execution lifecycle states (initialized, executing, complete, interrupted)
129
129
  - outcomes/statuses.md: Business outcome statuses (success, skipped, failed) and transitions
130
+ - outcomes/errors.md: Structured per-attribute error container accumulated during input/output verification and exposed on result.errors
130
131
  Attributes:
131
- - attributes/definitions.md: Attribute declarations (required/optional), validation, and type coercion
132
- - attributes/naming.md: Customizing accessor method names with prefixes and suffixes
133
- - attributes/coercions.md: Automatic type conversion for inputs (string to integer, date parsing, etc.)
134
- - attributes/validations.md: Input validation rules (presence, length, format, numeric, inclusion, exclusion)
135
- - attributes/defaults.md: Default values for optional attributes (static, dynamic, callable)
136
- - attributes/transformations.md: Value transformation after coercion but before validation
132
+ - inputs/definitions.md: Attribute declarations (required/optional), validation, and type coercion
133
+ - inputs/naming.md: Customizing accessor method names with prefixes and suffixes
134
+ - inputs/coercions.md: Automatic type conversion for inputs (string to integer, date parsing, etc.)
135
+ - inputs/validations.md: Input validation rules (presence, length, format, numeric, inclusion, exclusion)
136
+ - inputs/defaults.md: Default values for optional inputs (static, dynamic, callable)
137
+ - inputs/transformations.md: Value transformation after coercion but before validation
137
138
  Features:
138
139
  - callbacks.md: Execution lifecycle callbacks (before_execution, on_success, on_failure, etc.)
139
140
  - middlewares.md: Cross-cutting concerns wrapping task execution (authentication, caching, timeouts)
@@ -141,13 +142,13 @@ plugins:
141
142
  - internationalization.md: Multi-language support for error messages and validations (90+ locales)
142
143
  - retries.md: Automatic retry functionality for transient failures with jitter and selective retries
143
144
  - deprecation.md: Managing deprecated tasks with logging, warnings, or execution prevention
144
- - returns.md: Declaring expected context outputs that must be set after task execution
145
+ - outputs.md: Declaring expected context outputs that must be set after task execution
145
146
  - workflows.md: Composing multiple tasks into sequential pipelines with conditional execution
146
147
  More:
147
148
  - testing.md: Best practices for testing CMDx tasks and workflows with RSpec
148
- - exceptions.md: Complete exception hierarchy and error type reference
149
149
  - tips_and_tricks.md: Best practices, patterns, and techniques for maintainable CMDx applications
150
150
  - comparison.md: Comparison with other command/service object frameworks
151
+ - v2-migration.md: Migration guide from CMDx 1.x to 2.0
151
152
  nav:
152
153
  - Home: index.md
153
154
  - Documentation:
@@ -159,20 +160,21 @@ nav:
159
160
  - Context: basics/context.md
160
161
  - Chain: basics/chain.md
161
162
  - Interruptions:
162
- - Halt: interruptions/halt.md
163
+ - Signals: interruptions/signals.md
163
164
  - Faults: interruptions/faults.md
164
165
  - Exceptions: interruptions/exceptions.md
165
166
  - Outcomes:
166
167
  - Result: outcomes/result.md
167
168
  - States: outcomes/states.md
168
169
  - Statuses: outcomes/statuses.md
169
- - Attributes:
170
- - Definitions: attributes/definitions.md
171
- - Naming: attributes/naming.md
172
- - Coercions: attributes/coercions.md
173
- - Validations: attributes/validations.md
174
- - Defaults: attributes/defaults.md
175
- - Transformations: attributes/transformations.md
170
+ - Errors: outcomes/errors.md
171
+ - Inputs:
172
+ - Definitions: inputs/definitions.md
173
+ - Naming: inputs/naming.md
174
+ - Coercions: inputs/coercions.md
175
+ - Validations: inputs/validations.md
176
+ - Defaults: inputs/defaults.md
177
+ - Transformations: inputs/transformations.md
176
178
  - Features:
177
179
  - Callbacks: callbacks.md
178
180
  - Middlewares: middlewares.md
@@ -180,13 +182,13 @@ nav:
180
182
  - Internationalization: internationalization.md
181
183
  - Retries: retries.md
182
184
  - Deprecation: deprecation.md
183
- - Returns: returns.md
185
+ - Outputs: outputs.md
184
186
  - Workflows: workflows.md
185
187
  - More:
186
188
  - Testing: testing.md
187
- - Exceptions: exceptions.md
188
189
  - Tips and Tricks: tips_and_tricks.md
189
190
  - Comparison: comparison.md
191
+ - v1 → v2 Migration: v2-migration.md
190
192
  - References:
191
193
  - API Documentation: https://drexed.github.io/cmdx/api/index.html
192
194
  - llms.txt: https://drexed.github.io/cmdx/llms.txt