interactify 0.3.0.pre.alpha.1 → 0.4.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/.rubocop.yml +1 -0
- data/.ruby-version +1 -0
- data/Appraisals +23 -0
- data/CHANGELOG.md +17 -0
- data/README.md +33 -44
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/no_railties_no_sidekiq.gemfile +18 -0
- data/gemfiles/no_railties_no_sidekiq.gemfile.lock +127 -0
- data/gemfiles/railties_6.gemfile +14 -0
- data/gemfiles/railties_6.gemfile.lock +253 -0
- data/gemfiles/railties_6_no_sidekiq.gemfile +19 -0
- data/gemfiles/railties_6_no_sidekiq.gemfile.lock +159 -0
- data/gemfiles/railties_6_sidekiq.gemfile +20 -0
- data/gemfiles/railties_6_sidekiq.gemfile.lock +168 -0
- data/gemfiles/railties_7_no_sidekiq.gemfile +19 -0
- data/gemfiles/railties_7_no_sidekiq.gemfile.lock +158 -0
- data/gemfiles/railties_7_sidekiq.gemfile +20 -0
- data/gemfiles/railties_7_sidekiq.gemfile.lock +167 -0
- data/lib/interactify/async/job_klass.rb +63 -0
- data/lib/interactify/async/job_maker.rb +58 -0
- data/lib/interactify/async/jobable.rb +96 -0
- data/lib/interactify/async/null_job.rb +23 -0
- data/lib/interactify/configuration.rb +15 -0
- data/lib/interactify/contracts/call_wrapper.rb +19 -0
- data/lib/interactify/contracts/failure.rb +8 -0
- data/lib/interactify/contracts/helpers.rb +81 -0
- data/lib/interactify/contracts/mismatching_promise_error.rb +19 -0
- data/lib/interactify/contracts/promising.rb +36 -0
- data/lib/interactify/contracts/setup.rb +39 -0
- data/lib/interactify/dsl/each_chain.rb +96 -0
- data/lib/interactify/dsl/if_interactor.rb +81 -0
- data/lib/interactify/dsl/if_klass.rb +82 -0
- data/lib/interactify/dsl/organizer.rb +32 -0
- data/lib/interactify/dsl/unique_klass_name.rb +23 -0
- data/lib/interactify/dsl/wrapper.rb +74 -0
- data/lib/interactify/dsl.rb +12 -6
- data/lib/interactify/rspec_matchers/matchers.rb +68 -0
- data/lib/interactify/version.rb +1 -1
- data/lib/interactify/{interactor_wiring → wiring}/callable_representation.rb +2 -2
- data/lib/interactify/{interactor_wiring → wiring}/constants.rb +4 -4
- data/lib/interactify/{interactor_wiring → wiring}/error_context.rb +1 -1
- data/lib/interactify/{interactor_wiring → wiring}/files.rb +1 -1
- data/lib/interactify/{interactor_wiring.rb → wiring.rb} +5 -5
- data/lib/interactify.rb +58 -38
- metadata +49 -72
- data/lib/interactify/async_job_klass.rb +0 -61
- data/lib/interactify/call_wrapper.rb +0 -17
- data/lib/interactify/contract_failure.rb +0 -6
- data/lib/interactify/contract_helpers.rb +0 -71
- data/lib/interactify/each_chain.rb +0 -88
- data/lib/interactify/if_interactor.rb +0 -70
- data/lib/interactify/interactor_wrapper.rb +0 -72
- data/lib/interactify/job_maker.rb +0 -56
- data/lib/interactify/jobable.rb +0 -92
- data/lib/interactify/mismatching_promise_error.rb +0 -17
- data/lib/interactify/organizer.rb +0 -30
- data/lib/interactify/promising.rb +0 -34
- data/lib/interactify/rspec/matchers.rb +0 -67
- data/lib/interactify/unique_klass_name.rb +0 -21
    
        metadata
    CHANGED
    
    | @@ -1,45 +1,31 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: interactify
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.4.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Mark Burns
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2023-12- | 
| 11 | 
            +
            date: 2023-12-31 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 | 
            -
              name:  | 
| 15 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 16 | 
            -
                requirements:
         | 
| 17 | 
            -
                - - ">="
         | 
| 18 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 19 | 
            -
                    version: '0'
         | 
| 20 | 
            -
              type: :runtime
         | 
| 21 | 
            -
              prerelease: false
         | 
| 22 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 23 | 
            -
                requirements:
         | 
| 24 | 
            -
                - - ">="
         | 
| 25 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 26 | 
            -
                    version: '0'
         | 
