core-pipeline 0.1.0 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12857259602df10fd3cb27322098ba04c9f3b7706fbd982939ba162e97f4dbcb
4
- data.tar.gz: fbb77341b33a2cb8195dd6431fd23efeb99499fd6bf3b175a1cadc831feae135
3
+ metadata.gz: 28a2f0e27827605918442c956cb6e4236cb146ba16c180f9418569dd09711da9
4
+ data.tar.gz: f7927e0c5657dfaa13e1bc03a48bfe0fb75ff5cb2b47d5417545c89a6cf41f78
5
5
  SHA512:
6
- metadata.gz: 8383cd41dc3db75a6b8329baff6f7af529b4fcb2f82464fa3be3c5afbb3fdfe44a8666aa2815ef115a191316066cb1a49c11a48747dd1b8755d9b89233329762
7
- data.tar.gz: 254a3bc8e99465394dd6f7b2bbe3dc8e90a73d655d037e3c1b44580c0de172f19360fe696683940aaf7d22c72950b91ef59ab7bd209bd30e09afdbc3929aaeb6
6
+ metadata.gz: 379641bc184684af5be9e35b02a926b5f85a52f63c83723afa95722136184a05c2474f64a8c8f67b5261989b098051eec20d5920901356dbaadc4063ee276dfa
7
+ data.tar.gz: 5bf61a391a6aac27d282eb7cb7fa8d1d973e50496316dc405760e9ef9510c7299cb46920993db62ed80b190a677342c80f4afcfd707526e14132e90621fbacc2
data/CHANGELOG.md CHANGED
@@ -1,7 +1,28 @@
1
+ ## [v0.4.0](https://github.com/metabahn/corerb/releases/tag/2021-11-02.1)
2
+
3
+ *released on 2021-11-02*
4
+
5
+ * `add` [#98](https://github.com/metabahn/corerb/pull/98) Add a finalizer to pipelines ([bryanp](https://github.com/bryanp))
6
+
7
+ ## [v0.3.0](https://github.com/metabahn/corerb/releases/tag/2021-11-02)
8
+
9
+ *released on 2021-11-02*
10
+
11
+ * `chg` [#97](https://github.com/metabahn/corerb/pull/97) Designate internal state with leading and trailing double underscores ([bryanp](https://github.com/bryanp))
12
+ * `chg` [#89](https://github.com/metabahn/corerb/pull/89) Allow the pipeline compiler to be extended ([bryanp](https://github.com/bryanp))
13
+
14
+ ## [v0.2.0](https://github.com/metabahn/corerb/releases/tag/2021-10-24)
15
+
16
+ *released on 2021-10-24*
17
+
18
+ * `chg` [#77](https://github.com/metabahn/corerb/pull/77) Add recompile support to pipelines ([bryanp](https://github.com/bryanp))
19
+
1
20
  ## [v0.1.0](https://github.com/metabahn/corerb/releases/tag/2021-07-15)
2
21
 
3
22
  *released on 2021-07-15*
4
23
 
24
+ * `fix` [#81](https://github.com/metabahn/corerb/pull/81) Tie up loose ends around curried pipeline actions ([bryanp](https://github.com/bryanp))
25
+ * `add` [#80](https://github.com/metabahn/corerb/pull/80) Define curried pipeline actions ([bryanp](https://github.com/bryanp))
5
26
  * `fix` [#69](https://github.com/metabahn/corerb/pull/69) Allow pipelines to be called at the class level ([bryanp](https://github.com/bryanp))
6
27
  * `add` [#64](https://github.com/metabahn/corerb/pull/64) Add a method for checking if a callable pipeline will call any actions ([bryanp](https://github.com/bryanp))
7
28
  * `chg` [#63](https://github.com/metabahn/corerb/pull/63) Improve inspect output for callable pipelines ([bryanp](https://github.com/bryanp))
@@ -10,26 +10,26 @@ module Core
10
10
  #
11
11
  class Action
12
12
  include Is::Stateful
13
- state :__used_random_suffixes, default: []
13
+ state :__used_random_suffixes__, default: []
14
14
 
15
15
  class << self
16
16
  # [public] Builds an action for a given target.
17
17
  #
18
- def build(target = nil, *args, before: nil, after: nil, context: nil, &block)
18
+ def build(target = nil, *args, before: nil, after: nil, context: nil, curry: false, &block)
19
19
  if block
20
- Actions::Block.new(target, before: before, after: after, context: context, &block)
20
+ Actions::Block.new(target, before: before, after: after, context: context, curry: curry, &block)
21
21
  else
22
- build_target(target, *args, before: before, after: after, context: context)
22
+ build_target(target, *args, before: before, after: after, context: context, curry: curry)
23
23
  end
24
24
  end
25
25
 
26
- private def build_target(first, *args, before:, after:, context:)
26
+ private def build_target(first, *args, before:, after:, context:, curry:)
27
27
  case first
28
28
  when String, Symbol
29
- if (target = build_target(args[0], *args[1..], before: before, after: after, context: context))
29
+ if (target = build_target(args[0], *args[1..], before: before, after: after, context: context, curry: curry))
30
30
  target
31
31
  else
32
- Actions::Method.new(first, before: before, after: after, context: context)
32
+ Actions::Method.new(first, before: before, after: after, context: context, curry: curry)
33
33
  end
34
34
  when NilClass
35
35
  nil
@@ -40,10 +40,10 @@ module Core
40
40
 
41
41
  def build_name
42
42
  suffix = generate_random_suffix
43
- if __used_random_suffixes.include?(suffix)
43
+ if __used_random_suffixes__.include?(suffix)
44
44
  build_name
45
45
  else
46
- __used_random_suffixes << suffix
46
+ __used_random_suffixes__ << suffix
47
47
  "action_#{suffix}"
48
48
  end
49
49
  end
@@ -55,11 +55,12 @@ module Core
55
55
 
56
56
  include Is::Inspectable
57
57
 
58
- def initialize(name, before: nil, after: nil, context: nil)
58
+ def initialize(name, before: nil, after: nil, context: nil, curry: false)
59
59
  @name = (name || self.class.build_name).to_sym
60
60
  @before = before
61
61
  @after = after
62
62
  @context = context
63
+ @curry = curry
63
64
  end
64
65
 
65
66
  # [public] The action name.
@@ -74,6 +75,16 @@ module Core
74
75
  #
75
76
  attr_reader :after
76
77
 
78
+ # [public] The context this action should be called in.
79
+ #
80
+ attr_reader :context
81
+
82
+ # [public] Returns `true` if the action should be curried.
83
+ #
84
+ def curried?
85
+ @curry == true
86
+ end
87
+
77
88
  # [public] Finalizes the action for the given context.
78
89
  #
79
90
  def finalize(context)
@@ -10,10 +10,10 @@ module Core
10
10
  class Block < Action
11
11
  include Is::Inspectable
12
12
 
13
- def initialize(name = nil, before: nil, after: nil, context: nil, &block)
13
+ def initialize(name = nil, before: nil, after: nil, context: nil, curry: false, &block)
14
14
  @block = block
15
15
 
16
- super(name, before: before, after: after, context: context)
16
+ super(name, before: before, after: after, context: context, curry: curry)
17
17
  end
18
18
 
19
19
  # [public]
@@ -21,13 +21,19 @@ module Core
21
21
  def finalize(context)
22
22
  case @context
23
23
  when NilClass
24
- context.define_method(@name, &@block)
24
+ unless context.method_defined?(@name)
25
+ context.define_method(@name, &@block)
26
+ end
27
+
25
28
  @name
26
29
  else
27
30
  if @block.binding.receiver.equal?(@context)
28
31
  @block
29
32
  else
30
- @context.define_singleton_method(@name, &@block)
33
+ unless context.singleton_class.method_defined?(@name)
34
+ @context.define_singleton_method(@name, &@block)
35
+ end
36
+
31
37
  @context.method(@name).to_proc
32
38
  end
33
39
  end
@@ -10,10 +10,10 @@ module Core
10
10
  class Method < Action
11
11
  include Is::Inspectable
12
12
 
13
- def initialize(name = nil, before: nil, after: nil, context: nil)
13
+ def initialize(name = nil, before: nil, after: nil, context: nil, curry: false)
14
14
  @method = nil
15
15
 
16
- super(name, before: before, after: after, context: context)
16
+ super(name, before: before, after: after, context: context, curry: curry)
17
17
  end
18
18
 
19
19
  # [public]
@@ -18,11 +18,29 @@ module Core
18
18
  @mutex = Mutex.new
19
19
  @actions = []
20
20
  @skipped = []
21
+ @compiled = false
22
+ @compiler = Compiler
23
+ end
24
+
25
+ def initialize_copy(...)
26
+ @actions = @actions.clone
27
+ @skipped = @skipped.clone
28
+ super
21
29
  end
22
30
 
23
31
  attr_reader :actions
24
32
  attr_reader :skipped
25
33
 
34
+ # [public]
35
+ #
36
+ attr_writer :compiler
37
+
38
+ # [public] Relocates to another object context.
39
+ #
40
+ def relocate(object)
41
+ @object = object
42
+ end
43
+
26
44
  # [public] Returns true if the pipeline will call any actions.
27
45
  #
28
46
  def any?
@@ -31,14 +49,16 @@ module Core
31
49
 
32
50
  # [public] Defines a pipeline action.
33
51
  #
34
- def action(*args, before: nil, after: nil, context: nil, &block)
35
- @actions << Action.build(*args, before: before, after: after, context: context, &block)
52
+ def action(*args, before: nil, after: nil, context: nil, curry: false, &block)
53
+ @actions << Action.build(*args, before: before, after: after, context: context, curry: curry, &block)
54
+ recompile if compiled?
36
55
  end
37
56
 
38
57
  # [public] Skips the given action.
39
58
  #
40
59
  def skip(name)
41
60
  @skipped << name.to_sym
61
+ recompile if compiled?
42
62
  end
43
63
 
44
64
  # [public] Replaces existing actions with actions from the given pipeline.
@@ -48,6 +68,7 @@ module Core
48
68
  @mutex.synchronize do
49
69
  @actions.clear
50
70
  @actions.concat(pipeline.pipeline.actions)
71
+ recompile if compiled?
51
72
  end
52
73
  else
53
74
  raise ArgumentError, "expected a pipeline"
@@ -59,6 +80,7 @@ module Core
59
80
  def include(pipeline)
60
81
  if (pipeline.is_a?(Class) || pipeline.is_a?(Module)) && pipeline.ancestors.include?(Is::Pipeline)
61
82
  @actions.concat(pipeline.pipeline.actions)
83
+ recompile if compiled?
62
84
  else
63
85
  raise ArgumentError, "expected a pipeline"
64
86
  end
@@ -70,6 +92,7 @@ module Core
70
92
  if (pipeline.is_a?(Class) || pipeline.is_a?(Module)) && pipeline.ancestors.include?(Is::Pipeline)
71
93
  pipeline.pipeline.actions.each do |action|
72
94
  @actions.delete(action)
95
+ recompile if compiled?
73
96
  end
74
97
  else
75
98
  raise ArgumentError, "expected a pipeline"
@@ -79,14 +102,30 @@ module Core
79
102
  # [public] Calls the pipeline in context of an object with the given arguments.
80
103
  #
81
104
  def call(object, ...)
82
- compile.call(object, ...)
105
+ finalize.call(object, ...)
83
106
  end
84
107
 
85
- private def compile
86
- instance_eval(Compiler.compile(self, @object), __FILE__, __LINE__ - 1)
108
+ # [public] Finalizes the pipeline.
109
+ #
110
+ def finalize
111
+ compile
87
112
 
88
113
  self
89
114
  end
115
+
116
+ private def compile
117
+ instance_eval(@compiler.compile(self, @object), __FILE__, __LINE__ - 1)
118
+ @compiled = true
119
+ end
120
+
121
+ private def recompile
122
+ singleton_class.remove_method(:call)
123
+ compile
124
+ end
125
+
126
+ private def compiled?
127
+ @compiled == true
128
+ end
90
129
  end
91
130
  end
92
131
  end
@@ -21,28 +21,39 @@ module Core
21
21
  CODE
22
22
  end
23
23
 
24
+ # [public]
25
+ #
24
26
  private def compile_call(callable, object)
25
27
  compiled = +""
26
- finalized_actions(callable, object).each_pair do |object_id, action|
27
- compiled << "begin; "
28
+ finalized_actions(callable, object).each_value do |action|
29
+ compiled << "begin\n"
30
+ compiled << compile_action(action, object)
31
+ compiled << "rescue Core::Pipeline::Signals::Rejected\n"
32
+ compiled << "end\n"
33
+ end
34
+
35
+ compiled
36
+ end
28
37
 
29
- compiled << case action
30
- when Symbol
31
- "object.#{action}(...); "
38
+ # [public]
39
+ #
40
+ private def compile_action(action, object)
41
+ case action[:finalized]
42
+ when Symbol
43
+ if object.private_method_defined?(action[:finalized])
44
+ "object.send(#{action[:finalized].inspect}, ...)\n"
32
45
  else
33
- "@__finalized_actions[#{object_id}].call(...); "
46
+ "object.#{action[:finalized]}(...)\n"
34
47
  end
35
-
36
- compiled << "rescue Core::Pipeline::Signals::Rejected; end\n"
48
+ else
49
+ "@__finalized_actions__[#{action[:object_id]}][:finalized].call(...)\n"
37
50
  end
38
-
39
- compiled
40
51
  end
41
52
 
42
53
  private def finalized_actions(callable, object)
43
54
  validate_skipped_actions(callable)
44
55
  finalized_actions = build_finalized_actions(callable, object)
45
- callable.instance_variable_set(:@__finalized_actions, finalized_actions)
56
+ callable.instance_variable_set(:@__finalized_actions__, finalized_actions)
46
57
  end
47
58
 
48
59
  private def validate_skipped_actions(callable)
@@ -57,9 +68,17 @@ module Core
57
68
  ordered_actions(callable).reject { |action|
58
69
  callable.skipped.include?(action.name)
59
70
  }.map { |action|
60
- action.finalize(object)
71
+ finalized = action.finalize(object)
72
+
73
+ finalized = if action.curried?
74
+ wrap_finalized_action_for_context(finalized, action.context || object)
75
+ else
76
+ finalized
77
+ end
78
+
79
+ {object: action, finalized: finalized, object_id: finalized.object_id}
61
80
  }.each_with_object({}) { |action, lookup|
62
- lookup[action.object_id] = action
81
+ lookup[action[:object_id]] = action
63
82
  }
64
83
  end
65
84
 
@@ -113,6 +132,205 @@ module Core
113
132
 
114
133
  ordered
115
134
  end
135
+
136
+ private def wrap_finalized_action_for_context(finalized, context)
137
+ case finalized
138
+ when Symbol
139
+ wrapped_name = :"curried_#{finalized}"
140
+ method = context.instance_method(finalized)
141
+ signature = [
142
+ build_method_arguments_signature(method),
143
+ build_method_keywords_signature(method),
144
+ "&block"
145
+ ].compact.join(", ")
146
+
147
+ code = <<~CODE
148
+ def #{wrapped_name}(*args, **kwargs, &block)
149
+ self.#{finalized}(#{signature})
150
+ end
151
+ CODE
152
+
153
+ context.class_eval(code, __FILE__, __LINE__ - 1)
154
+
155
+ wrapped_name
156
+ else
157
+ if callable_accepts_keyword_arguments?(finalized)
158
+ finalized_keywords = callable_keywords(finalized)
159
+
160
+ if callable_accepts_arguments?(finalized)
161
+ argument_count = callable_arguments(finalized).count
162
+
163
+ if callable_accepts_keyword_arguments_splat?(finalized)
164
+ if callable_accepts_arguments_splat?(finalized)
165
+ if RbConfig::CONFIG["RUBY_PROGRAM_VERSION"] < "3"
166
+ proc { |*args, **kwargs, &block|
167
+ finalized.call(*args.take(argument_count), *args[argument_count..], **kwargs.slice(*finalized_keywords), **kwargs.reject { |kwarg, _| finalized_keywords.include?(kwarg) }, &block)
168
+ }
169
+ else
170
+ proc { |*args, **kwargs, &block|
171
+ finalized.call(*args.take(argument_count), *args[argument_count..], **kwargs.slice(*finalized_keywords), **kwargs.except(*finalized_keywords), &block)
172
+ }
173
+ end
174
+ elsif RbConfig::CONFIG["RUBY_PROGRAM_VERSION"] < "3"
175
+ proc { |*args, **kwargs, &block|
176
+ finalized.call(*args.take(argument_count), **kwargs.slice(*finalized_keywords), **kwargs.reject { |kwarg, _| finalized_keywords.include?(kwarg) }, &block)
177
+ }
178
+ else
179
+ proc { |*args, **kwargs, &block|
180
+ finalized.call(*args.take(argument_count), **kwargs.slice(*finalized_keywords), **kwargs.except(*finalized_keywords), &block)
181
+ }
182
+ end
183
+ elsif callable_accepts_arguments_splat?(finalized)
184
+ proc { |*args, **kwargs, &block|
185
+ finalized.call(*args.take(argument_count), *args[argument_count..], **kwargs.slice(*finalized_keywords), &block)
186
+ }
187
+ else
188
+ proc { |*args, **kwargs, &block|
189
+ finalized.call(*args.take(argument_count), **kwargs.slice(*finalized_keywords), &block)
190
+ }
191
+ end
192
+ elsif callable_accepts_keyword_arguments_splat?(finalized)
193
+ if callable_accepts_arguments_splat?(finalized)
194
+ if RbConfig::CONFIG["RUBY_PROGRAM_VERSION"] < "3"
195
+ proc { |*args, **kwargs, &block|
196
+ finalized.call(*args, **kwargs.slice(*finalized_keywords), **kwargs.reject { |kwarg, _| finalized_keywords.include?(kwarg) }, &block)
197
+ }
198
+ else
199
+ proc { |*args, **kwargs, &block|
200
+ finalized.call(*args, **kwargs.slice(*finalized_keywords), **kwargs.except(*finalized_keywords), &block)
201
+ }
202
+ end
203
+ elsif RbConfig::CONFIG["RUBY_PROGRAM_VERSION"] < "3"
204
+ proc { |*, **kwargs, &block|
205
+ finalized.call(**kwargs.slice(*finalized_keywords), **kwargs.reject { |kwarg, _| finalized_keywords.include?(kwarg) }, &block)
206
+ }
207
+ else
208
+ proc { |*, **kwargs, &block|
209
+ finalized.call(**kwargs.slice(*finalized_keywords), **kwargs.except(*finalized_keywords), &block)
210
+ }
211
+ end
212
+ elsif callable_accepts_arguments_splat?(finalized)
213
+ proc { |*args, **kwargs, &block|
214
+ finalized.call(*args, **kwargs.slice(*finalized_keywords), &block)
215
+ }
216
+ else
217
+ proc { |*, **kwargs, &block|
218
+ finalized.call(**kwargs.slice(*finalized_keywords), &block)
219
+ }
220
+ end
221
+ elsif callable_accepts_arguments?(finalized)
222
+ argument_count = callable_arguments(finalized).count
223
+
224
+ if callable_accepts_keyword_arguments_splat?(finalized)
225
+ if callable_accepts_arguments_splat?(finalized)
226
+ proc { |*args, **kwargs, &block|
227
+ finalized.call(*args.take(argument_count), *args[argument_count..], **kwargs, &block)
228
+ }
229
+ else
230
+ proc { |*args, **kwargs, &block|
231
+ finalized.call(*args.take(argument_count), **kwargs, &block)
232
+ }
233
+ end
234
+ elsif callable_accepts_arguments_splat?(finalized)
235
+ proc { |*args, **, &block|
236
+ finalized.call(*args.take(argument_count), *args[argument_count..], &block)
237
+ }
238
+ else
239
+ proc { |*args, **, &block|
240
+ finalized.call(*args.take(argument_count), &block)
241
+ }
242
+ end
243
+ elsif callable_accepts_keyword_arguments_splat?(finalized)
244
+ if callable_accepts_arguments_splat?(finalized)
245
+ proc { |*args, **kwargs, &block|
246
+ finalized.call(*args, **kwargs, &block)
247
+ }
248
+ else
249
+ proc { |*, **kwargs, &block|
250
+ finalized.call(**kwargs, &block)
251
+ }
252
+ end
253
+ elsif callable_accepts_arguments_splat?(finalized)
254
+ proc { |*args, **, &block|
255
+ finalized.call(*args, &block)
256
+ }
257
+ else
258
+ proc { |*, **, &block|
259
+ finalized.call(&block)
260
+ }
261
+ end
262
+ end
263
+ end
264
+
265
+ private def build_method_arguments_signature(method)
266
+ return if method.arity == 0
267
+
268
+ arguments = callable_arguments(method)
269
+
270
+ if arguments.any?
271
+ if callable_accepts_arguments_splat?(method)
272
+ "*args.take(#{arguments.count}), *args[#{arguments.count}..]"
273
+ else
274
+ "*args.take(#{arguments.count})"
275
+ end
276
+ elsif callable_accepts_arguments_splat?(method)
277
+ "*args"
278
+ end
279
+ end
280
+
281
+ private def build_method_keywords_signature(method)
282
+ return if method.arity == 0
283
+
284
+ keywords = callable_keywords(method)
285
+
286
+ if keywords.any?
287
+ keywords_string = keywords.map { |keyword| ":#{keyword}" }.join(", ")
288
+
289
+ if callable_accepts_keyword_arguments_splat?(method)
290
+ if RbConfig::CONFIG["RUBY_PROGRAM_VERSION"] < "3"
291
+ "**kwargs.slice(#{keywords_string}), **kwargs.reject { |kwarg, _| [#{keywords_string}].include?(kwarg) }"
292
+ else
293
+ "**kwargs.slice(#{keywords_string}), **kwargs.except(*#{keywords_string})"
294
+ end
295
+ else
296
+ "**kwargs.slice(#{keywords_string})"
297
+ end
298
+ elsif callable_accepts_keyword_arguments_splat?(method)
299
+ "**kwargs"
300
+ end
301
+ end
302
+
303
+ private def callable_accepts_arguments_splat?(callable)
304
+ callable.parameters.any? { |type, _| type == :rest }
305
+ end
306
+
307
+ private def callable_accepts_keyword_arguments_splat?(callable)
308
+ callable.parameters.any? { |type, _| type == :keyrest }
309
+ end
310
+
311
+ private def callable_accepts_arguments?(callable)
312
+ callable.parameters.any? { |type, _| type == :req || type == :opt }
313
+ end
314
+
315
+ private def callable_accepts_keyword_arguments?(callable)
316
+ callable.parameters.any? { |type, _| type == :keyreq || type == :key }
317
+ end
318
+
319
+ private def callable_arguments(callable)
320
+ callable.parameters.select { |type, _|
321
+ type == :req || type == :opt
322
+ }.map { |_, name|
323
+ name
324
+ }
325
+ end
326
+
327
+ private def callable_keywords(callable)
328
+ callable.parameters.select { |type, _|
329
+ type == :keyreq || type == :key
330
+ }.map { |_, name|
331
+ name
332
+ }
333
+ end
116
334
  end
117
335
  end
118
336
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Core
4
4
  module Pipeline
5
- VERSION = "0.1.0"
5
+ VERSION = "0.4.0"
6
6
 
7
7
  def self.version
8
8
  VERSION
data/lib/is/pipeline.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "is/async"
4
3
  require "is/extension"
5
4
  require "is/stateful"
6
5
 
@@ -28,8 +27,8 @@ module Is
28
27
  extends :definition do
29
28
  # [public] Defines a pipeline action.
30
29
  #
31
- def action(*args, before: nil, after: nil, context: nil, &block)
32
- pipeline.action(*args, before: before, after: after, context: context, &block)
30
+ def action(*args, before: nil, after: nil, context: nil, curry: false, &block)
31
+ pipeline.action(*args, before: before, after: after, context: context, curry: curry, &block)
33
32
  end
34
33
 
35
34
  # [public] Skips the given action.
@@ -63,9 +62,50 @@ module Is
63
62
  def call(...)
64
63
  @pipeline.call(self, ...)
65
64
  end
65
+
66
+ # [public] Defines a pipeline action, isolated to the instance.
67
+ #
68
+ def action(*args, before: nil, after: nil, context: nil, curry: false, &block)
69
+ pipeline.relocate(singleton_class)
70
+ pipeline.action(*args, before: before, after: after, context: context, curry: curry, &block)
71
+ end
72
+
73
+ # [public] Skips the given action, isolated to the instance.
74
+ #
75
+ def skip_action(name)
76
+ pipeline.relocate(singleton_class)
77
+ pipeline.skip(name)
78
+ end
79
+
80
+ # [public] Replaces existing actions with actions from the given pipeline, isolated to the instance.
81
+ #
82
+ def use_pipeline(other_pipeline)
83
+ pipeline.relocate(singleton_class)
84
+ pipeline.use(other_pipeline)
85
+ end
86
+
87
+ # [public] Includes actions from the given pipeline, isolated to the instance.
88
+ #
89
+ def include_pipeline(other_pipeline)
90
+ pipeline.relocate(singleton_class)
91
+ pipeline.include(other_pipeline)
92
+ end
93
+
94
+ # [public] Excludes actions from the given pipeline, isolated to the instance.
95
+ #
96
+ def exclude_pipeline(other_pipeline)
97
+ pipeline.relocate(singleton_class)
98
+ pipeline.exclude(other_pipeline)
99
+ end
66
100
  end
67
101
 
68
102
  extends :implementation, prepend: true do
103
+ def finalize
104
+ super if defined?(super)
105
+ pipeline.finalize
106
+ self
107
+ end
108
+
69
109
  # [public] Halts the execution of the pipeline, setting the pipeline's current value to the given object.
70
110
  #
71
111
  private def halt(value = nil)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: core-pipeline
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bryan Powell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-15 00:00:00.000000000 Z
11
+ date: 2021-11-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: core-extension
@@ -89,7 +89,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
89
  - !ruby/object:Gem::Version
90
90
  version: '0'
91
91
  requirements: []
92
- rubygems_version: 3.2.15
92
+ rubygems_version: 3.2.22
93
93
  signing_key:
94
94
  specification_version: 4
95
95
  summary: Turns Ruby objects into pipelines.