nxt_pipeline 0.3.1 → 0.4.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/Gemfile.lock +4 -2
- data/README.md +4 -4
- data/lib/nxt_pipeline/dsl.rb +17 -13
- data/lib/nxt_pipeline/pipeline.rb +39 -29
- data/lib/nxt_pipeline/step.rb +26 -12
- data/lib/nxt_pipeline/version.rb +2 -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: e8762564262fbcc4274226dd10acd423e960f31624ae20ca539a4951a626e211
|
4
|
+
data.tar.gz: 17f1adb27f76aaddf71e2dd00ae303e8837560e4fdfae911a98812f30408e541
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: efb282aef978706713a0f76332a66298c99d5278794e6935742d08a5d54d271d9c01a633e0c8fcf7d5b67a4c0f945d3fe4de64b871558e7e4a80ac5e87088264
|
7
|
+
data.tar.gz: 48b4ba6cbb45a9a7f2848e70bc3bd4e6bde884badf820e74cda8d1fea69903f5119204bc073f5f8b6e6386ef6c805f5b0e009938dd881a024d8842947a3697e5
|
data/Gemfile.lock
CHANGED
@@ -1,17 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
nxt_pipeline (0.
|
4
|
+
nxt_pipeline (0.4.0)
|
5
5
|
activesupport
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
activesupport (
|
10
|
+
activesupport (6.0.0)
|
11
11
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
12
|
i18n (>= 0.7, < 2)
|
13
13
|
minitest (~> 5.1)
|
14
14
|
tzinfo (~> 1.1)
|
15
|
+
zeitwerk (~> 2.1, >= 2.1.8)
|
15
16
|
coderay (1.1.2)
|
16
17
|
concurrent-ruby (1.1.5)
|
17
18
|
diff-lcs (1.3)
|
@@ -72,6 +73,7 @@ GEM
|
|
72
73
|
thread_safe (0.3.6)
|
73
74
|
tzinfo (1.2.5)
|
74
75
|
thread_safe (~> 0.1)
|
76
|
+
zeitwerk (2.1.9)
|
75
77
|
|
76
78
|
PLATFORMS
|
77
79
|
ruby
|
data/README.md
CHANGED
@@ -90,11 +90,11 @@ will be set to :inline.
|
|
90
90
|
You can then execute the steps with:
|
91
91
|
|
92
92
|
```ruby
|
93
|
-
pipeline.execute('initial argument')
|
93
|
+
pipeline.execute(arg: 'initial argument')
|
94
94
|
|
95
95
|
# Or run the steps directly using block syntax
|
96
96
|
|
97
|
-
pipeline.execute('initial argument') do |p|
|
97
|
+
pipeline.execute(arg: 'initial argument') do |p|
|
98
98
|
p.step :service, service_class: MyServiceClass, to_s: 'First step'
|
99
99
|
p.step :service, service_class: MyOtherServiceClass, to_s: 'Second step'
|
100
100
|
p.step :job, job_class: MyJobClass # to_s is optional
|
@@ -106,7 +106,7 @@ end
|
|
106
106
|
You can also directly execute a pipeline with:
|
107
107
|
|
108
108
|
```ruby
|
109
|
-
NxtPipeline::Pipeline.execute('initial argument') do |p|
|
109
|
+
NxtPipeline::Pipeline.execute(arg: 'initial argument') do |p|
|
110
110
|
p.step do |_, arg:|
|
111
111
|
{ arg: arg.upcase }
|
112
112
|
end
|
@@ -137,7 +137,7 @@ You can also define guard clauses that take a proc to prevent the execution of a
|
|
137
137
|
When the guard takes an argument the step argument is yielded.
|
138
138
|
|
139
139
|
```ruby
|
140
|
-
pipeline.execute('initial argument') do |p|
|
140
|
+
pipeline.execute(arg: 'initial argument') do |p|
|
141
141
|
p.step :service, service_class: MyServiceClass, if: -> (arg:) { arg == 'initial argument' }
|
142
142
|
p.step :service, service_class: MyOtherServiceClass, unless: -> { false }
|
143
143
|
end
|
data/lib/nxt_pipeline/dsl.rb
CHANGED
@@ -1,27 +1,22 @@
|
|
1
1
|
module NxtPipeline
|
2
2
|
module Dsl
|
3
3
|
module ClassMethods
|
4
|
-
def pipeline(name = :default, &block)
|
4
|
+
def pipeline(name = :default, parent = NxtPipeline::Pipeline, &block)
|
5
5
|
name = name.to_sym
|
6
|
-
|
7
|
-
if
|
8
|
-
|
9
|
-
pipeline_registry[name] = block
|
10
|
-
else
|
11
|
-
config = pipeline_registry.fetch(name) { raise KeyError, "No pipeline #{name} registered"}
|
12
|
-
NxtPipeline::Pipeline.new(&config)
|
13
|
-
end
|
6
|
+
raise ArgumentError, "No block given!" unless block_given?
|
7
|
+
raise_already_registered_error(name) if pipeline_registry.key?(name)
|
8
|
+
register_pipeline(name, block, parent)
|
14
9
|
end
|
15
10
|
|
16
|
-
def pipeline!(name, &block)
|
11
|
+
def pipeline!(name, parent = NxtPipeline::Pipeline, &block)
|
17
12
|
raise ArgumentError, "No block given!" unless block_given?
|
18
|
-
|
13
|
+
register_pipeline(name, block, parent)
|
19
14
|
end
|
20
15
|
|
21
16
|
private
|
22
17
|
|
23
18
|
def inherited(child)
|
24
|
-
child.instance_variable_set(:@pipeline_registry, pipeline_registry.
|
19
|
+
child.instance_variable_set(:@pipeline_registry, pipeline_registry.deep_dup)
|
25
20
|
end
|
26
21
|
|
27
22
|
def raise_already_registered_error(name)
|
@@ -31,13 +26,22 @@ module NxtPipeline
|
|
31
26
|
def pipeline_registry
|
32
27
|
@pipeline_registry ||= ActiveSupport::HashWithIndifferentAccess.new
|
33
28
|
end
|
29
|
+
|
30
|
+
def register_pipeline(name, block, parent)
|
31
|
+
pipeline_registry[name] = { config: block, parent: parent }
|
32
|
+
end
|
34
33
|
end
|
35
34
|
|
36
35
|
def self.included(base)
|
37
36
|
base.extend(ClassMethods)
|
38
37
|
|
39
38
|
def pipeline(name = :default)
|
40
|
-
self.class.
|
39
|
+
registry = self.class.send(:pipeline_registry)
|
40
|
+
entry = registry.fetch(name) { raise KeyError, "No pipeline #{name} registered"}
|
41
|
+
config = entry.fetch(:config)
|
42
|
+
pipeline = entry.fetch(:parent).new
|
43
|
+
instance_exec(pipeline, &config)
|
44
|
+
pipeline
|
41
45
|
end
|
42
46
|
end
|
43
47
|
end
|
@@ -4,14 +4,15 @@ module NxtPipeline
|
|
4
4
|
new(&block).execute(**opts)
|
5
5
|
end
|
6
6
|
|
7
|
-
def initialize(&block)
|
7
|
+
def initialize(step_resolvers = default_step_resolvers, &block)
|
8
8
|
@steps = []
|
9
9
|
@error_callbacks = []
|
10
10
|
@logger = Logger.new
|
11
11
|
@current_step = nil
|
12
12
|
@current_arg = nil
|
13
13
|
@default_constructor_name = nil
|
14
|
-
@
|
14
|
+
@constructors = {}
|
15
|
+
@step_resolvers = step_resolvers
|
15
16
|
|
16
17
|
configure(&block) if block_given?
|
17
18
|
end
|
@@ -22,14 +23,18 @@ module NxtPipeline
|
|
22
23
|
|
23
24
|
def constructor(name, **opts, &constructor)
|
24
25
|
name = name.to_sym
|
25
|
-
raise StandardError, "Already registered step :#{name}" if
|
26
|
+
raise StandardError, "Already registered step :#{name}" if constructors[name]
|
26
27
|
|
27
|
-
|
28
|
+
constructors[name] = Constructor.new(name, opts, constructor)
|
28
29
|
|
29
30
|
return unless opts.fetch(:default, false)
|
30
31
|
set_default_constructor(name)
|
31
32
|
end
|
32
33
|
|
34
|
+
def step_resolver(&block)
|
35
|
+
step_resolvers << block
|
36
|
+
end
|
37
|
+
|
33
38
|
def set_default_constructor(name)
|
34
39
|
raise_duplicate_default_constructor if default_constructor_name.present?
|
35
40
|
self.default_constructor_name = name
|
@@ -39,43 +44,44 @@ module NxtPipeline
|
|
39
44
|
raise ArgumentError, 'Default step already defined'
|
40
45
|
end
|
41
46
|
|
42
|
-
def step(
|
43
|
-
type = type&.to_sym
|
44
|
-
|
47
|
+
def step(argument = nil, **opts, &block)
|
45
48
|
constructor = if block_given?
|
46
49
|
# make type the :to_s of inline steps
|
47
50
|
# fall back to :inline if no type is given
|
48
|
-
|
49
|
-
opts.reverse_merge!(to_s:
|
50
|
-
Constructor.new(
|
51
|
+
argument ||= :inline
|
52
|
+
opts.reverse_merge!(to_s: argument)
|
53
|
+
Constructor.new(:inline, opts, block)
|
51
54
|
else
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
constructor = step_resolvers.lazy.map do |resolver|
|
56
|
+
resolver.call(argument)
|
57
|
+
end.find(&:itself)
|
58
|
+
|
59
|
+
if constructor
|
60
|
+
constructor && constructors.fetch(constructor) { raise KeyError, "No step :#{argument} registered" }
|
61
|
+
elsif default_constructor
|
62
|
+
argument ||= default_constructor_name
|
63
|
+
default_constructor
|
55
64
|
else
|
56
|
-
|
57
|
-
type = default_constructor_name
|
58
|
-
# If none was given - raise
|
59
|
-
default_constructor || (raise StandardError, 'No default step registered')
|
65
|
+
raise StandardError, "Could not resolve step from: #{argument}"
|
60
66
|
end
|
61
67
|
end
|
62
68
|
|
63
|
-
steps << Step.new(
|
69
|
+
steps << Step.new(argument, constructor, steps.count, **opts)
|
64
70
|
end
|
65
71
|
|
66
|
-
def execute(**
|
72
|
+
def execute(**changeset, &block)
|
67
73
|
reset
|
68
74
|
|
69
75
|
configure(&block) if block_given?
|
70
|
-
before_execute_callback.call(self,
|
76
|
+
before_execute_callback.call(self, changeset) if before_execute_callback.respond_to?(:call)
|
71
77
|
|
72
|
-
result = steps.inject(
|
73
|
-
execute_step(step, **
|
78
|
+
result = steps.inject(changeset) do |changeset, step|
|
79
|
+
execute_step(step, **changeset)
|
74
80
|
rescue StandardError => error
|
75
81
|
callback = find_error_callback(error)
|
76
82
|
raise unless callback && callback.continue_after_error?
|
77
83
|
handle_step_error(error)
|
78
|
-
|
84
|
+
changeset
|
79
85
|
end
|
80
86
|
|
81
87
|
after_execute_callback.call(self, result) if after_execute_callback.respond_to?(:call)
|
@@ -109,7 +115,7 @@ module NxtPipeline
|
|
109
115
|
|
110
116
|
private
|
111
117
|
|
112
|
-
attr_reader :error_callbacks, :
|
118
|
+
attr_reader :error_callbacks, :constructors, :step_resolvers
|
113
119
|
attr_accessor :current_step,
|
114
120
|
:current_arg,
|
115
121
|
:default_constructor_name,
|
@@ -119,15 +125,15 @@ module NxtPipeline
|
|
119
125
|
def default_constructor
|
120
126
|
return unless default_constructor_name
|
121
127
|
|
122
|
-
@default_constructor ||=
|
128
|
+
@default_constructor ||= constructors[default_constructor_name.to_sym]
|
123
129
|
end
|
124
130
|
|
125
|
-
def execute_step(step, **
|
131
|
+
def execute_step(step, **changeset)
|
126
132
|
self.current_step = step
|
127
|
-
self.current_arg =
|
128
|
-
result = step.execute(**
|
133
|
+
self.current_arg = changeset
|
134
|
+
result = step.execute(**changeset)
|
129
135
|
log_step(step)
|
130
|
-
result ||
|
136
|
+
result || changeset
|
131
137
|
end
|
132
138
|
|
133
139
|
def find_error_callback(error)
|
@@ -148,5 +154,9 @@ module NxtPipeline
|
|
148
154
|
def raise_reserved_type_inline_error
|
149
155
|
raise ArgumentError, 'Type :inline is reserved for inline steps!'
|
150
156
|
end
|
157
|
+
|
158
|
+
def default_step_resolvers
|
159
|
+
[->(step_argument) { step_argument.is_a?(Symbol) && step_argument }]
|
160
|
+
end
|
151
161
|
end
|
152
162
|
end
|
data/lib/nxt_pipeline/step.rb
CHANGED
@@ -1,32 +1,41 @@
|
|
1
1
|
module NxtPipeline
|
2
2
|
class Step
|
3
|
-
def initialize(
|
3
|
+
def initialize(argument, constructor, index, **opts)
|
4
4
|
define_attr_readers(opts)
|
5
5
|
|
6
|
-
@
|
6
|
+
@argument = argument
|
7
7
|
@index = index
|
8
8
|
@opts = opts
|
9
9
|
@constructor = constructor
|
10
|
-
@to_s = "#{opts.merge(
|
10
|
+
@to_s = "#{opts.merge(argument: argument)}"
|
11
|
+
@options_mapper = opts[:map_options]
|
11
12
|
|
12
13
|
@status = nil
|
13
14
|
@result = nil
|
14
15
|
@error = nil
|
16
|
+
@mapped_options = nil
|
15
17
|
end
|
16
18
|
|
17
|
-
attr_reader :
|
19
|
+
attr_reader :argument, :result, :status, :error, :opts, :index, :mapped_options
|
18
20
|
attr_accessor :to_s
|
19
21
|
|
20
22
|
alias_method :name=, :to_s=
|
21
23
|
alias_method :name, :to_s
|
22
24
|
|
23
|
-
def execute(**
|
24
|
-
|
25
|
+
def execute(**changeset)
|
26
|
+
mapper = options_mapper || default_options_mapper
|
27
|
+
mapper_args = [changeset, self].take(mapper.arity)
|
28
|
+
self.mapped_options = mapper.call(*mapper_args)
|
29
|
+
|
30
|
+
guard_args = [changeset, self]
|
31
|
+
|
25
32
|
if_guard_args = guard_args.take(if_guard.arity)
|
26
33
|
unless_guard_guard_args = guard_args.take(unless_guard.arity)
|
27
34
|
|
28
35
|
if !unless_guard.call(*unless_guard_guard_args) && if_guard.call(*if_guard_args)
|
29
|
-
|
36
|
+
constructor_args = [self, changeset]
|
37
|
+
constructor_args = constructor_args.take(constructor.arity)
|
38
|
+
self.result = constructor.call(*constructor_args)
|
30
39
|
end
|
31
40
|
|
32
41
|
set_status
|
@@ -37,14 +46,14 @@ module NxtPipeline
|
|
37
46
|
raise
|
38
47
|
end
|
39
48
|
|
40
|
-
def type?(potential_type)
|
41
|
-
|
42
|
-
end
|
49
|
+
# def type?(potential_type)
|
50
|
+
# constructor.resolve_type(potential_type)
|
51
|
+
# end
|
43
52
|
|
44
53
|
private
|
45
54
|
|
46
|
-
attr_writer :result, :status, :error
|
47
|
-
attr_reader :constructor
|
55
|
+
attr_writer :result, :status, :error, :mapped_options
|
56
|
+
attr_reader :constructor, :options_mapper
|
48
57
|
|
49
58
|
def if_guard
|
50
59
|
opts.fetch(:if) { guard(true) }
|
@@ -69,5 +78,10 @@ module NxtPipeline
|
|
69
78
|
def set_status
|
70
79
|
self.status = result.present? ? :success : :skipped
|
71
80
|
end
|
81
|
+
|
82
|
+
def default_options_mapper
|
83
|
+
# returns an empty hash
|
84
|
+
->(changeset) { {} }
|
85
|
+
end
|
72
86
|
end
|
73
87
|
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
|
+
version: 0.4.0
|
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: 2019-08-
|
13
|
+
date: 2019-08-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|