| 27 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 28 | 
            -
              name: interactor-contracts
         | 
| 14 | 
            +
              name: activesupport
         | 
| 29 15 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 30 16 | 
             
                requirements:
         | 
| 31 17 | 
             
                - - ">="
         | 
| 32 18 | 
             
                  - !ruby/object:Gem::Version
         | 
| 33 | 
            -
                    version:  | 
| 19 | 
            +
                    version: 6.0.0
         | 
| 34 20 | 
             
              type: :runtime
         | 
| 35 21 | 
             
              prerelease: false
         | 
| 36 22 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 37 23 | 
             
                requirements:
         | 
| 38 24 | 
             
                - - ">="
         | 
| 39 25 | 
             
                  - !ruby/object:Gem::Version
         | 
| 40 | 
            -
                    version:  | 
| 26 | 
            +
                    version: 6.0.0
         | 
| 41 27 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 42 | 
            -
              name:  | 
| 28 | 
            +
              name: interactor
         | 
| 43 29 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 44 30 | 
             
                requirements:
         | 
| 45 31 | 
             
                - - ">="
         | 
| @@ -53,7 +39,7 @@ dependencies: | |
| 53 39 | 
             
                  - !ruby/object:Gem::Version
         | 
| 54 40 | 
             
                    version: '0'
         | 
| 55 41 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 56 | 
            -
              name:  | 
| 42 | 
            +
              name: interactor-contracts
         | 
| 57 43 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 58 44 | 
             
                requirements:
         | 
| 59 45 | 
             
                - - ">="
         | 
| @@ -66,34 +52,6 @@ dependencies: | |
| 66 52 | 
             
                - - ">="
         | 
| 67 53 | 
             
                  - !ruby/object:Gem::Version
         | 
| 68 54 | 
             
                    version: '0'
         | 
| 69 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 70 | 
            -
              name: debug
         | 
| 71 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 72 | 
            -
                requirements:
         | 
| 73 | 
            -
                - - ">="
         | 
| 74 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 75 | 
            -
                    version: '0'
         | 
| 76 | 
            -
              type: :development
         | 
| 77 | 
            -
              prerelease: false
         | 
| 78 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 79 | 
            -
                requirements:
         | 
| 80 | 
            -
                - - ">="
         | 
| 81 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 82 | 
            -
                    version: '0'
         | 
| 83 | 
            -
            - !ruby/object:Gem::Dependency
         | 
| 84 | 
            -
              name: deep_matching
         | 
| 85 | 
            -
              requirement: !ruby/object:Gem::Requirement
         | 
| 86 | 
            -
                requirements:
         | 
| 87 | 
            -
                - - ">="
         | 
| 88 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 89 | 
            -
                    version: '0'
         | 
| 90 | 
            -
              type: :development
         | 
| 91 | 
            -
              prerelease: false
         | 
| 92 | 
            -
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 93 | 
            -
                requirements:
         | 
| 94 | 
            -
                - - ">="
         | 
| 95 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 96 | 
            -
                    version: '0'
         | 
| 97 55 | 
             
            description: |
         | 
| 98 56 | 
             
              Adds the following to your interactor chains
         | 
| 99 57 | 
             
                - lambda support
         | 
| @@ -110,32 +68,51 @@ extra_rdoc_files: [] | |
| 110 68 | 
             
            files:
         | 
| 111 69 | 
             
            - ".rspec"
         | 
| 112 70 | 
             
            - ".rubocop.yml"
         | 
| 71 | 
            +
            - ".ruby-version"
         | 
| 72 | 
            +
            - Appraisals
         | 
| 113 73 | 
             
            - CHANGELOG.md
         | 
| 114 74 | 
             
            - LICENSE.txt
         | 
| 115 75 | 
             
            - README.md
         | 
| 116 76 | 
             
            - Rakefile
         | 
| 77 | 
            +
            - gemfiles/.bundle/config
         | 
| 78 | 
            +
            - gemfiles/no_railties_no_sidekiq.gemfile
         | 
| 79 | 
            +
            - gemfiles/no_railties_no_sidekiq.gemfile.lock
         | 
| 80 | 
            +
            - gemfiles/railties_6.gemfile
         | 
| 81 | 
            +
            - gemfiles/railties_6.gemfile.lock
         | 
| 82 | 
            +
            - gemfiles/railties_6_no_sidekiq.gemfile
         | 
| 83 | 
            +
            - gemfiles/railties_6_no_sidekiq.gemfile.lock
         | 
