cmdx 1.6.1 → 1.7.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 (105) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/rules/cursor-instructions.mdc +2 -2
  3. data/CHANGELOG.md +16 -1
  4. data/LLM.md +168 -2
  5. data/docs/attributes/coercions.md +2 -0
  6. data/docs/attributes/validations.md +2 -0
  7. data/docs/callbacks.md +2 -0
  8. data/docs/getting_started.md +8 -0
  9. data/docs/internationalization.md +106 -2
  10. data/docs/middlewares.md +2 -0
  11. data/docs/workflows.md +48 -0
  12. data/lib/cmdx/pipeline.rb +43 -11
  13. data/lib/cmdx/railtie.rb +2 -2
  14. data/lib/cmdx/version.rb +1 -1
  15. data/lib/cmdx.rb +2 -0
  16. data/lib/generators/cmdx/locale_generator.rb +39 -0
  17. data/lib/generators/cmdx/templates/install.rb +7 -0
  18. data/lib/generators/cmdx/templates/workflow.rb.tt +8 -0
  19. data/lib/generators/cmdx/workflow_generator.rb +57 -0
  20. data/lib/locales/af.yml +49 -0
  21. data/lib/locales/ar.yml +49 -0
  22. data/lib/locales/az.yml +49 -0
  23. data/lib/locales/be.yml +49 -0
  24. data/lib/locales/bg.yml +49 -0
  25. data/lib/locales/bn.yml +49 -0
  26. data/lib/locales/bs.yml +49 -0
  27. data/lib/locales/ca.yml +49 -0
  28. data/lib/locales/cnr.yml +49 -0
  29. data/lib/locales/cs.yml +49 -0
  30. data/lib/locales/cy.yml +49 -0
  31. data/lib/locales/da.yml +49 -0
  32. data/lib/locales/de.yml +49 -0
  33. data/lib/locales/dz.yml +49 -0
  34. data/lib/locales/el.yml +49 -0
  35. data/lib/locales/eo.yml +49 -0
  36. data/lib/locales/es.yml +49 -0
  37. data/lib/locales/et.yml +49 -0
  38. data/lib/locales/eu.yml +49 -0
  39. data/lib/locales/fa.yml +49 -0
  40. data/lib/locales/fi.yml +49 -0
  41. data/lib/locales/fr.yml +49 -0
  42. data/lib/locales/fy.yml +49 -0
  43. data/lib/locales/gd.yml +49 -0
  44. data/lib/locales/gl.yml +49 -0
  45. data/lib/locales/he.yml +49 -0
  46. data/lib/locales/hi.yml +49 -0
  47. data/lib/locales/hr.yml +49 -0
  48. data/lib/locales/hu.yml +49 -0
  49. data/lib/locales/hy.yml +49 -0
  50. data/lib/locales/id.yml +49 -0
  51. data/lib/locales/is.yml +49 -0
  52. data/lib/locales/it.yml +49 -0
  53. data/lib/locales/ja.yml +49 -0
  54. data/lib/locales/ka.yml +49 -0
  55. data/lib/locales/kk.yml +49 -0
  56. data/lib/locales/km.yml +49 -0
  57. data/lib/locales/kn.yml +49 -0
  58. data/lib/locales/ko.yml +49 -0
  59. data/lib/locales/lb.yml +49 -0
  60. data/lib/locales/lo.yml +49 -0
  61. data/lib/locales/lt.yml +49 -0
  62. data/lib/locales/lv.yml +49 -0
  63. data/lib/locales/mg.yml +49 -0
  64. data/lib/locales/mk.yml +49 -0
  65. data/lib/locales/ml.yml +49 -0
  66. data/lib/locales/mn.yml +49 -0
  67. data/lib/locales/mr-IN.yml +49 -0
  68. data/lib/locales/ms.yml +49 -0
  69. data/lib/locales/nb.yml +49 -0
  70. data/lib/locales/ne.yml +49 -0
  71. data/lib/locales/nl.yml +49 -0
  72. data/lib/locales/nn.yml +49 -0
  73. data/lib/locales/oc.yml +49 -0
  74. data/lib/locales/or.yml +49 -0
  75. data/lib/locales/pa.yml +49 -0
  76. data/lib/locales/pl.yml +49 -0
  77. data/lib/locales/pt.yml +49 -0
  78. data/lib/locales/rm.yml +49 -0
  79. data/lib/locales/ro.yml +49 -0
  80. data/lib/locales/ru.yml +49 -0
  81. data/lib/locales/sc.yml +49 -0
  82. data/lib/locales/sk.yml +49 -0
  83. data/lib/locales/sl.yml +49 -0
  84. data/lib/locales/sq.yml +49 -0
  85. data/lib/locales/sr.yml +49 -0
  86. data/lib/locales/st.yml +49 -0
  87. data/lib/locales/sv.yml +49 -0
  88. data/lib/locales/sw.yml +49 -0
  89. data/lib/locales/ta.yml +49 -0
  90. data/lib/locales/te.yml +49 -0
  91. data/lib/locales/th.yml +49 -0
  92. data/lib/locales/tl.yml +49 -0
  93. data/lib/locales/tr.yml +49 -0
  94. data/lib/locales/tt.yml +49 -0
  95. data/lib/locales/ug.yml +49 -0
  96. data/lib/locales/uk.yml +49 -0
  97. data/lib/locales/ur.yml +49 -0
  98. data/lib/locales/uz.yml +49 -0
  99. data/lib/locales/vi.yml +49 -0
  100. data/lib/locales/wo.yml +49 -0
  101. data/lib/locales/zh-CN.yml +49 -0
  102. data/lib/locales/zh-HK.yml +49 -0
  103. data/lib/locales/zh-TW.yml +49 -0
  104. data/lib/locales/zh-YUE.yml +49 -0
  105. metadata +117 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c054b422d416bb8f3605c0c75961c2dc65fc3ba7aba3125fcd66f1107276dc8a
