flows 0.5.1 → 0.6.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/.rubocop.yml +3 -1
- data/.rubocop_todo.yml +27 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +17 -1
- data/bin/benchmark_cli/examples/.rubocop.yml +3 -0
- data/bin/errors +10 -2
- data/bin/errors_cli/interface_error_demo.rb +17 -0
- data/flows.gemspec +2 -0
- data/lib/flows/contract.rb +2 -2
- data/lib/flows/contract/error.rb +1 -2
- data/lib/flows/plugin.rb +1 -0
- data/lib/flows/plugin/dependency_injector.rb +11 -0
- data/lib/flows/plugin/dependency_injector/dependency_list.rb +1 -3
- data/lib/flows/plugin/interface.rb +84 -0
- data/lib/flows/plugin/output_contract/dsl.rb +1 -1
- data/lib/flows/plugin/output_contract/errors.rb +1 -1
- data/lib/flows/plugin/profiler/report/flat/method_report.rb +1 -2
- data/lib/flows/plugin/profiler/report/tree/calculated_node.rb +1 -1
- data/lib/flows/plugin/profiler/report/tree/node.rb +1 -2
- data/lib/flows/railway/step.rb +7 -7
- data/lib/flows/shared_context_pipeline.rb +46 -3
- data/lib/flows/shared_context_pipeline/dsl/callbacks.rb +1 -4
- data/lib/flows/shared_context_pipeline/dsl/tracks.rb +4 -4
- data/lib/flows/shared_context_pipeline/mutation_step.rb +3 -2
- data/lib/flows/shared_context_pipeline/step.rb +15 -4
- data/lib/flows/shared_context_pipeline/track.rb +1 -1
- data/lib/flows/shared_context_pipeline/wrap.rb +1 -2
- data/lib/flows/util/inheritable_singleton_vars/dup_strategy.rb +8 -6
- data/lib/flows/util/prepend_to_class.rb +14 -2
- data/lib/flows/version.rb +1 -1
- metadata +6 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: dd10b19c7b749fd46c6b8897db3c9912603b4111af7793449d5ff49f69adfcb1
         | 
| 4 | 
            +
              data.tar.gz: b18271b7321f199e978ebd4f66f2d21e532c20dd37cd61b6b641b00d875c2f4c
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 6b3e90d9b76911f1e0a0539bd89eee76a68dcba04f4136858412e4d0e0e1ca51ff8f35027963ef52fdd870f2b74ffe9a326aca4802cd443af2e55f8bf18f67b1
         | 
| 7 | 
            +
              data.tar.gz: 5a6306a15a6024a1c9412f325ab3454b029abcd7d80defee6a9d5b286e8664981b572fb0ecf6f91d06b98c7d5f3040169fe02aae43b8ee8261fa7b65c469fe54
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/.rubocop_todo.yml
    ADDED
    
    | @@ -0,0 +1,27 @@ | |
| 1 | 
            +
            # This configuration was generated by
         | 
| 2 | 
            +
            # `rubocop --auto-gen-config --auto-gen-only-exclude`
         | 
| 3 | 
            +
            # on 2020-08-22 07:49:05 UTC using RuboCop version 0.89.1.
         | 
| 4 | 
            +
            # The point is for the user to remove these configuration records
         | 
| 5 | 
            +
            # one by one as the offenses are removed from the code base.
         | 
| 6 | 
            +
            # Note that changes in the inspected code, or installation of new
         | 
| 7 | 
            +
            # versions of RuboCop, may require this file to be generated again.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # Offense count: 27
         | 
| 10 | 
            +
            #
         | 
| 11 | 
            +
            # *** NON-GENERATED COMMENT ***
         | 
| 12 | 
            +
            # I'm not sure about enabling this cop
         | 
| 13 | 
            +
            # * using super may has performance impact
         | 
| 14 | 
            +
            # * but for some cases it still can be useful
         | 
| 15 | 
            +
            # Research needed
         | 
| 16 | 
            +
            Lint/MissingSuper:
         | 
| 17 | 
            +
              Enabled: false
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            # Offense count: 5
         | 
| 20 | 
            +
            # Configuration parameters: AllowSubject, Max.
         | 
| 21 | 
            +
            #
         | 
| 22 | 
            +
            # *** NON-GENERATED COMMENT ***
         | 
| 23 | 
            +
            # Might be it's impossible to satisfy this cop or significant refactoring of these tests needed
         | 
| 24 | 
            +
            RSpec/MultipleMemoizedHelpers:
         | 
| 25 | 
            +
              Exclude:
         | 
| 26 | 
            +
                - 'spec/flows/flow/node_spec.rb'
         | 