| 84 | 
            +
            - gemfiles/railties_6_sidekiq.gemfile
         | 
| 85 | 
            +
            - gemfiles/railties_6_sidekiq.gemfile.lock
         | 
| 86 | 
            +
            - gemfiles/railties_7_no_sidekiq.gemfile
         | 
| 87 | 
            +
            - gemfiles/railties_7_no_sidekiq.gemfile.lock
         | 
| 88 | 
            +
            - gemfiles/railties_7_sidekiq.gemfile
         | 
| 89 | 
            +
            - gemfiles/railties_7_sidekiq.gemfile.lock
         | 
| 117 90 | 
             
            - lib/interactify.rb
         | 
| 118 | 
            -
            - lib/interactify/ | 
| 119 | 
            -
            - lib/interactify/ | 
| 120 | 
            -
            - lib/interactify/ | 
| 121 | 
            -
            - lib/interactify/ | 
| 91 | 
            +
            - lib/interactify/async/job_klass.rb
         | 
| 92 | 
            +
            - lib/interactify/async/job_maker.rb
         | 
| 93 | 
            +
            - lib/interactify/async/jobable.rb
         | 
| 94 | 
            +
            - lib/interactify/async/null_job.rb
         | 
| 95 | 
            +
            - lib/interactify/configuration.rb
         | 
| 96 | 
            +
            - lib/interactify/contracts/call_wrapper.rb
         | 
| 97 | 
            +
            - lib/interactify/contracts/failure.rb
         | 
| 98 | 
            +
            - lib/interactify/contracts/helpers.rb
         | 
| 99 | 
            +
            - lib/interactify/contracts/mismatching_promise_error.rb
         | 
| 100 | 
            +
            - lib/interactify/contracts/promising.rb
         | 
| 101 | 
            +
            - lib/interactify/contracts/setup.rb
         | 
| 122 102 | 
             
            - lib/interactify/dsl.rb
         | 
| 123 | 
            -
            - lib/interactify/each_chain.rb
         | 
| 124 | 
            -
            - lib/interactify/if_interactor.rb
         | 
| 125 | 
            -
            - lib/interactify/ | 
| 126 | 
            -
            - lib/interactify/ | 
| 127 | 
            -
            - lib/interactify/ | 
| 128 | 
            -
            - lib/interactify/ | 
| 129 | 
            -
            - lib/interactify/ | 
| 130 | 
            -
            - lib/interactify/interactor_wrapper.rb
         | 
| 131 | 
            -
            - lib/interactify/job_maker.rb
         | 
| 132 | 
            -
            - lib/interactify/jobable.rb
         | 
| 133 | 
            -
            - lib/interactify/mismatching_promise_error.rb
         | 
| 134 | 
            -
            - lib/interactify/organizer.rb
         | 
| 135 | 
            -
            - lib/interactify/promising.rb
         | 
| 136 | 
            -
            - lib/interactify/rspec/matchers.rb
         | 
| 137 | 
            -
            - lib/interactify/unique_klass_name.rb
         | 
| 103 | 
            +
            - lib/interactify/dsl/each_chain.rb
         | 
| 104 | 
            +
            - lib/interactify/dsl/if_interactor.rb
         | 
| 105 | 
            +
            - lib/interactify/dsl/if_klass.rb
         | 
| 106 | 
            +
            - lib/interactify/dsl/organizer.rb
         | 
| 107 | 
            +
            - lib/interactify/dsl/unique_klass_name.rb
         | 
| 108 | 
            +
            - lib/interactify/dsl/wrapper.rb
         | 
| 109 | 
            +
            - lib/interactify/rspec_matchers/matchers.rb
         | 
| 138 110 | 
             
            - lib/interactify/version.rb
         | 
| 111 | 
            +
            - lib/interactify/wiring.rb
         | 
| 112 | 
            +
            - lib/interactify/wiring/callable_representation.rb
         | 
| 113 | 
            +
            - lib/interactify/wiring/constants.rb
         | 
| 114 | 
            +
            - lib/interactify/wiring/error_context.rb
         | 
| 115 | 
            +
            - lib/interactify/wiring/files.rb
         | 
| 139 116 | 
             
            - sig/interactify.rbs
         | 
| 140 117 | 
             
            homepage: https://github.com/markburns/interactify
         | 
| 141 118 | 
             
            licenses:
         | 
| @@ -154,14 +131,14 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 154 131 | 
             
              requirements:
         | 
| 155 132 | 
             
              - - ">="
         | 
| 156 133 | 
             
                - !ruby/object:Gem::Version
         | 
