cmdx 1.8.0 → 1.9.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 (103) hide show
  1. checksums.yaml +4 -4
  2. data/.DS_Store +0 -0
  3. data/.cursor/prompts/docs.md +3 -3
  4. data/.cursor/prompts/llms.md +1 -3
  5. data/.cursor/prompts/yardoc.md +1 -0
  6. data/.irbrc +14 -2
  7. data/CHANGELOG.md +64 -45
  8. data/LLM.md +159 -53
  9. data/README.md +26 -83
  10. data/docs/.DS_Store +0 -0
  11. data/docs/assets/favicon.ico +0 -0
  12. data/docs/assets/favicon.svg +1 -0
  13. data/docs/attributes/coercions.md +12 -24
  14. data/docs/attributes/defaults.md +3 -16
  15. data/docs/attributes/definitions.md +16 -30
  16. data/docs/attributes/naming.md +3 -13
  17. data/docs/attributes/transformations.md +63 -0
  18. data/docs/attributes/validations.md +14 -33
  19. data/docs/basics/chain.md +14 -23
  20. data/docs/basics/context.md +13 -22
  21. data/docs/basics/execution.md +8 -26
  22. data/docs/basics/setup.md +8 -19
  23. data/docs/callbacks.md +19 -32
  24. data/docs/deprecation.md +8 -25
  25. data/docs/getting_started.md +109 -76
  26. data/docs/index.md +132 -0
  27. data/docs/internationalization.md +6 -18
  28. data/docs/interruptions/exceptions.md +10 -16
  29. data/docs/interruptions/faults.md +8 -25
  30. data/docs/interruptions/halt.md +12 -27
  31. data/docs/logging.md +7 -17
  32. data/docs/middlewares.md +13 -29
  33. data/docs/outcomes/result.md +21 -38
  34. data/docs/outcomes/states.md +8 -22
  35. data/docs/outcomes/statuses.md +10 -21
  36. data/docs/stylesheets/extra.css +42 -0
  37. data/docs/tips_and_tricks.md +7 -46
  38. data/docs/workflows.md +23 -38
  39. data/examples/active_record_query_tagging.md +46 -0
  40. data/examples/paper_trail_whatdunnit.md +39 -0
  41. data/lib/cmdx/attribute.rb +88 -6
  42. data/lib/cmdx/attribute_registry.rb +20 -0
  43. data/lib/cmdx/attribute_value.rb +56 -10
  44. data/lib/cmdx/callback_registry.rb +31 -2
  45. data/lib/cmdx/chain.rb +34 -1
  46. data/lib/cmdx/coercion_registry.rb +18 -0
  47. data/lib/cmdx/coercions/array.rb +2 -0
  48. data/lib/cmdx/coercions/big_decimal.rb +3 -0
  49. data/lib/cmdx/coercions/boolean.rb +5 -0
  50. data/lib/cmdx/coercions/complex.rb +2 -0
  51. data/lib/cmdx/coercions/date.rb +4 -0
  52. data/lib/cmdx/coercions/date_time.rb +5 -0
  53. data/lib/cmdx/coercions/float.rb +2 -0
  54. data/lib/cmdx/coercions/hash.rb +4 -0
  55. data/lib/cmdx/coercions/integer.rb +2 -0
  56. data/lib/cmdx/coercions/rational.rb +2 -0
  57. data/lib/cmdx/coercions/string.rb +2 -0
  58. data/lib/cmdx/coercions/symbol.rb +2 -0
  59. data/lib/cmdx/coercions/time.rb +5 -0
  60. data/lib/cmdx/configuration.rb +119 -3
  61. data/lib/cmdx/context.rb +36 -0
  62. data/lib/cmdx/deprecator.rb +6 -3
  63. data/lib/cmdx/errors.rb +22 -0
  64. data/lib/cmdx/executor.rb +136 -7
  65. data/lib/cmdx/faults.rb +14 -0
  66. data/lib/cmdx/identifier.rb +2 -0
  67. data/lib/cmdx/locale.rb +3 -0
  68. data/lib/cmdx/log_formatters/json.rb +2 -0
  69. data/lib/cmdx/log_formatters/key_value.rb +2 -0
  70. data/lib/cmdx/log_formatters/line.rb +2 -0
  71. data/lib/cmdx/log_formatters/logstash.rb +2 -0
  72. data/lib/cmdx/log_formatters/raw.rb +2 -0
  73. data/lib/cmdx/middleware_registry.rb +20 -0
  74. data/lib/cmdx/middlewares/correlate.rb +11 -0
  75. data/lib/cmdx/middlewares/runtime.rb +4 -0
  76. data/lib/cmdx/middlewares/timeout.rb +4 -0
  77. data/lib/cmdx/pipeline.rb +24 -5
  78. data/lib/cmdx/railtie.rb +13 -0
  79. data/lib/cmdx/result.rb +133 -2
  80. data/lib/cmdx/task.rb +103 -8
  81. data/lib/cmdx/utils/call.rb +2 -0
  82. data/lib/cmdx/utils/condition.rb +3 -0
  83. data/lib/cmdx/utils/format.rb +5 -0
  84. data/lib/cmdx/validator_registry.rb +18 -0
  85. data/lib/cmdx/validators/exclusion.rb +2 -0
  86. data/lib/cmdx/validators/format.rb +2 -0
  87. data/lib/cmdx/validators/inclusion.rb +2 -0
  88. data/lib/cmdx/validators/length.rb +14 -0
  89. data/lib/cmdx/validators/numeric.rb +14 -0
  90. data/lib/cmdx/validators/presence.rb +2 -0
  91. data/lib/cmdx/version.rb +4 -1
  92. data/lib/cmdx/workflow.rb +10 -0
  93. data/lib/cmdx.rb +9 -0
  94. data/lib/generators/cmdx/locale_generator.rb +0 -1
  95. data/lib/generators/cmdx/templates/install.rb +9 -0
  96. data/mkdocs.yml +122 -0
  97. data/src/cmdx-dark-logo.png +0 -0
  98. data/src/cmdx-favicon.svg +1 -0
  99. data/src/cmdx-light-logo.png +0 -0
  100. data/src/cmdx-logo.svg +1 -0
  101. metadata +14 -3
  102. data/lib/cmdx/freezer.rb +0 -51
  103. data/src/cmdx-logo.png +0 -0
