README.md in nxt_pipeline-0.2.8 vs README.md in nxt_pipeline-0.3.0
- old
+ new
@@ -30,30 +30,35 @@
by the step yielded to the constructor.
```ruby
pipeline = NxtPipeline::Pipeline.new do |p|
# Add a named constructor that will be used to execute your steps later
- # All options that you pass in your step will be available through accessors in your constructor
- p.constructor(:service, default: true) do |step, arg|
- step.service_class.new(options: arg).call
+ # All options that you pass in your step will be available through accessors in your constructor
+ # You can call :to_s on a step to set it by default. You can later overwrite at execution for each step if needed.
+ p.constructor(:service, default: true) do |step, arg:|
+ step.to_s = step.service_class.to_s
+ result = step.service_class.new(options: arg).call
+ result && { arg: result }
end
- p.constructor(:job) do |step, arg|
- step.job_class.perform_later(*arg) && arg
+ p.constructor(:job) do |step, arg:|
+ step.job_class.perform_later(*arg) && { arg: arg }
end
end
# Once a pipeline was created you can still configure it
-pipeline.constructor(:call) do |step, arg|
- step.caller.new(arg).call
+pipeline.constructor(:call) do |step, arg:|
+ result = step.caller.new(arg).call
+ result && { arg: result }
end
# same with block syntax
# You can use this to split up execution from configuration
pipeline.configure do |p|
- p.constructor(:call) do |step, arg|
- step.caller.new(arg).call
+ p.constructor(:call) do |step, arg:|
+ result = step.caller.new(arg).call
+ result && { arg: result }
end
end
```
### Defining steps
@@ -65,15 +70,15 @@
pipeline.step service_class: MyOtherServiceClass, to_s: 'Second step'
# ^ Since service is the default step you don't have to specify it the step type each time
pipeline.step :job, job_class: MyJobClass # to_s is optional
pipeline.step :job, job_class: MyOtherJobClass
-pipeline.step :step_name_for_better_log do |_, arg|
+pipeline.step :step_name_for_better_log do |_, arg:|
# ...
end
-pipeline.step to_s: 'This is the same as above' do |step, arg|
+pipeline.step to_s: 'This is the same as above' do |step, arg:|
# ... step.to_s => 'This is the same as above'
end
```
You can also define inline steps, meaning the block will be executed. When you do not provide a :to_s option, type
@@ -100,12 +105,12 @@
You can also directly execute a pipeline with:
```ruby
NxtPipeline::Pipeline.execute('initial argument') do |p|
- p.step do |_, arg|
- arg.upcase
+ p.step do |_, arg:|
+ { arg: arg.upcase }
end
end
```
You can query the steps of your pipeline simply by calling `pipeline.steps`. A NxtPipeline::Step will provide you with
@@ -131,11 +136,11 @@
You can also define guard clauses that take a proc to prevent the execution of a step.
When the guard takes an argument the step argument is yielded.
```ruby
pipeline.execute('initial argument') do |p|
- p.step :service, service_class: MyServiceClass, if: -> (arg) { arg == 'initial argument' }
+ p.step :service, service_class: MyServiceClass, if: -> (arg:) { arg == 'initial argument' }
p.step :service, service_class: MyOtherServiceClass, unless: -> { false }
end
```
@@ -143,28 +148,28 @@
Apart from defining constructors and steps you can also define error callbacks.
```ruby
NxtPipeline::Pipeline.new do |p|
- p.step do |_, arg|
- arg.upcase
+ p.step do |_, arg:|
+ { arg: arg.upcase }
end
- p.on_error MyCustomError do |step, arg, error|
+ p.on_error MyCustomError do |step, opts, error|
# First matching error callback will be executed!
end
- p.on_errors ArgumentError, KeyError do |step, arg, error|
+ p.on_errors ArgumentError, KeyError do |step, opts, error|
# First matching error callback will be executed!
end
- p.on_errors YetAnotherError, halt_on_error: false do |step, arg, error|
+ p.on_errors YetAnotherError, halt_on_error: false do |step, opts, error|
# After executing the callback the pipeline will not halt but continue to
# execute the next steps.
end
- p.on_errors do |step, arg, error|
+ p.on_errors do |step, opts, error|
# This will match all errors inheriting from StandardError
end
end
```
@@ -172,22 +177,75 @@
You can also define callbacks that run before and after the `#execute` action. Both callback blocks get the pipeline instance (to access stuff like the `log`) and the argument of the pipeline yielded.
```ruby
NxtPipeline::Pipeline.new do |p|
- p.before_execute do |pipeline, arg|
+ p.before_execute do |pipeline, arg:|
# Will be called from within #execute before entering the first step
# After any configure block though!
end
- p.after_execute do |pipeline, arg|
+ p.after_execute do |pipeline, arg:|
# Will be called from within #execute after executing last step
end
end
```
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.
+### DSL
+
+The gem also comes with an easy DSL to make pipeline handling in your code more convenient.
+Simply include NxtPipeline::Dsl in your class:
+
+```ruby
+class MyAwesomeClass
+ include NxtPipeline::Dsl
+
+ # register a pipeline with a name and a block
+ pipeline :validation do |p|
+ pipeline.constructor(:validate) do |step, arg:|
+ result = step.validator.call(arg: arg)
+ result && { arg: result }
+ end
+
+ pipeline.step :validate, validator: NameValidator
+ pipeline.step :validate, validator: AdressValidator
+ pipeline.step :validate, validator: BankAccountValidator
+ pipeline.step :validate, validator: PhoneNumberValidator
+
+ p.on_error ValidationError do |step, opts, error|
+ # ...
+ end
+ end
+
+ pipeline :execution do |p|
+ p.step do |_, arg:|
+ { arg: arg.upcase }
+ end
+
+ p.on_error MyCustomError do |step, opts, error|
+ # nesting pipelines also works
+ pipeline(:error).execute(error)
+ end
+ end
+
+ pipeline :error do |p|
+ p.step do |_, error|
+ error # do something here
+ end
+ end
+
+ def call(arg)
+ # execute a pipeline simply by fetching it and calling execute on it as you would normally
+ pipeline(:execution).execute(arg: arg)
+ end
+end
+```
+
+## Topics
+- Step orchestration (chainable steps)
+- Constructors should take arg as first and step as second arg
## Development
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.