| 157 | 
            -
                  version:  | 
| 134 | 
            +
                  version: 3.1.4
         | 
| 158 135 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 159 136 | 
             
              requirements:
         | 
| 160 | 
            -
              - - " | 
| 137 | 
            +
              - - ">="
         | 
| 161 138 | 
             
                - !ruby/object:Gem::Version
         | 
| 162 | 
            -
                  version:  | 
| 139 | 
            +
                  version: '0'
         | 
| 163 140 | 
             
            requirements: []
         | 
| 164 | 
            -
            rubygems_version: 3. | 
| 141 | 
            +
            rubygems_version: 3.3.26
         | 
| 165 142 | 
             
            signing_key:
         | 
| 166 143 | 
             
            specification_version: 4
         | 
| 167 144 | 
             
            summary: Interactors with bells and whistles
         | 
| @@ -1,61 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module Interactify
         | 
| 4 | 
            -
              class AsyncJobKlass
         | 
| 5 | 
            -
                attr_reader :container_klass, :klass_suffix
         | 
| 6 | 
            -
             | 
| 7 | 
            -
                def initialize(container_klass:, klass_suffix:)
         | 
| 8 | 
            -
                  @container_klass = container_klass
         | 
| 9 | 
            -
                  @klass_suffix = klass_suffix
         | 
| 10 | 
            -
                end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                def async_job_klass
         | 
| 13 | 
            -
                  klass = Class.new do
         | 
| 14 | 
            -
                    include Interactor
         | 
| 15 | 
            -
                    include Interactor::Contracts
         | 
| 16 | 
            -
                  end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
                  attach_call(klass)
         | 
| 19 | 
            -
                  attach_call!(klass)
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                  klass
         | 
| 22 | 
            -
                end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                def attach_call(async_job_klass)
         | 
| 25 | 
            -
                  # e.g. SomeInteractor::AsyncWithSuffix.call(foo: 'bar')
         | 
| 26 | 
            -
                  async_job_klass.send(:define_singleton_method, :call) do |context|
         | 
| 27 | 
            -
                    call!(context)
         | 
| 28 | 
            -
                  end
         | 
| 29 | 
            -
                end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                def attach_call!(async_job_klass)
         | 
| 32 | 
            -
                  this = self
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                  # e.g. SomeInteractor::AsyncWithSuffix.call!(foo: 'bar')
         | 
| 35 | 
            -
                  async_job_klass.send(:define_singleton_method, :call!) do |context|
         | 
| 36 | 
            -
                    # e.g. SomeInteractor::JobWithSuffix
         | 
| 37 | 
            -
                    job_klass = this.container_klass.const_get("Job#{this.klass_suffix}")
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                    # e.g. SomeInteractor::JobWithSuffix.perform_async({foo: 'bar'})
         | 
| 40 | 
            -
                    job_klass.perform_async(this.args(context))
         | 
| 41 | 
            -
                  end
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                def args(context)
         | 
| 45 | 
            -
                  args = context.to_h.stringify_keys
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                  return args unless container_klass.respond_to?(:expected_keys)
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                  restrict_to_optional_or_keys_from_contract(args)
         | 
| 50 | 
            -
                end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                def restrict_to_optional_or_keys_from_contract(args)
         | 
| 53 | 
            -
                  keys = container_klass.expected_keys.map(&:to_s)
         | 
| 54 | 
            -
             | 
| 55 | 
            -
                  optional = Array(container_klass.optional_attrs).map(&:to_s)
         | 
| 56 | 
            -
                  keys += optional
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                  args.slice(*keys)
         | 
| 59 | 
            -
                end
         | 
| 60 | 
            -
              end
         | 
| 61 | 
            -
            end
         | 
| @@ -1,17 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            module Interactify
         | 
| 4 | 
            -
              module CallWrapper
         | 
| 5 | 
            -
                # https://github.com/collectiveidea/interactor/blob/57b2af9a5a5afeb2c01059c40b792485cc21b052/lib/interactor.rb#L114
         | 
| 6 | 
            -
                # Interactor#run calls Interactor#run!
         | 
| 7 | 
            -
                # https://github.com/collectiveidea/interactor/blob/57b2af9a5a5afeb2c01059c40b792485cc21b052/lib/interactor.rb#L49
         | 
| 8 | 
            -
                # Interactor.call calls Interactor.run
         | 
| 9 | 
            -
                #
         | 
| 10 | 
            -
                # The non bang methods call the bang methods and rescue
         | 
| 11 | 
            -
                def run
         | 
