pathway 0.12.2 → 1.0.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/.github/workflows/tests.yml +2 -2
- data/CHANGELOG.md +13 -0
- data/README.md +3 -7
- data/lib/pathway/plugins/auto_deconstruct_state.rb +14 -4
- data/lib/pathway/plugins/dry_validation.rb +73 -12
- data/lib/pathway/plugins/responder.rb +3 -5
- data/lib/pathway/plugins/sequel_models.rb +15 -15
- data/lib/pathway/plugins/simple_auth.rb +1 -3
- data/lib/pathway/result.rb +16 -42
- data/lib/pathway/rspec/matchers/fail_on.rb +6 -6
- data/lib/pathway/version.rb +1 -1
- data/lib/pathway.rb +46 -61
- data/pathway.gemspec +4 -4
- metadata +22 -29
- data/lib/pathway/plugins/auto_deconstruct_state/ruby3.rb +0 -22
- data/lib/pathway/plugins/dry_validation/v0_11.rb +0 -86
- data/lib/pathway/plugins/dry_validation/v0_12.rb +0 -86
- data/lib/pathway/plugins/dry_validation/v1_0.rb +0 -78
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: dc09be062809a2afe5a1874e1da97c15be0353059116e2932d8224d0857b3899
         | 
| 4 | 
            +
              data.tar.gz: dbc788f70ba9f95bfa700c790aff1a1c2313b2802b58417e4598314263c2af6a
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: e39b0e7702a87427d242f722deb03ccf18186bb47e271a1fbb2c218bd1bde948db7fece51805a2b8de0c3f232273f624dd4c28cf743a50aa83bf00262c161cf2
         | 
| 7 | 
            +
              data.tar.gz: 2b528a4f6c8f8172294265fafe0e3751c62a3412bc67a2deeef09f124dd38a419302502e7c7be77ead661088b3ccb54c2eb0f35c65e848a0e5947117470d294f
         | 
    
        data/.github/workflows/tests.yml
    CHANGED
    
    | @@ -11,7 +11,7 @@ jobs: | |
| 11 11 | 
             
                runs-on: ubuntu-latest
         | 
| 12 12 | 
             
                strategy:
         | 
| 13 13 | 
             
                  matrix:
         | 