4
- data.tar.gz: 05b168249fcf03d62cee5a68a98b30fb038f5da90bea4044809a6e52ee1f2ca2
3
+ metadata.gz: 8483d78b67a6dfffa6721b39e623ac08d57d443b499287891bfb9c6e06422c89
4
+ data.tar.gz: 02cb722299d6a97fb4e2d07a84880c7374a8c17b691f42bee995bd4f3ea698ab
5
5
  SHA512:
6
- metadata.gz: fe3426a7c2d2a8839583695c9682fb3499bc6e2707349a5e872b293a7100442a7f328212783e083c68f3995379fd8db0cf44b56156506b71e14abf59f3c0d3ec
7
- data.tar.gz: d29594887e332518500b3af872f987540fc41ff8293a13252bf665b0a2669da38944875b91caab1916d004de6e7b616ef17016de55b667ad80fcff301a153dc7
6
+ metadata.gz: b6600b6d617c11a3ec3b66367a7fa309e191bd2d1f20a3fb1a538565a0c2b45e05f8093f2c3e07edbb155e308e6c90c486f069db171aac68e8658bbe85bd4b34
7
+ data.tar.gz: 6ad4a1348066d3aa4d0ed2733fc88f94af293835cc970be5986f3c002cf3b3615f474bff774a2b48f7e043920ca01b5f278cd26850b5b4827a70d2a4b0e6ab50
@@ -10,8 +10,8 @@ Follow the official Ruby gem guides for best practices.
10
10
  Reference the guides outlined in https://guides.rubygems.org
11
11
 
12
12
  ## Project Context
13
- CMDx provides a framework for designing and executing complex
14
- business logic within service/command objects.
13
+ CMDx provides a framework for designing and executing complex business logic within service/command objects.
14
+ Reference the CMDx documentation in https://github.com/drexed/cmdx/blob/main/LLM.md
15
15
 
16
16
  ## Technology Stack
17
17
  - Ruby 3.4+
data/CHANGELOG.md CHANGED
@@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [TODO]
8
8
 
9
+ ## [1.7.0] - 2025-08-25
10
+
11
+ ### Added
12
+ - Workflow generator
13
+
14
+ ### Changes
15
+ - Port over `cmdx-parallel` changes
16
+ - Port over `cmdx-i18n` changes
17
+
18
+ ## [1.6.2] - 2025-08-24
19
+
20
+ ### Changes
21
+ - Prefix railtie I18n with `::` to play nice with `CMDx::I18n`
22
+ - Use `cmdx-rspec` for matchers support
23
+
9
24
  ## [1.6.1] - 2025-08-23