| 12 | 
            -
                  @_interactor_called_by_non_bang_method = true
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                  super
         | 
| 15 | 
            -
                end
         | 
| 16 | 
            -
              end
         | 
| 17 | 
            -
            end
         | 
| @@ -1,71 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require "interactify/jobable"
         | 
| 4 | 
            -
            require "interactify/call_wrapper"
         | 
| 5 | 
            -
            require "interactify/organizer"
         | 
| 6 | 
            -
            require "interactify/contract_failure"
         | 
| 7 | 
            -
             | 
| 8 | 
            -
            module Interactify
         | 
| 9 | 
            -
              module ContractHelpers
         | 
| 10 | 
            -
                extend ActiveSupport::Concern
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                class_methods do
         | 
| 13 | 
            -
                  def expect(*attrs, filled: true)
         | 
| 14 | 
            -
                    expects do
         | 
| 15 | 
            -
                      attrs.each do |attr|
         | 
| 16 | 
            -
                        field = required(attr)
         | 
| 17 | 
            -
                        field.filled if filled
         | 
| 18 | 
            -
                      end
         | 
| 19 | 
            -
                    end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                    delegate(*attrs, to: :context)
         | 
| 22 | 
            -
                  end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  def optional(*attrs)
         | 
| 25 | 
            -
                    @optional_attrs ||= []
         | 
| 26 | 
            -
                    @optional_attrs += attrs
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                    delegate(*attrs, to: :context)
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                  attr_reader :optional_attrs
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                  def promise(*attrs, filled: true, should_delegate: true)
         | 
| 34 | 
            -
                    promises do
         | 
| 35 | 
            -
                      attrs.each do |attr|
         | 
| 36 | 
            -
                        field = required(attr)
         | 
| 37 | 
            -
                        field.filled if filled
         | 
| 38 | 
            -
                      end
         | 
| 39 | 
            -
                    end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                    delegate(*attrs, to: :context) if should_delegate
         | 
| 42 | 
            -
                  end
         | 
| 43 | 
            -
                end
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                included do
         | 
| 46 | 
            -
                  c = Class.new(ContractFailure)
         | 
| 47 | 
            -
                  # example self is Whatever::SomeInteractor
         | 
| 48 | 
            -
                  # failure class:  Whatever::SomeInteractor::InteractorContractFailure
         | 
| 49 | 
            -
                  const_set "InteractorContractFailure", c
         | 
| 50 | 
            -
                  prepend CallWrapper
         | 
| 51 | 
            -
                  include Organizer
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                  on_breach do |breaches|
         | 
| 54 | 
            -
                    breaches = breaches.map { |b| { b.property => b.messages } }.inject(&:merge)
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    Interactify.trigger_contract_breach_hook(context, breaches)
         | 
| 57 | 
            -
             | 
| 58 | 
            -
                    if @_interactor_called_by_non_bang_method == true
         | 
| 59 | 
            -
                      context.fail! contract_failures: breaches
         | 
| 60 | 
            -
                    else
         | 
| 61 | 
            -
                      # e.g. raises
         | 
| 62 | 
            -
                      # SomeNamespace::SomeClass::ContractFailure, {whatever: 'is missing'}
         | 
| 63 | 
            -
                      # but also sending the context into Sentry
         | 
| 64 | 
            -
                      exception = c.new(breaches.to_json)
         | 
| 65 | 
            -
                      Interactify.trigger_before_raise_hook(exception)
         | 
| 66 | 
            -
                      raise exception
         | 
| 67 | 
            -
                    end
         | 
| 68 | 
            -
                  end
         | 
| 69 | 
            -
                end
         | 
| 70 | 
            -
              end
         | 
| 71 | 
            -
            end
         | 
| @@ -1,88 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require "interactify/unique_klass_name"
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            module Interactify
         | 
| 6 | 
            -
              class EachChain
         | 
| 7 | 
            -
                attr_reader :each_loop_klasses, :plural_resource_name, :evaluating_receiver
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                def self.attach_klass(evaluating_receiver, plural_resource_name, *each_loop_klasses)
         | 
| 10 | 
            -
                  iteratable = new(each_loop_klasses, plural_resource_name, evaluating_receiver)
         | 
| 11 | 
            -
                  iteratable.attach_klass
         | 
| 12 | 
            -
                end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                def initialize(each_loop_klasses, plural_resource_name, evaluating_receiver)
         | 
| 15 | 
            -
                  @each_loop_klasses = each_loop_klasses
         | 
| 16 | 
            -
                  @plural_resource_name = plural_resource_name
         | 
