cmdx 1.6.2 → 1.7.1

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 (99) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/LLM.md +165 -2
  4. data/docs/internationalization.md +106 -2
  5. data/docs/outcomes/result.md +17 -0
  6. data/docs/workflows.md +48 -0
  7. data/lib/cmdx/pipeline.rb +43 -11
  8. data/lib/cmdx/task.rb +7 -6
  9. data/lib/cmdx/version.rb +1 -1
  10. data/lib/cmdx.rb +2 -0
  11. data/lib/generators/cmdx/locale_generator.rb +39 -0
  12. data/lib/generators/cmdx/templates/workflow.rb.tt +8 -0
  13. data/lib/generators/cmdx/workflow_generator.rb +57 -0
  14. data/lib/locales/af.yml +49 -0
  15. data/lib/locales/ar.yml +49 -0
  16. data/lib/locales/az.yml +49 -0
  17. data/lib/locales/be.yml +49 -0
  18. data/lib/locales/bg.yml +49 -0
  19. data/lib/locales/bn.yml +49 -0
  20. data/lib/locales/bs.yml +49 -0
  21. data/lib/locales/ca.yml +49 -0
  22. data/lib/locales/cnr.yml +49 -0
  23. data/lib/locales/cs.yml +49 -0
  24. data/lib/locales/cy.yml +49 -0
  25. data/lib/locales/da.yml +49 -0
  26. data/lib/locales/de.yml +49 -0
  27. data/lib/locales/dz.yml +49 -0
  28. data/lib/locales/el.yml +49 -0
  29. data/lib/locales/eo.yml +49 -0
  30. data/lib/locales/es.yml +49 -0
  31. data/lib/locales/et.yml +49 -0
  32. data/lib/locales/eu.yml +49 -0
  33. data/lib/locales/fa.yml +49 -0
  34. data/lib/locales/fi.yml +49 -0
  35. data/lib/locales/fr.yml +49 -0
  36. data/lib/locales/fy.yml +49 -0
  37. data/lib/locales/gd.yml +49 -0
  38. data/lib/locales/gl.yml +49 -0
  39. data/lib/locales/he.yml +49 -0
  40. data/lib/locales/hi.yml +49 -0
  41. data/lib/locales/hr.yml +49 -0
  42. data/lib/locales/hu.yml +49 -0
  43. data/lib/locales/hy.yml +49 -0
  44. data/lib/locales/id.yml +49 -0
  45. data/lib/locales/is.yml +49 -0
  46. data/lib/locales/it.yml +49 -0
  47. data/lib/locales/ja.yml +49 -0
  48. data/lib/locales/ka.yml +49 -0
  49. data/lib/locales/kk.yml +49 -0
  50. data/lib/locales/km.yml +49 -0
  51. data/lib/locales/kn.yml +49 -0
  52. data/lib/locales/ko.yml +49 -0
  53. data/lib/locales/lb.yml +49 -0
  54. data/lib/locales/lo.yml +49 -0
  55. data/lib/locales/lt.yml +49 -0
  56. data/lib/locales/lv.yml +49 -0
  57. data/lib/locales/mg.yml +49 -0
  58. data/lib/locales/mk.yml +49 -0
  59. data/lib/locales/ml.yml +49 -0
  60. data/lib/locales/mn.yml +49 -0
  61. data/lib/locales/mr-IN.yml +49 -0
  62. data/lib/locales/ms.yml +49 -0
  63. data/lib/locales/nb.yml +49 -0
  64. data/lib/locales/ne.yml +49 -0
  65. data/lib/locales/nl.yml +49 -0
  66. data/lib/locales/nn.yml +49 -0
  67. data/lib/locales/oc.yml +49 -0
  68. data/lib/locales/or.yml +49 -0
  69. data/lib/locales/pa.yml +49 -0
  70. data/lib/locales/pl.yml +49 -0
  71. data/lib/locales/pt.yml +49 -0
  72. data/lib/locales/rm.yml +49 -0
  73. data/lib/locales/ro.yml +49 -0
  74. data/lib/locales/ru.yml +49 -0
  75. data/lib/locales/sc.yml +49 -0
  76. data/lib/locales/sk.yml +49 -0
  77. data/lib/locales/sl.yml +49 -0
  78. data/lib/locales/sq.yml +49 -0
  79. data/lib/locales/sr.yml +49 -0
  80. data/lib/locales/st.yml +49 -0
  81. data/lib/locales/sv.yml +49 -0
  82. data/lib/locales/sw.yml +49 -0
  83. data/lib/locales/ta.yml +49 -0
  84. data/lib/locales/te.yml +49 -0
  85. data/lib/locales/th.yml +49 -0
  86. data/lib/locales/tl.yml +49 -0
  87. data/lib/locales/tr.yml +49 -0
  88. data/lib/locales/tt.yml +49 -0
  89. data/lib/locales/ug.yml +49 -0
  90. data/lib/locales/uk.yml +49 -0
  91. data/lib/locales/ur.yml +49 -0
  92. data/lib/locales/uz.yml +49 -0
  93. data/lib/locales/vi.yml +49 -0
  94. data/lib/locales/wo.yml +49 -0
  95. data/lib/locales/zh-CN.yml +49 -0
  96. data/lib/locales/zh-HK.yml +49 -0
  97. data/lib/locales/zh-TW.yml +49 -0
  98. data/lib/locales/zh-YUE.yml +49 -0
  99. metadata +103 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8b62e944f3c8fdb0f69dba9e33e3aad9f62d90b6a7487b18e9c0104392c4a8d
