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.
- checksums.yaml +4 -4
- data/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +3 -3
- data/.cursor/prompts/llms.md +1 -3
- data/.cursor/prompts/yardoc.md +1 -0
- data/.irbrc +14 -2
- data/CHANGELOG.md +64 -45
- data/LLM.md +159 -53
- data/README.md +26 -83
- data/docs/.DS_Store +0 -0
- data/docs/assets/favicon.ico +0 -0
- data/docs/assets/favicon.svg +1 -0
- data/docs/attributes/coercions.md +12 -24
- data/docs/attributes/defaults.md +3 -16
- data/docs/attributes/definitions.md +16 -30
- data/docs/attributes/naming.md +3 -13
- data/docs/attributes/transformations.md +63 -0
- data/docs/attributes/validations.md +14 -33
- data/docs/basics/chain.md +14 -23
- data/docs/basics/context.md +13 -22
- data/docs/basics/execution.md +8 -26
- data/docs/basics/setup.md +8 -19
- data/docs/callbacks.md +19 -32
- data/docs/deprecation.md +8 -25
- data/docs/getting_started.md +109 -76
- data/docs/index.md +132 -0
- data/docs/internationalization.md +6 -18
- data/docs/interruptions/exceptions.md +10 -16
- data/docs/interruptions/faults.md +8 -25
- data/docs/interruptions/halt.md +12 -27
- data/docs/logging.md +7 -17
- data/docs/middlewares.md +13 -29
- data/docs/outcomes/result.md +21 -38
- data/docs/outcomes/states.md +8 -22
- data/docs/outcomes/statuses.md +10 -21
- data/docs/stylesheets/extra.css +42 -0
- data/docs/tips_and_tricks.md +7 -46
- data/docs/workflows.md +23 -38
- data/examples/active_record_query_tagging.md +46 -0
- data/examples/paper_trail_whatdunnit.md +39 -0
- data/lib/cmdx/attribute.rb +88 -6
- data/lib/cmdx/attribute_registry.rb +20 -0
- data/lib/cmdx/attribute_value.rb +56 -10
- data/lib/cmdx/callback_registry.rb +31 -2
- data/lib/cmdx/chain.rb +34 -1
- data/lib/cmdx/coercion_registry.rb +18 -0
- data/lib/cmdx/coercions/array.rb +2 -0
- data/lib/cmdx/coercions/big_decimal.rb +3 -0
- data/lib/cmdx/coercions/boolean.rb +5 -0
- data/lib/cmdx/coercions/complex.rb +2 -0
- data/lib/cmdx/coercions/date.rb +4 -0
- data/lib/cmdx/coercions/date_time.rb +5 -0
- data/lib/cmdx/coercions/float.rb +2 -0
- data/lib/cmdx/coercions/hash.rb +4 -0
- data/lib/cmdx/coercions/integer.rb +2 -0
- data/lib/cmdx/coercions/rational.rb +2 -0
- data/lib/cmdx/coercions/string.rb +2 -0
- data/lib/cmdx/coercions/symbol.rb +2 -0
- data/lib/cmdx/coercions/time.rb +5 -0
- data/lib/cmdx/configuration.rb +119 -3
- data/lib/cmdx/context.rb +36 -0
- data/lib/cmdx/deprecator.rb +6 -3
- data/lib/cmdx/errors.rb +22 -0
- data/lib/cmdx/executor.rb +136 -7
- data/lib/cmdx/faults.rb +14 -0
- data/lib/cmdx/identifier.rb +2 -0
- data/lib/cmdx/locale.rb +3 -0
- data/lib/cmdx/log_formatters/json.rb +2 -0
- data/lib/cmdx/log_formatters/key_value.rb +2 -0
- data/lib/cmdx/log_formatters/line.rb +2 -0
- data/lib/cmdx/log_formatters/logstash.rb +2 -0
- data/lib/cmdx/log_formatters/raw.rb +2 -0
- data/lib/cmdx/middleware_registry.rb +20 -0
- data/lib/cmdx/middlewares/correlate.rb +11 -0
- data/lib/cmdx/middlewares/runtime.rb +4 -0
- data/lib/cmdx/middlewares/timeout.rb +4 -0
- data/lib/cmdx/pipeline.rb +24 -5
- data/lib/cmdx/railtie.rb +13 -0
- data/lib/cmdx/result.rb +133 -2
- data/lib/cmdx/task.rb +103 -8
- data/lib/cmdx/utils/call.rb +2 -0
- data/lib/cmdx/utils/condition.rb +3 -0
- data/lib/cmdx/utils/format.rb +5 -0
- data/lib/cmdx/validator_registry.rb +18 -0
- data/lib/cmdx/validators/exclusion.rb +2 -0
- data/lib/cmdx/validators/format.rb +2 -0
- data/lib/cmdx/validators/inclusion.rb +2 -0
- data/lib/cmdx/validators/length.rb +14 -0
- data/lib/cmdx/validators/numeric.rb +14 -0
- data/lib/cmdx/validators/presence.rb +2 -0
- data/lib/cmdx/version.rb +4 -1
- data/lib/cmdx/workflow.rb +10 -0
- data/lib/cmdx.rb +9 -0
- data/lib/generators/cmdx/locale_generator.rb +0 -1
- data/lib/generators/cmdx/templates/install.rb +9 -0
- data/mkdocs.yml +122 -0
- data/src/cmdx-dark-logo.png +0 -0
- data/src/cmdx-favicon.svg +1 -0
- data/src/cmdx-light-logo.png +0 -0
- data/src/cmdx-logo.svg +1 -0
- metadata +14 -3
- data/lib/cmdx/freezer.rb +0 -51
- data/src/cmdx-logo.png +0 -0
    
        data/lib/cmdx/faults.rb
    CHANGED
    
    | @@ -11,6 +11,14 @@ module CMDx | |