10
25
 
11
26
  ### Changes
@@ -27,7 +42,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
27
42
  ## [1.5.1] - 2025-08-21
28
43
 
29
44
  ### Changes
30
- - Prefix I18n with `::` to play nice with `CMDx::I18n`
45
+ - Prefix locale I18n with `::` to play nice with `CMDx::I18n`
31
46
  - Safe navigate length and numeric validators
32
47
  - Update railtie file path points to correct directory
33
48
 
data/LLM.md CHANGED
@@ -72,6 +72,8 @@ end
72
72
 
73
73
  ### Middlewares
74
74
 
75
+ See the [Middelwares](#https://github.com/drexed/cmdx/blob/main/docs/middlewares.md#declarations) docs for task level configurations.
76
+
75
77
  ```ruby
76
78
  CMDx.configure do |config|
77
79
  # Via callable (must respond to `call(task, options)`)
@@ -99,6 +101,8 @@ end
99
101
 
100
102
  ### Callbacks
101
103
 
104
+ See the [Callbacks](#https://github.com/drexed/cmdx/blob/main/docs/callbacks.md#declarations) docs for task level configurations.
105
+
102
106
  ```ruby
103
107
  CMDx.configure do |config|
104
108
  # Via method
@@ -123,6 +127,8 @@ end
123
127
 
124
128
  ### Coercions
125
129
 
130
+ See the [Attributes - Coercions](#https://github.com/drexed/cmdx/blob/main/docs/attributes/coercions.md#declarations) docs for task level configurations.
131
+
126
132
  ```ruby
127
133
  CMDx.configure do |config|
128
134
  # Via callable (must respond to `call(value, options)`)
@@ -147,6 +153,8 @@ end
147
153
 
148
154
  ### Validators
149
155
 
156
+ See the [Attributes - Validations](#https://github.com/drexed/cmdx/blob/main/docs/attributes/validations.md#declarations) docs for task level configurations.
157
+
150
158
  ```ruby
151
159
  CMDx.configure do |config|
152
160
  # Via callable (must respond to `call(value, options)`)
@@ -907,6 +915,7 @@ fail!("Unsupported")
907
915
  # Bad: Default, cannot determine reason
908
916
  skip! #=> "no reason given"
909
917
  fail! #=> "no reason given"
918
+ ```
910
919
 
911
920
  ---
912
921
 
@@ -1727,6 +1736,7 @@ result.metadata #=> {
1727
1736
  # port: ["is required"]
1728
1737
  # }
1729
1738
  # }
1739
+ ```
1730
1740
 
1731
1741
  ---
1732
1742
 
@@ -1810,6 +1820,8 @@ url: https://github.com/drexed/cmdx/blob/main/docs/attributes/coercions.md
1810
1820
 
1811
1821
  Attribute coercions automatically convert task arguments to expected types, ensuring type safety while providing flexible input handling. Coercions transform raw input values into the specified types, supporting simple conversions like string-to-integer and complex operations like JSON parsing.
1812
1822
 
1823
+ Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#coercions) docs for global configuration.
1824
+
1813
1825
  ## Usage
1814
1826
 
1815
1827
  Define attribute types to enable automatic coercion:
@@ -1952,6 +1964,7 @@ result.metadata #=> {
1952
1964
  # score: ["could not coerce into one of: float, big_decimal"]
1953
1965
  # }
1954
1966
  # }
1967
+ ```
1955
1968
 
1956
1969
  ---
1957
1970
 
@@ -1962,6 +1975,8 @@ url: https://github.com/drexed/cmdx/blob/main/docs/attributes/validations.md
1962
1975
 
1963
1976
  Attribute validations ensure task arguments meet specified requirements before execution begins. Validations run after coercions and provide declarative rules for data integrity, supporting both built-in validators and custom validation logic.
1964
1977
 
1978
+ Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#validations) docs for global configuration.
1979
+
1965
1980
  ## Usage
1966
1981
 
1967
1982
  Define validation rules on attributes to enforce data requirements:
@@ -2338,6 +2353,8 @@ url: https://github.com/drexed/cmdx/blob/main/docs/callbacks.md
2338
2353
 
2339
2354
  Callbacks provide precise control over task execution lifecycle, running custom logic at specific transition points. Callback callables have access to the same context and result information as the `execute` method, enabling rich integration patterns.
2340
2355
 
2356
+ Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#callbacks) docs for global configuration.
2357
+
2341
2358
  > [!IMPORTANT]
2342
2359
  > Callbacks execute in the order they are declared within each hook type. Multiple callbacks of the same type execute in declaration order (FIFO: first in, first out).
2343
2360
 
@@ -2497,6 +2514,8 @@ url: https://github.com/drexed/cmdx/blob/main/docs/middlewares.md
2497
2514
 
2498
2515
  Middleware provides Rack-style wrappers around task execution for cross-cutting concerns like authentication, logging, caching, and error handling.
2499
2516
 
2517
+ Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#middlewares) docs for global configuration.
2518
+
2500
2519
  ## Order
2501
2520
 
2502
2521
  Middleware executes in a nested fashion, creating an onion-like execution pattern:
@@ -2811,8 +2830,109 @@ I18n.with_locale(:fr) do
2811
2830
  end
2812
2831
  ```
2813
2832
 
2814
- > [!TIP]
2815
- > CMDx supports 85+ locales via the [cmdx-i18n](https://github.com/drexed/cmdx-i18n) gem.
2833
+ ## Configuration
2834
+
2835
+ Localization is handled by the `I18n` gem. In Rails applications, locales are loaded automatically and managed via the `I18n.available_locales` setting.
2836
+
2837
+ ### Local Copies
2838
+
2839
+ Execute the following command to copy any locale into the Rails applications `config/locales` directory:
2840
+
2841
+ ```bash
2842
+ rails generate cmdx:locale [LOCALE]
2843
+
2844
+ # Eg: generate french locale
2845
+ rails generate cmdx:locale fr
2846
+ ```
2847
+
2848
+ ### Available Locales
2849
+
2850
+ - af - Afrikaans
2851
+ - ar - Arabic
2852
+ - az - Azerbaijani
2853
+ - be - Belarusian
2854
+ - bg - Bulgarian
2855
+ - bn - Bengali
2856
+ - bs - Bosnian
2857
+ - ca - Catalan
2858
+ - cnr - Montenegrin
2859
+ - cs - Czech
2860
+ - cy - Welsh
2861
+ - da - Danish
2862
+ - de - German
2863
+ - dz - Dzongkha
2864
+ - el - Greek
2865
+ - en - English
2866
+ - eo - Esperanto
2867
+ - es - Spanish
2868
+ - et - Estonian
2869
+ - eu - Basque
2870
+ - fa - Persian
2871
+ - fi - Finnish
2872
+ - fr - French
2873
+ - fy - Western Frisian
2874
+ - gd - Scottish Gaelic
2875
+ - gl - Galician
2876
+ - he - Hebrew
2877
+ - hi - Hindi
2878
+ - hr - Croatian
2879
+ - hu - Hungarian
2880
+ - hy - Armenian
2881
+ - id - Indonesian
2882
+ - is - Icelandic
2883
+ - it - Italian
2884
+ - ja - Japanese
2885
+ - ka - Georgian
2886
+ - kk - Kazakh
2887
+ - km - Khmer
2888
+ - kn - Kannada
2889
+ - ko - Korean
2890
+ - lb - Luxembourgish
2891
+ - lo - Lao
2892
+ - lt - Lithuanian
2893
+ - lv - Latvian
2894
+ - mg - Malagasy
2895
+ - mk - Macedonian
2896
+ - ml - Malayalam
2897
+ - mn - Mongolian
2898
+ - mr-IN - Marathi (India)
2899
+ - ms - Malay
2900
+ - nb - Norwegian Bokmål
2901
+ - ne - Nepali
2902
+ - nl - Dutch
2903
+ - nn - Norwegian Nynorsk
2904
+ - oc - Occitan
2905
+ - or - Odia
2906
+ - pa - Punjabi
2907
+ - pl - Polish
2908
+ - pt - Portuguese
2909
+ - rm - Romansh
2910
+ - ro - Romanian
2911
+ - ru - Russian
2912
+ - sc - Sardinian
2913
+ - sk - Slovak
2914
+ - sl - Slovenian
2915
+ - sq - Albanian
2916
+ - sr - Serbian
2917
+ - st - Southern Sotho
2918
+ - sv - Swedish
2919
+ - sw - Swahili
2920
+ - ta - Tamil
2921
+ - te - Telugu
2922
+ - th - Thai
2923
+ - tl - Tagalog
2924
+ - tr - Turkish
2925
+ - tt - Tatar
2926
+ - ug - Uyghur
2927
+ - uk - Ukrainian
2928
+ - ur - Urdu
2929
+ - uz - Uzbek
2930
+ - vi - Vietnamese
2931
+ - wo - Wolof
2932
+ - zh-CN - Chinese (Simplified)
2933
+ - zh-HK - Chinese (Hong Kong)
2934
+ - zh-TW - Chinese (Traditional)
2935
+ - zh-YUE - Chinese (Yue)
2816
2936
 
2817
2937
  ---
2818
2938
 
@@ -3147,6 +3267,52 @@ class CompleteEmailWorkflow < CMDx::Task
3147
3267
  end
3148
3268
  ```
3149
3269
 
3270
+ ## Parallel Execution
3271
+
3272
+ Parallel task execution leverages the [Parallel](https://github.com/grosser/parallel) gem, which automatically detects the number of available processors to maximize concurrent task execution.
3273
+
3274
+ > [!IMPORTANT]
3275
+ > Context cannot be modified during parallel execution. Ensure that all required data is preloaded into the context before parallelization begins.
3276
+
3277
+ ```ruby
3278
+ class SendWelcomeNotifications < CMDx::Task
3279
+ include CMDx::Workflow
3280
+
3281
+ # Default options (dynamically calculated to available processors)
3282
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel
3283
+
3284
+ # Fix number of threads
3285
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel, in_threads: 2
3286
+
3287
+ # Fix number of forked processes
3288
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel, in_processes: 2
3289
+
3290
+ # NOTE: Reactors are not supported
3291
+ end
3292
+ ```
3293
+
3294
+ ## Task Generator
3295
+
3296
+ Generate new CMDx workflow tasks quickly using the built-in generator:
3297
+
3298
+ ```bash
3299
+ rails generate cmdx:workflow SendNotifications
3300
+ ```
3301
+
3302
+ This creates a new workflow task file with the basic structure:
3303
+
3304
+ ```ruby
3305
+ # app/tasks/send_notifications.rb
3306
+ class SendNotifications < CMDx::Task
3307
+ include CMDx::Workflow
3308
+
3309
+ tasks Task1, Task2
3310
+ end
3311
+ ```
3312
+
3313
+ > [!TIP]
3314
+ > Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
3315
+
3150
3316
  ---
3151
3317
 
3152
3318
  url: https://github.com/drexed/cmdx/blob/main/docs/tips_and_tricks.md
@@ -2,6 +2,8 @@
2
2
 
3
3
  Attribute coercions automatically convert task arguments to expected types, ensuring type safety while providing flexible input handling. Coercions transform raw input values into the specified types, supporting simple conversions like string-to-integer and complex operations like JSON parsing.
4
4
 
5
+ Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#coercions) docs for global configuration.
6
+
5
7
  ## Table of Contents
6
8
 
7
9
  - [Usage](#usage)
@@ -2,6 +2,8 @@
2
2
 
3
3
  Attribute validations ensure task arguments meet specified requirements before execution begins. Validations run after coercions and provide declarative rules for data integrity, supporting both built-in validators and custom validation logic.
4
4
 
5
+ Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#validations) docs for global configuration.
6
+
5
7
  ## Table of Contents
6
8
 
7
9
  - [Usage](#usage)
data/docs/callbacks.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Callbacks provide precise control over task execution lifecycle, running custom logic at specific transition points. Callback callables have access to the same context and result information as the `execute` method, enabling rich integration patterns.
4
4
 
5
+ Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#callbacks) docs for global configuration.
6
+
5
7
  > [!IMPORTANT]
6
8
  > Callbacks execute in the order they are declared within each hook type. Multiple callbacks of the same type execute in declaration order (FIFO: first in, first out).
7
9
 
@@ -82,6 +82,8 @@ end
82
82
 
83
83
  ### Middlewares
84
84
 
85
+ See the [Middelwares](#https://github.com/drexed/cmdx/blob/main/docs/middlewares.md#declarations) docs for task level configurations.
86
+
85
87
  ```ruby
86
88
  CMDx.configure do |config|
87
89
  # Via callable (must respond to `call(task, options)`)
@@ -109,6 +111,8 @@ end
109
111
 
110
112
  ### Callbacks
111
113
 
114
+ See the [Callbacks](#https://github.com/drexed/cmdx/blob/main/docs/callbacks.md#declarations) docs for task level configurations.
115
+
112
116
  ```ruby
113
117
  CMDx.configure do |config|
114
118
  # Via method
@@ -133,6 +137,8 @@ end
133
137
 
134
138
  ### Coercions
135
139
 
140
+ See the [Attributes - Coercions](#https://github.com/drexed/cmdx/blob/main/docs/attributes/coercions.md#declarations) docs for task level configurations.
141
+
136
142
  ```ruby
137
143
  CMDx.configure do |config|
138
144
  # Via callable (must respond to `call(value, options)`)
@@ -157,6 +163,8 @@ end
157
163
 
158
164
  ### Validators
159
165
 
166
+ See the [Attributes - Validations](#https://github.com/drexed/cmdx/blob/main/docs/attributes/validations.md#declarations) docs for task level configurations.
167
+
160
168
  ```ruby
161
169
  CMDx.configure do |config|
162
170
  # Via callable (must respond to `call(value, options)`)
@@ -5,6 +5,9 @@ CMDx provides comprehensive internationalization support for all error messages,
5
5
  ## Table of Contents
6
6
 
7
7
  - [Localization](#localization)
8
+ - [Configuration](#configuration)
9
+ - [Local Copies](#local-copies)
10
+ - [Available Locales](#available-locales)
8
11
 
9
12
  ## Localization
10
13
 
@@ -25,8 +28,109 @@ I18n.with_locale(:fr) do
25
28
  end
26
29
  ```
27
30
 
28
- > [!TIP]
29
- > CMDx supports 85+ locales via the [cmdx-i18n](https://github.com/drexed/cmdx-i18n) gem.
31
+ ## Configuration
32
+
33
+ Localization is handled by the `I18n` gem. In Rails applications, locales are loaded automatically and managed via the `I18n.available_locales` setting.
34
+
35
+ ### Local Copies
36
+
37
+ Execute the following command to copy any locale into the Rails applications `config/locales` directory:
38
+
39
+ ```bash
40
+ rails generate cmdx:locale [LOCALE]
41
+
42
+ # Eg: generate french locale
43
+ rails generate cmdx:locale fr
44
+ ```
45
+
46
+ ### Available Locales
47
+
48
+ - af - Afrikaans
49
+ - ar - Arabic
50
+ - az - Azerbaijani
51
+ - be - Belarusian
52
+ - bg - Bulgarian
53
+ - bn - Bengali
54
+ - bs - Bosnian
55
+ - ca - Catalan
56
+ - cnr - Montenegrin
57
+ - cs - Czech
58
+ - cy - Welsh
59
+ - da - Danish
60
+ - de - German
61
+ - dz - Dzongkha
62
+ - el - Greek
63
+ - en - English
64
+ - eo - Esperanto
65
+ - es - Spanish
66
+ - et - Estonian
67
+ - eu - Basque
68
+ - fa - Persian
69
+ - fi - Finnish
70
+ - fr - French
71
+ - fy - Western Frisian
72
+ - gd - Scottish Gaelic
73
+ - gl - Galician
74
+ - he - Hebrew
75
+ - hi - Hindi
76
+ - hr - Croatian
77
+ - hu - Hungarian
78
+ - hy - Armenian
79
+ - id - Indonesian
80
+ - is - Icelandic
81
+ - it - Italian
82
+ - ja - Japanese
83
+ - ka - Georgian
84
+ - kk - Kazakh
85
+ - km - Khmer
86
+ - kn - Kannada
87
+ - ko - Korean
88
+ - lb - Luxembourgish
89
+ - lo - Lao
90
+ - lt - Lithuanian
91
+ - lv - Latvian
92
+ - mg - Malagasy
93
+ - mk - Macedonian
94
+ - ml - Malayalam
95
+ - mn - Mongolian
96
+ - mr-IN - Marathi (India)
97
+ - ms - Malay
98
+ - nb - Norwegian Bokmål
99
+ - ne - Nepali
100
+ - nl - Dutch
101
+ - nn - Norwegian Nynorsk
102
+ - oc - Occitan
103
+ - or - Odia
104
+ - pa - Punjabi
105
+ - pl - Polish
106
+ - pt - Portuguese
107
+ - rm - Romansh
108
+ - ro - Romanian
109
+ - ru - Russian
110
+ - sc - Sardinian
111
+ - sk - Slovak
112
+ - sl - Slovenian
113
+ - sq - Albanian
114
+ - sr - Serbian
115
+ - st - Southern Sotho
116
+ - sv - Swedish
117
+ - sw - Swahili
118
+ - ta - Tamil
119
+ - te - Telugu
120
+ - th - Thai
121
+ - tl - Tagalog
122
+ - tr - Turkish
123
+ - tt - Tatar
124
+ - ug - Uyghur
125
+ - uk - Ukrainian
126
+ - ur - Urdu
127
+ - uz - Uzbek
128
+ - vi - Vietnamese
129
+ - wo - Wolof
130
+ - zh-CN - Chinese (Simplified)
131
+ - zh-HK - Chinese (Hong Kong)
132
+ - zh-TW - Chinese (Traditional)
133
+ - zh-YUE - Chinese (Yue)
30
134
 
31
135
  ---
32
136
 
data/docs/middlewares.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Middleware provides Rack-style wrappers around task execution for cross-cutting concerns like authentication, logging, caching, and error handling.
4
4
 
5
+ Check out the [Getting Started](https://github.com/drexed/cmdx/blob/main/docs/getting_started.md#middlewares) docs for global configuration.
6
+
5
7
  ## Table of Contents
6
8
 
7
9
  - [Order](#order)
data/docs/workflows.md CHANGED
@@ -12,6 +12,8 @@ Workflow orchestrates sequential execution of multiple tasks in a linear pipelin
12
12
  - [Task Configuration](#task-configuration)
13
13
  - [Group Configuration](#group-configuration)
14
14
  - [Nested Workflows](#nested-workflows)
15
+ - [Parallel Execution](#parallel-execution)
16
+ - [Task Generator](#task-generator)
15
17
 
16
18
  ## Declarations
17
19
 
@@ -187,6 +189,52 @@ class CompleteEmailWorkflow < CMDx::Task
187
189
  end
188
190
  ```
189
191
 
192
+ ## Parallel Execution
193
+
194
+ Parallel task execution leverages the [Parallel](https://github.com/grosser/parallel) gem, which automatically detects the number of available processors to maximize concurrent task execution.
195
+
196
+ > [!IMPORTANT]
197
+ > Context cannot be modified during parallel execution. Ensure that all required data is preloaded into the context before parallelization begins.
198
+
199
+ ```ruby
200
+ class SendWelcomeNotifications < CMDx::Task
201
+ include CMDx::Workflow
202
+
203
+ # Default options (dynamically calculated to available processors)
204
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel
205
+
206
+ # Fix number of threads
207
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel, in_threads: 2
208
+
209
+ # Fix number of forked processes
210
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel, in_processes: 2
211
+
212
+ # NOTE: Reactors are not supported
213
+ end
214
+ ```
215
+
216
+ ## Task Generator
217
+
218
+ Generate new CMDx workflow tasks quickly using the built-in generator:
219
+
220
+ ```bash
221
+ rails generate cmdx:workflow SendNotifications
222
+ ```
223
+
224
+ This creates a new workflow task file with the basic structure:
225
+
226
+ ```ruby
227
+ # app/tasks/send_notifications.rb
228
+ class SendNotifications < CMDx::Task
229
+ include CMDx::Workflow
230
+
231
+ tasks Task1, Task2
232
+ end
233
+ ```
234
+
235
+ > [!TIP]
236
+ > Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
237
+
190
238
  ---
191
239
 
192
240
  - **Prev:** [Deprecation](deprecation.md)
data/lib/cmdx/pipeline.rb CHANGED
@@ -55,23 +55,22 @@ module CMDx
55
55
 
56
56
  private
57
57
 
58
- # Executes tasks within a group using the configured execution strategy.
59
- # Override this method to implement custom execution strategies like parallel
60
- # processing or conditional task execution.
58
+ # Executes a group of tasks using the specified execution strategy.
61
59
  #
62
- # @param group [ExecutionGroup] The group of tasks to execute
63
- # @param breakpoints [Array<String>] Breakpoint statuses that trigger workflow interruption
60
+ # @param group [CMDx::Group] The task group to execute
61
+ # @param breakpoints [Array<Symbol>] Status values that trigger execution breaks
62
+ # @option group.options [Symbol, String] :strategy Execution strategy (:sequential, :parallel, or nil for default)
64
63
  #
65
64
  # @return [void]
66
65
  #
67
66
  # @example
68
- # def execute_group_tasks(group, breakpoints)
69
- # # Custom parallel execution strategy
70
- # group.tasks.map { |task| Thread.new { task.execute(workflow.context) } }
71
- # end
67
+ # execute_group_tasks(group, ["failed", "skipped"])
72
68
  def execute_group_tasks(group, breakpoints)
73
- # NOTE: Override this method to introduce alternative execution strategies
74
- execute_tasks_in_sequence(group, breakpoints)
69
+ case strategy = group.options[:strategy]
70
+ when NilClass, /sequential/ then execute_tasks_in_sequence(group, breakpoints)
71
+ when /parallel/ then execute_tasks_in_parallel(group, breakpoints)
72
+ else raise "unknown execution strategy #{strategy.inspect}"
73
+ end
75
74
  end
76
75
 
77
76
  # Executes tasks sequentially within a group, checking breakpoints after each task.
@@ -95,5 +94,38 @@ module CMDx
95
94
  end
96
95
  end
97
96
 
97
+ # Executes tasks in parallel using the parallel gem.
98
+ #
99
+ # @param group [CMDx::Group] The task group to execute in parallel
100
+ # @param breakpoints [Array<Symbol>] Status values that trigger execution breaks
101
+ # @option group.options [Integer] :in_threads Number of threads to use
102
+ # @option group.options [Integer] :in_processes Number of processes to use
103
+ #
104
+ # @return [void]
105
+ #
106
+ # @raise [HaltError] When a task result status matches a breakpoint
107
+ #
108
+ # @example
109
+ # execute_tasks_in_parallel(group, ["failed"])
110
+ def execute_tasks_in_parallel(group, breakpoints)
111
+ raise "install the `parallel` gem to use this feature" unless defined?(::Parallel)
112
+
113
+ parallel_options = group.options.slice(:in_threads, :in_processes)
114
+ throwable_result = nil
115
+
116
+ ::Parallel.each(group.tasks, **parallel_options) do |task|
117
+ Chain.current = workflow.chain
118
+
119
+ task_result = task.execute(workflow.context)
120
+ next unless breakpoints.include?(task_result.status)
121
+
122
+ raise ::Parallel::Break, throwable_result = task_result
123
+ end
124
+
125
+ return if throwable_result.nil?
126
+
127
+ workflow.throw!(throwable_result)
128
+ end
129
+
98
130
  end
99
131
  end
data/lib/cmdx/railtie.rb CHANGED
@@ -26,10 +26,10 @@ module CMDx
26
26
  path = CMDx.gem_path.join("lib/locales/#{locale}.yml")
27
27
  next unless File.file?(path)
28
28
 
29
- I18n.load_path << path
29
+ ::I18n.load_path << path
30
30
  end
31
31
 
32
- I18n.reload!
32
+ ::I18n.reload!
33
33
  end
34
34
 
35
35
  end
data/lib/cmdx/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CMDx
4
4
 
5
- VERSION = "1.6.1"
5
+ VERSION = "1.7.0"
6
6
 
7
7
  end
data/lib/cmdx.rb CHANGED
@@ -48,7 +48,9 @@ require_relative "cmdx/faults"
48
48
  # Conditionally load Rails components if Rails is available
49
49
  if defined?(Rails::Generators)
50
50
  require_relative "generators/cmdx/install_generator"
51
+ require_relative "generators/cmdx/locale_generator"
51
52
  require_relative "generators/cmdx/task_generator"
53
+ require_relative "generators/cmdx/workflow_generator"
52
54
  end
53
55
 
54
56
  # Load the Railtie last after everything else is required so we don't