| 27 | 
            +
                - 'spec/flows/util/inheritable_singleton_vars/isolation_strategy_spec.rb'
         | 
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            2.6. | 
| 1 | 
            +
            2.6.6
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -16,6 +16,21 @@ Types of changes: | |
| 16 16 |  | 
| 17 17 | 
             
            ## [Unreleased]
         | 
| 18 18 |  | 
| 19 | 
            +
            ## [0.6.0] - 2020-09-23
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ### Added
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            * `Flows::Plugin::Interface` basic implementation
         | 
| 24 | 
            +
            * `Flows::SharedContextPipeline` simple sub-pipelines injection
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ### Changed
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            * `Flows::SharedContextPipeline` callbacks execution method is changed to `instance_exec` (previously was `.call`)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
            ### Fixed
         | 
| 31 | 
            +
             | 
| 32 | 
            +
            * `Flows::Plugin::DependencyInjector` and modules generated by `Flows::Util::InheritableSingletonVars::DupStrategy` now can be safely included several times in the inheritance chain
         | 
| 33 | 
            +
             | 
| 19 34 | 
             
            ## [0.5.1] - 2020-06-29
         | 
| 20 35 |  | 
| 21 36 | 
             
            ### Fixed
         | 
| @@ -59,7 +74,8 @@ Types of changes: | |
| 59 74 | 
             
            * `Flows::Util::PrependToClass` - allows to prepend some module to class even if
         | 
| 60 75 | 
             
              target module did not included directly into class.
         | 
| 61 76 |  | 
| 62 | 
            -
            [unreleased]: https://github.com/ffloyd/flows/compare/v0. | 
| 77 | 
            +
            [unreleased]: https://github.com/ffloyd/flows/compare/v0.6.0...HEAD
         | 
| 78 | 
            +
            [0.6.0]: https://github.com/ffloyd/flows/compare/v0.5.1...v0.6.0
         | 
| 63 79 | 
             
            [0.5.1]: https://github.com/ffloyd/flows/compare/v0.5.0...v0.5.1
         | 
| 64 80 | 
             
            [0.5.0]: https://github.com/ffloyd/flows/compare/v0.4.0...v0.5.0
         | 
| 65 81 | 
             
            [0.4.0]: https://github.com/ffloyd/flows/compare/v0.3.0...v0.4.0
         | 
    
        data/bin/errors
    CHANGED
    
    | @@ -17,6 +17,7 @@ require_relative 'errors_cli/railway_error_demo' | |
| 17 17 | 
             
            require_relative 'errors_cli/result_error_demo'
         | 
| 18 18 | 
             
            require_relative 'errors_cli/scp_error_demo'
         | 
| 19 19 | 
             
            require_relative 'errors_cli/flow_error_demo'
         | 
| 20 | 
            +
            require_relative 'errors_cli/interface_error_demo'
         | 
| 20 21 |  | 
| 21 22 | 
             
            class ErrorsCLI
         | 
| 22 23 | 
             
              extend GLI::App
         | 
| @@ -30,11 +31,11 @@ class ErrorsCLI | |
| 30 31 | 
             
                ctx.command name do |cmd|
         | 
| 31 32 | 
             
                  cmd.action do |_, _, _|
         | 
| 32 33 | 
             
                    puts title.green
         | 