| 11 11 |  | 
| 12 12 | 
             
                extend Forwardable
         | 
| 13 13 |  | 
| 14 | 
            +
                # Returns the result that caused this fault.
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # @return [Result] The result instance
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                # @example
         | 
| 19 | 
            +
                #   fault.result.reason # => "Validation failed"
         | 
| 20 | 
            +
                #
         | 
| 21 | 
            +
                # @rbs @result: Result
         | 
| 14 22 | 
             
                attr_reader :result
         | 
| 15 23 |  | 
| 16 24 | 
             
                def_delegators :result, :task, :context, :chain
         | 
| @@ -24,6 +32,8 @@ module CMDx | |
| 24 32 | 
             
                # @example
         | 
| 25 33 | 
             
                #   fault = Fault.new(task_result)
         | 
| 26 34 | 
             
                #   fault.result.reason # => "Task validation failed"
         | 
| 35 | 
            +
                #
         | 
| 36 | 
            +
                # @rbs (Result result) -> void
         | 
| 27 37 | 
             
                def initialize(result)
         | 
| 28 38 | 
             
                  @result = result
         | 
| 29 39 |  | 
| @@ -41,6 +51,8 @@ module CMDx | |
| 41 51 | 
             
                  # @example
         | 
| 42 52 | 
             
                  #   Fault.for?(UserTask, AdminUserTask)
         | 
| 43 53 | 
             
                  #   # => true if fault.task is a UserTask or AdminUserTask
         | 
| 54 | 
            +
                  #
         | 
| 55 | 
            +
                  # @rbs (*Class tasks) -> Class
         | 
| 44 56 | 
             
                  def for?(*tasks)
         | 
| 45 57 | 
             
                    temp_fault = Class.new(self) do
         | 
| 46 58 | 
             
                      def self.===(other)
         | 
| @@ -62,6 +74,8 @@ module CMDx | |
| 62 74 | 
             
                  # @example
         | 
| 63 75 | 
             
                  #   Fault.matches? { |fault| fault.result.metadata[:critical] }
         | 