data/lib/cmdx/result.rb CHANGED
@@ -11,18 +11,22 @@ module CMDx
11
11
 
12
12
  extend Forwardable
13
13
 
14
+ # @rbs STATES: Array[String]
14
15
  STATES = [
15
16
  INITIALIZED = "initialized", # Initial state before execution
16
17
  EXECUTING = "executing", # Currently executing task logic
17
18
  COMPLETE = "complete", # Successfully completed execution
18
19
  INTERRUPTED = "interrupted" # Execution was halted due to failure
19
20
  ].freeze
21
+
22
+ # @rbs STATUSES: Array[String]
20
23
  STATUSES = [
21
24
  SUCCESS = "success", # Task completed successfully
22
25
  SKIPPED = "skipped", # Task was skipped intentionally
23
26
  FAILED = "failed" # Task failed due to error or validation
24
27
  ].freeze
25
28
 
29
+ # @rbs STRIP_FAILURE: Proc
26
30
  STRIP_FAILURE = proc do |hash, result, key|
27
31
  unless result.send(:"#{key}?")
28
32
  # Strip caused/threw failures since its the same info as the log line
@@ -31,7 +35,65 @@ module CMDx
31
35
  end.freeze
32
36
  private_constant :STRIP_FAILURE
33
37
 
34
- attr_reader :task, :state, :status, :metadata, :reason, :cause
38
+ # Returns the task instance associated with this result.
39
+ #
40
+ # @return [CMDx::Task] The task instance
41
+ #
42
+ # @example
43
+ # result.task.id # => "users/create"
44
+ #
45
+ # @rbs @task: Task
46
+ attr_reader :task
47
+
48
+ # Returns the current execution state of the result.
49
+ #
50
+ # @return [String] One of: "initialized", "executing", "complete", "interrupted"
51
+ #
52
+ # @example
53
+ # result.state # => "complete"
54
+ #
55
+ # @rbs @state: String
56
+ attr_reader :state
57
+
58
+ # Returns the execution status of the result.
59
+ #
60
+ # @return [String] One of: "success", "skipped", "failed"
61
+ #
62
+ # @example
63
+ # result.status # => "success"
64
+ #
65
+ # @rbs @status: String
66
+ attr_reader :status
67
+
68
+ # Returns additional metadata about the result.
69
+ #
70
+ # @return [Hash{Symbol => Object}] Metadata hash
71
+ #
72
+ # @example
73
+ # result.metadata # => { duration: 1.5, retries: 2 }
74
+ #
75
+ # @rbs @metadata: Hash[Symbol, untyped]
76
+ attr_reader :metadata
77
+
78
+ # Returns the reason for interruption (skip or failure).
79
+ #
80
+ # @return [String, nil] The reason message, or nil if not interrupted
81
+ #
82
+ # @example
83
+ # result.reason # => "Validation failed"
84
+ #
85
+ # @rbs @reason: (String | nil)
86
+ attr_reader :reason
87
+
88
+ # Returns the exception that caused the interruption.
89
+ #
90
+ # @return [Exception, nil] The causing exception, or nil if not interrupted
91
+ #
92
+ # @example
93
+ # result.cause # => #<StandardError: Connection timeout>
94
+ #
95
+ # @rbs @cause: (Exception | nil)
96
+ attr_reader :cause
35
97
 
