cmdx 1.13.0 → 1.15.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +92 -76
- data/LICENSE.txt +3 -20
- data/README.md +16 -8
- data/lib/cmdx/attribute.rb +42 -5
- data/lib/cmdx/context.rb +16 -0
- data/lib/cmdx/executor.rb +9 -9
- data/lib/cmdx/result.rb +27 -7
- data/lib/cmdx/task.rb +19 -0
- data/lib/cmdx/validator_registry.rb +1 -0
- data/lib/cmdx/validators/absence.rb +61 -0
- data/lib/cmdx/version.rb +1 -1
- data/lib/locales/af.yml +1 -0
- data/lib/locales/ar.yml +1 -0
- data/lib/locales/az.yml +1 -0
- data/lib/locales/be.yml +1 -0
- data/lib/locales/bg.yml +1 -0
- data/lib/locales/bn.yml +1 -0
- data/lib/locales/bs.yml +1 -0
- data/lib/locales/ca.yml +1 -0
- data/lib/locales/cnr.yml +1 -0
- data/lib/locales/cs.yml +1 -0
- data/lib/locales/cy.yml +1 -0
- data/lib/locales/da.yml +1 -0
- data/lib/locales/de.yml +1 -0
- data/lib/locales/dz.yml +1 -0
- data/lib/locales/el.yml +1 -0
- data/lib/locales/en.yml +1 -0
- data/lib/locales/eo.yml +1 -0
- data/lib/locales/es.yml +1 -0
- data/lib/locales/et.yml +1 -0
- data/lib/locales/eu.yml +1 -0
- data/lib/locales/fa.yml +1 -0
- data/lib/locales/fi.yml +1 -0
- data/lib/locales/fr.yml +1 -0
- data/lib/locales/fy.yml +1 -0
- data/lib/locales/gd.yml +1 -0
- data/lib/locales/gl.yml +1 -0
- data/lib/locales/he.yml +1 -0
- data/lib/locales/hi.yml +1 -0
- data/lib/locales/hr.yml +1 -0
- data/lib/locales/hu.yml +1 -0
- data/lib/locales/hy.yml +1 -0
- data/lib/locales/id.yml +1 -0
- data/lib/locales/is.yml +1 -0
- data/lib/locales/it.yml +1 -0
- data/lib/locales/ja.yml +1 -0
- data/lib/locales/ka.yml +1 -0
- data/lib/locales/kk.yml +1 -0
- data/lib/locales/km.yml +1 -0
- data/lib/locales/kn.yml +1 -0
- data/lib/locales/ko.yml +1 -0
- data/lib/locales/lb.yml +1 -0
- data/lib/locales/lo.yml +1 -0
- data/lib/locales/lt.yml +1 -0
- data/lib/locales/lv.yml +1 -0
- data/lib/locales/mg.yml +1 -0
- data/lib/locales/mk.yml +1 -0
- data/lib/locales/ml.yml +1 -0
- data/lib/locales/mn.yml +1 -0
- data/lib/locales/mr-IN.yml +1 -0
- data/lib/locales/ms.yml +1 -0
- data/lib/locales/nb.yml +1 -0
- data/lib/locales/ne.yml +1 -0
- data/lib/locales/nl.yml +1 -0
- data/lib/locales/nn.yml +1 -0
- data/lib/locales/oc.yml +1 -0
- data/lib/locales/or.yml +1 -0
- data/lib/locales/pa.yml +1 -0
- data/lib/locales/pl.yml +1 -0
- data/lib/locales/pt.yml +1 -0
- data/lib/locales/rm.yml +1 -0
- data/lib/locales/ro.yml +1 -0
- data/lib/locales/ru.yml +1 -0
- data/lib/locales/sc.yml +1 -0
- data/lib/locales/sk.yml +1 -0
- data/lib/locales/sl.yml +1 -0
- data/lib/locales/sq.yml +1 -0
- data/lib/locales/sr.yml +1 -0
- data/lib/locales/st.yml +1 -0
- data/lib/locales/sv.yml +1 -0
- data/lib/locales/sw.yml +1 -0
- data/lib/locales/ta.yml +1 -0
- data/lib/locales/te.yml +1 -0
- data/lib/locales/th.yml +1 -0
- data/lib/locales/tl.yml +1 -0
- data/lib/locales/tr.yml +1 -0
- data/lib/locales/tt.yml +1 -0
- data/lib/locales/ug.yml +1 -0
- data/lib/locales/uk.yml +1 -0
- data/lib/locales/ur.yml +1 -0
- data/lib/locales/uz.yml +1 -0
- data/lib/locales/vi.yml +1 -0
- data/lib/locales/wo.yml +1 -0
- data/lib/locales/zh-CN.yml +1 -0
- data/lib/locales/zh-HK.yml +1 -0
- data/lib/locales/zh-TW.yml +1 -0
- data/lib/locales/zh-YUE.yml +1 -0
- data/mkdocs.yml +65 -36
- metadata +4 -57
- data/.cursor/prompts/docs.md +0 -12
- data/.cursor/prompts/llms.md +0 -8
- data/.cursor/prompts/rspec.md +0 -24
- data/.cursor/prompts/yardoc.md +0 -15
- data/.cursor/rules/cursor-instructions.mdc +0 -68
- data/.irbrc +0 -18
- data/.rspec +0 -4
- data/.rubocop.yml +0 -95
- data/.ruby-version +0 -1
- data/.yard-lint.yml +0 -174
- data/.yardopts +0 -7
- data/docs/.DS_Store +0 -0
- data/docs/assets/favicon.ico +0 -0
- data/docs/assets/favicon.svg +0 -1
- data/docs/attributes/coercions.md +0 -155
- data/docs/attributes/defaults.md +0 -77
- data/docs/attributes/definitions.md +0 -283
- data/docs/attributes/naming.md +0 -68
- data/docs/attributes/transformations.md +0 -63
- data/docs/attributes/validations.md +0 -336
- data/docs/basics/chain.md +0 -108
- data/docs/basics/context.md +0 -121
- data/docs/basics/execution.md +0 -152
- data/docs/basics/setup.md +0 -107
- data/docs/callbacks.md +0 -157
- data/docs/configuration.md +0 -314
- data/docs/deprecation.md +0 -143
- data/docs/getting_started.md +0 -137
- data/docs/index.md +0 -134
- data/docs/internationalization.md +0 -126
- data/docs/interruptions/exceptions.md +0 -52
- data/docs/interruptions/faults.md +0 -169
- data/docs/interruptions/halt.md +0 -216
- data/docs/logging.md +0 -90
- data/docs/middlewares.md +0 -191
- data/docs/outcomes/result.md +0 -197
- data/docs/outcomes/states.md +0 -66
- data/docs/outcomes/statuses.md +0 -65
- data/docs/retries.md +0 -121
- data/docs/stylesheets/extra.css +0 -42
- data/docs/tips_and_tricks.md +0 -157
- data/docs/workflows.md +0 -226
- data/examples/active_record_database_transaction.md +0 -27
- data/examples/active_record_query_tagging.md +0 -46
- data/examples/flipper_feature_flags.md +0 -50
- data/examples/paper_trail_whatdunnit.md +0 -39
- data/examples/redis_idempotency.md +0 -71
- data/examples/sentry_error_tracking.md +0 -46
- data/examples/sidekiq_async_execution.md +0 -29
- data/examples/stoplight_circuit_breaker.md +0 -36
- data/src/cmdx-dark-logo.png +0 -0
- data/src/cmdx-favicon.svg +0 -1
- data/src/cmdx-light-logo.png +0 -0
- data/src/cmdx-logo.svg +0 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f23ba43366877a7e368b02f036bd98212c53ee1d52ae47c09e4d689ac305651e
|
|
4
|
+
data.tar.gz: 4b4e778baa84ae14274c8313464c979fb1be9c9d0651f45ca0483bc7f530a3c2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e1ea9eeebd2d84da3c8d0813dbf8739f8776adc0fb749ee9309f63bff258026b4ec9a8f53e32bca6c8a806ae135a617773709ff41d9b52fd3def07f914b2199d
|
|
7
|
+
data.tar.gz: 1dc6797d0e13aa08f900464c731f81cc5fd15672094c9ce3f02d0487d99395ce219b21ad7a9e95aa1d833b3dd36a9394a156fec503cd417109e3e08d33e41449
|
data/CHANGELOG.md
CHANGED
|
@@ -4,175 +4,191 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [Unreleased]
|
|
8
8
|
|
|
9
|
-
## [1.
|
|
9
|
+
## [1.15.0] - 2025-01-21
|
|
10
10
|
|
|
11
11
|
### Added
|
|
12
|
+
- Add attribute `Absence` validator
|
|
13
|
+
- Add attribute `:description` option
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
- Added `dry_run` option to task execution with inheritance support for nested tasks
|
|
15
|
-
- Added context `delete` alias for `delete!`
|
|
16
|
-
- Added context `merge` alias for `merge!`
|
|
15
|
+
## [1.14.0] - 2025-01-09
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
### Added
|
|
18
|
+
- Add Ruby 4.0 compatibility
|
|
19
|
+
- Add `Context#clear!` method to remove all context data
|
|
20
|
+
- Add `Task.attribute_schema` class method for attribute introspection
|
|
21
|
+
- Add `#to_h` method for attribute serialization
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- **BREAKING**: Switch license from MIT to LGPLv3
|
|
25
|
+
- Replace `instance_eval` with `define_singleton_method` for attribute method definitions
|
|
26
|
+
- Move retry count from metadata to result object
|
|
27
|
+
- Exclude non-essential files from gem package
|
|
28
|
+
|
|
29
|
+
### Removed
|
|
30
|
+
- Remove public `Result#rolled_back!` method to hide internal implementation
|
|
31
|
+
|
|
32
|
+
## [1.13.0] - 2025-12-23
|
|
19
33
|
|
|
20
34
|
### Added
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
35
|
+
- Add rollback tracking and logging for task execution
|
|
36
|
+
- Add `dry_run` execution option with inheritance support for nested tasks
|
|
37
|
+
- Add `Context#delete` alias for `Context#delete!`
|
|
38
|
+
- Add `Context#merge` alias for `Context#merge!`
|
|
39
|
+
|
|
40
|
+
## [1.12.0] - 2025-12-18
|
|
41
|
+
|
|
42
|
+
### Changed
|
|
43
|
+
- Optimize logging ancestor chain lookup performance
|
|
44
|
+
- Use `String#chop` instead of range indexing for improved string performance
|
|
45
|
+
- Make boolean coercion `TRUTHY` and `FALSEY` patterns case-insensitive
|
|
46
|
+
- Enhance YARD documentation using `yard-lint` validation
|
|
47
|
+
|
|
48
|
+
### Removed
|
|
49
|
+
- Remove `handle_*` callback methods in favor of `on(*states_or_statuses)` for flexible state handling
|
|
32
50
|
|
|
33
51
|
## [1.11.0] - 2025-11-08
|
|
34
52
|
|
|
35
|
-
###
|
|
36
|
-
-
|
|
37
|
-
- Update specs to use new `cmdx-rspec` matcher
|
|
53
|
+
### Changed
|
|
54
|
+
- Add conditional requirement support for attribute validation
|
|
55
|
+
- Update specs to use new `cmdx-rspec` matcher naming conventions
|
|
38
56
|
|
|
39
57
|
## [1.10.1] - 2025-11-06
|
|
40
58
|
|
|
41
59
|
### Added
|
|
42
|
-
-
|
|
43
|
-
- Added YARDoc documentation to docs site
|
|
60
|
+
- Add YARDoc documentation to documentation site
|
|
44
61
|
|
|
45
62
|
### Removed
|
|
46
|
-
-
|
|
63
|
+
- Remove unused `Executor#repeator` method
|
|
47
64
|
|
|
48
65
|
## [1.10.0] - 2025-10-26
|
|
49
66
|
|
|
50
67
|
### Added
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
- Added Stoplight circuit breaker integration example
|
|
68
|
+
- Add `rollback` capability to undo operations based on status
|
|
69
|
+
- Add retry mechanism documentation
|
|
54
70
|
|
|
55
|
-
###
|
|
56
|
-
-
|
|
71
|
+
### Changed
|
|
72
|
+
- Extend `retry_jitter` option to accept symbols, procs, and callable objects
|
|
57
73
|
|
|
58
74
|
## [1.9.1] - 2025-10-22
|
|
59
75
|
|
|
60
76
|
### Added
|
|
61
|
-
-
|
|
62
|
-
-
|
|
77
|
+
- Add RBS inline type signatures
|
|
78
|
+
- Add YARDocs for `attr_reader` and `attr_accessor` methods
|
|
63
79
|
|
|
64
80
|
## [1.9.0] - 2025-10-21
|
|
65
81
|
|
|
66
82
|
### Added
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
-
|
|
71
|
-
-
|
|
72
|
-
-
|
|
83
|
+
- Add `transform` option for attribute value transformations
|
|
84
|
+
- Add optional failure backtrace output
|
|
85
|
+
- Add exception handling for non-bang execution methods
|
|
86
|
+
- Add automatic retry mechanism for execution durability
|
|
87
|
+
- Add `to_h` hash coercion support
|
|
88
|
+
- Add MkDocs configuration with Material theme
|
|
73
89
|
|
|
74
90
|
### Changed
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
91
|
+
- Improve task settings initialization performance
|
|
92
|
+
- Improve exception error message clarity
|
|
93
|
+
- Improve parent settings inheritance behavior
|
|
94
|
+
- Clean halt backtrace frames for better readability
|
|
79
95
|
|
|
80
96
|
### Removed
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
84
|
-
-
|
|
97
|
+
- Remove `Freezer` module; consolidate logic into `Executor#freeze_execution!`
|
|
98
|
+
- Remove `task` parameter from callback method signatures
|
|
99
|
+
- Remove `task` and `workflow` arguments from conditional checks
|
|
100
|
+
- Remove chain persistence after execution in specs
|
|
85
101
|
|
|
86
102
|
## [1.8.0] - 2025-09-22
|
|
87
103
|
|
|
88
104
|
### Changed
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
-
|
|
93
|
-
-
|
|
105
|
+
- Generalize locale values for `invalid` and `unspecified` faults
|
|
106
|
+
- Nest attribute error messages under `error` key in metadata
|
|
107
|
+
- Reorder Logstash formatter keys for consistency
|
|
108
|
+
- Improve error messaging for duplicate item definitions
|
|
109
|
+
- Return empty hash `{}` for `nil` hash coercion
|
|
94
110
|
|
|
95
111
|
## [1.7.5] - 2025-09-10
|
|
96
112
|
|
|
97
113
|
### Added
|
|
98
|
-
-
|
|
99
|
-
-
|
|
100
|
-
-
|
|
101
|
-
-
|
|
114
|
+
- Add `Context#fetch_or_store` method for atomic get-or-set operations
|
|
115
|
+
- Add `Result#ctx` alias for `Result#context`
|
|
116
|
+
- Add `Result#ok?` alias for `Result#good?`
|
|
117
|
+
- Add result deconstruction support for pattern matching
|
|
102
118
|
|
|
103
119
|
## [1.7.4] - 2025-09-03
|
|
104
120
|
|
|
105
121
|
### Added
|
|
106
|
-
-
|
|
107
|
-
-
|
|
122
|
+
- Add errors delegation from result object
|
|
123
|
+
- Add `Errors#full_messages` and `Errors#to_hash` methods
|
|
108
124
|
|
|
109
125
|
## [1.7.3] - 2025-09-03
|
|
110
126
|
|
|
111
127
|
### Changed
|
|
112
|
-
-
|
|
113
|
-
-
|
|
128
|
+
- Use generic validation reason values
|
|
129
|
+
- Move validation full message to `:full_message` key in metadata
|
|
114
130
|
|
|
115
131
|
## [1.7.2] - 2025-09-03
|
|
116
132
|
|
|
117
133
|
### Changed
|
|
118
|
-
-
|
|
134
|
+
- Set correlation ID before proceeding to subsequent execution steps
|
|
119
135
|
|
|
120
136
|
## [1.7.1] - 2025-08-26
|
|
121
137
|
|
|
122
138
|
### Added
|
|
123
|
-
-
|
|
139
|
+
- Add block yielding support to `execute` and `execute!` methods
|
|
124
140
|
|
|
125
141
|
## [1.7.0] - 2025-08-25
|
|
126
142
|
|
|
127
143
|
### Added
|
|
128
|
-
-
|
|
144
|
+
- Add workflow generator
|
|
129
145
|
|
|
130
146
|
### Changed
|
|
131
|
-
-
|
|
132
|
-
-
|
|
147
|
+
- Integrate `cmdx-parallel` functionality into core
|
|
148
|
+
- Integrate `cmdx-i18n` functionality into core
|
|
133
149
|
|
|
134
150
|
## [1.6.2] - 2025-08-24
|
|
135
151
|
|
|
136
152
|
### Changed
|
|
137
|
-
-
|
|
138
|
-
-
|
|
153
|
+
- Prefix railtie I18n with `::` for `CMDx::I18n` compatibility
|
|
154
|
+
- Switch to `cmdx-rspec` for matcher support
|
|
139
155
|
|
|
140
156
|
## [1.6.1] - 2025-08-23
|
|
141
157
|
|
|
142
158
|
### Changed
|
|
143
|
-
-
|
|
144
|
-
-
|
|
159
|
+
- Log task results before freezing execution state
|
|
160
|
+
- Rename `execute_tasks_sequentially` to `execute_tasks_in_sequence`
|
|
145
161
|
|
|
146
162
|
## [1.6.0] - 2025-08-22
|
|
147
163
|
|
|
148
164
|
### Added
|
|
149
|
-
-
|
|
165
|
+
- Add workflow task `:breakpoints` support
|
|
150
166
|
|
|
151
167
|
### Changed
|
|
152
|
-
-
|
|
153
|
-
-
|
|
168
|
+
- Rename `Worker` class to `Executor`
|
|
169
|
+
- Extract workflow execution logic into `Pipeline` class
|
|
154
170
|
|
|
155
171
|
## [1.5.2] - 2025-08-22
|
|
156
172
|
|
|
157
173
|
### Changed
|
|
158
|
-
-
|
|
174
|
+
- Rename workflow `execution_groups` attribute to `pipeline`
|
|
159
175
|
|
|
160
176
|
## [1.5.1] - 2025-08-21
|
|
161
177
|
|
|
162
178
|
### Changed
|
|
163
|
-
-
|
|
164
|
-
-
|
|
165
|
-
-
|
|
179
|
+
- Prefix locale I18n with `::` for `CMDx::I18n` compatibility
|
|
180
|
+
- Add safe navigation to length and numeric validators
|
|
181
|
+
- Fix railtie file path to reference correct directory
|
|
166
182
|
|
|
167
183
|
## [1.5.0] - 2025-08-21
|
|
168
184
|
|
|
169
185
|
### Changed
|
|
170
|
-
- **BREAKING**:
|
|
186
|
+
- **BREAKING**: Complete architecture redesign for improved clarity, transparency, and performance
|
|
171
187
|
|
|
172
188
|
## [1.1.2] - 2025-07-20
|
|
173
189
|
|
|
174
190
|
### Changed
|
|
175
|
-
-
|
|
191
|
+
- See git tags for changes between versions 0.1.0 and 1.1.2
|
|
176
192
|
|
|
177
193
|
## [0.1.0] - 2025-03-07
|
|
178
194
|
|
data/LICENSE.txt
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
Copyright (c) Drexed
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
|
13
|
-
all copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
THE SOFTWARE.
|
|
3
|
+
CMDx is an Open Source project licensed under the terms of the LGPLv3 license.
|
|
4
|
+
Please see <http://www.gnu.org/licenses/lgpl-3.0.html> for license text.
|
data/README.md
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<img src="./src/cmdx-light-logo.png#gh-light-mode-only" width="200" alt="CMDx Logo">
|
|
3
|
-
<img src="./src/cmdx-dark-logo.png#gh-dark-mode-only" width="200" alt="CMDx Logo">
|
|
2
|
+
<img src="./src/cmdx-light-logo.png#gh-light-mode-only" width="200" alt="CMDx Light Logo">
|
|
3
|
+
<img src="./src/cmdx-dark-logo.png#gh-dark-mode-only" width="200" alt="CMDx Dark Logo">
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
Build business logic that’s powerful, predictable, and maintainable.
|
|
8
8
|
|
|
9
|
-
[
|
|
9
|
+
[Home](https://drexed.github.io/cmdx) ·
|
|
10
|
+
[Documentation](https://drexed.github.io/cmdx/getting_started) ·
|
|
11
|
+
[Blog](https://drexed.github.io/cmdx/blog) ·
|
|
12
|
+
[Changelog](./CHANGELOG.md) ·
|
|
13
|
+
[Report Bug](https://github.com/drexed/cmdx/issues) ·
|
|
14
|
+
[Request Feature](https://github.com/drexed/cmdx/issues) ·
|
|
15
|
+
[llms.txt](https://drexed.github.io/cmdx/llms.txt) ·
|
|
16
|
+
[llms-full.txt](https://drexed.github.io/cmdx/llms-full.txt)
|
|
10
17
|
|
|
11
18
|
<img alt="Version" src="https://img.shields.io/gem/v/cmdx">
|
|
12
19
|
<img alt="Build" src="https://github.com/drexed/cmdx/actions/workflows/ci.yml/badge.svg">
|
|
13
|
-
<img alt="License" src="https://img.shields.io/
|
|
20
|
+
<img alt="License" src="https://img.shields.io/badge/license-LGPL%20v3-blue.svg">
|
|
14
21
|
</div>
|
|
15
22
|
|
|
16
23
|
# CMDx
|
|
@@ -18,13 +25,14 @@
|
|
|
18
25
|
Say goodbye to messy service objects. CMDx helps you design business logic with clarity and consistency—build faster, debug easier, and ship with confidence.
|
|
19
26
|
|
|
20
27
|
> [!NOTE]
|
|
21
|
-
> Documentation reflects the latest code on `main`. For version-specific documentation, please refer to the `docs/` directory within that version's tag.
|
|
28
|
+
> [Documentation](https://drexed.github.io/cmdx/getting_started/) reflects the latest code on `main`. For version-specific documentation, please refer to the `docs/` directory within that version's tag.
|
|
22
29
|
|
|
23
30
|
## Requirements
|
|
24
31
|
|
|
25
|
-
- Ruby: MRI 3.1+ or JRuby 9.4
|
|
32
|
+
- Ruby: MRI 3.1+ or JRuby 9.4+
|
|
33
|
+
- Dependencies: None
|
|
26
34
|
|
|
27
|
-
|
|
35
|
+
Rails support is built-in, but it's framework-agnostic at its core.
|
|
28
36
|
|
|
29
37
|
## Installation
|
|
30
38
|
|
|
@@ -125,4 +133,4 @@ Bug reports and pull requests are welcome at <https://github.com/drexed/cmdx>. W
|
|
|
125
133
|
|
|
126
134
|
## License
|
|
127
135
|
|
|
128
|
-
The gem is available as open source under the terms of the [
|
|
136
|
+
The gem is available as open source under the terms of the [LGPLv3 License](https://www.gnu.org/licenses/lgpl-3.0.html).
|
data/lib/cmdx/attribute.rb
CHANGED
|
@@ -72,6 +72,16 @@ module CMDx
|
|
|
72
72
|
# @rbs @types: Array[Class]
|
|
73
73
|
attr_reader :types
|
|
74
74
|
|
|
75
|
+
# Returns the description of the attribute.
|
|
76
|
+
#
|
|
77
|
+
# @return [String] The description of the attribute
|
|
78
|
+
#
|
|
79
|
+
# @example
|
|
80
|
+
# attribute.description # => "The user's name"
|
|
81
|
+
#
|
|
82
|
+
# @rbs @description: String
|
|
83
|
+
attr_reader :description
|
|
84
|
+
|
|
75
85
|
# Creates a new attribute with the specified name and configuration.
|
|
76
86
|
#
|
|
77
87
|
# @param name [Symbol, String] The name of the attribute
|
|
@@ -79,6 +89,7 @@ module CMDx
|
|
|
79
89
|
# @option options [Attribute] :parent The parent attribute for nested structures
|
|
80
90
|
# @option options [Boolean] :required Whether the attribute is required (default: false)
|
|
81
91
|
# @option options [Array<Class>, Class] :types The expected type(s) for the attribute value
|
|
92
|
+
# @option options [String] :description The description of the attribute
|
|
82
93
|
# @option options [Symbol, String, Proc] :source The source of the attribute value
|
|
83
94
|
# @option options [Symbol, String] :as The method name to use for this attribute
|
|
84
95
|
# @option options [Symbol, String, Boolean] :prefix The prefix to add to the method name
|
|
@@ -98,6 +109,7 @@ module CMDx
|
|
|
98
109
|
@parent = options.delete(:parent)
|
|
99
110
|
@required = options.delete(:required) || false
|
|
100
111
|
@types = Array(options.delete(:types) || options.delete(:type))
|
|
112
|
+
@description = options.delete(:description) || options.delete(:desc)
|
|
101
113
|
|
|
102
114
|
@name = name.to_sym
|
|
103
115
|
@options = options
|
|
@@ -235,6 +247,32 @@ module CMDx
|
|
|
235
247
|
end
|
|
236
248
|
end
|
|
237
249
|
|
|
250
|
+
# @return [Hash] A hash representation of the attribute
|
|
251
|
+
#
|
|
252
|
+
# @example
|
|
253
|
+
# attribute.to_h # => {
|
|
254
|
+
# name: :user_id,
|
|
255
|
+
# method_name: :current_user_id,
|
|
256
|
+
# description: "The user's name",
|
|
257
|
+
# required: true,
|
|
258
|
+
# types: [:integer],
|
|
259
|
+
# options: {},
|
|
260
|
+
# children: []
|
|
261
|
+
# }
|
|
262
|
+
#
|
|
263
|
+
# @rbs () -> Hash[Symbol, untyped]
|
|
264
|
+
def to_h
|
|
265
|
+
{
|
|
266
|
+
name: name,
|
|
267
|
+
method_name: method_name,
|
|
268
|
+
description: description,
|
|
269
|
+
required: required?,
|
|
270
|
+
types: types,
|
|
271
|
+
options: options.except(:if, :unless),
|
|
272
|
+
children: children.map(&:to_h)
|
|
273
|
+
}
|
|
274
|
+
end
|
|
275
|
+
|
|
238
276
|
private
|
|
239
277
|
|
|
240
278
|
# Creates nested attributes as children of this attribute.
|
|
@@ -312,11 +350,10 @@ module CMDx
|
|
|
312
350
|
attribute_value.generate
|
|
313
351
|
attribute_value.validate
|
|
314
352
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
RUBY
|
|
353
|
+
name_of_method = method_name
|
|
354
|
+
task.define_singleton_method(name_of_method) do
|
|
355
|
+
attributes[name_of_method]
|
|
356
|
+
end
|
|
320
357
|
end
|
|
321
358
|
|
|
322
359
|
end
|
data/lib/cmdx/context.rb
CHANGED
|
@@ -185,6 +185,22 @@ module CMDx
|
|
|
185
185
|
end
|
|
186
186
|
alias delete delete!
|
|
187
187
|
|
|
188
|
+
# Clears all key-value pairs from the context.
|
|
189
|
+
#
|
|
190
|
+
# @return [Context] self for method chaining
|
|
191
|
+
#
|
|
192
|
+
# @example
|
|
193
|
+
# context = Context.new(name: "John")
|
|
194
|
+
# context.clear!
|
|
195
|
+
# context.to_h # => {}
|
|
196
|
+
#
|
|
197
|
+
# @rbs () -> self
|
|
198
|
+
def clear!
|
|
199
|
+
table.clear
|
|
200
|
+
self
|
|
201
|
+
end
|
|
202
|
+
alias clear clear!
|
|
203
|
+
|
|
188
204
|
# Compares this context with another object for equality.
|
|
189
205
|
#
|
|
190
206
|
# @param other [Object] the object to compare with
|
data/lib/cmdx/executor.rb
CHANGED
|
@@ -138,17 +138,17 @@ module CMDx
|
|
|
138
138
|
#
|
|
139
139
|
# @rbs (Exception exception) -> bool
|
|
140
140
|
def retry_execution?(exception)
|
|
141
|
-
available_retries = (task.class.settings[:retries] || 0)
|
|
141
|
+
available_retries = Integer(task.class.settings[:retries] || 0)
|
|
142
142
|
return false unless available_retries.positive?
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
remaining_retries = available_retries -
|
|
144
|
+
current_retry = result.retries
|
|
145
|
+
remaining_retries = available_retries - current_retry
|
|
146
146
|
return false unless remaining_retries.positive?
|
|
147
147
|
|
|
148
148
|
exceptions = Array(task.class.settings[:retry_on] || StandardError)
|
|
149
149
|
return false unless exceptions.any? { |e| exception.class <= e }
|
|
150
150
|
|
|
151
|
-
result.
|
|
151
|
+
result.retries += 1
|
|
152
152
|
|
|
153
153
|
task.logger.warn do
|
|
154
154
|
reason = "[#{exception.class}] #{exception.message}"
|
|
@@ -158,13 +158,13 @@ module CMDx
|
|
|
158
158
|
jitter = task.class.settings[:retry_jitter]
|
|
159
159
|
jitter =
|
|
160
160
|
if jitter.is_a?(Symbol)
|
|
161
|
-
task.send(jitter,
|
|
161
|
+
task.send(jitter, current_retry)
|
|
162
162
|
elsif jitter.is_a?(Proc)
|
|
163
|
-
task.instance_exec(
|
|
163
|
+
task.instance_exec(current_retry, &jitter)
|
|
164
164
|
elsif jitter.respond_to?(:call)
|
|
165
|
-
jitter.call(task,
|
|
165
|
+
jitter.call(task, current_retry)
|
|
166
166
|
else
|
|
167
|
-
jitter.to_f *
|
|
167
|
+
jitter.to_f * current_retry
|
|
168
168
|
end
|
|
169
169
|
|
|
170
170
|
sleep(jitter) if jitter.positive?
|
|
@@ -320,7 +320,7 @@ module CMDx
|
|
|
320
320
|
statuses = Array(statuses).map(&:to_s).uniq
|
|
321
321
|
return unless statuses.include?(result.status)
|
|
322
322
|
|
|
323
|
-
result.rolled_back
|
|
323
|
+
result.rolled_back = true
|
|
324
324
|
task.rollback
|
|
325
325
|
end
|
|
326
326
|
|
data/lib/cmdx/result.rb
CHANGED
|
@@ -70,7 +70,7 @@ module CMDx
|
|
|
70
70
|
# @return [Hash{Symbol => Object}] Metadata hash
|
|
71
71
|
#
|
|
72
72
|
# @example
|
|
73
|
-
# result.metadata # => { duration: 1.5,
|
|
73
|
+
# result.metadata # => { duration: 1.5, code: 200, message: "Success" }
|
|
74
74
|
#
|
|
75
75
|
# @rbs @metadata: Hash[Symbol, untyped]
|
|
76
76
|
attr_reader :metadata
|
|
@@ -95,6 +95,26 @@ module CMDx
|
|
|
95
95
|
# @rbs @cause: (Exception | nil)
|
|
96
96
|
attr_reader :cause
|
|
97
97
|
|
|
98
|
+
# Returns the number of retries attempted.
|
|
99
|
+
#
|
|
100
|
+
# @return [Integer] The number of retries attempted
|
|
101
|
+
#
|
|
102
|
+
# @example
|
|
103
|
+
# result.retries # => 2
|
|
104
|
+
#
|
|
105
|
+
# @rbs @retries: Integer
|
|
106
|
+
attr_accessor :retries
|
|
107
|
+
|
|
108
|
+
# Returns whether the result has been rolled back.
|
|
109
|
+
#
|
|
110
|
+
# @return [Boolean] Whether the result has been rolled back
|
|
111
|
+
#
|
|
112
|
+
# @example
|
|
113
|
+
# result.rolled_back? # => true
|
|
114
|
+
#
|
|
115
|
+
# @rbs @rolled_back: bool
|
|
116
|
+
attr_accessor :rolled_back
|
|
117
|
+
|
|
98
118
|
def_delegators :task, :context, :chain, :errors, :dry_run?
|
|
99
119
|
alias ctx context
|
|
100
120
|
|
|
@@ -118,6 +138,7 @@ module CMDx
|
|
|
118
138
|
@metadata = {}
|
|
119
139
|
@reason = nil
|
|
120
140
|
@cause = nil
|
|
141
|
+
@retries = 0
|
|
121
142
|
@rolled_back = false
|
|
122
143
|
end
|
|
123
144
|
|
|
@@ -420,15 +441,14 @@ module CMDx
|
|
|
420
441
|
failed? && !caused_failure?
|
|
421
442
|
end
|
|
422
443
|
|
|
423
|
-
# @return [
|
|
444
|
+
# @return [Boolean] Whether the result has been retried
|
|
424
445
|
#
|
|
425
446
|
# @example
|
|
426
|
-
# result.
|
|
427
|
-
# result.rolled_back? # => true
|
|
447
|
+
# result.retried? # => true
|
|
428
448
|
#
|
|
429
|
-
# @rbs () ->
|
|
430
|
-
def
|
|
431
|
-
|
|
449
|
+
# @rbs () -> bool
|
|
450
|
+
def retried?
|
|
451
|
+
retries.positive?
|
|
432
452
|
end
|
|
433
453
|
|
|
434
454
|
# @return [Boolean] Whether the result has been rolled back
|
data/lib/cmdx/task.rb
CHANGED
|
@@ -217,6 +217,25 @@ module CMDx
|
|
|
217
217
|
end
|
|
218
218
|
alias remove_attribute remove_attributes
|
|
219
219
|
|
|
220
|
+
# @return [Hash] Hash of attribute names to their configurations
|
|
221
|
+
#
|
|
222
|
+
# @example
|
|
223
|
+
# MyTask.attributes_schema #=> {
|
|
224
|
+
# user_id: { name: :user_id, method_name: :user_id, required: true, types: [:integer], options: {}, children: [] },
|
|
225
|
+
# email: { name: :email, method_name: :email, required: false, types: [:string], options: { default: nil }, children: [] },
|
|
226
|
+
# profile: { name: :profile, method_name: :profile, required: false, types: [:hash], options: {}, children: [
|
|
227
|
+
# { name: :bio, method_name: :bio, required: false, types: [:string], options: {}, children: [] },
|
|
228
|
+
# { name: :name, method_name: :name, required: true, types: [:string], options: {}, children: [] }
|
|
229
|
+
# ] }
|
|
230
|
+
# }
|
|
231
|
+
#
|
|
232
|
+
# @rbs () -> Hash[Symbol, Hash[Symbol, untyped]]
|
|
233
|
+
def attributes_schema
|
|
234
|
+
Array(settings[:attributes]).each_with_object({}) do |attr, schema|
|
|
235
|
+
schema[attr.method_name] = attr.to_h
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
220
239
|
CallbackRegistry::TYPES.each do |callback|
|
|
221
240
|
# @param callables [Array] Callable objects to register as callbacks
|
|
222
241
|
# @param options [Hash] Options for the callback registration
|
|
@@ -29,6 +29,7 @@ module CMDx
|
|
|
29
29
|
# @rbs (?Hash[Symbol, Class]? registry) -> void
|
|
30
30
|
def initialize(registry = nil)
|
|
31
31
|
@registry = registry || {
|
|
32
|
+
absence: Validators::Absence,
|
|
32
33
|
exclusion: Validators::Exclusion,
|
|
33
34
|
format: Validators::Format,
|
|
34
35
|
inclusion: Validators::Inclusion,
|