| 64 76 | 
             
                  #   # => true if fault has critical metadata
         | 
| 77 | 
            +
                  #
         | 
| 78 | 
            +
                  # @rbs () { (Fault) -> bool } -> Class
         | 
| 65 79 | 
             
                  def matches?(&block)
         | 
| 66 80 | 
             
                    raise ArgumentError, "block required" unless block_given?
         | 
| 67 81 |  | 
    
        data/lib/cmdx/identifier.rb
    CHANGED
    
    
    
        data/lib/cmdx/locale.rb
    CHANGED
    
    | @@ -8,6 +8,7 @@ module CMDx | |
| 8 8 |  | 
| 9 9 | 
             
                extend self
         | 
| 10 10 |  | 
| 11 | 
            +
                # @rbs EN: Hash[String, untyped]
         | 
| 11 12 | 
             
                EN = YAML.load_file(CMDx.gem_path.join("lib/locales/en.yml")).freeze
         | 
| 12 13 | 
             
                private_constant :EN
         | 
| 13 14 |  | 
| @@ -34,6 +35,8 @@ module CMDx | |
| 34 35 | 
             
                # @example With fallback
         | 
| 35 36 | 
             
                #   Locale.translate("missing.key", default: "Custom fallback message")
         | 
| 36 37 | 
             
                #   # => "Custom fallback message"
         | 
| 38 | 
            +
                #
         | 
| 39 | 
            +
                # @rbs ((String | Symbol) key, **untyped options) -> String
         | 
| 37 40 | 
             
                def translate(key, **options)
         | 
| 38 41 | 
             
                  options[:default] ||= EN.dig("en", *key.to_s.split("."))
         | 
| 39 42 | 
             
                  return ::I18n.t(key, **options) if defined?(::I18n)
         | 
| @@ -21,6 +21,8 @@ module CMDx | |
| 21 21 | 
             
                  # @example Basic usage
         | 
| 22 22 | 
             
                  #   logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
         | 
| 23 23 | 
             
                  #   # => '{"severity":"INFO","timestamp":"2024-01-15T10:30:45.123456Z","progname":"MyApp","pid":12345,"message":"User logged in"}\n'
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # @rbs (String severity, Time time, String? progname, String message) -> String
         | 
| 24 26 | 
             
                  def call(severity, time, progname, message)
         | 