36
98
  def_delegators :task, :context, :chain, :errors
37
99
  alias ctx context
@@ -45,6 +107,8 @@ module CMDx
45
107
  # @example
46
108
  # result = CMDx::Result.new(my_task)
47
109
  # result.state # => "initialized"
110
+ #
111
+ # @rbs (Task) -> void
48
112
  def initialize(task)
49
113
  raise TypeError, "must be a CMDx::Task" unless task.is_a?(CMDx::Task)
50
114
 
@@ -62,6 +126,8 @@ module CMDx
62
126
  # @example
63
127
  # result.initialized? # => true
64
128
  # result.executing? # => false
129
+ #
130
+ # @rbs () -> bool
65
131
  define_method(:"#{s}?") { state == s }
66
132
 
67
133
  # @param block [Proc] Block to execute conditionally
@@ -75,6 +141,8 @@ module CMDx
75
141
  # @example
76
142
  # result.handle_initialized { |r| puts "Starting execution" }
77
143
  # result.handle_complete { |r| puts "Task completed" }
144
+ #
145
+ # @rbs () { (Result) -> void } -> self
78
146
  define_method(:"handle_#{s}") do |&block|
79
147
  raise ArgumentError, "block required" unless block
80
148
 
@@ -87,6 +155,8 @@ module CMDx
87
155
  #
88
156
  # @example
89
157
  # result.executed! # Transitions to complete or interrupted
158
+ #
159
+ # @rbs () -> self
90
160
  def executed!
91
161
  success? ? complete! : interrupt!
92
162
  end
@@ -95,6 +165,8 @@ module CMDx
95
165
  #
96
166
  # @example
97
167
  # result.executed? # => true if complete? || interrupted?
168
+ #
169
+ # @rbs () -> bool
98
170
  def executed?
99
171
  complete? || interrupted?
100
172
  end
@@ -109,6 +181,8 @@ module CMDx
109
181
  #
110
182
  # @example
111
183
  # result.handle_executed { |r| puts "Task finished: #{r.outcome}" }
184
+ #
185
+ # @rbs () { (Result) -> void } -> self
112
186
  def handle_executed(&)
113
187
  raise ArgumentError, "block required" unless block_given?
114
188
 
@@ -120,6 +194,8 @@ module CMDx
120
194
  #
121
195
  # @example
122
196
  # result.executing! # Transitions from initialized to executing
197
+ #
198
+ # @rbs () -> void
123
199
  def executing!
124
200
  return if executing?
125
201
 
@@ -132,6 +208,8 @@ module CMDx
132
208
  #
133
209
  # @example
134
210
  # result.complete! # Transitions from executing to complete
211
+ #
212
+ # @rbs () -> void
135
213
  def complete!
136
214
  return if complete?
137
215
 