| 17 | 
            -
                  @evaluating_receiver = evaluating_receiver
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
             | 
| 20 | 
            -
                # allows us to dynamically create an interactor chain
         | 
| 21 | 
            -
                # that iterates over the packages and
         | 
| 22 | 
            -
                # uses the passed in each_loop_klasses
         | 
| 23 | 
            -
                # rubocop:disable all
         | 
| 24 | 
            -
                def klass
         | 
| 25 | 
            -
                  this = self
         | 
| 26 | 
            -
             | 
| 27 | 
            -
                  Class.new do                                                                    # class SomeNamespace::EachPackage
         | 
| 28 | 
            -
                    include Interactify                                          #   include Interactify
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                    expects do                                                                    #   expects do
         | 
| 31 | 
            -
                      required(this.plural_resource_name)                                         #     required(:packages)
         | 
| 32 | 
            -
                    end                                                                           #   end
         | 
| 33 | 
            -
             | 
| 34 | 
            -
                    define_singleton_method(:source_location) do                                  #   def self.source_location
         | 
| 35 | 
            -
                      const_source_location this.evaluating_receiver.to_s                                     #     [file, line]
         | 
| 36 | 
            -
                    end                                                                           #   end
         | 
| 37 | 
            -
             | 
| 38 | 
            -
                    define_method(:run!) do                                                       #  def run!
         | 
| 39 | 
            -
                      context.send(this.plural_resource_name).each_with_index do |resource, index|#    context.packages.each_with_index do |package, index|
         | 
| 40 | 
            -
                        context[this.singular_resource_name] = resource                           #       context.package = package
         | 
| 41 | 
            -
                        context[this.singular_resource_index_name] = index                        #       context.package_index = index
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                        klasses = InteractorWrapper.wrap_many(self, this.each_loop_klasses)
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                        klasses.each do |interactor|                                              #       [A, B, C].each do |interactor|
         | 
| 46 | 
            -
                          interactor.call!(context)                                               #         interactor.call!(context)
         | 
| 47 | 
            -
                        end                                                                       #       end
         | 
| 48 | 
            -
                      end                                                                         #     end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                      context[this.singular_resource_name] = nil                                  #     context.package = nil
         | 
| 51 | 
            -
                      context[this.singular_resource_index_name] = nil                            #     context.package_index = nil
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                      context                                                                     #     context
         | 
| 54 | 
            -
                    end                                                                           #   end
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                    define_method(:inspect) do
         | 
| 57 | 
            -
                      "<#{this.namespace}::#{this.iterator_klass_name} iterates_over: #{this.each_loop_klasses.inspect}>"
         | 
| 58 | 
            -
                    end
         | 
| 59 | 
            -
                  end
         | 
| 60 | 
            -
                end
         | 
| 61 | 
            -
                # rubocop:enable all
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                def attach_klass
         | 
| 64 | 
            -
                  name = iterator_klass_name
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                  namespace.const_set(name, klass)
         | 
| 67 | 
            -
                  namespace.const_get(name)
         | 
| 68 | 
            -
                end
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                def namespace
         | 
| 71 | 
            -
                  evaluating_receiver
         | 
| 72 | 
            -
                end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                def iterator_klass_name
         | 
| 75 | 
            -
                  prefix = "Each#{singular_resource_name.to_s.camelize}"
         | 
| 76 | 
            -
             | 
| 77 | 
            -
                  UniqueKlassName.for(namespace, prefix)
         | 
| 78 | 
            -
                end
         | 
| 79 | 
            -
             | 
| 80 | 
            -
                def singular_resource_name
         | 
| 81 | 
            -
                  plural_resource_name.to_s.singularize.to_sym
         | 
| 82 | 
            -
                end
         | 
| 83 | 
            -
             | 
| 84 | 
            -
                def singular_resource_index_name
         | 
| 85 | 
            -
                  "#{singular_resource_name}_index".to_sym
         | 
| 86 | 
            -
                end
         | 
| 87 | 
            -
              end
         | 
| 88 | 
            -
            end
         | 
| @@ -1,70 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require "interactify/unique_klass_name"
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            module Interactify
         | 
| 6 | 
            -
              class IfInteractor
         | 
| 7 | 
            -
                attr_reader :condition, :success_interactor, :failure_interactor, :evaluating_receiver
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                def self.attach_klass(evaluating_receiver, condition, succcess_interactor, failure_interactor)
         | 
| 10 | 
            -
                  ifable = new(evaluating_receiver, condition, succcess_interactor, failure_interactor)
         | 
