cmdx 1.1.0 → 1.1.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/.cursor/prompts/docs.md +9 -0
  3. data/.cursor/prompts/rspec.md +13 -12
  4. data/.cursor/prompts/yardoc.md +11 -6
  5. data/CHANGELOG.md +13 -2
  6. data/README.md +1 -0
  7. data/docs/ai_prompts.md +269 -195
  8. data/docs/basics/call.md +124 -58
  9. data/docs/basics/chain.md +190 -160
  10. data/docs/basics/context.md +242 -154
  11. data/docs/basics/setup.md +302 -32
  12. data/docs/callbacks.md +390 -94
  13. data/docs/configuration.md +181 -65
  14. data/docs/deprecation.md +245 -0
  15. data/docs/getting_started.md +161 -39
  16. data/docs/internationalization.md +590 -70
  17. data/docs/interruptions/exceptions.md +135 -118
  18. data/docs/interruptions/faults.md +150 -125
  19. data/docs/interruptions/halt.md +134 -80
  20. data/docs/logging.md +181 -118
  21. data/docs/middlewares.md +150 -377
  22. data/docs/outcomes/result.md +140 -112
  23. data/docs/outcomes/states.md +134 -99
  24. data/docs/outcomes/statuses.md +204 -146
  25. data/docs/parameters/coercions.md +232 -281
  26. data/docs/parameters/defaults.md +224 -169
  27. data/docs/parameters/definitions.md +289 -141
  28. data/docs/parameters/namespacing.md +250 -161
  29. data/docs/parameters/validations.md +260 -133
  30. data/docs/testing.md +191 -197
  31. data/docs/workflows.md +143 -98
  32. data/lib/cmdx/callback.rb +23 -19
  33. data/lib/cmdx/callback_registry.rb +1 -3
  34. data/lib/cmdx/chain_inspector.rb +23 -23
  35. data/lib/cmdx/chain_serializer.rb +38 -19
  36. data/lib/cmdx/coercion.rb +20 -12
  37. data/lib/cmdx/coercion_registry.rb +51 -32
  38. data/lib/cmdx/configuration.rb +84 -31
  39. data/lib/cmdx/context.rb +32 -21
  40. data/lib/cmdx/core_ext/hash.rb +13 -13
  41. data/lib/cmdx/core_ext/module.rb +1 -1
  42. data/lib/cmdx/core_ext/object.rb +12 -12
  43. data/lib/cmdx/correlator.rb +60 -39
  44. data/lib/cmdx/errors.rb +105 -131
  45. data/lib/cmdx/fault.rb +66 -45
  46. data/lib/cmdx/immutator.rb +20 -21
  47. data/lib/cmdx/lazy_struct.rb +78 -70
  48. data/lib/cmdx/log_formatters/json.rb +1 -1
  49. data/lib/cmdx/log_formatters/key_value.rb +1 -1
  50. data/lib/cmdx/log_formatters/line.rb +1 -1
  51. data/lib/cmdx/log_formatters/logstash.rb +1 -1
  52. data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
  53. data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
  54. data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
  55. data/lib/cmdx/log_formatters/raw.rb +2 -2
  56. data/lib/cmdx/logger.rb +19 -14
  57. data/lib/cmdx/logger_ansi.rb +33 -17
  58. data/lib/cmdx/logger_serializer.rb +85 -24
  59. data/lib/cmdx/middleware.rb +39 -21
  60. data/lib/cmdx/middleware_registry.rb +4 -3
  61. data/lib/cmdx/parameter.rb +151 -89
  62. data/lib/cmdx/parameter_inspector.rb +34 -21
  63. data/lib/cmdx/parameter_registry.rb +36 -30
  64. data/lib/cmdx/parameter_serializer.rb +21 -14
  65. data/lib/cmdx/result.rb +136 -135
  66. data/lib/cmdx/result_ansi.rb +31 -17
  67. data/lib/cmdx/result_inspector.rb +32 -27
  68. data/lib/cmdx/result_logger.rb +23 -14
  69. data/lib/cmdx/result_serializer.rb +65 -27
  70. data/lib/cmdx/task.rb +234 -113
  71. data/lib/cmdx/task_deprecator.rb +22 -25
  72. data/lib/cmdx/task_processor.rb +89 -88
  73. data/lib/cmdx/task_serializer.rb +27 -14
  74. data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
  75. data/lib/cmdx/validator.rb +25 -16
  76. data/lib/cmdx/validator_registry.rb +53 -31
  77. data/lib/cmdx/validators/exclusion.rb +1 -1
  78. data/lib/cmdx/validators/format.rb +2 -2
  79. data/lib/cmdx/validators/inclusion.rb +2 -2
  80. data/lib/cmdx/validators/length.rb +2 -2
  81. data/lib/cmdx/validators/numeric.rb +3 -3
  82. data/lib/cmdx/validators/presence.rb +2 -2
  83. data/lib/cmdx/version.rb +1 -1
  84. data/lib/cmdx/workflow.rb +54 -33
  85. data/lib/generators/cmdx/task_generator.rb +6 -6
  86. data/lib/generators/cmdx/workflow_generator.rb +6 -6
  87. metadata +3 -1