4
- data.tar.gz: a032133acd6f0e6d5999d8336a179df495fd4460fbf632385a8dbcd4ee31fd66
3
+ metadata.gz: 9bbf1d8db7665b82da9af2dd5e017977945bbd550700177368b1363a8e63275e
4
+ data.tar.gz: 0f1720432a999ff31399d67c602e5277ee8cb1a8062117165c425a39233eb81c
5
5
  SHA512:
6
- metadata.gz: 05a82e75e96e364df809f158a791a015ce22cff03b10f1ae255ba2e116d602fadd741d0a82638c5feabcbbdf96e3e61e9a9ae54be8c3220253d542f0d8a303d5
7
- data.tar.gz: 881fe8149e8a029fbb79a1164faced4406f4f28d1e206659e09ee460129d9246a9a074aef76a61cbd94a38ed4f1a39612753a6842460e3a3827b3bd1c5301cc1
6
+ metadata.gz: 144c01abf663258e34b40eaa9e1deba09b59347b97773237f9bd84f5d82474825aca38f21b6ad0c052f1b058f6a5550e24ef8f3598da4cdecad94da1689bea5c
7
+ data.tar.gz: 25220966f85607b73740107b5af5da7889e75592055ad17156bc48f157550e2d030f542b7f279ec731cbb78ef732be1c6507b8e448a97a8324749d4746549d95
data/CHANGELOG.md CHANGED
@@ -6,6 +6,20 @@ 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.1] - 2025-08-26
10
+
11
+ ### Added
12
+ - Yield result if block given to `execute` and `execute!` methods
13
+
14
+ ## [1.7.0] - 2025-08-25
15
+
16
+ ### Added
17
+ - Workflow generator
18
+
19
+ ### Changes
20
+ - Port over `cmdx-parallel` changes
21
+ - Port over `cmdx-i18n` changes
22
+
9
23
  ## [1.6.2] - 2025-08-24
10
24
 
11
25
  ### Changes
data/LLM.md CHANGED
@@ -1251,6 +1251,22 @@ result.index #=> 0 (first task in chain)
1251
1251
  result.chain.results[result.index] == result #=> true