| 25 27 | 
             
                    hash = {
         | 
| 26 28 | 
             
                      severity:,
         | 
| @@ -21,6 +21,8 @@ module CMDx | |
| 21 21 | 
             
                  # @example Basic usage
         | 
| 22 22 | 
             
                  #   logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
         | 
| 23 23 | 
             
                  #   # => "severity=INFO timestamp=2024-01-15T10:30:45.123456Z progname=MyApp pid=12345 message=User logged in\n"
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # @rbs (String severity, Time time, String? progname, String message) -> String
         | 
| 24 26 | 
             
                  def call(severity, time, progname, message)
         | 
| 25 27 | 
             
                    hash = {
         | 
| 26 28 | 
             
                      severity:,
         | 
| @@ -21,6 +21,8 @@ module CMDx | |
| 21 21 | 
             
                  # @example Basic usage
         | 
| 22 22 | 
             
                  #   logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
         | 
| 23 23 | 
             
                  #   # => "I, [2024-01-15T10:30:45.123456Z #12345] INFO -- MyApp: User logged in\n"
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # @rbs (String severity, Time time, String? progname, String message) -> String
         | 
| 24 26 | 
             
                  def call(severity, time, progname, message)
         | 
| 25 27 | 
             
                    "#{severity[0]}, [#{time.utc.iso8601(6)} ##{Process.pid}] #{severity} -- #{progname}: #{message}\n"
         | 
| 26 28 | 
             
                  end
         | 
| @@ -22,6 +22,8 @@ module CMDx | |
| 22 22 | 
             
                  # @example Basic usage
         | 
| 23 23 | 
             
                  #   logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
         | 
| 24 24 | 
             
                  #   # => '{"severity":"INFO","progname":"MyApp","pid":12345,"message":"User logged in","@version":"1","@timestamp":"2024-01-15T10:30:45.123456Z"}\n'
         | 
| 25 | 
            +
                  #
         | 
| 26 | 
            +
                  # @rbs (String severity, Time time, String? progname, String message) -> String
         | 
| 25 27 | 
             
                  def call(severity, time, progname, message)
         | 
| 26 28 | 
             
                    hash = {
         | 
| 27 29 | 
             
                      severity:,
         | 
| @@ -22,6 +22,8 @@ module CMDx | |
| 22 22 | 
             
                  # @example Basic usage
         | 
| 23 23 | 
             
                  #   logger_formatter.call("INFO", Time.now, "MyApp", "User logged in")
         | 
| 24 24 | 
             
                  #   # => "User logged in\n"
         | 
| 25 | 
            +
                  #
         | 
| 26 | 
            +
                  # @rbs (String severity, Time time, String? progname, String message) -> String
         | 
| 25 27 | 
             
                  def call(severity, time, progname, message)
         | 
| 26 28 | 
             
                    "#{message}\n"
         | 
| 27 29 | 
             
                  end
         | 
| @@ -9,6 +9,14 @@ module CMDx | |
| 9 9 | 
             
              # they were registered.
         | 
| 10 10 | 
             
              class MiddlewareRegistry
         | 
| 11 11 |  | 
| 12 | 
            +
                # Returns the ordered collection of middleware entries.
         | 
| 13 | 
            +
                #
         | 
| 14 | 
            +
                # @return [Array<Array>] Array of middleware-options pairs
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # @example
         | 
| 17 | 
            +
                #   registry.registry # => [[LoggingMiddleware, {level: :debug}], [AuthMiddleware, {}]]
         | 
| 18 | 
            +
                #
         | 
| 19 | 
            +
                # @rbs @registry: Array[Array[untyped]]
         | 
| 12 20 | 
             
                attr_reader :registry
         | 
| 13 21 | 
             
                alias to_a registry
         | 
| 14 22 |  | 
| @@ -19,6 +27,8 @@ module CMDx | |
| 19 27 | 
             
                # @example
         | 
| 20 28 | 
             
                #   registry = MiddlewareRegistry.new
         | 
| 21 29 | 
             
                #   registry = MiddlewareRegistry.new([[MyMiddleware, {option: 'value'}]])
         | 
| 30 | 
            +
                #
         | 
| 31 | 
            +
                # @rbs (?Array[Array[untyped]] registry) -> void
         | 
| 22 32 | 
             
                def initialize(registry = [])
         | 
| 23 33 | 
             
                  @registry = registry
         | 
| 24 34 | 
             
                end
         | 
| @@ -29,6 +39,8 @@ module CMDx | |
| 29 39 | 
             
                #
         | 
| 30 40 | 
             
                # @example
         | 
| 31 41 | 
             
                #   new_registry = registry.dup
         | 
| 42 | 
            +
                #
         | 
| 43 | 
            +
                # @rbs () -> MiddlewareRegistry
         | 
| 32 44 | 
             
                def dup
         | 
| 33 45 | 
             
                  self.class.new(registry.map(&:dup))
         | 
| 34 46 | 
             
                end
         | 
| @@ -46,6 +58,8 @@ module CMDx | |
| 46 58 | 
             
                # @example
         | 
| 47 59 | 
             
                #   registry.register(LoggingMiddleware, at: 0, log_level: :debug)
         | 
| 48 60 | 
             
                #   registry.register(AuthMiddleware, at: -1, timeout: 30)
         | 
| 61 | 
            +
                #
         | 
| 62 | 
            +
                # @rbs (untyped middleware, ?at: Integer, **untyped options) -> self
         | 
| 49 63 | 
             
                def register(middleware, at: -1, **options)
         | 
| 50 64 | 
             
                  registry.insert(at, [middleware, options])
         | 
| 51 65 | 
             
                  self
         | 
| @@ -59,6 +73,8 @@ module CMDx | |
| 59 73 | 
             
                #
         | 
| 60 74 | 
             
                # @example
         | 
| 61 75 | 
             
                #   registry.deregister(LoggingMiddleware)
         | 
| 76 | 
            +
                #
         | 
| 77 | 
            +
                # @rbs (untyped middleware) -> self
         | 
| 62 78 | 
             
                def deregister(middleware)
         | 
| 63 79 | 
             
                  registry.reject! { |mw, _opts| mw == middleware }
         | 
| 64 80 | 
             
                  self
         | 
| @@ -79,6 +95,8 @@ module CMDx | |
| 79 95 | 
             
                #   result = registry.call!(my_task) do |processed_task|
         | 
| 80 96 | 
             
                #     processed_task.execute
         | 
| 81 97 | 
             
                #   end
         | 
| 98 | 
            +
                #
         | 
| 99 | 
            +
                # @rbs (untyped task) { (untyped) -> untyped } -> untyped
         | 
| 82 100 | 
             
                def call!(task, &)
         | 
| 83 101 | 
             
                  raise ArgumentError, "block required" unless block_given?
         | 
| 84 102 |  | 
| @@ -96,6 +114,8 @@ module CMDx | |
| 96 114 | 
             
                # @yieldparam task [Object] The processed task object
         | 
| 97 115 | 
             
                #
         | 
| 98 116 | 
             
                # @return [Object] Result of the block execution or next middleware call
         | 
| 117 | 
            +
                #
         | 
| 118 | 
            +
                # @rbs (Integer index, untyped task) { (untyped) -> untyped } -> untyped
         | 
| 99 119 | 
             
                def recursively_call_middleware(index, task, &block)
         | 
| 100 120 | 
             
                  return yield(task) if index >= registry.size
         | 
| 101 121 |  | 
| @@ -12,6 +12,7 @@ module CMDx | |
| 12 12 |  | 
| 13 13 | 
             
                  extend self
         | 
| 14 14 |  | 
| 15 | 
            +
                  # @rbs THREAD_KEY: Symbol
         | 
| 15 16 | 
             
                  THREAD_KEY = :cmdx_correlate
         | 
| 16 17 |  | 
| 17 18 | 
             
                  # Retrieves the current correlation ID from thread-local storage.
         | 
| @@ -20,6 +21,8 @@ module CMDx | |
| 20 21 | 
             
                  #
         | 
| 21 22 | 
             
                  # @example Get current correlation ID
         | 
| 22 23 | 
             
                  #   Correlate.id # => "550e8400-e29b-41d4-a716-446655440000"
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # @rbs () -> String?
         | 
| 23 26 | 
             
                  def id
         | 
| 24 27 | 
             
                    Thread.current[THREAD_KEY]
         | 
| 25 28 | 
             
                  end
         | 
| @@ -31,6 +34,8 @@ module CMDx | |
| 31 34 | 
             
                  #
         | 
| 32 35 | 
             
                  # @example Set correlation ID
         | 
| 33 36 | 
             
                  #   Correlate.id = "abc-123-def"
         | 
| 37 | 
            +
                  #
         | 
| 38 | 
            +
                  # @rbs (String id) -> String
         | 
| 34 39 | 
             
                  def id=(id)
         | 
| 35 40 | 
             
                    Thread.current[THREAD_KEY] = id
         | 
| 36 41 | 
             
                  end
         | 
| @@ -41,6 +46,8 @@ module CMDx | |
| 41 46 | 
             
                  #
         | 
| 42 47 | 
             
                  # @example Clear correlation ID
         | 
| 43 48 | 
             
                  #   Correlate.clear
         | 
| 49 | 
            +
                  #
         | 
| 50 | 
            +
                  # @rbs () -> nil
         | 
| 44 51 | 
             
                  def clear
         | 
| 45 52 | 
             
                    Thread.current[THREAD_KEY] = nil
         | 
| 46 53 | 
             
                  end
         | 
| @@ -58,6 +65,8 @@ module CMDx | |
| 58 65 | 
             
                  #     perform_operation
         | 
| 59 66 | 
             
                  #   end
         | 
| 60 67 | 
             
                  #   # Previous ID is restored
         | 
| 68 | 
            +
                  #
         | 
| 69 | 
            +
                  # @rbs (String new_id) { () -> untyped } -> untyped
         | 
| 61 70 | 
             
                  def use(new_id)
         | 
| 62 71 | 
             
                    old_id = id
         | 
| 63 72 | 
             
                    self.id = new_id
         | 
| @@ -92,6 +101,8 @@ module CMDx | |
| 92 101 | 
             
                  #   Correlate.call(task, id: -> { "dynamic-#{Time.now.to_i}" }, &block)
         | 
| 93 102 | 
             
                  # @example Conditional correlation
         | 
| 94 103 | 
             
                  #   Correlate.call(task, if: :enable_correlation, &block)
         | 
| 104 | 
            +
                  #
         | 
| 105 | 
            +
                  # @rbs (Task task, **untyped options) { () -> untyped } -> untyped
         | 
| 95 106 | 
             
                  def call(task, **options, &)
         | 
| 96 107 | 
             
                    return yield unless Utils::Condition.evaluate(task, options)
         | 
| 97 108 |  | 
| @@ -32,6 +32,8 @@ module CMDx | |
| 32 32 | 
             
                  #   Runtime.call(task, if: :enable_profiling, &block)
         | 
| 33 33 | 
             
                  # @example Disable runtime measurement
         | 
| 34 34 | 
             
                  #   Runtime.call(task, unless: :skip_profiling, &block)
         | 
| 35 | 
            +
                  #
         | 
| 36 | 
            +
                  # @rbs (Task task, **untyped options) { () -> untyped } -> untyped
         | 
| 35 37 | 
             
                  def call(task, **options)
         | 
| 36 38 | 
             
                    return yield unless Utils::Condition.evaluate(task, options)
         | 
| 37 39 |  | 
| @@ -49,6 +51,8 @@ module CMDx | |
| 49 51 | 
             
                  # timing measurements that are not affected by system clock changes.
         | 
| 50 52 | 
             
                  #
         | 
| 51 53 | 
             
                  # @return [Integer] Current monotonic time in milliseconds
         | 
| 54 | 
            +
                  #
         | 
| 55 | 
            +
                  # @rbs () -> Integer
         | 
| 52 56 | 
             
                  def monotonic_time
         | 
| 53 57 | 
             
                    Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
         | 
| 54 58 | 
             
                  end
         | 
| @@ -21,6 +21,8 @@ module CMDx | |
| 21 21 | 
             
                  extend self
         | 
| 22 22 |  | 
| 23 23 | 
             
                  # Default timeout limit in seconds when none is specified.
         | 
| 24 | 
            +
                  #
         | 
| 25 | 
            +
                  # @rbs DEFAULT_LIMIT: Integer
         | 
| 24 26 | 
             
                  DEFAULT_LIMIT = 3
         | 
| 25 27 |  | 
| 26 28 | 
             
                  # Middleware entry point that enforces execution time limits.
         | 
| @@ -51,6 +53,8 @@ module CMDx | |
| 51 53 | 
             
                  #   Timeout.call(task, seconds: -> { calculate_timeout }, &block)
         | 
| 52 54 | 
             
                  # @example Conditional timeout control
         | 
| 53 55 | 
             
                  #   Timeout.call(task, if: :enable_timeout, &block)
         | 
| 56 | 
            +
                  #
         | 
| 57 | 
            +
                  # @rbs (Task task, **untyped options) { () -> untyped } -> untyped
         | 
| 54 58 | 
             
                  def call(task, **options, &)
         | 
| 55 59 | 
             
                    return yield unless Utils::Condition.evaluate(task, options)
         | 
| 56 60 |  | 
    
        data/lib/cmdx/pipeline.rb
    CHANGED
    
    | @@ -6,7 +6,14 @@ module CMDx | |
| 6 6 | 
             
              # and handling breakpoints that can interrupt execution at specific task statuses.
         | 
| 7 7 | 
             
              class Pipeline
         | 
| 8 8 |  | 
| 9 | 
            -
                #  | 
| 9 | 
            +
                # Returns the workflow being executed by this pipeline.
         | 
| 10 | 
            +
                #
         | 
| 11 | 
            +
                # @return [Workflow] The workflow instance
         | 
| 12 | 
            +
                #
         | 
| 13 | 
            +
                # @example
         | 
| 14 | 
            +
                #   pipeline.workflow.context[:status] # => "processing"
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # @rbs @workflow: Workflow
         | 
| 10 17 | 
             
                attr_reader :workflow
         | 
| 11 18 |  | 
| 12 19 | 
             
                # @param workflow [Workflow] The workflow to execute
         | 
| @@ -15,6 +22,8 @@ module CMDx | |
| 15 22 | 
             
                #
         | 
| 16 23 | 
             
                # @example
         | 
| 17 24 | 
             
                #   pipeline = Pipeline.new(my_workflow)
         | 
| 25 | 
            +
                #
         | 
| 26 | 
            +
                # @rbs (Workflow workflow) -> void
         | 
| 18 27 | 
             
                def initialize(workflow)
         | 
| 19 28 | 
             
                  @workflow = workflow
         | 
| 20 29 | 
             
                end
         | 
| @@ -27,6 +36,8 @@ module CMDx | |
| 27 36 | 
             
                #
         | 
| 28 37 | 
             
                # @example
         | 
| 29 38 | 
             
                #   Pipeline.execute(my_workflow)
         | 
| 39 | 
            +
                #
         | 
| 40 | 
            +
                # @rbs (Workflow workflow) -> void
         | 
| 30 41 | 
             
                def self.execute(workflow)
         | 
| 31 42 | 
             
                  new(workflow).execute
         | 
| 32 43 | 
             
                end
         | 
| @@ -40,9 +51,11 @@ module CMDx | |
| 40 51 | 
             
                # @example
         | 
| 41 52 | 
             
                #   pipeline = Pipeline.new(my_workflow)
         | 
| 42 53 | 
             
                #   pipeline.execute
         | 
| 54 | 
            +
                #
         | 
| 55 | 
            +
                # @rbs () -> void
         | 
| 43 56 | 
             
                def execute
         | 
| 44 57 | 
             
                  workflow.class.pipeline.each do |group|
         | 
| 45 | 
            -
                    next unless Utils::Condition.evaluate(workflow, group.options | 
| 58 | 
            +
                    next unless Utils::Condition.evaluate(workflow, group.options)
         | 
| 46 59 |  | 
| 47 60 | 
             
                    breakpoints = group.options[:breakpoints] ||
         | 
| 48 61 | 
             
                                  workflow.class.settings[:breakpoints] ||
         | 
| @@ -65,6 +78,8 @@ module CMDx | |
| 65 78 | 
             
                #
         | 
| 66 79 | 
             
                # @example
         | 
| 67 80 | 
             
                #   execute_group_tasks(group, ["failed", "skipped"])
         | 
| 81 | 
            +
                #
         | 
| 82 | 
            +
                # @rbs (untyped group, Array[String] breakpoints) -> void
         | 
| 68 83 | 
             
                def execute_group_tasks(group, breakpoints)
         | 
| 69 84 | 
             
                  case strategy = group.options[:strategy]
         | 
| 70 85 | 
             
                  when NilClass, /sequential/ then execute_tasks_in_sequence(group, breakpoints)
         | 
| @@ -85,6 +100,8 @@ module CMDx | |
| 85 100 | 
             
                #
         | 
| 86 101 | 
             
                # @example
         | 
| 87 102 | 
             
                #   execute_tasks_in_sequence(group, ["failed", "skipped"])
         | 
| 103 | 
            +
                #
         | 
| 104 | 
            +
                # @rbs (untyped group, Array[String] breakpoints) -> void
         | 
| 88 105 | 
             
                def execute_tasks_in_sequence(group, breakpoints)
         | 
| 89 106 | 
             
                  group.tasks.each do |task|
         | 
| 90 107 | 
             
                    task_result = task.execute(workflow.context)
         | 
| @@ -107,19 +124,21 @@ module CMDx | |
| 107 124 | 
             
                #
         | 
| 108 125 | 
             
                # @example
         | 
| 109 126 | 
             
                #   execute_tasks_in_parallel(group, ["failed"])
         | 
| 127 | 
            +
                #
         | 
| 128 | 
            +
                # @rbs (untyped group, Array[String] breakpoints) -> void
         | 
| 110 129 | 
             
                def execute_tasks_in_parallel(group, breakpoints)
         | 
| 111 | 
            -
                  raise "install the `parallel` gem to use this feature" unless defined?( | 
| 130 | 
            +
                  raise "install the `parallel` gem to use this feature" unless defined?(Parallel)
         | 
| 112 131 |  | 
| 113 132 | 
             
                  parallel_options = group.options.slice(:in_threads, :in_processes)
         | 
| 114 133 | 
             
                  throwable_result = nil
         | 
| 115 134 |  | 
| 116 | 
            -
                   | 
| 135 | 
            +
                  Parallel.each(group.tasks, **parallel_options) do |task|
         | 
| 117 136 | 
             
                    Chain.current = workflow.chain
         | 
| 118 137 |  | 
| 119 138 | 
             
                    task_result = task.execute(workflow.context)
         | 
| 120 139 | 
             
                    next unless breakpoints.include?(task_result.status)
         | 
| 121 140 |  | 
| 122 | 
            -
                    raise  | 
| 141 | 
            +
                    raise Parallel::Break, throwable_result = task_result
         | 
| 123 142 | 
             
                  end
         | 
| 124 143 |  | 
| 125 144 | 
             
                  return if throwable_result.nil?
         | 
    
        data/lib/cmdx/railtie.rb
    CHANGED
    
    | @@ -21,6 +21,8 @@ module CMDx | |
| 21 21 | 
             
                #   # This initializer runs automatically when Rails starts
         | 
| 22 22 | 
             
                #   # It will load locales like en.yml, es.yml, fr.yml if they exist
         | 
| 23 23 | 
             
                #   # in the CMDx gem's locales directory
         | 
| 24 | 
            +
                #
         | 
| 25 | 
            +
                # @rbs (untyped app) -> void
         | 
| 24 26 | 
             
                initializer("cmdx.configure_locales") do |app|
         | 
| 25 27 | 
             
                  Array(app.config.i18n.available_locales).each do |locale|
         | 
| 26 28 | 
             
                    path = CMDx.gem_path.join("lib/locales/#{locale}.yml")
         | 
| @@ -32,5 +34,16 @@ module CMDx | |
| 32 34 | 
             
                  ::I18n.reload!
         | 
| 33 35 | 
             
                end
         | 
| 34 36 |  | 
| 37 | 
            +
                # Configures the backtrace cleaner for CMDx in a Rails environment.
         | 
| 38 | 
            +
                #
         | 
| 39 | 
            +
                # Sets the backtrace cleaner to the Rails backtrace cleaner.
         | 
| 40 | 
            +
                #
         | 
| 41 | 
            +
                # @rbs () -> void
         | 
| 42 | 
            +
                initializer("cmdx.backtrace_cleaner") do
         | 
| 43 | 
            +
                  CMDx.configuration.backtrace_cleaner = lambda do |backtrace|
         | 
| 44 | 
            +
                    Rails.backtrace_cleaner.clean(backtrace)
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 35 48 | 
             
              end
         | 
| 36 49 | 
             
            end
         |