@@ -40,7 +40,7 @@ module CMDx
40
40
  #
41
41
  # @example Range validation
42
42
  # Validators::Numeric.call(5, numeric: { within: 1..10 })
43
- # # => nil (no error raised)
43
+ # #=> nil (no error raised)
44
44
  #
45
45
  # @example Range exclusion
46
46
  # Validators::Numeric.call(5, numeric: { not_within: 1..10 })
@@ -48,7 +48,7 @@ module CMDx
48
48
  #
49
49
  # @example Min/max validation
50
50
  # Validators::Numeric.call(15, numeric: { min: 10, max: 20 })
51
- # # => nil (no error raised)
51
+ # #=> nil (no error raised)
52
52
  #
53
53
  # @example Minimum value validation
54
54
  # Validators::Numeric.call(5, numeric: { min: 10 })
@@ -56,7 +56,7 @@ module CMDx
56
56
  #
57
57
  # @example Exact value validation
58
58
  # Validators::Numeric.call(42, numeric: { is: 42 })
59
- # # => nil (no error raised)
59
+ # #=> nil (no error raised)
60
60
  #
61
61
  # @example Custom error message
62
62
  # Validators::Numeric.call(5, numeric: { min: 10, message: "Age must be at least %{min}" })
@@ -23,7 +23,7 @@ module CMDx
23
23
  #
24
24
  # @example Validating a non-empty string
25
25
  # Validators::Presence.call("hello", presence: {})
26
- # # => nil (no error raised)
26
+ # #=> nil (no error raised)
27
27
  #
28
28
  # @example Validating an empty string
29
29
  # Validators::Presence.call("", presence: {})
@@ -35,7 +35,7 @@ module CMDx
35
35
  #
36
36
  # @example Validating a non-empty array
37
37
  # Validators::Presence.call([1, 2, 3], presence: {})
38
- # # => nil (no error raised)
38
+ # #=> nil (no error raised)
39
39
  #
40
40
  # @example Validating an empty array
41
41
  # Validators::Presence.call([], presence: {})
data/lib/cmdx/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module CMDx
4
4
 
5
- VERSION = "1.1.0"
5
+ VERSION = "1.1.1"
6
6
 
7
7
  end
data/lib/cmdx/workflow.rb CHANGED
@@ -1,63 +1,86 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CMDx
4
- # Orchestrates sequential execution of multiple tasks and workflows.
4
+ # Sequential task execution orchestration system for CMDx framework.
5
5
  #
6
- # Workflow provides a way to chain multiple tasks together with conditional
7
- # execution logic and halt behavior. Tasks are organized into groups that can
8
- # be conditionally executed based on options, and execution can be halted
9
- # based on task results.
6
+ # Workflow provides declarative composition of multiple tasks into linear pipelines
7
+ # with conditional execution, context propagation, and configurable halt behavior.
8
+ # Workflows inherit from Task, gaining all task capabilities including callbacks,
9
+ # parameter validation, result tracking, and configuration while coordinating
10
+ # other tasks rather than implementing business logic directly.
10
11
  class Workflow < Task
11
12
 
12
- # Container for holding a group of tasks and their execution options.
13
+ # Data structure containing a group of tasks and their execution options.
13
14
  #
14
15
  # @!attribute [r] tasks
15
- # @return [Array<Task>] the tasks in this group
16
+ # @return [Array<Class>] array of Task or Workflow classes to execute
16
17
  # @!attribute [r] options
17
- # @return [Hash] the execution options for this group
18
+ # @return [Hash] execution options including conditional and halt configuration
18
19
  Group = Struct.new(:tasks, :options)
19
20
 
20
21
  class << self
21
22
 
22
- # Returns the collection of workflow groups defined for this workflow.
23
+ # Returns the array of workflow groups defined for this workflow class.
23
24
  #
24
- # @return [Array<Group>] array of workflow groups to be executed
25
+ # Each group contains tasks and their execution options. Groups are processed
26
+ # sequentially during workflow execution, with each group's tasks executing
27
+ # in order unless halted by a result status.
28
+ #
29
+ # @return [Array<Group>] array of workflow groups containing tasks and options
25
30
  #
26
31
  # @example Access workflow groups