| 14 | 
            -
                    ruby-version: [ | 
| 14 | 
            +
                    ruby-version: [3.1, 3.2, 3.3]
         | 
| 15 15 | 
             
                steps:
         | 
| 16 16 | 
             
                - uses: actions/checkout@v3
         | 
| 17 17 | 
             
                - name: Set up Ruby
         | 
| @@ -23,7 +23,7 @@ jobs: | |
| 23 23 | 
             
                - name: Run tests
         | 
| 24 24 | 
             
                  run: bundle exec rake
         | 
| 25 25 | 
             
                - name: Coveralls GitHub Action
         | 
| 26 | 
            -
                  if: matrix.ruby-version == '3. | 
| 26 | 
            +
                  if: matrix.ruby-version == '3.3'
         | 
| 27 27 | 
             
                  uses: coverallsapp/github-action@v2
         | 
| 28 28 | 
             
                  with:
         | 
| 29 29 | 
             
                    github-token: ${{ secrets.GITHUB_TOKEN }}
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,16 @@ | |
| 1 | 
            +
            ## [1.0.0] - 2025-05-19
         | 
| 2 | 
            +
            ### Changed
         | 
| 3 | 
            +
            - Removed support for `Ruby` versions older than 3.0
         | 
| 4 | 
            +
            - Removed support for `dry-validation` versions older than 1.0
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            ## [0.12.3] - 2024-08-13
         | 
| 7 | 
            +
            ### Changed
         | 
| 8 | 
            +
            - Renamed config option `:auto_wire_options` to `:auto_wire` at `:dry_validation` plugin
         | 
| 9 | 
            +
            - Updated `Pathway::State#use` to accept block with postional parameters
         | 
| 10 | 
            +
            - Updated `Pathway::State#use` to raise an `ArgumentError` exception on invalid arguments
         | 
| 11 | 
            +
            ### Added
         | 
| 12 | 
            +
            - Provide alias `Pathway::State#use` to `Pathway::State#unwrap`
         | 
| 13 | 
            +
             | 
| 1 14 | 
             
            ## [0.12.2] - 2024-08-06
         | 
| 2 15 | 
             
            ### Added
         | 
| 3 16 | 
             
            - Add `Pathway::State#unwrap` and `Pathway::State#u` to access internal state
         | 
    
        data/README.md
    CHANGED
    
    | @@ -407,12 +407,12 @@ end | |
| 407 407 |  | 
| 408 408 | 
             
            If you are familiar with `dry-validation` you probably know it provides a way to [inject options](https://dry-rb.org/gems/dry-validation/1.4/external-dependencies/) before calling the contract.
         | 
| 409 409 |  | 
| 410 | 
            -
            In those scenarios, you must either set the ` | 
| 410 | 
            +
            In those scenarios, you must either set the `auto_wire: true` plugin argument or specify how to map options from the execution state to the contract when calling `step :validate`.
         | 
| 411 411 | 
             
            Lets see and example for the first case:
         | 
| 412 412 |  | 
| 413 413 | 
             
            ```ruby
         | 
| 414 414 | 
             
            class CreateNugget < Pathway::Operation
         | 
| 415 | 
            -
              plugin :dry_validation,  | 
| 415 | 
            +
              plugin :dry_validation, auto_wire: true
         | 
| 416 416 |  | 
| 417 417 | 
             
              context :user_name
         | 
| 418 418 |  | 
| @@ -438,7 +438,7 @@ class CreateNugget < Pathway::Operation | |
| 438 438 | 
             
            end
         | 
| 439 439 | 
             
            ```
         | 
| 440 440 |  | 
| 441 | 
            -
            Here the defined contract needs a `:user_name` option, so we tell the operation to grab the attribute with the same name from the state by activating `: | 
| 441 | 
            +
            Here the defined contract needs a `:user_name` option, so we tell the operation to grab the attribute with the same name from the state by activating `:auto_wire`, afterwards, when the validation runs, the contract will already have the user name available.
         | 
| 442 442 |  | 
| 443 443 | 
             
            Mind you, this option is `false` by default, so be sure to set it to `true` at `Pathway::Operation` if you'd rather have it enabled for all your operations.
         | 
| 444 444 |  | 
| @@ -474,10 +474,6 @@ end | |
| 474 474 |  | 
| 475 475 | 
             
            The `with:` parameter can always be specified for `step :validate`, and allows you to override the default mapping regardless if auto-wiring is active or not.
         | 
| 476 476 |  | 
| 477 | 
            -
            ##### Older versions of `dry-validation`
         | 
| 478 | 
            -
             | 
| 479 | 
            -
            Pathway supports the `dry-validation` gem down to version `0.11` (inclusive) in case you still have unmigrated code. When using versions below `1.0` the concept of contract is not present and instead of calling the `contract` method to set up your validation logic, you must use the `form` method. Everything else remains the same except, obviously, that you would have to use `dry-definition`'s [old API](https://dry-rb.org/gems/dry-validation/0.13/) which is a bit different from the current one.
         | 
| 480 | 
            -
             | 
| 481 477 | 
             
            #### `SimpleAuth` plugin
         | 
| 482 478 |  | 
| 483 479 | 
             
            This very simple plugin adds a custom step called `:authorize`, that can be used to check for permissions and halt the operation with a `:forbidden` error when they aren't fulfilled.
         | 
| @@ -1,12 +1,22 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            if RUBY_VERSION =~ /^3\./
         | 
| 4 | 
            -
              require 'pathway/plugins/auto_deconstruct_state/ruby3'
         | 
| 5 | 
            -
            end
         | 
| 6 | 
            -
             | 
| 7 3 | 
             
            module Pathway
         | 
| 8 4 | 
             
              module Plugins
         | 
| 9 5 | 
             
                module AutoDeconstructState
         | 
| 6 | 
            +
                  module DSLMethods
         | 
| 7 | 
            +
                    private
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    def _callable(callable)
         | 
| 10 | 
            +
                      if callable.is_a?(Symbol) && @operation.respond_to?(callable, true) &&
         | 
| 11 | 
            +
                        @operation.method(callable).arity != 0 &&
         | 
| 12 | 
            +
                        @operation.method(callable).parameters.all? { _1 in [:key|:keyreq|:keyrest|:block,*] }
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                        -> state { @operation.send(callable, **state) }
         | 
| 15 | 
            +
                      else
         | 
| 16 | 
            +
                        super
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                  end
         | 
| 10 20 | 
             
                end
         | 
| 11 21 | 
             
              end
         | 
| 12 22 | 
             
            end
         | 
| @@ -5,21 +5,82 @@ require 'dry/validation' | |
| 5 5 | 
             
            module Pathway
         | 
| 6 6 | 
             
              module Plugins
         | 
| 7 7 | 
             
                module DryValidation
         | 
| 8 | 
            -
                   | 
| 8 | 
            +
                  module ClassMethods
         | 
| 9 | 
            +
                    attr_reader :contract_class, :contract_options
         | 
| 10 | 
            +
                    attr_accessor :auto_wire
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    alias_method :auto_wire_options, :auto_wire
         | 
| 13 | 
            +
                    alias_method :auto_wire_options=, :auto_wire=
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    def contract(base = nil, &block)
         | 
| 16 | 
            +
                      if block_given?
         | 
| 17 | 
            +
                        base ||= _base_contract
         | 
| 18 | 
            +
                        self.contract_class = Class.new(base, &block)
         | 
| 19 | 
            +
                      elsif base
         | 
| 20 | 
            +
                        self.contract_class = base
         | 
| 21 | 
            +
                      else
         | 
| 22 | 
            +
                        raise ArgumentError, 'Either a contract class or a block must be provided'
         | 
| 23 | 
            +
                      end
         | 
| 24 | 
            +
                    end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                    def params(*args, **kwargs, &block)
         | 
| 27 | 
            +
                      contract { params(*args, **kwargs, &block) }
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    def contract_class= klass
         | 
| 31 | 
            +
                      @contract_class   = klass
         | 
| 32 | 
            +
                      @contract_options = (klass.dry_initializer.options - Dry::Validation::Contract.dry_initializer.options).map(&:target)
         | 
| 33 | 
            +
                      @builded_contract = @contract_options.empty? && klass.schema ? klass.new : nil
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                    def build_contract(**opts)
         | 
| 37 | 
            +
                      @builded_contract || contract_class.new(**opts)
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    def inherited(subclass)
         | 
| 41 | 
            +
                      super
         | 
| 42 | 
            +
                      subclass.auto_wire      = auto_wire
         | 
| 43 | 
            +
                      subclass.contract_class = contract_class
         | 
| 44 | 
            +
                    end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    private
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    def _base_contract
         | 
| 49 | 
            +
                      superclass.respond_to?(:contract_class) ? superclass.contract_class : Dry::Validation::Contract
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  module InstanceMethods
         | 
| 54 | 
            +
                    extend Forwardable
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    delegate %i[build_contract contract_options auto_wire_options auto_wire] => 'self.class'
         | 
| 57 | 
            +
                    alias_method :contract, :build_contract
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    def validate(state, with: nil)
         | 
| 60 | 
            +
                      if auto_wire && contract_options.any?
         | 
| 61 | 
            +
                        with ||= contract_options.zip(contract_options).to_h
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
                      opts = Hash(with).map { |to, from| [to, state[from]] }.to_h
         | 
| 64 | 
            +
                      validate_with(state[:input], **opts)
         | 
| 65 | 
            +
                        .then { |params| state.update(params:) }
         | 
| 66 | 
            +
                    end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    def validate_with(input, **opts)
         | 
| 69 | 
            +
                      result = contract(**opts).call(input)
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                      result.success? ? wrap(result.values.to_h) : error(:validation, details: result.errors.to_h)
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
                  end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  def self.apply(operation, auto_wire_options: (auto_wire_options_was_not_used=true; false), auto_wire: auto_wire_options)
         | 
| 9 76 | 
             
                    #:nocov:
         | 
| 10 | 
            -
                     | 
| 11 | 
            -
                       | 
| 12 | 
            -
                    elsif Gem.loaded_specs['dry-validation'].version < Gem::Version.new('0.12')
         | 
| 13 | 
            -
                      require 'pathway/plugins/dry_validation/v0_11'
         | 
| 14 | 
            -
                      operation.plugin(Plugins::DryValidation::V0_11, **kwargs)
         | 
| 15 | 
            -
                    elsif Gem.loaded_specs['dry-validation'].version < Gem::Version.new('1.0')
         | 
| 16 | 
            -
                      require 'pathway/plugins/dry_validation/v0_12'
         | 
| 17 | 
            -
                      operation.plugin(Plugins::DryValidation::V0_12, **kwargs)
         | 
| 18 | 
            -
                    else
         | 
| 19 | 
            -
                      require 'pathway/plugins/dry_validation/v1_0'
         | 
| 20 | 
            -
                      operation.plugin(Plugins::DryValidation::V1_0, **kwargs)
         | 
| 77 | 
            +
                    unless auto_wire_options_was_not_used
         | 
| 78 | 
            +
                      warn "[DEPRECATION] `auto_wire_options` is deprecated. Please use `auto_wire` instead"
         | 
| 21 79 | 
             
                    end
         | 
| 22 80 | 
             
                    #:nocov:
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    operation.auto_wire      = auto_wire
         | 
| 83 | 
            +
                    operation.contract_class = Dry::Validation::Contract
         | 
| 23 84 | 
             
                  end
         | 
| 24 85 | 
             
                end
         | 
| 25 86 | 
             
              end
         | 
| @@ -4,8 +4,8 @@ module Pathway | |
| 4 4 | 
             
              module Plugins
         | 
| 5 5 | 
             
                module Responder
         | 
| 6 6 | 
             
                  module ClassMethods
         | 
| 7 | 
            -
                     | 
| 8 | 
            -
                      result = super(*args)
         | 
| 7 | 
            +
                    def call(*args, **kwargs, &bl)
         | 
| 8 | 
            +
                      result = super(*args, **kwargs)
         | 
| 9 9 | 
             
                      block_given? ? Responder.respond(result, &bl) : result
         | 
| 10 10 | 
             
                    end
         | 
| 11 11 | 
             
                  end
         | 
| @@ -21,9 +21,7 @@ module Pathway | |
| 21 21 | 
             
                      instance_eval(&bl)
         | 
| 22 22 | 
             
                    end
         | 
| 23 23 |  | 
| 24 | 
            -
                    def success(&bl)
         | 
| 25 | 
            -
                      @ok = bl
         | 
| 26 | 
            -
                    end
         | 
| 24 | 
            +
                    def success(&bl)= @ok = bl
         | 
| 27 25 |  | 
| 28 26 | 
             
                    def failure(type = nil, &bl)
         | 
| 29 27 | 
             
                      if type.nil?
         | 
| @@ -6,33 +6,33 @@ module Pathway | |
| 6 6 | 
             
              module Plugins
         | 
| 7 7 | 
             
                module SequelModels
         | 
| 8 8 | 
             
                  module DSLMethods
         | 
| 9 | 
            -
                    def transaction(step_name = nil, & | 
| 10 | 
            -
                       | 
| 9 | 
            +
                    def transaction(step_name = nil, &dsl_bl)
         | 
| 10 | 
            +
                      raise 'must provide a step or a block but not both' if !step_name.nil? == block_given?
         | 
| 11 11 |  | 
| 12 12 | 
             
                      if step_name
         | 
| 13 13 | 
             
                        transaction { step step_name }
         | 
| 14 14 | 
             
                      else
         | 
| 15 | 
            -
                        around(-> | 
| 15 | 
            +
                        around(->(runner, _) {
         | 
| 16 16 | 
             
                          db.transaction(savepoint: true) do
         | 
| 17 | 
            -
                            raise Sequel::Rollback if  | 
| 17 | 
            +
                            raise Sequel::Rollback if runner.call.failure?
         | 
| 18 18 | 
             
                          end
         | 
| 19 | 
            -
                        }, & | 
| 19 | 
            +
                        }, &dsl_bl)
         | 
| 20 20 | 
             
                      end
         | 
| 21 21 | 
             
                    end
         | 
| 22 22 |  | 
| 23 | 
            -
                    def after_commit(step_name = nil, & | 
| 24 | 
            -
                       | 
| 23 | 
            +
                    def after_commit(step_name = nil, &dsl_bl)
         | 
| 24 | 
            +
                      raise 'must provide a step or a block but not both' if !step_name.nil? == block_given?
         | 
| 25 25 |  | 
| 26 26 | 
             
                      if step_name
         | 
| 27 27 | 
             
                        after_commit { step step_name }
         | 
| 28 28 | 
             
                      else
         | 
| 29 | 
            -
                        around(-> | 
| 30 | 
            -
                           | 
| 29 | 
            +
                        around(->(runner, state) {
         | 
| 30 | 
            +
                          dsl_copy = self.class::DSL.new(State.new(self, state.to_h.dup), self)
         | 
| 31 31 |  | 
| 32 32 | 
             
                          db.after_commit do
         | 
| 33 | 
            -
                             | 
| 33 | 
            +
                            runner.call(dsl_copy)
         | 
| 34 34 | 
             
                          end
         | 
| 35 | 
            -
                        }, & | 
| 35 | 
            +
                        }, &dsl_bl)
         | 
| 36 36 | 
             
                      end
         | 
| 37 37 | 
             
                    end
         | 
| 38 38 | 
             
                  end
         | 
| @@ -41,10 +41,10 @@ module Pathway | |
| 41 41 | 
             
                    attr_accessor :model_class, :search_field, :model_not_found
         | 
| 42 42 |  | 
| 43 43 | 
             
                    def model(model_class, search_by: model_class.primary_key, set_result_key: true, set_context_param: true, error_message: nil)
         | 
| 44 | 
            -
                      self.model_class | 
| 45 | 
            -
                      self.search_field | 
| 46 | 
            -
                      self.result_key | 
| 47 | 
            -
                      self.model_not_found | 
| 44 | 
            +
                      self.model_class     = model_class
         | 
| 45 | 
            +
                      self.search_field    = search_by
         | 
| 46 | 
            +
                      self.result_key      = Inflector.underscore(Inflector.demodulize(model_class.name)).to_sym if set_result_key
         | 
| 47 | 
            +
                      self.model_not_found = error_message || "#{Inflector.humanize(Inflector.underscore(Inflector.demodulize(model_class.name)))} not found".freeze
         | 
| 48 48 |  | 
| 49 49 | 
             
                      self.context(result_key => Contextualizer::OPTIONAL) if set_result_key && set_context_param
         | 
| 50 50 | 
             
                    end
         | 
    
        data/lib/pathway/result.rb
    CHANGED
    
    | @@ -6,13 +6,8 @@ module Pathway | |
| 6 6 | 
             
                attr_reader :value, :error
         | 
| 7 7 |  | 
| 8 8 | 
             
                class Success < Result
         | 
| 9 | 
            -
                  def initialize(value)
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                  end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                  def success?
         | 
| 14 | 
            -
                    true
         | 
| 15 | 
            -
                  end
         | 
| 9 | 
            +
                  def initialize(value) = @value = value
         | 
| 10 | 
            +
                  def success? = true
         | 
| 16 11 |  | 
| 17 12 | 
             
                  def then(bl=nil)
         | 
| 18 13 | 
             
                    result(block_given? ? yield(value): bl.call(value))
         | 
| @@ -25,29 +20,18 @@ module Pathway | |
| 25 20 |  | 
| 26 21 | 
             
                  private
         | 
| 27 22 |  | 
| 28 | 
            -
                   | 
| 23 | 
            +
                  alias_method :value_for_deconstruct, :value
         | 
| 29 24 | 
             
                end
         | 
| 30 25 |  | 
| 31 26 | 
             
                class Failure < Result
         | 
| 32 | 
            -
                  def initialize(error)
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                   | 
| 35 | 
            -
             | 
| 36 | 
            -
                  def success?
         | 
| 37 | 
            -
                    false
         | 
| 38 | 
            -
                  end
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                  def then(_=nil)
         | 
| 41 | 
            -
                    self
         | 
| 42 | 
            -
                  end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                  def tee(_=nil)
         | 
| 45 | 
            -
                    self
         | 
| 46 | 
            -
                  end
         | 
| 27 | 
            +
                  def initialize(error) = @error = error
         | 
| 28 | 
            +
                  def success? = false
         | 
| 29 | 
            +
                  def then(_=nil) = self
         | 
| 30 | 
            +
                  def tee(_=nil) = self
         | 
| 47 31 |  | 
| 48 32 | 
             
                  private
         | 
| 49 33 |  | 
| 50 | 
            -
                   | 
| 34 | 
            +
                  alias_method :value_for_deconstruct, :error
         | 
| 51 35 | 
             
                end
         | 
| 52 36 |  | 
| 53 37 | 
             
                module Mixin
         | 
| @@ -55,10 +39,16 @@ module Pathway | |
| 55 39 | 
             
                  Failure = Result::Failure
         | 
| 56 40 | 
             
                end
         | 
| 57 41 |  | 
| 58 | 
            -
                def  | 
| 59 | 
            -
             | 
| 42 | 
            +
                def self.success(value) = Success.new(value)
         | 
| 43 | 
            +
                def self.failure(error) = Failure.new(error)
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def self.result(object)
         | 
| 46 | 
            +
                  object.is_a?(Result) ? object : success(object)
         | 
| 60 47 | 
             
                end
         | 
| 61 48 |  | 
| 49 | 
            +
                def failure? = !success?
         | 
| 50 | 
            +
                def deconstruct = [value_for_deconstruct]
         | 
| 51 | 
            +
             | 
| 62 52 | 
             
                def deconstruct_keys(keys)
         | 
| 63 53 | 
             
                  if value_for_deconstruct.respond_to?(:deconstruct_keys)
         | 
| 64 54 | 
             
                    value_for_deconstruct.deconstruct_keys(keys)
         | 
| @@ -67,22 +57,6 @@ module Pathway | |
| 67 57 | 
             
                  end
         | 
| 68 58 | 
             
                end
         | 
| 69 59 |  | 
| 70 | 
            -
                def failure?
         | 
| 71 | 
            -
                  !success?
         | 
| 72 | 
            -
                end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                def self.success(value)
         | 
| 75 | 
            -
                  Success.new(value)
         | 
| 76 | 
            -
                end
         | 
| 77 | 
            -
             | 
| 78 | 
            -
                def self.failure(error)
         | 
| 79 | 
            -
                  Failure.new(error)
         | 
| 80 | 
            -
                end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                def self.result(object)
         | 
| 83 | 
            -
                  object.is_a?(Result) ? object : success(object)
         | 
| 84 | 
            -
                end
         | 
| 85 | 
            -
             | 
| 86 60 | 
             
                delegate :result => 'self.class'
         | 
| 87 61 | 
             
              end
         | 
| 88 62 | 
             
            end
         | 
| @@ -22,22 +22,22 @@ RSpec::Matchers.define :fail_on do |input| | |
| 22 22 | 
             
                @type = type
         | 
| 23 23 | 
             
              end
         | 
| 24 24 |  | 
| 25 | 
            -
               | 
| 26 | 
            -
               | 
| 25 | 
            +
              alias_method :with_type, :type
         | 
| 26 | 
            +
              alias_method :and_type, :type
         | 
| 27 27 |  | 
| 28 28 | 
             
              chain :message do |message|
         | 
| 29 29 | 
             
                @message = message
         | 
| 30 30 | 
             
              end
         | 
| 31 31 |  | 
| 32 | 
            -
               | 
| 33 | 
            -
               | 
| 32 | 
            +
              alias_method :with_message, :message
         | 
| 33 | 
            +
              alias_method :and_message, :message
         | 
| 34 34 |  | 
| 35 35 | 
             
              chain :details do |details|
         | 
| 36 36 | 
             
                @details = details
         | 
| 37 37 | 
             
              end
         | 
| 38 38 |  | 
| 39 | 
            -
               | 
| 40 | 
            -
               | 
| 39 | 
            +
              alias_method :with_details, :details
         | 
| 40 | 
            +
              alias_method :and_details, :details
         | 
| 41 41 |  | 
| 42 42 | 
             
              description do
         | 
| 43 43 | 
             
                'fail' + (@type ? " with :#@type error" : '')
         | 
    
        data/lib/pathway/version.rb
    CHANGED
    
    
    
        data/lib/pathway.rb
    CHANGED
    
    | @@ -1,6 +1,5 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            require 'ruby2_keywords'
         | 
| 4 3 | 
             
            require 'forwardable'
         | 
| 5 4 | 
             
            require 'dry/inflector'
         | 
| 6 5 | 
             
            require 'contextualizer'
         | 
| @@ -11,7 +10,7 @@ module Pathway | |
| 11 10 | 
             
              Inflector = Dry::Inflector.new
         | 
| 12 11 | 
             
              class Operation
         | 
| 13 12 | 
             
                class << self
         | 
| 14 | 
            -
                   | 
| 13 | 
            +
                  def plugin(name,...)
         | 
| 15 14 | 
             
                    require "pathway/plugins/#{Inflector.underscore(name)}" if name.is_a?(Symbol)
         | 
| 16 15 |  | 
| 17 16 | 
             
                    plugin = name.is_a?(Module) ? name : Plugins.const_get(Inflector.camelize(name))
         | 
| @@ -20,7 +19,7 @@ module Pathway | |
| 20 19 | 
             
                    self.include plugin::InstanceMethods if plugin.const_defined? :InstanceMethods
         | 
| 21 20 | 
             
                    self::DSL.include plugin::DSLMethods if plugin.const_defined? :DSLMethods
         | 
| 22 21 |  | 
| 23 | 
            -
                    plugin.apply(self | 
| 22 | 
            +
                    plugin.apply(self,...) if plugin.respond_to?(:apply)
         | 
| 24 23 | 
             
                  end
         | 
| 25 24 |  | 
| 26 25 | 
             
                  def inherited(subclass)
         | 
| @@ -45,13 +44,8 @@ module Pathway | |
| 45 44 | 
             
                  @details = details || {}
         | 
| 46 45 | 
             
                end
         | 
| 47 46 |  | 
| 48 | 
            -
                def deconstruct
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                def deconstruct_keys(_)
         | 
| 53 | 
            -
                  { type: type, message: message, details: details }
         | 
| 54 | 
            -
                end
         | 
| 47 | 
            +
                def deconstruct = [type, message, details]
         | 
| 48 | 
            +
                def deconstruct_keys(_) = { type:, message:, details: }
         | 
| 55 49 |  | 
| 56 50 | 
             
                private
         | 
| 57 51 |  | 
| @@ -62,64 +56,61 @@ module Pathway | |
| 62 56 |  | 
| 63 57 | 
             
              class State
         | 
| 64 58 | 
             
                extend Forwardable
         | 
| 59 | 
            +
                delegate %i([] []= fetch store include? values_at deconstruct_keys) => :@hash
         | 
| 65 60 |  | 
| 66 61 | 
             
                def initialize(operation, values = {})
         | 
| 67 62 | 
             
                  @hash = operation.context.merge(values)
         | 
| 68 63 | 
             
                  @result_key = operation.result_key
         | 
| 69 64 | 
             
                end
         | 
| 70 65 |  | 
| 71 | 
            -
                delegate %i([] []= fetch store include? values_at deconstruct_keys) => :@hash
         | 
| 72 | 
            -
             | 
| 73 66 | 
             
                def update(kargs)
         | 
| 74 67 | 
             
                  @hash.update(kargs)
         | 
| 75 68 | 
             
                  self
         | 
| 76 69 | 
             
                end
         | 
| 77 70 |  | 
| 78 | 
            -
                def result
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                def to_hash
         | 
| 83 | 
            -
                  @hash
         | 
| 84 | 
            -
                end
         | 
| 71 | 
            +
                def result = @hash[@result_key]
         | 
| 72 | 
            +
                def to_hash = @hash
         | 
| 85 73 |  | 
| 86 | 
            -
                def  | 
| 87 | 
            -
                  raise 'a block must be provided' if !block_given?
         | 
| 88 | 
            -
                   | 
| 89 | 
            -
             | 
| 90 | 
            -
                    raise 'only keyword arguments are supported for unwraping'
         | 
| 74 | 
            +
                def use(&bl)
         | 
| 75 | 
            +
                  raise ArgumentError, 'a block must be provided' if !block_given?
         | 
| 76 | 
            +
                  if bl.parameters in [*, [:rest|:keyrest,], *]
         | 
| 77 | 
            +
                    raise ArgumentError, 'rest arguments are not supported'
         | 
| 91 78 | 
             
                  end
         | 
| 92 79 |  | 
| 93 | 
            -
                   | 
| 94 | 
            -
             | 
| 95 | 
            -
             | 
| 96 | 
            -
             | 
| 80 | 
            +
                  keys = bl.parameters.select { _1 in :key|:keyreq, }.map(&:last)
         | 
| 81 | 
            +
                  names = bl.parameters.select { _1 in :req|:opt, }.map(&:last)
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  if keys.any? && names.any?
         | 
| 84 | 
            +
                    raise ArgumentError, 'cannot mix positional and keyword arguments'
         | 
| 85 | 
            +
                  elsif keys.any?
         | 
| 97 86 | 
             
                    bl.call(**to_hash.slice(*keys))
         | 
| 87 | 
            +
                  else
         | 
| 88 | 
            +
                    bl.call(*to_hash.values_at(*names))
         | 
| 98 89 | 
             
                  end
         | 
| 99 90 | 
             
                end
         | 
| 100 91 |  | 
| 101 92 | 
             
                alias_method :to_h, :to_hash
         | 
| 102 | 
            -
                alias_method :u, : | 
| 93 | 
            +
                alias_method :u, :use
         | 
| 94 | 
            +
                alias_method :unwrap, :use
         | 
| 103 95 | 
             
              end
         | 
| 104 96 |  | 
| 105 97 | 
             
              module Plugins
         | 
| 106 98 | 
             
                module Base
         | 
| 107 99 | 
             
                  module ClassMethods
         | 
| 108 100 | 
             
                    attr_accessor :result_key
         | 
| 109 | 
            -
             | 
| 101 | 
            +
             | 
| 102 | 
            +
                    alias_method :result_at, :result_key=
         | 
| 110 103 |  | 
| 111 104 | 
             
                    def process(&bl)
         | 
| 112 105 | 
             
                      dsl = self::DSL
         | 
| 113 106 | 
             
                      define_method(:call) do |input|
         | 
| 114 | 
            -
                        dsl.new(State.new(self, input: | 
| 107 | 
            +
                        dsl.new(State.new(self, input:), self)
         | 
| 115 108 | 
             
                           .run(&bl)
         | 
| 116 109 | 
             
                           .then(&:result)
         | 
| 117 110 | 
             
                      end
         | 
| 118 111 | 
             
                    end
         | 
| 119 112 |  | 
| 120 | 
            -
                     | 
| 121 | 
            -
                      new(ctx).call(*params)
         | 
| 122 | 
            -
                    end
         | 
| 113 | 
            +
                    def call(ctx,...) = new(ctx).call(...)
         | 
| 123 114 |  | 
| 124 115 | 
             
                    def inherited(subclass)
         | 
| 125 116 | 
             
                      super
         | 
| @@ -133,18 +124,16 @@ module Pathway | |
| 133 124 | 
             
                    delegate :result_key => 'self.class'
         | 
| 134 125 | 
             
                    delegate %i[result success failure] => Result
         | 
| 135 126 |  | 
| 136 | 
            -
                     | 
| 127 | 
            +
                    alias_method :wrap, :result
         | 
| 137 128 |  | 
| 138 | 
            -
                    def call(*)
         | 
| 139 | 
            -
                      fail 'must implement at subclass'
         | 
| 140 | 
            -
                    end
         | 
| 129 | 
            +
                    def call(*) = raise 'must implement at subclass'
         | 
| 141 130 |  | 
| 142 131 | 
             
                    def error(type, message: nil, details: nil)
         | 
| 143 | 
            -
                      failure(Error.new(type | 
| 132 | 
            +
                      failure(Error.new(type:, message:, details:))
         | 
| 144 133 | 
             
                    end
         | 
| 145 134 |  | 
| 146 135 | 
             
                    def wrap_if_present(value, type: :not_found, message: nil, details: {})
         | 
| 147 | 
            -
                      value.nil? ? error(type, message | 
| 136 | 
            +
                      value.nil? ? error(type, message:, details:) : success(value)
         | 
| 148 137 | 
             
                    end
         | 
| 149 138 | 
             
                  end
         | 
| 150 139 |  | 
| @@ -164,45 +153,43 @@ module Pathway | |
| 164 153 | 
             
                    end
         | 
| 165 154 |  | 
| 166 155 | 
             
                    # Execute step and preserve the former state
         | 
| 167 | 
            -
                     | 
| 156 | 
            +
                    def step(callable,...)
         | 
| 168 157 | 
             
                      bl = _callable(callable)
         | 
| 169 | 
            -
             | 
| 170 | 
            -
                      @result = @result.tee { |state| bl.call(state, *args) }
         | 
| 158 | 
            +
                      @result = @result.tee { |state| bl.call(state,...) }
         | 
| 171 159 | 
             
                    end
         | 
| 172 160 |  | 
| 173 161 | 
             
                    # Execute step and modify the former state setting the key
         | 
| 174 | 
            -
                    def set(callable, *args, to: @operation.result_key)
         | 
| 162 | 
            +
                    def set(callable, *args, to: @operation.result_key, **kwargs, &bl)
         | 
| 175 163 | 
             
                      bl = _callable(callable)
         | 
| 176 164 |  | 
| 177 165 | 
             
                      @result = @result.then do |state|
         | 
| 178 | 
            -
                        wrap(bl.call(state, *args))
         | 
| 166 | 
            +
                        wrap(bl.call(state, *args, **kwargs, &bl))
         | 
| 179 167 | 
             
                          .then { |value| state.update(to => value) }
         | 
| 180 168 | 
             
                      end
         | 
| 181 169 | 
             
                    end
         | 
| 182 170 |  | 
| 183 171 | 
             
                    # Execute step and replace the current state completely
         | 
| 184 | 
            -
                    def map(callable)
         | 
| 172 | 
            +
                    def map(callable,...)
         | 
| 185 173 | 
             
                      bl = _callable(callable)
         | 
| 186 | 
            -
                      @result = @result.then( | 
| 174 | 
            +
                      @result = @result.then { |state| bl.call(state,...) }
         | 
| 187 175 | 
             
                    end
         | 
| 188 176 |  | 
| 189 | 
            -
                    def around( | 
| 177 | 
            +
                    def around(execution_strategy, &dsl_block)
         | 
| 190 178 | 
             
                      @result.then do |state|
         | 
| 191 | 
            -
                         | 
| 192 | 
            -
             | 
| 179 | 
            +
                        dsl_runner = ->(dsl = self) { @result = dsl.run(&dsl_block) }
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                        _callable(execution_strategy).call(dsl_runner, state)
         | 
| 193 182 | 
             
                      end
         | 
| 194 183 | 
             
                    end
         | 
| 195 184 |  | 
| 196 | 
            -
                    def if_true(cond, & | 
| 185 | 
            +
                    def if_true(cond, &dsl_block)
         | 
| 197 186 | 
             
                      cond = _callable(cond)
         | 
| 198 | 
            -
                      around(-> | 
| 199 | 
            -
                        seq.call if cond.call(state)
         | 
| 200 | 
            -
                      }, &steps)
         | 
| 187 | 
            +
                      around(->(dsl_runner, state) { dsl_runner.call if cond.call(state) }, &dsl_block)
         | 
| 201 188 | 
             
                    end
         | 
| 202 189 |  | 
| 203 | 
            -
                    def if_false(cond, & | 
| 190 | 
            +
                    def if_false(cond, &dsl_block)
         | 
| 204 191 | 
             
                      cond = _callable(cond)
         | 
| 205 | 
            -
                      if_true(-> | 
| 192 | 
            +
                      if_true(->(state) { !cond.call(state) }, &dsl_block)
         | 
| 206 193 | 
             
                    end
         | 
| 207 194 |  | 
| 208 195 | 
             
                    alias_method :sequence, :around
         | 
| @@ -210,16 +197,14 @@ module Pathway | |
| 210 197 |  | 
| 211 198 | 
             
                    private
         | 
| 212 199 |  | 
| 213 | 
            -
                    def wrap(obj)
         | 
| 214 | 
            -
                      Result.result(obj)
         | 
| 215 | 
            -
                    end
         | 
| 200 | 
            +
                    def wrap(obj) = Result.result(obj)
         | 
| 216 201 |  | 
| 217 202 | 
             
                    def _callable(callable)
         | 
| 218 203 | 
             
                      case callable
         | 
| 219 204 | 
             
                      when Proc
         | 
| 220 | 
            -
                        -> | 
| 205 | 
            +
                        ->(*args, **kwargs) { @operation.instance_exec(*args, **kwargs, &callable) }
         | 
| 221 206 | 
             
                      when Symbol
         | 
| 222 | 
            -
                        -> | 
| 207 | 
            +
                        ->(*args, **kwargs) { @operation.send(callable, *args, **kwargs) }
         | 
| 223 208 | 
             
                      else
         | 
| 224 209 | 
             
                        callable
         | 
| 225 210 | 
             
                      end
         | 
    
        data/pathway.gemspec
    CHANGED
    
    | @@ -27,13 +27,12 @@ Gem::Specification.new do |spec| | |
| 27 27 | 
             
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 28 28 | 
             
              spec.require_paths = ["lib"]
         | 
| 29 29 |  | 
| 30 | 
            -
              spec.required_ruby_version = ">=  | 
| 30 | 
            +
              spec.required_ruby_version = ">= 3.1.0"
         | 
| 31 31 |  | 
| 32 32 | 
             
              spec.add_dependency "dry-inflector", ">= 0.1.0"
         | 
| 33 | 
            -
              spec.add_dependency "contextualizer", "~> 0.0 | 
| 34 | 
            -
              spec.add_dependency "ruby2_keywords"
         | 
| 33 | 
            +
              spec.add_dependency "contextualizer", "~> 0.1.0"
         | 
| 35 34 |  | 
| 36 | 
            -
              spec.add_development_dependency "dry-validation", ">= 0 | 
| 35 | 
            +
              spec.add_development_dependency "dry-validation", ">= 1.0"
         | 
| 37 36 | 
             
              spec.add_development_dependency "bundler", ">= 2.4.10"
         | 
| 38 37 | 
             
              spec.add_development_dependency "sequel", "~> 5.0"
         | 
| 39 38 | 
             
              spec.add_development_dependency "rake", "~> 13.0"
         | 
| @@ -41,6 +40,7 @@ Gem::Specification.new do |spec| | |
| 41 40 | 
             
              spec.add_development_dependency "simplecov-lcov", '~> 0.8.0'
         | 
| 42 41 | 
             
              spec.add_development_dependency "simplecov"
         | 
| 43 42 | 
             
              spec.add_development_dependency "pry"
         | 
| 43 | 
            +
              spec.add_development_dependency "byebug"
         | 
| 44 44 | 
             
              spec.add_development_dependency "pry-byebug"
         | 
| 45 45 | 
             
              spec.add_development_dependency "pry-doc"
         | 
| 46 46 | 
             
              spec.add_development_dependency "pry-stack"
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: pathway
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 1.0.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Pablo Herrero
         | 
| 8 | 
            -
            autorequire: 
         | 
| 9 8 | 
             
            bindir: exe
         | 
| 10 9 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 10 | 
            +
            date: 1980-01-02 00:00:00.000000000 Z
         | 
| 12 11 | 
             
            dependencies:
         | 
| 13 12 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 13 | 
             
              name: dry-inflector
         | 
| @@ -30,42 +29,28 @@ dependencies: | |
| 30 29 | 
             
                requirements:
         | 
| 31 30 | 
             
                - - "~>"
         | 
| 32 31 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version: 0.0 | 
| 32 | 
            +
                    version: 0.1.0
         | 
| 34 33 | 
             
              type: :runtime
         | 
| 35 34 | 
             
              prerelease: false
         | 
| 36 35 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 36 | 
             
                requirements:
         | 
| 38 37 | 
             
                - - "~>"
         | 
| 39 38 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version: 0.0 | 
| 41 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            -
              name: ruby2_keywords
         | 
| 43 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 | 
            -
                requirements:
         | 
| 45 | 
            -
                - - ">="
         | 
| 46 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 47 | 
            -
                    version: '0'
         | 
| 48 | 
            -
              type: :runtime
         | 
| 49 | 
            -
              prerelease: false
         | 
| 50 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 51 | 
            -
                requirements:
         | 
| 52 | 
            -
                - - ">="
         | 
| 53 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 54 | 
            -
                    version: '0'
         | 
| 39 | 
            +
                    version: 0.1.0
         | 
| 55 40 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 41 | 
             
              name: dry-validation
         | 
| 57 42 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 43 | 
             
                requirements:
         | 
| 59 44 | 
             
                - - ">="
         | 
| 60 45 | 
             
                  - !ruby/object:Gem::Version
         | 
| 61 | 
            -
                    version: '0 | 
| 46 | 
            +
                    version: '1.0'
         | 
| 62 47 | 
             
              type: :development
         | 
| 63 48 | 
             
              prerelease: false
         | 
| 64 49 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 65 50 | 
             
                requirements:
         | 
| 66 51 | 
             
                - - ">="
         | 
| 67 52 | 
             
                  - !ruby/object:Gem::Version
         | 
| 68 | 
            -
                    version: '0 | 
| 53 | 
            +
                    version: '1.0'
         | 
| 69 54 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 70 55 | 
             
              name: bundler
         | 
| 71 56 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -164,6 +149,20 @@ dependencies: | |
| 164 149 | 
             
                - - ">="
         | 
| 165 150 | 
             
                  - !ruby/object:Gem::Version
         | 
| 166 151 | 
             
                    version: '0'
         | 
| 152 | 
            +
            - !ruby/object:Gem::Dependency
         | 
| 153 | 
            +
              name: byebug
         | 
| 154 | 
            +
              requirement: !ruby/object:Gem::Requirement
         | 
| 155 | 
            +
                requirements:
         | 
| 156 | 
            +
                - - ">="
         | 
| 157 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 158 | 
            +
                    version: '0'
         | 
| 159 | 
            +
              type: :development
         | 
| 160 | 
            +
              prerelease: false
         | 
| 161 | 
            +
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 162 | 
            +
                requirements:
         | 
| 163 | 
            +
                - - ">="
         | 
| 164 | 
            +
                  - !ruby/object:Gem::Version
         | 
| 165 | 
            +
                    version: '0'
         | 
| 167 166 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 168 167 | 
             
              name: pry-byebug
         | 
| 169 168 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -228,11 +227,7 @@ files: | |
| 228 227 | 
             
            - bin/setup
         | 
| 229 228 | 
             
            - lib/pathway.rb
         | 
| 230 229 | 
             
            - lib/pathway/plugins/auto_deconstruct_state.rb
         | 
| 231 | 
            -
            - lib/pathway/plugins/auto_deconstruct_state/ruby3.rb
         | 
| 232 230 | 
             
            - lib/pathway/plugins/dry_validation.rb
         | 
| 233 | 
            -
            - lib/pathway/plugins/dry_validation/v0_11.rb
         | 
| 234 | 
            -
            - lib/pathway/plugins/dry_validation/v0_12.rb
         | 
| 235 | 
            -
            - lib/pathway/plugins/dry_validation/v1_0.rb
         | 
| 236 231 | 
             
            - lib/pathway/plugins/responder.rb
         | 
| 237 232 | 
             
            - lib/pathway/plugins/sequel_models.rb
         | 
| 238 233 | 
             
            - lib/pathway/plugins/simple_auth.rb
         | 
| @@ -254,7 +249,6 @@ licenses: | |
| 254 249 | 
             
            metadata:
         | 
| 255 250 | 
             
              bug_tracker_uri: https://github.com/pabloh/pathway/issues
         | 
| 256 251 | 
             
              source_code_uri: https://github.com/pabloh/pathway
         | 
| 257 | 
            -
            post_install_message: 
         | 
| 258 252 | 
             
            rdoc_options: []
         | 
| 259 253 | 
             
            require_paths:
         | 
| 260 254 | 
             
            - lib
         | 
| @@ -262,15 +256,14 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 262 256 | 
             
              requirements:
         | 
| 263 257 | 
             
              - - ">="
         | 
| 264 258 | 
             
                - !ruby/object:Gem::Version
         | 
| 265 | 
            -
                  version:  | 
| 259 | 
            +
                  version: 3.1.0
         | 
| 266 260 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 267 261 | 
             
              requirements:
         | 
| 268 262 | 
             
              - - ">="
         | 
| 269 263 | 
             
                - !ruby/object:Gem::Version
         | 
| 270 264 | 
             
                  version: '0'
         | 
| 271 265 | 
             
            requirements: []
         | 
| 272 | 
            -
            rubygems_version: 3. | 
| 273 | 
            -
            signing_key: 
         | 
| 266 | 
            +
            rubygems_version: 3.6.9
         | 
| 274 267 | 
             
            specification_version: 4
         | 
| 275 268 | 
             
            summary: Define your business logic in simple steps.
         | 
| 276 269 | 
             
            test_files: []
         | 
| @@ -1,22 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module Pathway
         | 
| 4 | 
            -
              module Plugins
         | 
| 5 | 
            -
                module AutoDeconstructState
         | 
| 6 | 
            -
                  module DSLMethods
         | 
| 7 | 
            -
                    private
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                    def _callable(callable)
         | 
| 10 | 
            -
                      if callable.is_a?(Symbol) && @operation.respond_to?(callable, true) &&
         | 
| 11 | 
            -
                        @operation.method(callable).arity != 0 &&
         | 
| 12 | 
            -
                        @operation.method(callable).parameters.all? { _1 in [:key|:keyreq|:keyrest|:block,*] }
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                        -> state { @operation.send(callable, **state) }
         | 
| 15 | 
            -
                      else
         | 
| 16 | 
            -
                        super
         | 
| 17 | 
            -
                      end
         | 
| 18 | 
            -
                    end
         | 
| 19 | 
            -
                  end
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
              end
         | 
| 22 | 
            -
            end
         | 
| @@ -1,86 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module Pathway
         | 
| 4 | 
            -
              module Plugins
         | 
| 5 | 
            -
                module DryValidation
         | 
| 6 | 
            -
                  module V0_11
         | 
| 7 | 
            -
                    module ClassMethods
         | 
| 8 | 
            -
                      attr_reader :form_class, :form_options
         | 
| 9 | 
            -
                      attr_accessor :auto_wire_options
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                      def form(base = nil, **opts, &block)
         | 
| 12 | 
            -
                        if block_given?
         | 
| 13 | 
            -
                          base ||= _base_form
         | 
| 14 | 
            -
                          self.form_class = _block_definition(base, opts, &block)
         | 
| 15 | 
            -
                        elsif base
         | 
| 16 | 
            -
                          self.form_class = _form_class(base)
         | 
| 17 | 
            -
                        else
         | 
| 18 | 
            -
                          raise ArgumentError, 'Either a form class or a block must be provided'
         | 
| 19 | 
            -
                        end
         | 
| 20 | 
            -
                      end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                      def form_class= klass
         | 
| 23 | 
            -
                        @builded_form = klass.options.empty? ? klass.new : nil
         | 
| 24 | 
            -
                        @form_class = klass
         | 
| 25 | 
            -
                        @form_options = klass.options.keys
         | 
| 26 | 
            -
                      end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                      def build_form(opts = {})
         | 
| 29 | 
            -
                        @builded_form || form_class.new(opts)
         | 
| 30 | 
            -
                      end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                      def inherited(subclass)
         | 
| 33 | 
            -
                        super
         | 
| 34 | 
            -
                        subclass.form_class = form_class
         | 
| 35 | 
            -
                        subclass.auto_wire_options = auto_wire_options
         | 
| 36 | 
            -
                      end
         | 
| 37 | 
            -
             | 
| 38 | 
            -
                      private
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                      def _base_form
         | 
| 41 | 
            -
                        superclass.respond_to?(:form_class) ? superclass.form_class : Dry::Validation::Schema::Form
         | 
| 42 | 
            -
                      end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                      def _form_class(form)
         | 
| 45 | 
            -
                        form.is_a?(Class) ? form : form.class
         | 
| 46 | 
            -
                      end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                      def _form_opts(opts = {})
         | 
| 49 | 
            -
                        opts.merge(build: false)
         | 
| 50 | 
            -
                      end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                      def _block_definition(base, opts, &block)
         | 
| 53 | 
            -
                        Dry::Validation.Form(_form_class(base), _form_opts(opts), &block)
         | 
| 54 | 
            -
                      end
         | 
| 55 | 
            -
                    end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                    module InstanceMethods
         | 
| 58 | 
            -
                      extend Forwardable
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                      delegate %i[build_form form_options auto_wire_options] => 'self.class'
         | 
| 61 | 
            -
                      alias :form :build_form
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                      def validate(state, with: nil)
         | 
| 64 | 
            -
                        if auto_wire_options && form_options.any?
         | 
| 65 | 
            -
                          with ||= form_options.zip(form_options).to_h
         | 
| 66 | 
            -
                        end
         | 
| 67 | 
            -
                        opts = Hash(with).map { |opt, key| [opt, state[key]] }.to_h
         | 
| 68 | 
            -
                        validate_with(state[:input], opts)
         | 
| 69 | 
            -
                          .then { |params| state.update(params: params) }
         | 
| 70 | 
            -
                      end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                      def validate_with(params, opts = {})
         | 
| 73 | 
            -
                        val = form(opts).call(params)
         | 
| 74 | 
            -
             | 
| 75 | 
            -
                        val.success? ? wrap(val.output) : error(:validation, details: val.messages)
         | 
| 76 | 
            -
                      end
         | 
| 77 | 
            -
                    end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                    def self.apply(operation, auto_wire_options: false)
         | 
| 80 | 
            -
                      operation.form_class = Dry::Validation::Schema::Form
         | 
| 81 | 
            -
                      operation.auto_wire_options = auto_wire_options
         | 
| 82 | 
            -
                    end
         | 
| 83 | 
            -
                  end
         | 
| 84 | 
            -
                end
         | 
| 85 | 
            -
              end
         | 
| 86 | 
            -
            end
         | 
| @@ -1,86 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module Pathway
         | 
| 4 | 
            -
              module Plugins
         | 
| 5 | 
            -
                module DryValidation
         | 
| 6 | 
            -
                  module V0_12
         | 
| 7 | 
            -
                    module ClassMethods
         | 
| 8 | 
            -
                      attr_reader :form_class, :form_options
         | 
| 9 | 
            -
                      attr_accessor :auto_wire_options
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                      def form(base = nil, **opts, &block)
         | 
| 12 | 
            -
                        if block_given?
         | 
| 13 | 
            -
                          base ||= _base_form
         | 
| 14 | 
            -
                          self.form_class = _block_definition(base, opts, &block)
         | 
| 15 | 
            -
                        elsif base
         | 
| 16 | 
            -
                          self.form_class = _form_class(base)
         | 
| 17 | 
            -
                        else
         | 
| 18 | 
            -
                          raise ArgumentError, 'Either a form class or a block must be provided'
         | 
| 19 | 
            -
                        end
         | 
| 20 | 
            -
                      end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                      def form_class= klass
         | 
| 23 | 
            -
                        @builded_form = klass.options.empty? ? klass.new : nil
         | 
| 24 | 
            -
                        @form_class = klass
         | 
| 25 | 
            -
                        @form_options = klass.options.keys
         | 
| 26 | 
            -
                      end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                      def build_form(opts = {})
         | 
| 29 | 
            -
                        @builded_form || form_class.new(opts)
         | 
| 30 | 
            -
                      end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                      def inherited(subclass)
         | 
| 33 | 
            -
                        super
         | 
| 34 | 
            -
                        subclass.form_class = form_class
         | 
| 35 | 
            -
                        subclass.auto_wire_options = auto_wire_options
         | 
| 36 | 
            -
                      end
         | 
| 37 | 
            -
             | 
| 38 | 
            -
                      private
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                      def _base_form
         | 
| 41 | 
            -
                        superclass.respond_to?(:form_class) ? superclass.form_class : Dry::Validation::Schema::Params
         | 
| 42 | 
            -
                      end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                      def _form_class(form)
         | 
| 45 | 
            -
                        form.is_a?(Class) ? form : form.class
         | 
| 46 | 
            -
                      end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
                      def _form_opts(opts = {})
         | 
| 49 | 
            -
                        opts.merge(build: false)
         | 
| 50 | 
            -
                      end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                      def _block_definition(base, opts, &block)
         | 
| 53 | 
            -
                        Dry::Validation.Params(_form_class(base), _form_opts(opts), &block)
         | 
| 54 | 
            -
                      end
         | 
| 55 | 
            -
                    end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                    module InstanceMethods
         | 
| 58 | 
            -
                      extend Forwardable
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                      delegate %i[build_form form_options auto_wire_options] => 'self.class'
         | 
| 61 | 
            -
                      alias :form :build_form
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                      def validate(state, with: nil)
         | 
| 64 | 
            -
                        if auto_wire_options && form_options.any?
         | 
| 65 | 
            -
                          with ||= form_options.zip(form_options).to_h
         | 
| 66 | 
            -
                        end
         | 
| 67 | 
            -
                        opts = Hash(with).map { |opt, key| [opt, state[key]] }.to_h
         | 
| 68 | 
            -
                        validate_with(state[:input], opts)
         | 
| 69 | 
            -
                          .then { |params| state.update(params: params) }
         | 
| 70 | 
            -
                      end
         | 
| 71 | 
            -
             | 
| 72 | 
            -
                      def validate_with(params, opts = {})
         | 
| 73 | 
            -
                        val = form(opts).call(params)
         | 
| 74 | 
            -
             | 
| 75 | 
            -
                        val.success? ? wrap(val.output) : error(:validation, details: val.messages)
         | 
| 76 | 
            -
                      end
         | 
| 77 | 
            -
                    end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
                    def self.apply(operation, auto_wire_options: false)
         | 
| 80 | 
            -
                      operation.form_class = Dry::Validation::Schema::Params
         | 
| 81 | 
            -
                      operation.auto_wire_options = auto_wire_options
         | 
| 82 | 
            -
                    end
         | 
| 83 | 
            -
                  end
         | 
| 84 | 
            -
                end
         | 
| 85 | 
            -
              end
         | 
| 86 | 
            -
            end
         | 
| @@ -1,78 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module Pathway
         | 
| 4 | 
            -
              module Plugins
         | 
| 5 | 
            -
                module DryValidation
         | 
| 6 | 
            -
                  module V1_0
         | 
| 7 | 
            -
                    module ClassMethods
         | 
| 8 | 
            -
                      attr_reader :contract_class, :contract_options
         | 
| 9 | 
            -
                      attr_accessor :auto_wire_options
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                      def contract(base = nil, &block)
         | 
| 12 | 
            -
                        if block_given?
         | 
| 13 | 
            -
                          base ||= _base_contract
         | 
| 14 | 
            -
                          self.contract_class = Class.new(base, &block)
         | 
| 15 | 
            -
                        elsif base
         | 
| 16 | 
            -
                          self.contract_class = base
         | 
| 17 | 
            -
                        else
         | 
| 18 | 
            -
                          raise ArgumentError, 'Either a contract class or a block must be provided'
         | 
| 19 | 
            -
                        end
         | 
| 20 | 
            -
                      end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                      ruby2_keywords def params(*args, &block)
         | 
| 23 | 
            -
                        contract { params(*args, &block) }
         | 
| 24 | 
            -
                      end
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                      def contract_class= klass
         | 
| 27 | 
            -
                        @contract_class = klass
         | 
| 28 | 
            -
                        @contract_options = (klass.dry_initializer.options - Dry::Validation::Contract.dry_initializer.options).map(&:target)
         | 
| 29 | 
            -
                        @builded_contract = @contract_options.empty? && klass.schema ? klass.new : nil
         | 
| 30 | 
            -
                      end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                      def build_contract(**opts)
         | 
| 33 | 
            -
                        @builded_contract || contract_class.new(**opts)
         | 
| 34 | 
            -
                      end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                      def inherited(subclass)
         | 
| 37 | 
            -
                        super
         | 
| 38 | 
            -
                        subclass.contract_class = contract_class
         | 
| 39 | 
            -
                        subclass.auto_wire_options = auto_wire_options
         | 
| 40 | 
            -
                      end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                      private
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                      def _base_contract
         | 
| 45 | 
            -
                        superclass.respond_to?(:contract_class) ? superclass.contract_class : Dry::Validation::Contract
         | 
| 46 | 
            -
                      end
         | 
| 47 | 
            -
                    end
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                    module InstanceMethods
         | 
| 50 | 
            -
                      extend Forwardable
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                      delegate %i[build_contract contract_options auto_wire_options] => 'self.class'
         | 
| 53 | 
            -
                      alias :contract :build_contract
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                      def validate(state, with: nil)
         | 
| 56 | 
            -
                        if auto_wire_options && contract_options.any?
         | 
| 57 | 
            -
                          with ||= contract_options.zip(contract_options).to_h
         | 
| 58 | 
            -
                        end
         | 
| 59 | 
            -
                        opts = Hash(with).map { |to, from| [to, state[from]] }.to_h
         | 
| 60 | 
            -
                        validate_with(state[:input], **opts)
         | 
| 61 | 
            -
                          .then { |params| state.update(params: params) }
         | 
| 62 | 
            -
                      end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                      def validate_with(input, **opts)
         | 
| 65 | 
            -
                        result = contract(**opts).call(input)
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                        result.success? ? wrap(result.values.to_h) : error(:validation, details: result.errors.to_h)
         | 
| 68 | 
            -
                      end
         | 
| 69 | 
            -
                    end
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                    def self.apply(operation, auto_wire_options: false)
         | 
| 72 | 
            -
                      operation.contract_class = Dry::Validation::Contract
         | 
| 73 | 
            -
                      operation.auto_wire_options = auto_wire_options
         | 
| 74 | 
            -
                    end
         | 
| 75 | 
            -
                  end
         | 
| 76 | 
            -
                end
         | 
| 77 | 
            -
              end
         | 
| 78 | 
            -
            end
         |