@@ -144,6 +222,8 @@ module CMDx
144
222
  #
145
223
  # @example
146
224
  # result.interrupt! # Transitions from executing to interrupted
225
+ #
226
+ # @rbs () -> void
147
227
  def interrupt!
148
228
  return if interrupted?
149
229
 
@@ -158,6 +238,8 @@ module CMDx
158
238
  # @example
159
239
  # result.success? # => true
160
240
  # result.failed? # => false
241
+ #
242
+ # @rbs () -> bool
161
243
  define_method(:"#{s}?") { status == s }
162
244
 
163
245
  # @param block [Proc] Block to execute conditionally
@@ -171,6 +253,8 @@ module CMDx
171
253
  # @example
172
254
  # result.handle_success { |r| puts "Task succeeded" }
173
255
  # result.handle_failed { |r| puts "Task failed: #{r.reason}" }
256
+ #
257
+ # @rbs () { (Result) -> void } -> self
174
258
  define_method(:"handle_#{s}") do |&block|
175
259
  raise ArgumentError, "block required" unless block
176
260
 
@@ -183,6 +267,8 @@ module CMDx
183
267
  #
184
268
  # @example
185
269
  # result.good? # => true if !failed?
270
+ #
271
+ # @rbs () -> bool
186
272
  def good?
187
273
  !failed?
188
274
  end
@@ -198,6 +284,8 @@ module CMDx
198
284
  #
199
285
  # @example
200
286
  # result.handle_good { |r| puts "Task completed successfully" }
287
+ #
288
+ # @rbs () { (Result) -> void } -> self
201
289
  def handle_good(&)
202
290
  raise ArgumentError, "block required" unless block_given?
203
291
 
@@ -209,6 +297,8 @@ module CMDx
209
297
  #
210
298
  # @example
211
299
  # result.bad? # => true if !success?
300
+ #
301
+ # @rbs () -> bool
212
302
  def bad?
213
303
  !success?
214
304
  end
@@ -223,6 +313,8 @@ module CMDx
223
313
  #
224
314
  # @example
225
315
  # result.handle_bad { |r| puts "Task had issues: #{r.reason}" }
316
+ #
317
+ # @rbs () { (Result) -> void } -> self
226
318
  def handle_bad(&)
227
319
  raise ArgumentError, "block required" unless block_given?
228
320
 
@@ -240,6 +332,8 @@ module CMDx
240
332
  # @example
241
333
  # result.skip!("Dependencies not met", cause: dependency_error)
242
334
  # result.skip!("Already processed", halt: false)
335
+ #
336
+ # @rbs (?String? reason, halt: bool, cause: Exception?, **untyped metadata) -> void
243
337
  def skip!(reason = nil, halt: true, cause: nil, **metadata)
244
338
  return if skipped?
245
339
 
@@ -264,6 +358,8 @@ module CMDx
264
358
  # @example
265
359
  # result.fail!("Validation failed", cause: validation_error)
266
360
  # result.fail!("Network timeout", halt: false, timeout: 30)
361
+ #
362
+ # @rbs (?String? reason, halt: bool, cause: Exception?, **untyped metadata) -> void
267
363
  def fail!(reason = nil, halt: true, cause: nil, **metadata)
268
364
  return if failed?
269
365
 
@@ -283,6 +379,8 @@ module CMDx
283
379
  #
284
380
  # @example
285
381
  # result.halt! # Raises appropriate fault based on status
382
+ #
383
+ # @rbs () -> void
286
384
  def halt!
287
385
  return if success?
288
386
 
@@ -291,7 +389,16 @@ module CMDx
291
389
 
292
390
  # Strip the first two frames (this method and the delegator)
293
391
  frames = caller_locations(3..-1)
294
- fault.set_backtrace(frames.map(&:to_s)) unless frames.empty?
392
+
393
+ unless frames.empty?
394
+ frames = frames.map(&:to_s)
395
+
396
+ if (cleaner = task.class.settings[:backtrace_cleaner])
397
+ cleaner.call(frames)
398
+ end
399
+
400
+ fault.set_backtrace(frames)
401
+ end
295
402
 
296
403
  raise(fault)