| 33 | 
            -
                    puts( | 
| 34 | 
            +
                    puts("BEGIN#{'-' * (title.length - 5)}".color(:darkgray))
         | 
| 34 35 | 
             
                    yield
         | 
| 35 36 | 
             
                  rescue StandardError => err
         | 
| 36 37 | 
             
                    puts err.message
         | 
| 37 | 
            -
                    puts( | 
| 38 | 
            +
                    puts("END#{'-' * (title.length - 3)}".color(:darkgray))
         | 
| 38 39 | 
             
                    puts
         | 
| 39 40 | 
             
                  end
         | 
| 40 41 | 
             
                end
         | 
| @@ -125,6 +126,13 @@ class ErrorsCLI | |
| 125 126 | 
             
                  FlowErrorDemo.invalid_node_route
         | 
| 126 127 | 
             
                end
         | 
| 127 128 | 
             
              end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
              desc 'Interface errors'
         | 
| 131 | 
            +
              command :interface do |cmd|
         | 
| 132 | 
            +
                make_cmd cmd, 'Missing Implementation', :missing_implementation do
         | 
| 133 | 
            +
                  InterfaceErrorDemo.missing_implementation
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
              end
         | 
| 128 136 | 
             
            end
         | 
| 129 137 |  | 
| 130 138 | 
             
            exit ErrorsCLI.run(ARGV)
         | 
    
        data/flows.gemspec
    CHANGED
    
    | @@ -21,6 +21,8 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength | |
| 21 21 | 
             
              spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
         | 
| 22 22 | 
             
              spec.require_paths = ['lib']
         | 
| 23 23 |  | 
| 24 | 
            +
              spec.required_ruby_version = '>= 2.5'
         | 
| 25 | 
            +
             | 
| 24 26 | 
             
              # This library has no production dependencies.
         | 
| 25 27 | 
             
              # So, it will not block you from updating any dependencies in your project.
         | 
| 26 28 | 
             
              # So, don't add production dependencies.
         | 
    
        data/lib/flows/contract.rb
    CHANGED
    
    | @@ -394,9 +394,9 @@ module Flows | |
| 394 394 |  | 
| 395 395 | 
             
                # :reek:UtilityFunction
         | 
| 396 396 | 
             
                def merge_nested_errors(description, nested_errors)
         | 
| 397 | 
            -
                  shifted = nested_errors.split("\n").map { |str|  | 
| 397 | 
            +
                  shifted = nested_errors.split("\n").map { |str| "    #{str}" }.join("\n")
         | 
| 398 398 |  | 
| 399 | 
            -
                  description | 
| 399 | 
            +
                  "#{description}\n#{shifted}"
         | 
| 400 400 | 
             
                end
         | 
| 401 401 | 
             
              end
         | 
| 402 402 | 
             
            end
         | 
    
        data/lib/flows/contract/error.rb
    CHANGED
    
    
    
        data/lib/flows/plugin.rb
    CHANGED
    
    
| @@ -136,6 +136,17 @@ module Flows | |
| 136 136 |  | 
| 137 137 | 
             
                  InitializerWrapper = Util::PrependToClass.make_module do
         | 
| 138 138 | 
             
                    def initialize(*args, **kwargs, &block) # rubocop:disable Metrics/MethodLength
         | 
| 139 | 
            +
                      if @__dependencies_injected__
         | 
| 140 | 
            +
                        if kwargs.empty? # https://bugs.ruby-lang.org/issues/14415
         | 
| 141 | 
            +
                          super(*args, &block)
         | 
| 142 | 
            +
                        else
         | 
| 143 | 
            +
                          super(*args, **kwargs, &block)
         | 
| 144 | 
            +
                        end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                        return
         | 
| 147 | 
            +
                      end
         | 
| 148 | 
            +
                      @__dependencies_injected__ = true
         | 
| 149 | 
            +
             | 
| 139 150 | 
             
                      klass = self.class
         | 
| 140 151 | 
             
                      DependencyList.new(
         | 
| 141 152 | 
             
                        klass: klass,
         | 
| @@ -5,9 +5,7 @@ module Flows | |
| 5 5 | 
             
                  #
         | 
| 6 6 | 
             
                  # @api private
         | 
| 7 7 | 
             
                  class DependencyList
         | 
| 8 | 
            -
                    attr_reader :definitions
         | 
| 9 | 
            -
                    attr_reader :provided_values
         | 
| 10 | 
            -
                    attr_reader :dependencies
         | 
| 8 | 
            +
                    attr_reader :definitions, :provided_values, :dependencies
         | 
| 11 9 |  | 
| 12 10 | 
             
                    def initialize(klass:, definitions:, provided_values:)
         | 
| 13 11 | 
             
                      @klass = klass
         | 
| @@ -0,0 +1,84 @@ | |
| 1 | 
            +
            module Flows
         | 
| 2 | 
            +
              module Plugin
         | 
| 3 | 
            +
                # Class extension to define Java/C#-like interfaces in Ruby.
         | 
| 4 | 
            +
                #
         | 
| 5 | 
            +
                # On target class initialization will check defined methods for existence.
         | 
| 6 | 
            +
                #
         | 
| 7 | 
            +
                # **Currently interface composition is not supported.** You cannot define
         | 
| 8 | 
            +
                # 2 interface modules and include it into one class.
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                # @example Simple interface
         | 
| 11 | 
            +
                #   class MyAction
         | 
| 12 | 
            +
                #     extend Flows::Plugin::Interface
         | 
| 13 | 
            +
                #
         | 
| 14 | 
            +
                #     defmethod :perform
         | 
| 15 | 
            +
                #   end
         | 
| 16 | 
            +
                #
         | 
| 17 | 
            +
                #   class InvalidAction < MyAction; end
         | 
| 18 | 
            +
                #   InvalidAction.new
         | 
| 19 | 
            +
                #   # will raise an error
         | 
| 20 | 
            +
                #
         | 
| 21 | 
            +
                #   class ValidAction < MyAction
         | 
| 22 | 
            +
                #     def perfrom
         | 
| 23 | 
            +
                #       puts 'Hello!'
         | 
| 24 | 
            +
                #     end
         | 
| 25 | 
            +
                #   end
         | 
| 26 | 
            +
                #   ValidAction.new.perform
         | 
| 27 | 
            +
                #   # => Hello!
         | 
| 28 | 
            +
                #
         | 
| 29 | 
            +
                # @example Interface as module
         | 
| 30 | 
            +
                #   module MyBehavior
         | 
| 31 | 
            +
                #     extend Flows::Plugin::Interface
         | 
| 32 | 
            +
                #
         | 
| 33 | 
            +
                #     defmethod :my_method
         | 
| 34 | 
            +
                #   end
         | 
| 35 | 
            +
                #
         | 
| 36 | 
            +
                #   class MyImplementation
         | 
| 37 | 
            +
                #     include MyBehaviour
         | 
| 38 | 
            +
                #
         | 
| 39 | 
            +
                #     def my_method; end
         | 
| 40 | 
            +
                #   end
         | 
| 41 | 
            +
                module Interface
         | 
| 42 | 
            +
                  # Base error class for interface errors.
         | 
| 43 | 
            +
                  class Error < ::Flows::Error; end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  # Raised when you're missed some dependency.
         | 
| 46 | 
            +
                  class MissingMethodsError < Error
         | 
| 47 | 
            +
                    def initialize(klass, names)
         | 
| 48 | 
            +
                      @klass = klass
         | 
| 49 | 
            +
                      @names = names
         | 
| 50 | 
            +
                    end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                    def message
         | 
| 53 | 
            +
                      "Methods required by interface for #{@klass} are missing: #{@names.map(&:to_s).join(', ')}"
         | 
| 54 | 
            +
                    end
         | 
| 55 | 
            +
                  end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  SingletonVarsSetup = Flows::Util::InheritableSingletonVars::DupStrategy.make_module(
         | 
| 58 | 
            +
                    '@interface_methods' => {}
         | 
| 59 | 
            +
                  )
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  include SingletonVarsSetup
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  InitializePatch = Flows::Util::PrependToClass.make_module do
         | 
| 64 | 
            +
                    def initialize(*)
         | 
| 65 | 
            +
                      klass = self.class
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                      required_methods = klass.instance_variable_get(:@interface_methods).keys
         | 
| 68 | 
            +
                      missing_methods = required_methods - methods
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                      raise MissingMethodsError.new(klass, missing_methods) if missing_methods.any?
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                      super
         | 
| 73 | 
            +
                    end
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  include InitializePatch
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  def defmethod(method_name)
         | 
| 79 | 
            +
                    method_list = instance_variable_get(:@interface_methods)
         | 
| 80 | 
            +
                    method_list[method_name.to_sym] = { required_by: self }
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
              end
         | 
| 84 | 
            +
            end
         | 
| @@ -39,7 +39,7 @@ module Flows | |
| 39 39 | 
             
                    # Disables contract check and transformation for current class and children.
         | 
| 40 40 | 
             
                    #
         | 
| 41 41 | 
             
                    # @param enable [Boolean] if true - contracts are disabled
         | 
| 42 | 
            -
                    def skip_output_contract(enable  | 
| 42 | 
            +
                    def skip_output_contract(enable: true)
         | 
| 43 43 | 
             
                      @skip_output_contract_flag = enable
         | 
| 44 44 | 
             
                    end
         | 
| 45 45 | 
             
                  end
         | 
    
        data/lib/flows/railway/step.rb
    CHANGED
    
    | @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            module Flows
         | 
| 2 2 | 
             
              class Railway
         | 
| 3 | 
            -
                 | 
| 4 | 
            -
                Step = Struct.new(:name, :lambda, :next_step, keyword_init: true) do
         | 
| 5 | 
            -
                  NODE_PREPROCESSOR = ->(input, _, _) { [[], input.unwrap] }
         | 
| 3 | 
            +
                NODE_PREPROCESSOR = ->(input, _, _) { [[], input.unwrap] }
         | 
| 6 4 |  | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 5 | 
            +
                NODE_POSTPROCESSOR = lambda do |output, context, meta|
         | 
| 6 | 
            +
                  context[:last_step] = meta[:name]
         | 
| 9 7 |  | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 8 | 
            +
                  output
         | 
| 9 | 
            +
                end
         | 
| 12 10 |  | 
| 11 | 
            +
                # @api private
         | 
| 12 | 
            +
                Step = Struct.new(:name, :lambda, :next_step, keyword_init: true) do
         | 
| 13 13 | 
             
                  def to_node(method_source)
         | 
| 14 14 | 
             
                    Flows::Flow::Node.new(
         | 
| 15 15 | 
             
                      body: lambda || method_source.method(name),
         | 
| @@ -141,6 +141,46 @@ module Flows | |
| 141 141 | 
             
              #       # steps implementations here
         | 
| 142 142 | 
             
              #     end
         | 
| 143 143 | 
             
              #
         | 
| 144 | 
            +
              # ## Simple injecting of nested pipelines
         | 
| 145 | 
            +
              #
         | 
| 146 | 
            +
              # If you provide some object which responds to `#call` instead of step name - this object will be used as a step body.
         | 
| 147 | 
            +
              #
         | 
| 148 | 
            +
              #     class SubOperation < Flows::SharedContextPipeline
         | 
| 149 | 
            +
              #       step :hello
         | 
| 150 | 
            +
              #
         | 
| 151 | 
            +
              #       def hello(**)
         | 
| 152 | 
            +
              #         ok(data: 'some data')
         | 
| 153 | 
            +
              #       end
         | 
| 154 | 
            +
              #     end
         | 
| 155 | 
            +
              #
         | 
| 156 | 
            +
              #     class MainOperation < Flows::SharedContextPipeline
         | 
| 157 | 
            +
              #       step :init
         | 
| 158 | 
            +
              #       step SubOperation
         | 
| 159 | 
            +
              #
         | 
| 160 | 
            +
              #       def init(**)
         | 
| 161 | 
            +
              #         ok(generated_by_init: true)
         | 
| 162 | 
            +
              #       end
         | 
| 163 | 
            +
              #     end
         | 
| 164 | 
            +
              #
         | 
| 165 | 
            +
              #     MainOperation.call
         | 
| 166 | 
            +
              #     # => ok(generated_by_init: true, data: 'some data')
         | 
| 167 | 
            +
              #
         | 
| 168 | 
            +
              # You can use the same object multiple times in the same pipeline:
         | 
| 169 | 
            +
              #
         | 
| 170 | 
            +
              #     step SubOperation
         | 
| 171 | 
            +
              #     step SubOperation
         | 
| 172 | 
            +
              #
         | 
| 173 | 
            +
              # If you need any input or output processing - refactor such step definition into normal step.
         | 
| 174 | 
            +
              #
         | 
| 175 | 
            +
              # This way has disadvantage: you cannot route to a such step because it has no explicit name.
         | 
| 176 | 
            +
              # To handle this you can use alternative syntax:
         | 
| 177 | 
            +
              #
         | 
| 178 | 
            +
              #     step :do_something, body: SubOperation
         | 
| 179 | 
            +
              #
         | 
| 180 | 
            +
              # Same features can be used with `mut_step`.
         | 
| 181 | 
            +
              #
         | 
| 182 | 
            +
              # This feature is primarily intended to simplify refactoring of big pipelines into smaller ones.
         | 
| 183 | 
            +
              #
         | 
| 144 184 | 
             
              # ## Wrappers
         | 
| 145 185 | 
             
              #
         | 
| 146 186 | 
             
              # Sometimes you have to execute some steps inside SQL-transaction or something like this.
         | 
| @@ -224,6 +264,9 @@ module Flows | |
| 224 264 | 
             
              #
         | 
| 225 265 | 
             
              # You may want to have some logic to execute before all steps, or after all, or before each, or after each.
         | 
| 226 266 | 
             
              # For example to inject generalized execution process logging.
         | 
| 267 | 
            +
              #
         | 
| 268 | 
            +
              # These callbacks are executed via `instance_exec` (in the context of instance).
         | 
| 269 | 
            +
              #
         | 
| 227 270 | 
             
              # To achieve this you can use callbacks:
         | 
| 228 271 | 
             
              #
         | 
| 229 272 | 
             
              #     class MySCP < Flows::SharedContextPipeline
         | 
| @@ -277,10 +320,10 @@ module Flows | |
| 277 320 | 
             
                def call(**data) # rubocop:disable Metrics/MethodLength
         | 
| 278 321 | 
             
                  klass = self.class
         | 
| 279 322 | 
             
                  meta = {}
         | 
| 280 | 
            -
                  context = { data: data, meta: meta, class: klass }
         | 
| 323 | 
            +
                  context = { data: data, meta: meta, class: klass, instance: self }
         | 
| 281 324 |  | 
| 282 325 | 
             
                  klass.before_all_callbacks.each do |callback|
         | 
| 283 | 
            -
                     | 
| 326 | 
            +
                    instance_exec(klass, data, meta, &callback)
         | 
| 284 327 | 
             
                  end
         | 
| 285 328 |  | 
| 286 329 | 
             
                  flow_result = @__flow.call(nil, context: context)
         | 
| @@ -292,7 +335,7 @@ module Flows | |
| 292 335 | 
             
                  )
         | 
| 293 336 |  | 
| 294 337 | 
             
                  klass.after_all_callbacks.reduce(final_result) do |result, callback|
         | 
| 295 | 
            -
                     | 
| 338 | 
            +
                    instance_exec(klass, result, data, meta, &callback)
         | 
| 296 339 | 
             
                  end
         | 
| 297 340 | 
             
                end
         | 
| 298 341 | 
             
              end
         | 
| @@ -12,10 +12,7 @@ module Flows | |
| 12 12 |  | 
| 13 13 | 
             
                    include SingletonVarsSetup
         | 
| 14 14 |  | 
| 15 | 
            -
                    attr_reader :before_all_callbacks
         | 
| 16 | 
            -
                    attr_reader :after_all_callbacks
         | 
| 17 | 
            -
                    attr_reader :before_each_callbacks
         | 
| 18 | 
            -
                    attr_reader :after_each_callbacks
         | 
| 15 | 
            +
                    attr_reader :before_all_callbacks, :after_all_callbacks, :before_each_callbacks, :after_each_callbacks
         | 
| 19 16 |  | 
| 20 17 | 
             
                    def before_all(&callback)
         | 
| 21 18 | 
             
                      before_all_callbacks << callback
         | 
| @@ -16,15 +16,15 @@ module Flows | |
| 16 16 |  | 
| 17 17 | 
             
                    attr_reader :tracks
         | 
| 18 18 |  | 
| 19 | 
            -
                    def step(name, router_def = DEFAULT_ROUTER_DEF,  | 
| 19 | 
            +
                    def step(name, router_def = DEFAULT_ROUTER_DEF, body: nil)
         | 
| 20 20 | 
             
                      tracks.add_step(
         | 
| 21 | 
            -
                        Step.new(name: name,  | 
| 21 | 
            +
                        Step.new(name: name, body: body, router_def: router_def)
         | 
| 22 22 | 
             
                      )
         | 
| 23 23 | 
             
                    end
         | 
| 24 24 |  | 
| 25 | 
            -
                    def mut_step(name, router_def = DEFAULT_ROUTER_DEF,  | 
| 25 | 
            +
                    def mut_step(name, router_def = DEFAULT_ROUTER_DEF, body: nil)
         | 
| 26 26 | 
             
                      tracks.add_step(
         | 
| 27 | 
            -
                        MutationStep.new(name: name,  | 
| 27 | 
            +
                        MutationStep.new(name: name, body: body, router_def: router_def)
         | 
| 28 28 | 
             
                      )
         | 
| 29 29 | 
             
                    end
         | 
| 30 30 |  | 
| @@ -8,7 +8,7 @@ module Flows | |
| 8 8 | 
             
                class MutationStep < Step
         | 
| 9 9 | 
             
                  NODE_PREPROCESSOR = lambda do |_input, context, node_meta|
         | 
| 10 10 | 
             
                    context[:class].before_each_callbacks.each do |callback|
         | 
| 11 | 
            -
                       | 
| 11 | 
            +
                      context[:instance].instance_exec(context[:class], node_meta[:name], context[:data], context[:meta], &callback)
         | 
| 12 12 | 
             
                    end
         | 
| 13 13 |  | 
| 14 14 | 
             
                    [[context[:data]], EMPTY_HASH]
         | 
| @@ -20,7 +20,8 @@ module Flows | |
| 20 20 | 
             
                    else output ? EMPTY_OK : EMPTY_ERR
         | 
| 21 21 | 
             
                    end.tap do |result|
         | 
| 22 22 | 
             
                      context[:class].after_each_callbacks.each do |callback|
         | 
| 23 | 
            -
                         | 
| 23 | 
            +
                        context[:instance]
         | 
| 24 | 
            +
                          .instance_exec(context[:class], node_meta[:name], result, context[:data], context[:meta], &callback)
         | 
| 24 25 | 
             
                      end
         | 
| 25 26 | 
             
                    end
         | 
| 26 27 | 
             
                  end
         | 
| @@ -3,12 +3,22 @@ module Flows | |
| 3 3 | 
             
                EMPTY_ARRAY = [].freeze
         | 
| 4 4 |  | 
| 5 5 | 
             
                # @api private
         | 
| 6 | 
            -
                Step = Struct.new(:name, : | 
| 6 | 
            +
                Step = Struct.new(:name, :body, :router_def, :next_step, keyword_init: true) do
         | 
| 7 | 
            +
                  # :reek:ManualDispatch
         | 
| 8 | 
            +
                  def initialize(name:, body: nil, **rest)
         | 
| 9 | 
            +
                    if name.respond_to?(:call)
         | 
| 10 | 
            +
                      body = name
         | 
| 11 | 
            +
                      name = "#{body}+Step-Object-ID-#{object_id}"
         | 
| 12 | 
            +
                    end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                    super(name: name, body: body, **rest)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 7 17 | 
             
                  def to_node(pipeline_class)
         | 
| 8 18 | 
             
                    klass = self.class
         | 
| 9 19 |  | 
| 10 20 | 
             
                    Flows::Flow::Node.new(
         | 
| 11 | 
            -
                      body:  | 
| 21 | 
            +
                      body: body || pipeline_class.method(name),
         | 
| 12 22 | 
             
                      router: router_def.to_router(next_step),
         | 
| 13 23 | 
             
                      meta: { name: name },
         | 
| 14 24 | 
             
                      preprocessor: klass::NODE_PREPROCESSOR,
         | 
| @@ -21,7 +31,7 @@ module Flows | |
| 21 31 | 
             
                  :NODE_PREPROCESSOR,
         | 
| 22 32 | 
             
                  lambda do |_input, context, node_meta|
         | 
| 23 33 | 
             
                    context[:class].before_each_callbacks.each do |callback|
         | 
| 24 | 
            -
                       | 
| 34 | 
            +
                      context[:instance].instance_exec(context[:class], node_meta[:name], context[:data], context[:meta], &callback)
         | 
| 25 35 | 
             
                    end
         | 
| 26 36 |  | 
| 27 37 | 
             
                    [EMPTY_ARRAY, context[:data]]
         | 
| @@ -34,7 +44,8 @@ module Flows | |
| 34 44 | 
             
                    context[:data].merge!(result.instance_variable_get(:@data))
         | 
| 35 45 |  | 
| 36 46 | 
             
                    context[:class].after_each_callbacks.each do |callback|
         | 
| 37 | 
            -
                       | 
| 47 | 
            +
                      context[:instance]
         | 
| 48 | 
            +
                        .instance_exec(context[:class], node_meta[:name], result, context[:data], context[:meta], &callback)
         | 
| 38 49 | 
             
                    end
         | 
| 39 50 |  | 
| 40 51 | 
             
                    result
         | 
| @@ -24,14 +24,16 @@ module Flows | |
| 24 24 |  | 
| 25 25 | 
             
                    # @api private
         | 
| 26 26 | 
             
                    module Migrator
         | 
| 27 | 
            -
                       | 
| 28 | 
            -
             | 
| 29 | 
            -
                         | 
| 27 | 
            +
                      # :reek:TooManyStatements is allowed here because it's impossible to split to smaller methods
         | 
| 28 | 
            +
                      def self.call(src_mod, dst_mod)
         | 
| 29 | 
            +
                        parent_var_list = src_mod.instance_variable_get(VAR_LIST_VAR_NAME)
         | 
| 30 | 
            +
                        child_var_list = dst_mod.instance_variable_get(VAR_LIST_VAR_NAME) || []
         | 
| 31 | 
            +
                        skip_list = parent_var_list & child_var_list
         | 
| 30 32 |  | 
| 31 | 
            -
                         | 
| 33 | 
            +
                        dst_mod.instance_variable_set(VAR_LIST_VAR_NAME, (child_var_list + parent_var_list).uniq)
         | 
| 32 34 |  | 
| 33 | 
            -
                        parent_var_list.each do |name|
         | 
| 34 | 
            -
                           | 
| 35 | 
            +
                        (parent_var_list - skip_list).each do |name|
         | 
| 36 | 
            +
                          dst_mod.instance_variable_set(name, src_mod.instance_variable_get(name).dup)
         | 
| 35 37 | 
             
                        end
         | 
| 36 38 | 
             
                      end
         | 
| 37 39 | 
             
                    end
         | 
| @@ -138,7 +138,8 @@ module Flows | |
| 138 138 | 
             
                    # * you can include `Mod` into `Mod2`, then include `Mod2` into `Mod3` -
         | 
| 139 139 | 
             
                    #   desribed behavior works for include chain of any length.
         | 
| 140 140 | 
             
                    #
         | 
| 141 | 
            -
                    #  | 
| 141 | 
            +
                    # Each `include` generates a new prepend. Be careful about this when including
         | 
| 142 | 
            +
                    # generated module several times in the inheritance chain.
         | 
| 142 143 | 
             
                    #
         | 
| 143 144 | 
             
                    # @yield body for module which will be prepended
         | 
| 144 145 | 
             
                    # @return [Module] module to be included or extended into your module
         | 
| @@ -160,7 +161,8 @@ module Flows | |
| 160 161 | 
             
                      mod.singleton_class.prepend(injector)
         | 
| 161 162 | 
             
                    end
         | 
| 162 163 |  | 
| 163 | 
            -
                     | 
| 164 | 
            +
                    # :reek:TooManyStatements :reek:DuplicateMethodCall
         | 
| 165 | 
            +
                    def make_injector_mod(module_to_prepend) # rubocop:disable Metrics/MethodLength
         | 
| 164 166 | 
             
                      Module.new.tap do |injector|
         | 
| 165 167 | 
             
                        injector.define_method(:included) do |target_mod|
         | 
| 166 168 | 
             
                          if target_mod.class == Class
         | 
| @@ -171,6 +173,16 @@ module Flows | |
| 171 173 |  | 
| 172 174 | 
             
                          super(target_mod)
         | 
| 173 175 | 
             
                        end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                        injector.define_method(:extended) do |target_mod|
         | 
| 178 | 
            +
                          if target_mod.class == Class
         | 
| 179 | 
            +
                            target_mod.prepend(module_to_prepend)
         | 
| 180 | 
            +
                          else # Module
         | 
| 181 | 
            +
                            target_mod.singleton_class.prepend injector
         | 
| 182 | 
            +
                          end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                          super(target_mod)
         | 
| 185 | 
            +
                        end
         | 
| 174 186 | 
             
                      end
         | 
| 175 187 | 
             
                    end
         | 
| 176 188 | 
             
                  end
         | 
    
        data/lib/flows/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: flows
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.6.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Roman Kolesnev
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020- | 
| 11 | 
            +
            date: 2020-09-23 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: bundler
         | 
| @@ -387,6 +387,7 @@ files: | |
| 387 387 | 
             
            - ".reek.yml"
         | 
| 388 388 | 
             
            - ".rspec"
         | 
| 389 389 | 
             
            - ".rubocop.yml"
         | 
| 390 | 
            +
            - ".rubocop_todo.yml"
         | 
| 390 391 | 
             
            - ".ruby-version"
         | 
| 391 392 | 
             
            - ".yardopts"
         | 
| 392 393 | 
             
            - CHANGELOG.md
         | 
| @@ -434,6 +435,7 @@ files: | |
| 434 435 | 
             
            - bin/errors_cli/di_error_demo.rb
         | 
| 435 436 | 
             
            - bin/errors_cli/flow_error_demo.rb
         | 
| 436 437 | 
             
            - bin/errors_cli/flows_router_error_demo.rb
         | 
| 438 | 
            +
            - bin/errors_cli/interface_error_demo.rb
         | 
| 437 439 | 
             
            - bin/errors_cli/oc_error_demo.rb
         | 
| 438 440 | 
             
            - bin/errors_cli/railway_error_demo.rb
         | 
| 439 441 | 
             
            - bin/errors_cli/result_error_demo.rb
         | 
| @@ -473,6 +475,7 @@ files: | |
| 473 475 | 
             
            - lib/flows/plugin/dependency_injector/dependency_list.rb
         | 
| 474 476 | 
             
            - lib/flows/plugin/dependency_injector/errors.rb
         | 
| 475 477 | 
             
            - lib/flows/plugin/implicit_init.rb
         | 
| 478 | 
            +
            - lib/flows/plugin/interface.rb
         | 
| 476 479 | 
             
            - lib/flows/plugin/output_contract.rb
         | 
| 477 480 | 
             
            - lib/flows/plugin/output_contract/dsl.rb
         | 
| 478 481 | 
             
            - lib/flows/plugin/output_contract/errors.rb
         | 
| @@ -529,7 +532,7 @@ required_ruby_version: !ruby/object:Gem::Requirement | |
| 529 532 | 
             
              requirements:
         | 
| 530 533 | 
             
              - - ">="
         | 
| 531 534 | 
             
                - !ruby/object:Gem::Version
         | 
| 532 | 
            -
                  version: ' | 
| 535 | 
            +
                  version: '2.5'
         | 
| 533 536 | 
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         | 
| 534 537 | 
             
              requirements:
         | 
| 535 538 | 
             
              - - ">="
         |