nxt_pipeline 0.4.2 → 0.4.3
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/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +35 -32
- data/lib/nxt_pipeline/step.rb +54 -24
- data/lib/nxt_pipeline/version.rb +1 -1
- metadata +2 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 0f47be27dd03af5d8a11274b4667a40e2a0c14b4be0a373dd90e1fc7deb93c03
         | 
| 4 | 
            +
              data.tar.gz: 6964e21671bb458e187dd3289538e49243e42b06c38c804ffc2b69ed94146612
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5ba8339e42e2e485e9c0c00a35d6df56324b1145605d564039a4931d384d0297ef44b3613c8e45e83dfcfea83f0ed7b5a377f3a6e89f2a03e5b9dbfcc6e47b9a
         | 
| 7 | 
            +
              data.tar.gz: f9c938b9302bf9f2b4c126ddaa1b978b99c2f02fe1cdbc6d17be307135a22a504e002c6b110fa0b2eb92a04b5623f4293c8f92575c82ad2240f3de0b4a49a8ad
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,3 +1,10 @@ | |
| 1 | 
            +
            ## nxt_pipeline 0.4.3 (October 20, 2020)
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Add new attribute readers on step object.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            After executing a step execution_finished_at execution_started_at and execution_duration
         | 
| 6 | 
            +
            will be set and can be accessed via attribute readers.
         | 
| 7 | 
            +
             | 
| 1 8 | 
             
            ## nxt_pipeline 0.4.2 (October 12, 2020)
         | 
| 2 9 |  | 
| 3 10 | 
             
            * Fix bug when registering an error without passing arguments in which case the callback didn't get executed. More info: https://github.com/nxt-insurance/nxt_pipeline/issues/39
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -24,35 +24,35 @@ Or install it yourself as: | |
| 24 24 |  | 
| 25 25 | 
             
            ### Constructors
         | 
| 26 26 |  | 
| 27 | 
            -
            First you probably want to configure a pipeline so that it can execute your steps. | 
| 28 | 
            -
            Therefore you want to define constructors for your steps. Constructors take a name | 
| 27 | 
            +
            First you probably want to configure a pipeline so that it can execute your steps.
         | 
| 28 | 
            +
            Therefore you want to define constructors for your steps. Constructors take a name
         | 
| 29 29 | 
             
            as the first argument and step options as the second. All step options are being exposed
         | 
| 30 | 
            -
            by the step yielded to the constructor. | 
| 30 | 
            +
            by the step yielded to the constructor.
         | 
| 31 31 |  | 
| 32 32 | 
             
            ```ruby
         | 
| 33 33 | 
             
            pipeline = NxtPipeline::Pipeline.new do |p|
         | 
| 34 34 | 
             
              # Add a named constructor that will be used to execute your steps later
         | 
| 35 35 | 
             
              # All options that you pass in your step will be available through accessors in your constructor
         | 
| 36 | 
            -
              # You can call :to_s on a step to set it by default. You can later overwrite at execution for each step if needed. | 
| 36 | 
            +
              # You can call :to_s on a step to set it by default. You can later overwrite at execution for each step if needed.
         | 
| 37 37 | 
             
              p.constructor(:service, default: true) do |step, arg:|
         | 
| 38 38 | 
             
                step.to_s = step.service_class.to_s
         | 
| 39 39 | 
             
                result = step.service_class.new(options: arg).call
         | 
| 40 40 | 
             
                result && { arg: result }
         | 
| 41 41 | 
             
              end
         | 
| 42 | 
            -
             | 
| 42 | 
            +
             | 
| 43 43 | 
             
              p.constructor(:job) do |step, arg:|
         | 
| 44 44 | 
             
                step.job_class.perform_later(*arg) && { arg: arg }
         | 
| 45 45 | 
             
              end
         | 
| 46 46 | 
             
            end
         | 
| 47 47 |  | 
| 48 | 
            -
            # Once a pipeline was created you can still configure it | 
| 48 | 
            +
            # Once a pipeline was created you can still configure it
         | 
| 49 49 | 
             
            pipeline.constructor(:call) do |step, arg:|
         | 
| 50 50 | 
             
              result = step.caller.new(arg).call
         | 
| 51 51 | 
             
              result && { arg: result }
         | 
| 52 52 | 
             
            end
         | 
| 53 53 |  | 
| 54 | 
            -
            # same with block syntax | 
| 55 | 
            -
            # You can use this to split up execution from configuration | 
| 54 | 
            +
            # same with block syntax
         | 
| 55 | 
            +
            # You can use this to split up execution from configuration
         | 
| 56 56 | 
             
            pipeline.configure do |p|
         | 
| 57 57 | 
             
             p.constructor(:call) do |step, arg:|
         | 
| 58 58 | 
             
               result = step.caller.new(arg).call
         | 
| @@ -61,13 +61,13 @@ pipeline.configure do |p| | |
| 61 61 | 
             
            end
         | 
| 62 62 | 
             
            ```
         | 