| 11 | 
            -
                  ifable.attach_klass
         | 
| 12 | 
            -
                end
         | 
| 13 | 
            -
             | 
| 14 | 
            -
                def initialize(evaluating_receiver, condition, succcess_interactor, failure_interactor)
         | 
| 15 | 
            -
                  @evaluating_receiver = evaluating_receiver
         | 
| 16 | 
            -
                  @condition = condition
         | 
| 17 | 
            -
                  @success_interactor = succcess_interactor
         | 
| 18 | 
            -
                  @failure_interactor = failure_interactor
         | 
| 19 | 
            -
                end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
                # allows us to dynamically create an interactor chain
         | 
| 22 | 
            -
                # that iterates over the packages and
         | 
| 23 | 
            -
                # uses the passed in each_loop_klasses
         | 
| 24 | 
            -
                # rubocop:disable all
         | 
| 25 | 
            -
                def klass
         | 
| 26 | 
            -
                  this = self
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                  Class.new do                                                           
         | 
| 29 | 
            -
                    include Interactor                                                    
         | 
| 30 | 
            -
                    include Interactor::Contracts                                          
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                    expects do                                                              
         | 
| 33 | 
            -
                      required(this.condition) unless this.condition.is_a?(Proc)
         | 
| 34 | 
            -
                    end                                                                       
         | 
| 35 | 
            -
             | 
| 36 | 
            -
                    define_singleton_method(:source_location) do                               
         | 
| 37 | 
            -
                      const_source_location this.evaluating_receiver.to_s                                     #     [file, line]
         | 
| 38 | 
            -
                    end                                                                          
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                    define_method(:run!) do                                                       
         | 
| 41 | 
            -
                      result = this.condition.is_a?(Proc) ? this.condition.call(context) : context.send(this.condition)
         | 
| 42 | 
            -
                      interactor = result ? this.success_interactor : this.failure_interactor
         | 
| 43 | 
            -
                      interactor&.respond_to?(:call!) ? interactor.call!(context) : interactor&.call(context)
         | 
| 44 | 
            -
                    end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                    define_method(:inspect) do
         | 
| 47 | 
            -
                      "<#{this.namespace}::#{this.if_klass_name} #{this.condition} ? #{this.success_interactor} : #{this.failure_interactor}>"
         | 
| 48 | 
            -
                    end
         | 
| 49 | 
            -
                  end
         | 
| 50 | 
            -
                end
         | 
| 51 | 
            -
                # rubocop:enable all
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                def attach_klass
         | 
| 54 | 
            -
                  name = if_klass_name
         | 
| 55 | 
            -
                  namespace.const_set(name, klass)
         | 
| 56 | 
            -
                  namespace.const_get(name)
         | 
| 57 | 
            -
                end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                def namespace
         | 
| 60 | 
            -
                  evaluating_receiver
         | 
| 61 | 
            -
                end
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                def if_klass_name
         | 
| 64 | 
            -
                  prefix = condition.is_a?(Proc) ? "Proc" : condition
         | 
| 65 | 
            -
                  prefix = "If#{prefix.to_s.camelize}"
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                  UniqueKlassName.for(namespace, prefix)
         | 
| 68 | 
            -
                end
         | 
| 69 | 
            -
              end
         | 
| 70 | 
            -
            end
         | 
| @@ -1,72 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require "interactify/unique_klass_name"
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            module Interactify
         | 
| 6 | 
            -
              class InteractorWrapper
         | 
| 7 | 
            -
                attr_reader :organizer, :interactor
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                def self.wrap_many(organizer, interactors)
         | 
| 10 | 
            -
                  Array(interactors).map do |interactor|
         | 
| 11 | 
            -
                    wrap(organizer, interactor)
         | 
| 12 | 
            -
                  end
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
                def self.wrap(organizer, interactor)
         | 
| 16 | 
            -
                  new(organizer, interactor).wrap
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                def initialize(organizer, interactor)
         | 
| 20 | 
            -
                  @organizer = organizer
         | 
| 21 | 
            -
                  @interactor = interactor
         | 
| 22 | 
            -
                end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                def wrap
         | 
| 25 | 
            -
                  case interactor
         | 
| 26 | 
            -
                  when Hash
         | 
| 27 | 
            -
                    wrap_conditional
         | 
| 28 | 
            -
                  when Array
         | 
| 29 | 
            -
                    wrap_chain
         | 
| 30 | 
            -
                  when Proc
         | 
| 31 | 
            -
                    wrap_proc
         | 
| 32 | 
            -
                  else
         | 