297
404
  end
@@ -306,6 +413,8 @@ module CMDx
306
413
  # @example
307
414
  # other_result = OtherTask.execute
308
415
  # result.throw!(other_result, cause: upstream_error)
416
+ #
417
+ # @rbs (Result result, halt: bool, cause: Exception?, **untyped metadata) -> void
309
418
  def throw!(result, halt: true, cause: nil, **metadata)
310
419
  raise TypeError, "must be a CMDx::Result" unless result.is_a?(Result)
311
420
 
@@ -323,6 +432,8 @@ module CMDx
323
432
  # @example
324
433
  # cause = result.caused_failure
325
434
  # puts "Caused by: #{cause.task.id}" if cause
435
+ #
436
+ # @rbs () -> Result?
326
437
  def caused_failure
327
438
  return unless failed?
328
439
 
@@ -335,6 +446,8 @@ module CMDx
335
446
  # if result.caused_failure?
336
447
  # puts "This task caused the failure"
337
448
  # end
449
+ #
450
+ # @rbs () -> bool
338
451
  def caused_failure?
339
452
  return false unless failed?
340
453
 
@@ -346,6 +459,8 @@ module CMDx
346
459
  # @example
347
460
  # thrown = result.threw_failure
348
461
  # puts "Thrown by: #{thrown.task.id}" if thrown
462
+ #
463
+ # @rbs () -> Result?
349
464
  def threw_failure
350
465
  return unless failed?
351
466
 
@@ -360,6 +475,8 @@ module CMDx
360
475
  # if result.threw_failure?
361
476
  # puts "This task threw the failure"
362
477
  # end
478
+ #
479
+ # @rbs () -> bool
363
480
  def threw_failure?
364
481
  return false unless failed?
365
482
 
@@ -372,6 +489,8 @@ module CMDx
372
489
  # if result.thrown_failure?
373
490
  # puts "This failure was thrown from another task"
374
491
  # end
492
+ #
493
+ # @rbs () -> bool
375
494
  def thrown_failure?
376
495
  failed? && !caused_failure?
377
496
  end
@@ -381,6 +500,8 @@ module CMDx
381
500
  # @example
382
501
  # position = result.index
383
502
  # puts "Task #{position + 1} of #{chain.results.count}"
503
+ #
504
+ # @rbs () -> Integer
384
505
  def index
385
506
  chain.index(self)
386
507
  end
@@ -389,6 +510,8 @@ module CMDx
389
510
  #
390
511
  # @example
391
512
  # result.outcome # => "success" or "interrupted"
513
+ #
514
+ # @rbs () -> String
392
515
  def outcome
393
516
  initialized? || thrown_failure? ? state : status
394
517
  end
@@ -398,6 +521,8 @@ module CMDx
398
521
  # @example
399
522
  # result.to_h
400
523
  # # => {state: "complete", status: "success", outcome: "success", metadata: {}}
524
+ #
525
+ # @rbs () -> Hash[Symbol, untyped]
401
526
  def to_h