| 63 63 |  | 
| 64 | 
            -
            ### Defining steps | 
| 64 | 
            +
            ### Defining steps
         | 
| 65 65 |  | 
| 66 66 | 
             
            Once your pipeline knows how to execute your steps you can add those.
         | 
| 67 67 |  | 
| 68 68 | 
             
            ```ruby
         | 
| 69 69 | 
             
            pipeline.step :service, service_class: MyServiceClass, to_s: 'First step'
         | 
| 70 | 
            -
            pipeline.step service_class: MyOtherServiceClass, to_s: 'Second step' | 
| 70 | 
            +
            pipeline.step service_class: MyOtherServiceClass, to_s: 'Second step'
         | 
| 71 71 | 
             
            # ^ Since service is the default step you don't have to specify it the step type each time
         | 
| 72 72 | 
             
            pipeline.step :job, job_class: MyJobClass # to_s is optional
         | 
| 73 73 | 
             
            pipeline.step :job, job_class: MyOtherJobClass
         | 
| @@ -82,12 +82,12 @@ end | |
| 82 82 | 
             
            ```
         | 
| 83 83 |  | 
| 84 84 | 
             
            You can also define inline steps, meaning the block will be executed. When you do not provide a :to_s option, type
         | 
| 85 | 
            -
            will be used as :to_s option per default. When no type was given for an inline block the type of the inline block | 
| 86 | 
            -
            will be set to :inline. | 
| 85 | 
            +
            will be used as :to_s option per default. When no type was given for an inline block the type of the inline block
         | 
| 86 | 
            +
            will be set to :inline.
         | 
| 87 87 |  | 
| 88 88 | 
             
            ### Execution
         | 
| 89 89 |  | 
| 90 | 
            -
            You can then execute the steps with: | 
| 90 | 
            +
            You can then execute the steps with:
         | 
| 91 91 |  | 
| 92 92 | 
             
            ```ruby
         | 
| 93 93 | 
             
            pipeline.execute(arg: 'initial argument')
         | 
| @@ -111,13 +111,13 @@ NxtPipeline::Pipeline.execute(arg: 'initial argument') do |p| | |
| 111 111 | 
             
                { arg: arg.upcase }
         | 
| 112 112 | 
             
              end
         | 
| 113 113 | 
             
            end
         | 
| 114 | 
            -
            ``` | 
| 114 | 
            +
            ```
         | 
| 115 115 |  | 
| 116 | 
            -
            You can query the steps of your pipeline simply by calling `pipeline.steps`. A NxtPipeline::Step will provide you with | 
| 117 | 
            -
            an interface to it's type, options, status (:success, :skipped, :failed), result, error and the index in the pipeline.
         | 
| 116 | 
            +
            You can query the steps of your pipeline simply by calling `pipeline.steps`. A NxtPipeline::Step will provide you with
         | 
| 117 | 
            +
            an interface to it's type, options, status (:success, :skipped, :failed), execution_finished_at execution_started_at, execution_duration, result, error and the index in the pipeline.
         | 
| 118 118 |  | 
| 119 119 | 
             
            ```
         | 
| 120 | 
            -
            pipeline.steps.first | 
| 120 | 
            +
            pipeline.steps.first
         | 
| 121 121 | 
             
            # will give you something like this:
         | 