| 33 | 
            -
                    interactor
         | 
| 34 | 
            -
                  end
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
             | 
| 37 | 
            -
                def wrap_chain
         | 
| 38 | 
            -
                  return self.class.wrap(organizer, interactor.first) if interactor.length == 1
         | 
| 39 | 
            -
             | 
| 40 | 
            -
                  klass_name = UniqueKlassName.for(organizer, "Chained")
         | 
| 41 | 
            -
                  organizer.chain(klass_name, *interactor.map { self.class.wrap(organizer, _1) })
         | 
| 42 | 
            -
                end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
                def wrap_conditional
         | 
| 45 | 
            -
                  raise ArgumentError, "Hash must have at least :if, and :then key" unless condition && then_do
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                  return organizer.if(condition, then_do, else_do) if else_do
         | 
| 48 | 
            -
             | 
| 49 | 
            -
                  organizer.if(condition, then_do)
         | 
| 50 | 
            -
                end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                def condition = interactor[:if]
         | 
| 53 | 
            -
                def then_do = interactor[:then]
         | 
| 54 | 
            -
                def else_do = interactor[:else]
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                def wrap_proc
         | 
| 57 | 
            -
                  this = self
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                  Class.new do
         | 
| 60 | 
            -
                    include Interactify
         | 
| 61 | 
            -
             | 
| 62 | 
            -
                    define_singleton_method :wrapped do
         | 
| 63 | 
            -
                      this.interactor
         | 
| 64 | 
            -
                    end
         | 
| 65 | 
            -
             | 
| 66 | 
            -
                    define_method(:call) do
         | 
| 67 | 
            -
                      this.interactor.call(context)
         | 
| 68 | 
            -
                    end
         | 
| 69 | 
            -
                  end
         | 
| 70 | 
            -
                end
         | 
| 71 | 
            -
              end
         | 
| 72 | 
            -
            end
         | 
| @@ -1,56 +0,0 @@ | |
| 1 | 
            -
            # frozen_string_literal: true
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            require "sidekiq"
         | 
| 4 | 
            -
            require "sidekiq/job"
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            require "interactify/async_job_klass"
         | 
| 7 | 
            -
             | 
| 8 | 
            -
            module Interactify
         | 
| 9 | 
            -
              class JobMaker
         | 
| 10 | 
            -
                attr_reader :opts, :method_name, :container_klass, :klass_suffix
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                def initialize(container_klass:, opts:, klass_suffix:, method_name: :call!)
         | 
| 13 | 
            -
                  @container_klass = container_klass
         | 
| 14 | 
            -
                  @opts = opts
         | 
| 15 | 
            -
                  @method_name = method_name
         | 
| 16 | 
            -
                  @klass_suffix = klass_suffix
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                concerning :JobClass do
         | 
| 20 | 
            -
                  def job_klass
         | 
| 21 | 
            -
                    @job_klass ||= define_job_klass
         | 
| 22 | 
            -
                  end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
                  private
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                  def define_job_klass
         | 
| 27 | 
            -
                    this = self
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                    invalid_keys = this.opts.symbolize_keys.keys - %i[queue retry dead backtrace pool tags]
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                    raise ArgumentError, "Invalid keys: #{invalid_keys}" if invalid_keys.any?
         | 
| 32 | 
            -
             | 
| 33 | 
            -
                    build_job_klass(opts).tap do |klass|
         | 
| 34 | 
            -
                      klass.const_set(:JOBABLE_OPTS, opts)
         | 
| 35 | 
            -
                      klass.const_set(:JOBABLE_METHOD_NAME, method_name)
         | 
| 36 | 
            -
                    end
         | 
| 37 | 
            -
                  end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                  def build_job_klass(opts)
         | 
| 40 | 
            -
                    Class.new do
         | 
| 41 | 
            -
                      include Sidekiq::Job
         | 
| 42 | 
            -
             | 
| 43 | 
            -
                      sidekiq_options(opts)
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                      def perform(...)
         | 
| 46 | 
            -
                        self.class.module_parent.send(self.class::JOBABLE_METHOD_NAME, ...)
         | 
| 47 | 
            -
                      end
         | 
| 48 | 
            -
                    end
         | 
| 49 | 
            -
                  end
         | 
| 50 | 
            -
                end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                def async_job_klass
         | 
| 53 | 
            -
                  AsyncJobKlass.new(container_klass:, klass_suffix:).async_job_klass
         | 
| 54 | 
            -
                end
         | 
| 55 | 
            -
              end
         | 
| 56 | 
            -
            end
         |