1252
1252
  ```
1253
1253
 
1254
+ ## Block Yield
1255
+
1256
+ Implement conditional logic using a block expression that yields a result for complete encapsulation.
1257
+
1258
+ ```ruby
1259
+ BuildApplication.execute(version: "1.2.3") do |result|
1260
+ if result.success?
1261
+ notify_deployment_ready(result)
1262
+ elsif result.failed?
1263
+ handle_build_failure(result)
1264
+ else
1265
+ log_skip_reason(result)
1266
+ end
1267
+ end
1268
+ ```
1269
+
1254
1270
  ## Handlers
1255
1271
 
1256
1272
  Use result handlers for clean, functional-style conditional logic. Handlers return the result object, enabling method chaining and fluent interfaces.
@@ -2830,8 +2846,109 @@ I18n.with_locale(:fr) do
2830
2846
  end
2831
2847
  ```
2832
2848
 
2833
- > [!TIP]
2834
- > CMDx supports 85+ locales via the [cmdx-i18n](https://github.com/drexed/cmdx-i18n) gem.
2849
+ ## Configuration
2850
+
2851
+ Localization is handled by the `I18n` gem. In Rails applications, locales are loaded automatically and managed via the `I18n.available_locales` setting.
2852
+
2853
+ ### Local Copies
2854
+
2855
+ Execute the following command to copy any locale into the Rails applications `config/locales` directory:
2856
+
2857
+ ```bash
2858
+ rails generate cmdx:locale [LOCALE]
2859
+
2860
+ # Eg: generate french locale
2861
+ rails generate cmdx:locale fr
2862
+ ```
2863
+
2864
+ ### Available Locales
2865
+
2866
+ - af - Afrikaans
2867
+ - ar - Arabic
2868
+ - az - Azerbaijani
2869
+ - be - Belarusian
2870
+ - bg - Bulgarian
2871
+ - bn - Bengali
2872
+ - bs - Bosnian
2873
+ - ca - Catalan
2874
+ - cnr - Montenegrin
2875
+ - cs - Czech
2876
+ - cy - Welsh
2877
+ - da - Danish
2878
+ - de - German
2879
+ - dz - Dzongkha
2880
+ - el - Greek
2881
+ - en - English
2882
+ - eo - Esperanto
2883
+ - es - Spanish
2884
+ - et - Estonian
2885
+ - eu - Basque
2886
+ - fa - Persian
2887
+ - fi - Finnish
2888
+ - fr - French
2889
+ - fy - Western Frisian
2890
+ - gd - Scottish Gaelic
2891
+ - gl - Galician
2892
+ - he - Hebrew
2893
+ - hi - Hindi
2894
+ - hr - Croatian
2895
+ - hu - Hungarian
2896
+ - hy - Armenian
2897
+ - id - Indonesian
2898
+ - is - Icelandic
2899
+ - it - Italian
2900
+ - ja - Japanese
2901
+ - ka - Georgian
2902
+ - kk - Kazakh
2903
+ - km - Khmer
2904
+ - kn - Kannada
2905
+ - ko - Korean
2906
+ - lb - Luxembourgish
2907
+ - lo - Lao
2908
+ - lt - Lithuanian
2909
+ - lv - Latvian
2910
+ - mg - Malagasy
2911
+ - mk - Macedonian
2912
+ - ml - Malayalam
2913
+ - mn - Mongolian
2914
+ - mr-IN - Marathi (India)
2915
+ - ms - Malay
2916
+ - nb - Norwegian Bokmål
2917
+ - ne - Nepali
2918
+ - nl - Dutch
2919
+ - nn - Norwegian Nynorsk
2920
+ - oc - Occitan
2921
+ - or - Odia
2922
+ - pa - Punjabi
2923
+ - pl - Polish
2924
+ - pt - Portuguese
2925
+ - rm - Romansh
2926
+ - ro - Romanian
2927
+ - ru - Russian
2928
+ - sc - Sardinian
2929
+ - sk - Slovak
2930
+ - sl - Slovenian
2931
+ - sq - Albanian
2932
+ - sr - Serbian
2933
+ - st - Southern Sotho
2934
+ - sv - Swedish
2935
+ - sw - Swahili
2936
+ - ta - Tamil
2937
+ - te - Telugu
2938
+ - th - Thai
2939
+ - tl - Tagalog
2940
+ - tr - Turkish
2941
+ - tt - Tatar
2942
+ - ug - Uyghur
2943
+ - uk - Ukrainian
2944
+ - ur - Urdu
2945
+ - uz - Uzbek
2946
+ - vi - Vietnamese
2947
+ - wo - Wolof
2948
+ - zh-CN - Chinese (Simplified)
2949
+ - zh-HK - Chinese (Hong Kong)
2950
+ - zh-TW - Chinese (Traditional)
2951
+ - zh-YUE - Chinese (Yue)
2835
2952
 
2836
2953
  ---
2837
2954
 
@@ -3166,6 +3283,52 @@ class CompleteEmailWorkflow < CMDx::Task
3166
3283
  end
3167
3284
  ```
3168
3285
 
3286
+ ## Parallel Execution
3287
+
3288
+ 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.
3289
+
3290
+ > [!IMPORTANT]
3291
+ > Context cannot be modified during parallel execution. Ensure that all required data is preloaded into the context before parallelization begins.
3292
+
3293
+ ```ruby
3294
+ class SendWelcomeNotifications < CMDx::Task
3295
+ include CMDx::Workflow
3296
+
3297
+ # Default options (dynamically calculated to available processors)
3298
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel
3299
+
3300
+ # Fix number of threads
3301
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel, in_threads: 2
3302
+
3303
+ # Fix number of forked processes
3304
+ tasks SendWelcomeEmail, SendWelcomeSms, SendWelcomePush, strategy: :parallel, in_processes: 2
3305
+
3306
+ # NOTE: Reactors are not supported
3307
+ end
3308
+ ```
3309
+
3310
+ ## Task Generator
3311
+
3312
+ Generate new CMDx workflow tasks quickly using the built-in generator:
3313
+
3314
+ ```bash
3315
+ rails generate cmdx:workflow SendNotifications
3316
+ ```
3317
+
3318
+ This creates a new workflow task file with the basic structure:
3319
+
3320
+ ```ruby
3321
+ # app/tasks/send_notifications.rb
3322
+ class SendNotifications < CMDx::Task
3323
+ include CMDx::Workflow
3324
+
3325
+ tasks Task1, Task2
3326
+ end
3327
+ ```
3328
+
3329
+ > [!TIP]
3330
+ > Use **present tense verbs + pluralized noun** for workflow task names, eg: `SendNotifications`, `DownloadFiles`, `ValidateDocuments`
3331
+
3169
3332
  ---
3170
3333
 
3171
3334
  url: https://github.com/drexed/cmdx/blob/main/docs/tips_and_tricks.md
@@ -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
 
@@ -9,6 +9,7 @@ The result object is the comprehensive return value of task execution, providing
9
9
  - [Outcome Analysis](#outcome-analysis)
10
10
  - [Chain Analysis](#chain-analysis)
11
11
  - [Index and Position](#index-and-position)
12
+ - [Block Yield](#block-yield)
12
13
  - [Handlers](#handlers)
13
14
  - [Pattern Matching](#pattern-matching)
14
15
  - [Array Pattern](#array-pattern)
@@ -113,6 +114,22 @@ result.index #=> 0 (first task in chain)
113
114
  result.chain.results[result.index] == result #=> true
114
115
  ```
115
116
 
117
+ ## Block Yield
118
+
119
+ Implement conditional logic using a block expression that yields a result for complete encapsulation.
120
+
121
+ ```ruby
122
+ BuildApplication.execute(version: "1.2.3") do |result|
123
+ if result.success?
124
+ notify_deployment_ready(result)
125
+ elsif result.failed?
126
+ handle_build_failure(result)
127
+ else
128
+ log_skip_reason(result)
129
+ end
130
+ end
131
+ ```
132
+
116
133
  ## Handlers
117
134
 
118
135
  Use result handlers for clean, functional-style conditional logic. Handlers return the result object, enabling method chaining and fluent interfaces.
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/task.rb CHANGED
@@ -169,10 +169,10 @@ module CMDx
169
169
  # if result.success?
170
170
  # puts "Task completed successfully"
171
171
  # end
172
- def execute(...)
173
- task = new(...)
172
+ def execute(*args, **kwargs)
173
+ task = new(*args, **kwargs)
174
174
  task.execute(raise: false)
175
- task.result
175
+ block_given? ? yield(task.result) : task.result
176
176
  end
177
177
 
178
178
  # @param args [Array] Arguments to pass to the task constructor
@@ -184,10 +184,10 @@ module CMDx
184
184
  # @example
185
185
  # result = MyTask.execute!(name: "example")
186
186
  # # Will raise an exception if execution fails
187
- def execute!(...)
188
- task = new(...)
187
+ def execute!(*args, **kwargs)
188
+ task = new(*args, **kwargs)
189
189
  task.execute(raise: true)
190
- task.result
190
+ block_given? ? yield(task.result) : task.result
191
191
  end
192
192
 
193
193
  end
@@ -201,6 +201,7 @@ module CMDx
201
201
  # result = task.execute(raise: true)
202
202
  def execute(raise: false)
203
203
  Executor.execute(self, raise:)
204
+ block_given? ? yield(result) : result
204
205
  end
205
206
 
206
207
  # @raise [UndefinedMethodError] Always raised as this method must be overridden
data/lib/cmdx/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CMDx
4
4
 
5
- VERSION = "1.6.2"
5
+ VERSION = "1.7.1"
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
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cmdx
4
+ # Generates CMDx locale files for Rails applications
5
+ #
6
+ # Rails generator that copies CMDx locale files into the application's
7
+ # config/locales directory. This allows applications to customize and extend
8
+ # the default CMDx locale files.
9
+ class LocaleGenerator < Rails::Generators::Base
10
+
11
+ source_root File.expand_path("../../locales", __dir__)
12
+
13
+ desc "Copies the locale with the given alpha-2 code"
14
+
15
+ argument :locale, type: :string, default: "en", banner: "locale: en, es, fr, etc"
16
+
17
+ # Copies the locale template to the Rails application
18
+ #
19
+ # Copies the specified locale file from the gem's locales directory to the
20
+ # application's config/locales directory. If the locale file doesn't exist
21
+ # in the gem, the generator will fail gracefully.
22
+ #
23
+ # @return [void]
24
+ #
25
+ # @example
26
+ # # Copy default (English) locale file
27
+ # rails generate cmdx:locale
28
+ # # => Creates config/locales/en.yml
29
+ #
30
+ # # Copy Spanish locale file
31
+ # rails generate cmdx:locale es
32
+ # # => Creates config/locales/es.yml
33
+ #
34
+ def copy_locale_files
35
+ copy_file("#{locale}.yml", "config/locales/#{locale}.yml")
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,8 @@
1
+ <% module_namespacing do -%>
2
+ class <%= class_name %> < <%= parent_class_name %>
3
+ include CMDx::Workflow
4
+
5
+ tasks Task1, Task2
6
+ # Docs: https://github.com/drexed/cmdx/docs/workflows.md
7
+ end
8
+ <% end -%>
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Cmdx
4
+ # Generates CMDx workflow files for Rails applications
5
+ #
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
+ class WorkflowGenerator < Rails::Generators::NamedBase
10
+
11
+ source_root File.expand_path("templates", __dir__)
12
+
13
+ desc "Creates a workflow with the given NAME"
14
+
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.
20
+ #
21
+ # @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
+ def copy_files
31
+ path = File.join("app/tasks", class_path, "#{file_name}.rb")
32
+ template("workflow.rb.tt", path)
33
+ end
34
+
35
+ private
36
+
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
47
+ #
48
+ # @example Fallback behavior
49
+ # parent_class_name # => CMDx::Task
50
+ def parent_class_name
51
+ ApplicationTask
52
+ rescue NameError
53
+ CMDx::Task
54
+ end
55
+
56
+ end
57
+ end