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 +4 -4
- data/CHANGELOG.md +21 -0
- data/lib/core/pipeline/action.rb +21 -10
- data/lib/core/pipeline/actions/block.rb +10 -4
- data/lib/core/pipeline/actions/method.rb +2 -2
- data/lib/core/pipeline/callable.rb +44 -5
- data/lib/core/pipeline/compiler.rb +231 -13
- data/lib/core/pipeline/version.rb +1 -1
- data/lib/is/pipeline.rb +43 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 28a2f0e27827605918442c956cb6e4236cb146ba16c180f9418569dd09711da9
|
4
|
+
data.tar.gz: f7927e0c5657dfaa13e1bc03a48bfe0fb75ff5cb2b47d5417545c89a6cf41f78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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))
|
data/lib/core/pipeline/action.rb
CHANGED
@@ -10,26 +10,26 @@ module Core
|
|
10
10
|
#
|
11
11
|
class Action
|
12
12
|
include Is::Stateful
|
13
|
-
state :
|
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
|
43
|
+
if __used_random_suffixes__.include?(suffix)
|
44
44
|
build_name
|
45
45
|
else
|
46
|
-
|
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.
|
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
|
-
|
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
|
-
|
105
|
+
finalize.call(object, ...)
|
83
106
|
end
|
84
107
|
|
85
|
-
|
86
|
-
|
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).
|
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
|
-
|
30
|
-
|
31
|
-
|
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
|
-
"
|
46
|
+
"object.#{action[:finalized]}(...)\n"
|
34
47
|
end
|
35
|
-
|
36
|
-
|
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(:@
|
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
|
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
|
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.
|
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-
|
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.
|
92
|
+
rubygems_version: 3.2.22
|
93
93
|
signing_key:
|
94
94
|
specification_version: 4
|
95
95
|
summary: Turns Ruby objects into pipelines.
|