402
527
  task.to_h.merge!(
403
528
  state:,
@@ -421,6 +546,8 @@ module CMDx
421
546
  #
422
547
  # @example
423
548
  # result.to_s # => "task_id=my_task state=complete status=success"
549
+ #
550
+ # @rbs () -> String
424
551
  def to_s
425
552
  Utils::Format.to_str(to_h) do |key, value|
426
553
  case key
@@ -437,6 +564,8 @@ module CMDx
437
564
  # @example
438
565
  # state, status = result.deconstruct
439
566
  # puts "State: #{state}, Status: #{status}"
567
+ #
568
+ # @rbs (*untyped) -> Array[untyped]
440
569
  def deconstruct(*)
441
570
  [state, status, reason, cause, metadata]
442
571
  end
@@ -452,6 +581,8 @@ module CMDx
452
581
  # in {bad: true}
453
582
  # puts "Task had issues"
454
583
  # end
584
+ #
585
+ # @rbs (*untyped) -> Hash[Symbol, untyped]
455
586
  def deconstruct_keys(*)
456
587
  {
457
588
  state: state,
data/lib/cmdx/task.rb CHANGED
@@ -8,10 +8,68 @@ module CMDx
8
8
 
9
9
  extend Forwardable
10
10
 
11
- attr_reader :attributes, :errors, :id, :context, :result, :chain
11
+ # Returns the hash of processed attribute values for this task.
12
+ #
13
+ # @return [Hash{Symbol => Object}] Hash of attribute names to their values
14
+ #
15
+ # @example
16
+ # task.attributes # => { user_id: 42, user_name: "John" }
17
+ #
18
+ # @rbs @attributes: Hash[Symbol, untyped]
19
+ attr_reader :attributes
20
+
21
+ # Returns the collection of validation and execution errors.
22
+ #
23
+ # @return [Errors] The errors collection
24
+ #
25
+ # @example
26
+ # task.errors.to_h # => { email: ["must be valid"] }
27
+ #
28
+ # @rbs @errors: Errors
29
+ attr_reader :errors
30
+
31
+ # Returns the unique identifier for this task instance.
32
+ #
33
+ # @return [String] The task identifier
34
+ #
35
+ # @example
36
+ # task.id # => "abc123xyz"
37
+ #
38
+ # @rbs @id: String
39
+ attr_reader :id
40
+
41
+ # Returns the execution context for this task.
42
+ #
43
+ # @return [Context] The context instance
44
+ #
45
+ # @example
46
+ # task.context[:user_id] # => 42
47
+ #
48
+ # @rbs @context: Context
49
+ attr_reader :context
12
50
  alias ctx context
51
+
52
+ # Returns the execution result for this task.
53
+ #
54
+ # @return [Result] The result instance
55
+ #
56
+ # @example
57
+ # task.result.status # => "success"
58
+ #
59
+ # @rbs @result: Result
60
+ attr_reader :result
13
61
  alias res result
14
62
 
63
+ # Returns the execution chain containing all task results.
64
+ #
65
+ # @return [Chain] The chain instance
66
+ #
67
+ # @example
68
+ # task.chain.results.size # => 3
69
+ #
70
+ # @rbs @chain: Chain
71
+ attr_reader :chain
72
+
15
73
  def_delegators :result, :skip!, :fail!, :throw!
16
74
 
17
75
  # @param context [Hash, Context] The initial context for the task
@@ -25,6 +83,8 @@ module CMDx
25
83
  # @example
26
84
  # task = MyTask.new(name: "example", priority: :high)
27
85
  # task = MyTask.new(Context.build(name: "example"))
86
+ #
87
+ # @rbs (untyped context) -> void
28
88
  def initialize(context = {})
29
89
  Deprecator.restrict(self)
30
90
 
@@ -40,9 +100,6 @@ module CMDx
40
100
  class << self
41
101
 
42
102
  # @param options [Hash] Configuration options to merge with existing settings
43
- # @option options [AttributeRegistry] :attributes Registry for task attributes
44
- # @option options [Boolean] :deprecate Whether the task is deprecated
45
- # @option options [Array<Symbol>] :tags Tags associated with the task
46
103
  #
47
104
  # @return [Hash] The merged settings hash
48
105
  #
@@ -50,17 +107,27 @@ module CMDx
50
107
  # class MyTask < Task
51
108
  # settings deprecate: true, tags: [:experimental]
52
109
  # end
110
+ #
111
+ # @rbs (**untyped options) -> Hash[Symbol, untyped]
53
112
  def settings(**options)
54
113
  @settings ||= begin
55
114
  hash =
56
115
  if superclass.respond_to?(:settings)
57
- superclass.settings
116
+ parent = superclass.settings
117
+ parent
118
+ .except(:backtrace_cleaner, :exception_handler, :logger, :deprecate)
119
+ .transform_values!(&:dup)
120
+ .merge!(
121
+ backtrace_cleaner: parent[:backtrace_cleaner] || CMDx.configuration.backtrace_cleaner,
122
+ exception_handler: parent[:exception_handler] || CMDx.configuration.exception_handler,
123
+ logger: parent[:logger] || CMDx.configuration.logger,
124
+ deprecate: parent[:deprecate]
125
+ )
58
126
  else
59
- CMDx.configuration.to_h.except(:logger)
60
- end.transform_values(&:dup)
127
+ CMDx.configuration.to_h
128
+ end
61
129
 
62
130
  hash[:attributes] ||= AttributeRegistry.new
63
- hash[:deprecate] ||= false
64
131
  hash[:tags] ||= []
65
132
 
66
133
  hash.merge!(options)
@@ -76,6 +143,8 @@ module CMDx
76
143
  # @example
77
144
  # register(:attribute, MyAttribute.new)
78
145
  # register(:callback, :before, -> { puts "before" })
146
+ #
147
+ # @rbs (Symbol type, untyped object, *untyped) -> void
79
148
  def register(type, object, ...)
80
149
  case type
81
150
  when :attribute then settings[:attributes].register(object, ...)
@@ -96,6 +165,8 @@ module CMDx
96
165
  # @example
97
166
  # deregister(:attribute, :name)
98
167
  # deregister(:callback, :before, MyCallback)
168
+ #
169
+ # @rbs (Symbol type, untyped object, *untyped) -> void
99
170
  def deregister(type, object, ...)
100
171
  case type
101
172
  when :attribute then settings[:attributes].deregister(object, ...)
@@ -112,6 +183,8 @@ module CMDx
112
183
  # @example
113
184
  # attributes :name, :email
114
185
  # attributes :age, type: Integer, default: 18
186
+ #
187
+ # @rbs (*untyped) -> void
115
188
  def attributes(...)
116
189
  register(:attribute, Attribute.build(...))
117
190
  end
@@ -122,6 +195,8 @@ module CMDx
122
195
  # @example
123
196
  # optional :description, :notes
124
197
  # optional :priority, type: Symbol, default: :normal
198
+ #
199
+ # @rbs (*untyped) -> void
125
200
  def optional(...)
126
201
  register(:attribute, Attribute.optional(...))
127
202
  end
@@ -131,6 +206,8 @@ module CMDx
131
206
  # @example
132
207
  # required :name, :email
133
208
  # required :age, type: Integer, min: 0
209
+ #
210
+ # @rbs (*untyped) -> void
134
211
  def required(...)
135
212
  register(:attribute, Attribute.required(...))
136
213
  end
@@ -139,6 +216,8 @@ module CMDx
139
216
  #
140
217
  # @example
141
218
  # remove_attributes :old_field, :deprecated_field
219
+ #
220
+ # @rbs (*Symbol names) -> void
142
221
  def remove_attributes(*names)
143
222
  deregister(:attribute, names)
144
223
  end
@@ -155,6 +234,8 @@ module CMDx
155
234
  # before { puts "before execution" }
156
235
  # after :cleanup, priority: :high
157
236
  # around ->(task) { task.logger.info("starting") }
237
+ #
238
+ # @rbs (*untyped callables, **untyped options) ?{ () -> void } -> void
158
239
  define_method(callback) do |*callables, **options, &block|
159
240
  register(:callback, callback, *callables, **options, &block)
160
241
  end
@@ -169,6 +250,8 @@ module CMDx
169
250
  # if result.success?
170
251
  # puts "Task completed successfully"
171
252
  # end
253
+ #
254
+ # @rbs (*untyped args, **untyped kwargs) ?{ (Result) -> void } -> Result
172
255
  def execute(*args, **kwargs)
173
256
  task = new(*args, **kwargs)
174
257
  task.execute(raise: false)
@@ -184,6 +267,8 @@ module CMDx
184
267
  # @example
185
268
  # result = MyTask.execute!(name: "example")
186
269
  # # Will raise an exception if execution fails
270
+ #
271
+ # @rbs (*untyped args, **untyped kwargs) ?{ (Result) -> void } -> Result
187
272
  def execute!(*args, **kwargs)
188
273
  task = new(*args, **kwargs)
189
274
  task.execute(raise: true)
@@ -199,6 +284,8 @@ module CMDx
199
284
  # @example
200
285
  # result = task.execute
201
286
  # result = task.execute(raise: true)
287
+ #
288
+ # @rbs (raise: bool) ?{ (Result) -> void } -> Result
202
289
  def execute(raise: false)
203
290
  Executor.execute(self, raise:)
204
291
  block_given? ? yield(result) : result
@@ -213,6 +300,8 @@ module CMDx
213
300
  # puts "Performing work..."
214
301
  # end
215
302
  # end
303
+ #
304
+ # @rbs () -> void
216
305
  def work
217
306
  raise UndefinedMethodError, "undefined method #{self.class.name}#work"
218
307
  end
@@ -222,6 +311,8 @@ module CMDx
222
311
  # @example
223
312
  # logger.info "Starting task execution"
224
313
  # logger.error "Task failed", error: exception
314
+ #
315
+ # @rbs () -> Logger
225
316
  def logger
226
317
  @logger ||= begin
227
318
  logger = self.class.settings[:logger] || CMDx.configuration.logger
@@ -244,6 +335,8 @@ module CMDx
244
335
  # task_hash = task.to_h
245
336
  # puts "Task type: #{task_hash[:type]}"
246
337
  # puts "Task tags: #{task_hash[:tags].join(', ')}"
338
+ #
339
+ # @rbs () -> Hash[Symbol, untyped]
247
340
  def to_h
248
341
  {
249
342
  index: result.index,
@@ -260,6 +353,8 @@ module CMDx
260
353
  # @example
261
354
  # puts task.to_s
262
355
  # # Output: "Task[MyTask] tags: [:important] id: abc123"
356
+ #
357
+ # @rbs () -> String
263
358
  def to_s
264
359
  Utils::Format.to_str(to_h)
265
360
  end
@@ -32,6 +32,8 @@ module CMDx
32
32
  # @example Invoking a callable object
33
33
  # callable = MyCallable.new
34
34
  # Call.invoke(user, callable, 'data')
35
+ #
36
+ # @rbs (untyped target, (Symbol | Proc | untyped) callable, *untyped args, **untyped kwargs) ?{ () -> untyped } -> untyped
35
37
  def invoke(target, callable, *args, **kwargs, &)
36
38
  if callable.is_a?(Symbol)
37
39
  target.send(callable, *args, **kwargs, &)
@@ -11,6 +11,7 @@ module CMDx
11
11
 
12
12
  extend self
13
13
 
14
+ # @rbs EVAL: Proc
14
15
  EVAL = proc do |target, callable, *args, **kwargs, &block|
15
16
  case callable
16
17
  when NilClass, FalseClass, TrueClass then !!callable
@@ -53,6 +54,8 @@ module CMDx
53
54
  # @example With arguments and block
54
55
  # Condition.evaluate(user, if: ->(u) { u.has_permission?(:admin) }, :admin)
55
56
  # # => true if the proc returns true when called with user and :admin
57
+ #
58
+ # @rbs (untyped target, Hash[Symbol, untyped] options, *untyped) ?{ () -> untyped } -> bool
56
59
  def evaluate(target, options, ...)
57
60
  case options
58
61
  in if: if_cond, unless: unless_cond
@@ -8,6 +8,7 @@ module CMDx
8
8
 
9
9
  extend self
10
10
 
11
+ # @rbs FORMATTER: Proc
11
12
  FORMATTER = proc do |key, value|
12
13
  "#{key}=#{value.inspect}"
13
14
  end.freeze
@@ -28,6 +29,8 @@ module CMDx
28
29
  # @example CMDx object
29
30
  # Format.to_log(CMDx::Task.new(name: "task1"))
30
31
  # # => {name: "task1"}
32
+ #
33
+ # @rbs (untyped message) -> untyped
31
34
  def to_log(message)
32
35
  if message.respond_to?(:to_h) && message.class.ancestors.any? { |a| a.to_s.start_with?("CMDx") }
33
36
  message.to_h
@@ -51,6 +54,8 @@ module CMDx
51
54
  # @example Custom formatter
52
55
  # Format.to_str({count: 5, total: 100}) { |k, v| "#{k}:#{v}" }
53
56
  # # => "count:5 total:100"
57
+ #
58
+ # @rbs (Hash[untyped, untyped] hash) ?{ (untyped, untyped) -> String } -> String
54
59
  def to_str(hash, &block)
55
60
  block ||= FORMATTER
56
61
  hash.map(&block).join(" ")