| 122 122 |  | 
| 123 123 | 
             
            #<NxtPipeline::Step:0x00007f83eb399448
         | 
| @@ -128,20 +128,23 @@ pipeline.steps.first | |
| 128 128 | 
             
             @opts={:to_s=>:transformer, :method=>:upcase},
         | 
| 129 129 | 
             
             @result=nil,
         | 
| 130 130 | 
             
             @status=nil,
         | 
| 131 | 
            -
             @type=:transformer | 
| 132 | 
            -
             | 
| 131 | 
            +
             @type=:transformer
         | 
| 132 | 
            +
             @execution_duration=1.0e-05,
         | 
| 133 | 
            +
             @execution_finished_at=2020-10-22 15:52:55.806417 +0100,
         | 
| 134 | 
            +
             @execution_started_at=2020-10-22 15:52:55.806407 +0100,>
         | 
| 135 | 
            +
            ```
         | 
| 133 136 |  | 
| 134 137 | 
             
            ### Guard clauses
         | 
| 135 138 |  | 
| 136 139 | 
             
            You can also define guard clauses that take a proc to prevent the execution of a step.
         | 
| 137 | 
            -
            When the guard takes an argument the step argument is yielded. | 
| 140 | 
            +
            When the guard takes an argument the step argument is yielded.
         | 
| 138 141 |  | 
| 139 142 | 
             
             ```ruby
         | 
| 140 143 | 
             
             pipeline.execute(arg: 'initial argument') do |p|
         | 
| 141 144 | 
             
               p.step :service, service_class: MyServiceClass, if: -> (arg:) { arg == 'initial argument' }
         | 
| 142 145 | 
             
               p.step :service, service_class: MyOtherServiceClass, unless: -> { false }
         | 
| 143 146 | 
             
             end
         | 
| 144 | 
            -
             | 
| 147 | 
            +
             | 
| 145 148 | 
             
             ```
         | 
| 146 149 |  | 
| 147 150 | 
             
            ### Error callbacks
         | 
| @@ -153,25 +156,25 @@ NxtPipeline::Pipeline.new do |p| | |
| 153 156 | 
             
              p.step do |_, arg:|
         | 
| 154 157 | 
             
                { arg: arg.upcase }
         | 
| 155 158 | 
             
              end
         | 
| 156 | 
            -
             | 
| 159 | 
            +
             | 
| 157 160 | 
             
              p.on_error MyCustomError do |step, opts, error|
         | 
| 158 161 | 
             
                # First matching error callback will be executed!
         | 
| 159 162 | 
             
              end
         | 
| 160 | 
            -
             | 
| 163 | 
            +
             | 
| 161 164 | 
             
              p.on_errors ArgumentError, KeyError do |step, opts, error|
         | 
| 162 165 | 
             
                # First matching error callback will be executed!
         | 
| 163 166 | 
             
              end
         | 
| 164 | 
            -
             | 
| 167 | 
            +
             | 
| 165 168 | 
             
              p.on_errors YetAnotherError, halt_on_error: false do |step, opts, error|
         | 
| 166 169 | 
             
                # After executing the callback the pipeline will not halt but continue to
         | 
| 167 170 | 
             
                # execute the next steps.
         | 
| 168 171 | 
             
              end
         | 
| 169 | 
            -
             | 
| 172 | 
            +
             | 
| 170 173 | 
             
              p.on_errors do |step, opts, error|
         | 
| 171 174 | 
             
                # This will match all errors inheriting from StandardError
         | 
| 172 175 | 
             
              end
         | 
| 173 176 | 
             
            end
         | 
| 174 | 
            -
            ``` | 
| 177 | 
            +
            ```
         | 
| 175 178 |  | 
| 176 179 | 
             
            ### Before and After callbacks
         | 
| 177 180 |  | 
| @@ -181,27 +184,27 @@ You can also define callbacks that run before and after the `#execute` action. B | |
| 181 184 | 
             
            NxtPipeline::Pipeline.new do |p|
         | 
| 182 185 | 
             
              p.before_execute do |pipeline, arg:|
         | 
| 183 186 | 
             
                # Will be called from within #execute before entering the first step
         | 