27
- # MyWorkflow.workflow_groups #=> [#<Group:...>, #<Group:...>]
32
+ # class MyWorkflow < CMDx::Workflow
33
+ # process TaskA, TaskB
34
+ # process TaskC, if: :condition_met?
35
+ # end
36
+ #
37
+ # MyWorkflow.workflow_groups.size #=> 2
38
+ # MyWorkflow.workflow_groups.first.tasks #=> [TaskA, TaskB]
28
39
  def workflow_groups
29
40
  @workflow_groups ||= []
30
41
  end
31
42
 
32
- # Defines a group of tasks to be executed as part of this workflow.
43
+ # Declares a group of tasks to execute sequentially with optional conditions.
44
+ #
45
+ # Tasks are executed in the order specified, with shared context propagated
46
+ # between executions. Groups support conditional execution and configurable
47
+ # halt behavior to control workflow flow based on task results.
33
48
  #
34
- # @param tasks [Array<Task>] tasks to include in this workflow group
35
- # @param options [Hash] execution options for this group
36
- # @option options [Symbol, Array<Symbol>] :workflow_halt status values that will halt workflow execution
37
- # @option options [Proc] :if conditional proc that determines if this group should execute
38
- # @option options [Proc] :unless conditional proc that determines if this group should be skipped
49
+ # @param tasks [Array<Class>] Task or Workflow classes to execute in sequence
50
+ # @param options [Hash] execution configuration options
51
+ #
52
+ # @option options [Proc, Symbol, String] :if condition that must be truthy for group execution
53
+ # @option options [Proc, Symbol, String] :unless condition that must be falsy for group execution
54
+ # @option options [String, Array<String>] :workflow_halt result statuses that halt workflow execution
39
55
  #
40
56
  # @return [void]
41
57
  #
42
- # @raise [TypeError] if any task is not a Task or Workflow subclass
58
+ # @raise [TypeError] when tasks contain objects that are not Task or Workflow classes
43
59
  #
44
- # @example Define a simple workflow group
45
- # MyWorkflow.process CreateUserTask, SendEmailTask
60
+ # @example Declare sequential tasks
61
+ # class UserRegistrationWorkflow < CMDx::Workflow
62
+ # process CreateUserTask, SendWelcomeEmailTask
63
+ # end
46
64
  #
47
- # @example Define a conditional workflow group
48
- # MyWorkflow.process NotifyAdminTask, if: ->(workflow) { workflow.context.admin.active? }
65
+ # @example Declare conditional task group
66
+ # class OrderProcessingWorkflow < CMDx::Workflow
67
+ # process ValidateOrderTask
68
+ # process ChargePaymentTask, if: ->(workflow) { workflow.context.payment_required? }
69
+ # process ShipOrderTask, unless: :digital_product?
70
+ # process NotifyAdminTask, if: proc { context.admin.active? }
71
+ # end
49
72
  #
50
- # @example Define a workflow group with halt behavior
51
- # MyWorkflow.process ValidateInputTask, ProcessDataTask, workflow_halt: :failed
73
+ # @example Configure halt behavior per group
74
+ # class DataProcessingWorkflow < CMDx::Workflow
75
+ # process LoadDataTask, ValidateDataTask, workflow_halt: %w[failed skipped]
76
+ # process OptionalCleanupTask, workflow_halt: []
77
+ # end
52
78
  def process(*tasks, **options)
53
79
  workflow_groups << Group.new(
54
80
  tasks.flatten.map do |task|
55
- unless task.is_a?(Class) && (task <= Task)
56
- raise TypeError,
57
- "must be a Task or Workflow"
58
- end
81
+ next task if task.is_a?(Class) && (task <= Task)
59
82
 
60
- task
83
+ raise TypeError, "must be a Task or Workflow"
61
84
  end,
62
85
  options
63
86
  )
@@ -65,8 +88,6 @@ module CMDx
65
88
 
66
89
  end
67
90
 
68
- # Executes all workflow groups in sequence.
69
- #
70
91
  # Each group is evaluated for conditional execution, and if the group should
71
92
  # execute, all tasks in the group are called in sequence. If any task returns
72
93
  # a status that matches the workflow halt criteria, execution is halted and
@@ -76,9 +97,9 @@ module CMDx
76
97
  #
77
98
  # @raise [Fault] if a task fails and its status matches the workflow halt criteria
78
99
  #
79
- # @example Execute workflow with halt on failure
100
+ # @example Execute workflow
80
101
  # workflow = MyWorkflow.new(user_id: 123)
81
- # workflow.call # Executes all groups until halt condition is met
102
+ # workflow.call
82
103
  def call
83
104
  self.class.workflow_groups.each do |group|