| 184 | 
            -
                # After any configure block though! | 
| 187 | 
            +
                # After any configure block though!
         | 
| 185 188 | 
             
              end
         | 
| 186 | 
            -
             | 
| 189 | 
            +
             | 
| 187 190 | 
             
              p.after_execute do |pipeline, arg:|
         | 
| 188 191 | 
             
                # Will be called from within #execute after executing last step
         | 
| 189 192 | 
             
              end
         | 
| 190 193 | 
             
            end
         | 
| 191 194 | 
             
            ```
         | 
| 192 195 |  | 
| 193 | 
            -
            Note that the `after_execute` callback will not be called, when an error is raised in one of the steps. See the previous section (_Error callbacks_) for how to define callbacks that run in case of errors. | 
| 196 | 
            +
            Note that the `after_execute` callback will not be called, when an error is raised in one of the steps. See the previous section (_Error callbacks_) for how to define callbacks that run in case of errors.
         | 
| 194 197 |  | 
| 195 198 | 
             
            ### Step resolvers
         | 
| 196 199 |  | 
| 197 200 | 
             
            NxtPipeline is using so called step_resolvers to find the constructor for a given step by the arguments passed in.
         | 
| 198 | 
            -
            You can also use this if you are not fine with resolving the constructor from the step argument. Check out the | 
| 199 | 
            -
            `nxt_pipeline/spec/step_resolver_spec.rb` for examples how you can implement your own step_resolvers. | 
| 201 | 
            +
            You can also use this if you are not fine with resolving the constructor from the step argument. Check out the
         | 
| 202 | 
            +
            `nxt_pipeline/spec/step_resolver_spec.rb` for examples how you can implement your own step_resolvers.
         | 
| 200 203 |  | 
| 201 204 |  | 
| 202 205 | 
             
            ## Topics
         | 
| 203 206 | 
             
            - Step orchestration (chainable steps)
         | 
| 204 | 
            -
            - Constructors should take arg as first and step as second arg | 
| 207 | 
            +
            - Constructors should take arg as first and step as second arg
         | 
| 205 208 |  | 
| 206 209 | 
             
            ## Development
         | 
| 207 210 |  | 
    
        data/lib/nxt_pipeline/step.rb
    CHANGED
    
    | @@ -16,47 +16,57 @@ module NxtPipeline | |
| 16 16 | 
             
                  @mapped_options = nil
         | 
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 | 
            -
                attr_reader :argument, :result, :status, :error, :opts, :index, :mapped_options
         | 
| 19 | 
            +
                attr_reader :argument, :result, :status, :execution_started_at, :execution_finished_at, :execution_duration, :error, :opts, :index, :mapped_options
         | 
| 20 20 | 
             
                attr_accessor :to_s
         | 
| 21 21 |  | 
| 22 22 | 
             
                alias_method :name=, :to_s=
         | 
| 23 23 | 
             
                alias_method :name, :to_s
         | 
| 24 24 |  | 
| 25 25 | 
             
                def execute(**changeset)
         | 
| 26 | 
            -
                   | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
                  guard_args = [changeset, self]
         | 
| 26 | 
            +
                  track_execution_time do
         | 
| 27 | 
            +
                    set_mapped_options(changeset)
         | 
| 28 | 
            +
                    guard_args = [changeset, self]
         | 
| 31 29 |  | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
                  if !instrumentalize_callable(unless_guard, unless_guard_guard_args) && instrumentalize_callable(if_guard, if_guard_args)
         | 
| 36 | 
            -
                    constructor_args = [self, changeset]
         | 
| 37 | 
            -
                    constructor_args = constructor_args.take(constructor.arity)
         | 
| 30 | 
            +
                    if evaluate_unless_guard(guard_args) && evaluate_if_guard(guard_args)
         | 
| 31 | 
            +
                      self.result = construct_result(changeset)
         | 
| 32 | 
            +
                    end
         | 
| 38 33 |  | 
| 39 | 
            -
                     | 
| 34 | 
            +
                    set_status
         | 
| 35 | 
            +
                    result
         | 
| 40 36 | 
             
                  end
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                  set_status
         | 
| 43 | 
            -
                  result
         | 
| 44 37 | 
             
                rescue StandardError => e
         | 
| 45 38 | 
             
                  self.status = :failed
         | 
| 46 39 | 
             
                  self.error = e
         | 
| 47 40 | 
             
                  raise
         | 
| 48 41 | 
             
                end
         | 
| 49 42 |  | 
| 50 | 
            -
                 | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 43 | 
            +
                def set_mapped_options(changeset)
         | 
| 44 | 
            +
                  mapper = options_mapper || default_options_mapper
         | 
| 45 | 
            +
                  mapper_args = [changeset, self].take(mapper.arity)
         | 
| 46 | 
            +
                  self.mapped_options = mapper.call(*mapper_args)
         | 
| 47 | 
            +
                end
         | 
| 53 48 |  | 
| 54 49 | 
             
                private
         | 
| 55 50 |  | 
| 56 | 
            -
                attr_writer :result, :status, :error, :mapped_options
         | 
| 51 | 
            +
                attr_writer :result, :status, :error, :mapped_options, :execution_started_at, :execution_finished_at, :execution_duration
         | 
| 57 52 | 
             
                attr_reader :constructor, :options_mapper
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                def  | 
| 53 | 
            +
             | 
| 54 | 
            +
                def evaluate_if_guard(args)
         | 
| 55 | 
            +
                  execute_callable(if_guard, args)
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                def evaluate_unless_guard(args)
         | 
| 59 | 
            +
                  !execute_callable(unless_guard, args)
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def construct_result(changeset)
         | 
| 63 | 
            +
                  args = [self, changeset]
         | 
| 64 | 
            +
                  execute_callable(constructor, args)
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def execute_callable(callable, args)
         | 
| 68 | 
            +
                  args =  args.take(callable.arity)
         | 
| 69 | 
            +
             | 
| 60 70 | 
             
                  if args.last.is_a?(Hash)
         | 
| 61 71 | 
             
                    callable.call(*args.take(args.length - 1), **args.last)
         | 
| 62 72 | 
             
                  else
         | 
| @@ -88,9 +98,29 @@ module NxtPipeline | |
| 88 98 | 
             
                  self.status = result.present? ? :success : :skipped
         | 
| 89 99 | 
             
                end
         | 
| 90 100 |  | 
| 101 | 
            +
                def track_execution_time(&block)
         | 
| 102 | 
            +
                  set_execution_started_at
         | 
| 103 | 
            +
                  block.call
         | 
| 104 | 
            +
                ensure
         | 
| 105 | 
            +
                  set_execution_finished_at
         | 
| 106 | 
            +
                  set_execution_duration
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                def set_execution_started_at
         | 
| 110 | 
            +
                  self.execution_started_at = Time.current
         | 
| 111 | 
            +
                end
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                def set_execution_finished_at
         | 
| 114 | 
            +
                  self.execution_finished_at = Time.current
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                def set_execution_duration
         | 
| 118 | 
            +
                  self.execution_duration = execution_finished_at - execution_started_at
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
             | 
| 91 121 | 
             
                def default_options_mapper
         | 
| 92 122 | 
             
                  # returns an empty hash
         | 
| 93 | 
            -
                  ->( | 
| 123 | 
            +
                  ->(_) { {} }
         | 
| 94 124 | 
             
                end
         | 
| 95 125 | 
             
              end
         | 
| 96 | 
            -
            end
         | 
| 126 | 
            +
            end
         | 
    
        data/lib/nxt_pipeline/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: nxt_pipeline
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0.4. | 
| 4 | 
            +
              version: 0.4.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Nils Sommer
         | 
| @@ -10,7 +10,7 @@ authors: | |
| 10 10 | 
             
            autorequire: 
         | 
| 11 11 | 
             
            bindir: exe
         | 
| 12 12 | 
             
            cert_chain: []
         | 
| 13 | 
            -
            date: 2020-10- | 
| 13 | 
            +
            date: 2020-10-23 00:00:00.000000000 Z
         | 
| 14 14 | 
             
            dependencies:
         | 
| 15 15 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 16 16 | 
             
              name: activesupport
         |