84
105
  next unless cmdx_eval(group.options)
@@ -24,11 +24,11 @@ module Cmdx
24
24
  #
25
25
  # @example Generate a user task
26
26
  # rails generate cmdx:task user
27
- # # => Creates app/cmds/user_task.rb
27
+ # #=> Creates app/cmds/user_task.rb
28
28
  #
29
29
  # @example Generate a nested task
30
30
  # rails generate cmdx:task admin/users
31
- # # => Creates app/cmds/admin/users_task.rb
31
+ # #=> Creates app/cmds/admin/users_task.rb
32
32
  def copy_files
33
33
  name = file_name.sub(/_?task$/i, "")
34
34
  path = File.join("app/cmds", class_path, "#{name}_task.rb")
@@ -47,11 +47,11 @@ module Cmdx
47
47
  #
48
48
  # @example Class name without suffix
49
49
  # # Given name: "User"
50
- # class_name # => "UserTask"
50
+ # class_name #=> "UserTask"
51
51
  #
52
52
  # @example Class name with suffix
53
53
  # # Given name: "UserTask"
54
- # class_name # => "UserTask"
54
+ # class_name #=> "UserTask"
55
55
  def class_name
56
56
  @class_name ||= super.end_with?("Task") ? super : "#{super}Task"
57
57
  end
@@ -68,10 +68,10 @@ module Cmdx
68
68
  # @raise [StandardError] if neither ApplicationTask nor CMDx::Task are available
69
69
  #
70
70
  # @example With ApplicationTask defined
71
- # parent_class_name # => ApplicationTask
71
+ # parent_class_name #=> ApplicationTask
72
72
  #
73
73
  # @example Without ApplicationTask
74
- # parent_class_name # => CMDx::Task
74
+ # parent_class_name #=> CMDx::Task
75
75
  def parent_class_name
76
76
  ApplicationTask
77
77
  rescue StandardError
@@ -26,11 +26,11 @@ module Cmdx
26
26
  #
27
27
  # @example Generate a user workflow
28
28
  # rails generate cmdx:workflow user
29
- # # => Creates app/cmds/user_workflow.rb
29
+ # #=> Creates app/cmds/user_workflow.rb
30
30
  #
31
31
  # @example Generate a nested workflow
32
32
  # rails generate cmdx:workflow admin/users
33
- # # => Creates app/cmds/admin/users_workflow.rb
33
+ # #=> Creates app/cmds/admin/users_workflow.rb
34
34
  def copy_files
35
35
  name = file_name.sub(/_?workflow$/i, "")
36
36
  path = File.join("app/cmds", class_path, "#{name}_workflow.rb")
@@ -49,11 +49,11 @@ module Cmdx
49
49
  #
50
50
  # @example Class name without suffix
51
51
  # # Given name: "User"
52
- # class_name # => "UserWorkflow"
52
+ # class_name #=> "UserWorkflow"
53
53
  #
54
54
  # @example Class name with suffix
55
55
  # # Given name: "UserWorkflow"
56
- # class_name # => "UserWorkflow"
56
+ # class_name #=> "UserWorkflow"
57
57
  def class_name
58
58
  @class_name ||= super.end_with?("Workflow") ? super : "#{super}Workflow"
59
59
  end
@@ -70,10 +70,10 @@ module Cmdx
70
70
  # @raise [StandardError] if neither ApplicationWorkflow nor CMDx::Workflow are available
71
71
  #
72
72
  # @example With ApplicationWorkflow defined
73
- # parent_class_name # => ApplicationWorkflow
73
+ # parent_class_name #=> ApplicationWorkflow
74
74
  #
75
75
  # @example Without ApplicationWorkflow
76
- # parent_class_name # => CMDx::Workflow
76
+ # parent_class_name #=> CMDx::Workflow
77
77
  def parent_class_name
78
78
  ApplicationWorkflow
79
79
  rescue StandardError
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cmdx
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Juan Gomez
@@ -186,6 +186,7 @@ extensions: []
186
186
  extra_rdoc_files: []
187
187
  files:
188
188
  - ".DS_Store"
189
+ - ".cursor/prompts/docs.md"
189
190
  - ".cursor/prompts/rspec.md"
190
191
  - ".cursor/prompts/yardoc.md"
191
192
  - ".cursor/rules/cursor-instructions.mdc"
@@ -204,6 +205,7 @@ files:
204
205
  - docs/basics/setup.md
205
206
  - docs/callbacks.md
206
207
  - docs/configuration.md
208
+ - docs/deprecation.md
207
209
  - docs/getting_started.md
208
210
  - docs/internationalization.md
209
211
  - docs/interruptions/exceptions.md