flows 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -1
- data/.rubocop_todo.yml +27 -0
- data/.ruby-version +1 -1
- data/CHANGELOG.md +17 -1
- data/bin/benchmark_cli/examples/.rubocop.yml +3 -0
- data/bin/errors +10 -2
- data/bin/errors_cli/interface_error_demo.rb +17 -0
- data/flows.gemspec +2 -0
- data/lib/flows/contract.rb +2 -2
- data/lib/flows/contract/error.rb +1 -2
- data/lib/flows/plugin.rb +1 -0
- data/lib/flows/plugin/dependency_injector.rb +11 -0
- data/lib/flows/plugin/dependency_injector/dependency_list.rb +1 -3
- data/lib/flows/plugin/interface.rb +84 -0
- data/lib/flows/plugin/output_contract/dsl.rb +1 -1
- data/lib/flows/plugin/output_contract/errors.rb +1 -1
- data/lib/flows/plugin/profiler/report/flat/method_report.rb +1 -2
- data/lib/flows/plugin/profiler/report/tree/calculated_node.rb +1 -1
- data/lib/flows/plugin/profiler/report/tree/node.rb +1 -2
- data/lib/flows/railway/step.rb +7 -7
- data/lib/flows/shared_context_pipeline.rb +46 -3
- data/lib/flows/shared_context_pipeline/dsl/callbacks.rb +1 -4
- data/lib/flows/shared_context_pipeline/dsl/tracks.rb +4 -4
- data/lib/flows/shared_context_pipeline/mutation_step.rb +3 -2
- data/lib/flows/shared_context_pipeline/step.rb +15 -4
- data/lib/flows/shared_context_pipeline/track.rb +1 -1
- data/lib/flows/shared_context_pipeline/wrap.rb +1 -2
- data/lib/flows/util/inheritable_singleton_vars/dup_strategy.rb +8 -6
- data/lib/flows/util/prepend_to_class.rb +14 -2
- data/lib/flows/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dd10b19c7b749fd46c6b8897db3c9912603b4111af7793449d5ff49f69adfcb1
|
4
|
+
data.tar.gz: b18271b7321f199e978ebd4f66f2d21e532c20dd37cd61b6b641b00d875c2f4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b3e90d9b76911f1e0a0539bd89eee76a68dcba04f4136858412e4d0e0e1ca51ff8f35027963ef52fdd870f2b74ffe9a326aca4802cd443af2e55f8bf18f67b1
|
7
|
+
data.tar.gz: 5a6306a15a6024a1c9412f325ab3454b029abcd7d80defee6a9d5b286e8664981b572fb0ecf6f91d06b98c7d5f3040169fe02aae43b8ee8261fa7b65c469fe54
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config --auto-gen-only-exclude`
|
3
|
+
# on 2020-08-22 07:49:05 UTC using RuboCop version 0.89.1.
|
4
|
+
# The point is for the user to remove these configuration records
|
5
|
+
# one by one as the offenses are removed from the code base.
|
6
|
+
# Note that changes in the inspected code, or installation of new
|
7
|
+
# versions of RuboCop, may require this file to be generated again.
|
8
|
+
|
9
|
+
# Offense count: 27
|
10
|
+
#
|
11
|
+
# *** NON-GENERATED COMMENT ***
|
12
|
+
# I'm not sure about enabling this cop
|
13
|
+
# * using super may has performance impact
|
14
|
+
# * but for some cases it still can be useful
|
15
|
+
# Research needed
|
16
|
+
Lint/MissingSuper:
|
17
|
+
Enabled: false
|
18
|
+
|
19
|
+
# Offense count: 5
|
20
|
+
# Configuration parameters: AllowSubject, Max.
|
21
|
+
#
|
22
|
+
# *** NON-GENERATED COMMENT ***
|
23
|
+
# Might be it's impossible to satisfy this cop or significant refactoring of these tests needed
|
24
|
+
RSpec/MultipleMemoizedHelpers:
|
25
|
+
Exclude:
|
26
|
+
- 'spec/flows/flow/node_spec.rb'
|
27
|
+
- 'spec/flows/util/inheritable_singleton_vars/isolation_strategy_spec.rb'
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.6.
|
1
|
+
2.6.6
|
data/CHANGELOG.md
CHANGED
@@ -16,6 +16,21 @@ Types of changes:
|
|
16
16
|
|
17
17
|
## [Unreleased]
|
18
18
|
|
19
|
+
## [0.6.0] - 2020-09-23
|
20
|
+
|
21
|
+
### Added
|
22
|
+
|
23
|
+
* `Flows::Plugin::Interface` basic implementation
|
24
|
+
* `Flows::SharedContextPipeline` simple sub-pipelines injection
|
25
|
+
|
26
|
+
### Changed
|
27
|
+
|
28
|
+
* `Flows::SharedContextPipeline` callbacks execution method is changed to `instance_exec` (previously was `.call`)
|
29
|
+
|
30
|
+
### Fixed
|
31
|
+
|
32
|
+
* `Flows::Plugin::DependencyInjector` and modules generated by `Flows::Util::InheritableSingletonVars::DupStrategy` now can be safely included several times in the inheritance chain
|
33
|
+
|
19
34
|
## [0.5.1] - 2020-06-29
|
20
35
|
|
21
36
|
### Fixed
|
@@ -59,7 +74,8 @@ Types of changes:
|
|
59
74
|
* `Flows::Util::PrependToClass` - allows to prepend some module to class even if
|
60
75
|
target module did not included directly into class.
|
61
76
|
|
62
|
-
[unreleased]: https://github.com/ffloyd/flows/compare/v0.
|
77
|
+
[unreleased]: https://github.com/ffloyd/flows/compare/v0.6.0...HEAD
|
78
|
+
[0.6.0]: https://github.com/ffloyd/flows/compare/v0.5.1...v0.6.0
|
63
79
|
[0.5.1]: https://github.com/ffloyd/flows/compare/v0.5.0...v0.5.1
|
64
80
|
[0.5.0]: https://github.com/ffloyd/flows/compare/v0.4.0...v0.5.0
|
65
81
|
[0.4.0]: https://github.com/ffloyd/flows/compare/v0.3.0...v0.4.0
|
data/bin/errors
CHANGED
@@ -17,6 +17,7 @@ require_relative 'errors_cli/railway_error_demo'
|
|
17
17
|
require_relative 'errors_cli/result_error_demo'
|
18
18
|
require_relative 'errors_cli/scp_error_demo'
|
19
19
|
require_relative 'errors_cli/flow_error_demo'
|
20
|
+
require_relative 'errors_cli/interface_error_demo'
|
20
21
|
|
21
22
|
class ErrorsCLI
|
22
23
|
extend GLI::App
|
@@ -30,11 +31,11 @@ class ErrorsCLI
|
|
30
31
|
ctx.command name do |cmd|
|
31
32
|
cmd.action do |_, _, _|
|
32
33
|
puts title.green
|
33
|
-
puts(
|
34
|
+
puts("BEGIN#{'-' * (title.length - 5)}".color(:darkgray))
|
34
35
|
yield
|
35
36
|
rescue StandardError => err
|
36
37
|
puts err.message
|
37
|
-
puts(
|
38
|
+
puts("END#{'-' * (title.length - 3)}".color(:darkgray))
|
38
39
|
puts
|
39
40
|
end
|
40
41
|
end
|
@@ -125,6 +126,13 @@ class ErrorsCLI
|
|
125
126
|
FlowErrorDemo.invalid_node_route
|
126
127
|
end
|
127
128
|
end
|
129
|
+
|
130
|
+
desc 'Interface errors'
|
131
|
+
command :interface do |cmd|
|
132
|
+
make_cmd cmd, 'Missing Implementation', :missing_implementation do
|
133
|
+
InterfaceErrorDemo.missing_implementation
|
134
|
+
end
|
135
|
+
end
|
128
136
|
end
|
129
137
|
|
130
138
|
exit ErrorsCLI.run(ARGV)
|
data/flows.gemspec
CHANGED
@@ -21,6 +21,8 @@ Gem::Specification.new do |spec| # rubocop:disable Metrics/BlockLength
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ['lib']
|
23
23
|
|
24
|
+
spec.required_ruby_version = '>= 2.5'
|
25
|
+
|
24
26
|
# This library has no production dependencies.
|
25
27
|
# So, it will not block you from updating any dependencies in your project.
|
26
28
|
# So, don't add production dependencies.
|
data/lib/flows/contract.rb
CHANGED
@@ -394,9 +394,9 @@ module Flows
|
|
394
394
|
|
395
395
|
# :reek:UtilityFunction
|
396
396
|
def merge_nested_errors(description, nested_errors)
|
397
|
-
shifted = nested_errors.split("\n").map { |str|
|
397
|
+
shifted = nested_errors.split("\n").map { |str| " #{str}" }.join("\n")
|
398
398
|
|
399
|
-
description
|
399
|
+
"#{description}\n#{shifted}"
|
400
400
|
end
|
401
401
|
end
|
402
402
|
end
|
data/lib/flows/contract/error.rb
CHANGED
data/lib/flows/plugin.rb
CHANGED
@@ -136,6 +136,17 @@ module Flows
|
|
136
136
|
|
137
137
|
InitializerWrapper = Util::PrependToClass.make_module do
|
138
138
|
def initialize(*args, **kwargs, &block) # rubocop:disable Metrics/MethodLength
|
139
|
+
if @__dependencies_injected__
|
140
|
+
if kwargs.empty? # https://bugs.ruby-lang.org/issues/14415
|
141
|
+
super(*args, &block)
|
142
|
+
else
|
143
|
+
super(*args, **kwargs, &block)
|
144
|
+
end
|
145
|
+
|
146
|
+
return
|
147
|
+
end
|
148
|
+
@__dependencies_injected__ = true
|
149
|
+
|
139
150
|
klass = self.class
|
140
151
|
DependencyList.new(
|
141
152
|
klass: klass,
|
@@ -5,9 +5,7 @@ module Flows
|
|
5
5
|
#
|
6
6
|
# @api private
|
7
7
|
class DependencyList
|
8
|
-
attr_reader :definitions
|
9
|
-
attr_reader :provided_values
|
10
|
-
attr_reader :dependencies
|
8
|
+
attr_reader :definitions, :provided_values, :dependencies
|
11
9
|
|
12
10
|
def initialize(klass:, definitions:, provided_values:)
|
13
11
|
@klass = klass
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Flows
|
2
|
+
module Plugin
|
3
|
+
# Class extension to define Java/C#-like interfaces in Ruby.
|
4
|
+
#
|
5
|
+
# On target class initialization will check defined methods for existence.
|
6
|
+
#
|
7
|
+
# **Currently interface composition is not supported.** You cannot define
|
8
|
+
# 2 interface modules and include it into one class.
|
9
|
+
#
|
10
|
+
# @example Simple interface
|
11
|
+
# class MyAction
|
12
|
+
# extend Flows::Plugin::Interface
|
13
|
+
#
|
14
|
+
# defmethod :perform
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# class InvalidAction < MyAction; end
|
18
|
+
# InvalidAction.new
|
19
|
+
# # will raise an error
|
20
|
+
#
|
21
|
+
# class ValidAction < MyAction
|
22
|
+
# def perfrom
|
23
|
+
# puts 'Hello!'
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# ValidAction.new.perform
|
27
|
+
# # => Hello!
|
28
|
+
#
|
29
|
+
# @example Interface as module
|
30
|
+
# module MyBehavior
|
31
|
+
# extend Flows::Plugin::Interface
|
32
|
+
#
|
33
|
+
# defmethod :my_method
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# class MyImplementation
|
37
|
+
# include MyBehaviour
|
38
|
+
#
|
39
|
+
# def my_method; end
|
40
|
+
# end
|
41
|
+
module Interface
|
42
|
+
# Base error class for interface errors.
|
43
|
+
class Error < ::Flows::Error; end
|
44
|
+
|
45
|
+
# Raised when you're missed some dependency.
|
46
|
+
class MissingMethodsError < Error
|
47
|
+
def initialize(klass, names)
|
48
|
+
@klass = klass
|
49
|
+
@names = names
|
50
|
+
end
|
51
|
+
|
52
|
+
def message
|
53
|
+
"Methods required by interface for #{@klass} are missing: #{@names.map(&:to_s).join(', ')}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
SingletonVarsSetup = Flows::Util::InheritableSingletonVars::DupStrategy.make_module(
|
58
|
+
'@interface_methods' => {}
|
59
|
+
)
|
60
|
+
|
61
|
+
include SingletonVarsSetup
|
62
|
+
|
63
|
+
InitializePatch = Flows::Util::PrependToClass.make_module do
|
64
|
+
def initialize(*)
|
65
|
+
klass = self.class
|
66
|
+
|
67
|
+
required_methods = klass.instance_variable_get(:@interface_methods).keys
|
68
|
+
missing_methods = required_methods - methods
|
69
|
+
|
70
|
+
raise MissingMethodsError.new(klass, missing_methods) if missing_methods.any?
|
71
|
+
|
72
|
+
super
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
include InitializePatch
|
77
|
+
|
78
|
+
def defmethod(method_name)
|
79
|
+
method_list = instance_variable_get(:@interface_methods)
|
80
|
+
method_list[method_name.to_sym] = { required_by: self }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -39,7 +39,7 @@ module Flows
|
|
39
39
|
# Disables contract check and transformation for current class and children.
|
40
40
|
#
|
41
41
|
# @param enable [Boolean] if true - contracts are disabled
|
42
|
-
def skip_output_contract(enable
|
42
|
+
def skip_output_contract(enable: true)
|
43
43
|
@skip_output_contract_flag = enable
|
44
44
|
end
|
45
45
|
end
|
data/lib/flows/railway/step.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
module Flows
|
2
2
|
class Railway
|
3
|
-
|
4
|
-
Step = Struct.new(:name, :lambda, :next_step, keyword_init: true) do
|
5
|
-
NODE_PREPROCESSOR = ->(input, _, _) { [[], input.unwrap] }
|
3
|
+
NODE_PREPROCESSOR = ->(input, _, _) { [[], input.unwrap] }
|
6
4
|
|
7
|
-
|
8
|
-
|
5
|
+
NODE_POSTPROCESSOR = lambda do |output, context, meta|
|
6
|
+
context[:last_step] = meta[:name]
|
9
7
|
|
10
|
-
|
11
|
-
|
8
|
+
output
|
9
|
+
end
|
12
10
|
|
11
|
+
# @api private
|
12
|
+
Step = Struct.new(:name, :lambda, :next_step, keyword_init: true) do
|
13
13
|
def to_node(method_source)
|
14
14
|
Flows::Flow::Node.new(
|
15
15
|
body: lambda || method_source.method(name),
|
@@ -141,6 +141,46 @@ module Flows
|
|
141
141
|
# # steps implementations here
|
142
142
|
# end
|
143
143
|
#
|
144
|
+
# ## Simple injecting of nested pipelines
|
145
|
+
#
|
146
|
+
# If you provide some object which responds to `#call` instead of step name - this object will be used as a step body.
|
147
|
+
#
|
148
|
+
# class SubOperation < Flows::SharedContextPipeline
|
149
|
+
# step :hello
|
150
|
+
#
|
151
|
+
# def hello(**)
|
152
|
+
# ok(data: 'some data')
|
153
|
+
# end
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# class MainOperation < Flows::SharedContextPipeline
|
157
|
+
# step :init
|
158
|
+
# step SubOperation
|
159
|
+
#
|
160
|
+
# def init(**)
|
161
|
+
# ok(generated_by_init: true)
|
162
|
+
# end
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# MainOperation.call
|
166
|
+
# # => ok(generated_by_init: true, data: 'some data')
|
167
|
+
#
|
168
|
+
# You can use the same object multiple times in the same pipeline:
|
169
|
+
#
|
170
|
+
# step SubOperation
|
171
|
+
# step SubOperation
|
172
|
+
#
|
173
|
+
# If you need any input or output processing - refactor such step definition into normal step.
|
174
|
+
#
|
175
|
+
# This way has disadvantage: you cannot route to a such step because it has no explicit name.
|
176
|
+
# To handle this you can use alternative syntax:
|
177
|
+
#
|
178
|
+
# step :do_something, body: SubOperation
|
179
|
+
#
|
180
|
+
# Same features can be used with `mut_step`.
|
181
|
+
#
|
182
|
+
# This feature is primarily intended to simplify refactoring of big pipelines into smaller ones.
|
183
|
+
#
|
144
184
|
# ## Wrappers
|
145
185
|
#
|
146
186
|
# Sometimes you have to execute some steps inside SQL-transaction or something like this.
|
@@ -224,6 +264,9 @@ module Flows
|
|
224
264
|
#
|
225
265
|
# You may want to have some logic to execute before all steps, or after all, or before each, or after each.
|
226
266
|
# For example to inject generalized execution process logging.
|
267
|
+
#
|
268
|
+
# These callbacks are executed via `instance_exec` (in the context of instance).
|
269
|
+
#
|
227
270
|
# To achieve this you can use callbacks:
|
228
271
|
#
|
229
272
|
# class MySCP < Flows::SharedContextPipeline
|
@@ -277,10 +320,10 @@ module Flows
|
|
277
320
|
def call(**data) # rubocop:disable Metrics/MethodLength
|
278
321
|
klass = self.class
|
279
322
|
meta = {}
|
280
|
-
context = { data: data, meta: meta, class: klass }
|
323
|
+
context = { data: data, meta: meta, class: klass, instance: self }
|
281
324
|
|
282
325
|
klass.before_all_callbacks.each do |callback|
|
283
|
-
|
326
|
+
instance_exec(klass, data, meta, &callback)
|
284
327
|
end
|
285
328
|
|
286
329
|
flow_result = @__flow.call(nil, context: context)
|
@@ -292,7 +335,7 @@ module Flows
|
|
292
335
|
)
|
293
336
|
|
294
337
|
klass.after_all_callbacks.reduce(final_result) do |result, callback|
|
295
|
-
|
338
|
+
instance_exec(klass, result, data, meta, &callback)
|
296
339
|
end
|
297
340
|
end
|
298
341
|
end
|
@@ -12,10 +12,7 @@ module Flows
|
|
12
12
|
|
13
13
|
include SingletonVarsSetup
|
14
14
|
|
15
|
-
attr_reader :before_all_callbacks
|
16
|
-
attr_reader :after_all_callbacks
|
17
|
-
attr_reader :before_each_callbacks
|
18
|
-
attr_reader :after_each_callbacks
|
15
|
+
attr_reader :before_all_callbacks, :after_all_callbacks, :before_each_callbacks, :after_each_callbacks
|
19
16
|
|
20
17
|
def before_all(&callback)
|
21
18
|
before_all_callbacks << callback
|
@@ -16,15 +16,15 @@ module Flows
|
|
16
16
|
|
17
17
|
attr_reader :tracks
|
18
18
|
|
19
|
-
def step(name, router_def = DEFAULT_ROUTER_DEF,
|
19
|
+
def step(name, router_def = DEFAULT_ROUTER_DEF, body: nil)
|
20
20
|
tracks.add_step(
|
21
|
-
Step.new(name: name,
|
21
|
+
Step.new(name: name, body: body, router_def: router_def)
|
22
22
|
)
|
23
23
|
end
|
24
24
|
|
25
|
-
def mut_step(name, router_def = DEFAULT_ROUTER_DEF,
|
25
|
+
def mut_step(name, router_def = DEFAULT_ROUTER_DEF, body: nil)
|
26
26
|
tracks.add_step(
|
27
|
-
MutationStep.new(name: name,
|
27
|
+
MutationStep.new(name: name, body: body, router_def: router_def)
|
28
28
|
)
|
29
29
|
end
|
30
30
|
|
@@ -8,7 +8,7 @@ module Flows
|
|
8
8
|
class MutationStep < Step
|
9
9
|
NODE_PREPROCESSOR = lambda do |_input, context, node_meta|
|
10
10
|
context[:class].before_each_callbacks.each do |callback|
|
11
|
-
|
11
|
+
context[:instance].instance_exec(context[:class], node_meta[:name], context[:data], context[:meta], &callback)
|
12
12
|
end
|
13
13
|
|
14
14
|
[[context[:data]], EMPTY_HASH]
|
@@ -20,7 +20,8 @@ module Flows
|
|
20
20
|
else output ? EMPTY_OK : EMPTY_ERR
|
21
21
|
end.tap do |result|
|
22
22
|
context[:class].after_each_callbacks.each do |callback|
|
23
|
-
|
23
|
+
context[:instance]
|
24
|
+
.instance_exec(context[:class], node_meta[:name], result, context[:data], context[:meta], &callback)
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
@@ -3,12 +3,22 @@ module Flows
|
|
3
3
|
EMPTY_ARRAY = [].freeze
|
4
4
|
|
5
5
|
# @api private
|
6
|
-
Step = Struct.new(:name, :
|
6
|
+
Step = Struct.new(:name, :body, :router_def, :next_step, keyword_init: true) do
|
7
|
+
# :reek:ManualDispatch
|
8
|
+
def initialize(name:, body: nil, **rest)
|
9
|
+
if name.respond_to?(:call)
|
10
|
+
body = name
|
11
|
+
name = "#{body}+Step-Object-ID-#{object_id}"
|
12
|
+
end
|
13
|
+
|
14
|
+
super(name: name, body: body, **rest)
|
15
|
+
end
|
16
|
+
|
7
17
|
def to_node(pipeline_class)
|
8
18
|
klass = self.class
|
9
19
|
|
10
20
|
Flows::Flow::Node.new(
|
11
|
-
body:
|
21
|
+
body: body || pipeline_class.method(name),
|
12
22
|
router: router_def.to_router(next_step),
|
13
23
|
meta: { name: name },
|
14
24
|
preprocessor: klass::NODE_PREPROCESSOR,
|
@@ -21,7 +31,7 @@ module Flows
|
|
21
31
|
:NODE_PREPROCESSOR,
|
22
32
|
lambda do |_input, context, node_meta|
|
23
33
|
context[:class].before_each_callbacks.each do |callback|
|
24
|
-
|
34
|
+
context[:instance].instance_exec(context[:class], node_meta[:name], context[:data], context[:meta], &callback)
|
25
35
|
end
|
26
36
|
|
27
37
|
[EMPTY_ARRAY, context[:data]]
|
@@ -34,7 +44,8 @@ module Flows
|
|
34
44
|
context[:data].merge!(result.instance_variable_get(:@data))
|
35
45
|
|
36
46
|
context[:class].after_each_callbacks.each do |callback|
|
37
|
-
|
47
|
+
context[:instance]
|
48
|
+
.instance_exec(context[:class], node_meta[:name], result, context[:data], context[:meta], &callback)
|
38
49
|
end
|
39
50
|
|
40
51
|
result
|
@@ -24,14 +24,16 @@ module Flows
|
|
24
24
|
|
25
25
|
# @api private
|
26
26
|
module Migrator
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
# :reek:TooManyStatements is allowed here because it's impossible to split to smaller methods
|
28
|
+
def self.call(src_mod, dst_mod)
|
29
|
+
parent_var_list = src_mod.instance_variable_get(VAR_LIST_VAR_NAME)
|
30
|
+
child_var_list = dst_mod.instance_variable_get(VAR_LIST_VAR_NAME) || []
|
31
|
+
skip_list = parent_var_list & child_var_list
|
30
32
|
|
31
|
-
|
33
|
+
dst_mod.instance_variable_set(VAR_LIST_VAR_NAME, (child_var_list + parent_var_list).uniq)
|
32
34
|
|
33
|
-
parent_var_list.each do |name|
|
34
|
-
|
35
|
+
(parent_var_list - skip_list).each do |name|
|
36
|
+
dst_mod.instance_variable_set(name, src_mod.instance_variable_get(name).dup)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
end
|
@@ -138,7 +138,8 @@ module Flows
|
|
138
138
|
# * you can include `Mod` into `Mod2`, then include `Mod2` into `Mod3` -
|
139
139
|
# desribed behavior works for include chain of any length.
|
140
140
|
#
|
141
|
-
#
|
141
|
+
# Each `include` generates a new prepend. Be careful about this when including
|
142
|
+
# generated module several times in the inheritance chain.
|
142
143
|
#
|
143
144
|
# @yield body for module which will be prepended
|
144
145
|
# @return [Module] module to be included or extended into your module
|
@@ -160,7 +161,8 @@ module Flows
|
|
160
161
|
mod.singleton_class.prepend(injector)
|
161
162
|
end
|
162
163
|
|
163
|
-
|
164
|
+
# :reek:TooManyStatements :reek:DuplicateMethodCall
|
165
|
+
def make_injector_mod(module_to_prepend) # rubocop:disable Metrics/MethodLength
|
164
166
|
Module.new.tap do |injector|
|
165
167
|
injector.define_method(:included) do |target_mod|
|
166
168
|
if target_mod.class == Class
|
@@ -171,6 +173,16 @@ module Flows
|
|
171
173
|
|
172
174
|
super(target_mod)
|
173
175
|
end
|
176
|
+
|
177
|
+
injector.define_method(:extended) do |target_mod|
|
178
|
+
if target_mod.class == Class
|
179
|
+
target_mod.prepend(module_to_prepend)
|
180
|
+
else # Module
|
181
|
+
target_mod.singleton_class.prepend injector
|
182
|
+
end
|
183
|
+
|
184
|
+
super(target_mod)
|
185
|
+
end
|
174
186
|
end
|
175
187
|
end
|
176
188
|
end
|
data/lib/flows/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: flows
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Roman Kolesnev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -387,6 +387,7 @@ files:
|
|
387
387
|
- ".reek.yml"
|
388
388
|
- ".rspec"
|
389
389
|
- ".rubocop.yml"
|
390
|
+
- ".rubocop_todo.yml"
|
390
391
|
- ".ruby-version"
|
391
392
|
- ".yardopts"
|
392
393
|
- CHANGELOG.md
|
@@ -434,6 +435,7 @@ files:
|
|
434
435
|
- bin/errors_cli/di_error_demo.rb
|
435
436
|
- bin/errors_cli/flow_error_demo.rb
|
436
437
|
- bin/errors_cli/flows_router_error_demo.rb
|
438
|
+
- bin/errors_cli/interface_error_demo.rb
|
437
439
|
- bin/errors_cli/oc_error_demo.rb
|
438
440
|
- bin/errors_cli/railway_error_demo.rb
|
439
441
|
- bin/errors_cli/result_error_demo.rb
|
@@ -473,6 +475,7 @@ files:
|
|
473
475
|
- lib/flows/plugin/dependency_injector/dependency_list.rb
|
474
476
|
- lib/flows/plugin/dependency_injector/errors.rb
|
475
477
|
- lib/flows/plugin/implicit_init.rb
|
478
|
+
- lib/flows/plugin/interface.rb
|
476
479
|
- lib/flows/plugin/output_contract.rb
|
477
480
|
- lib/flows/plugin/output_contract/dsl.rb
|
478
481
|
- lib/flows/plugin/output_contract/errors.rb
|
@@ -529,7 +532,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
529
532
|
requirements:
|
530
533
|
- - ">="
|
531
534
|
- !ruby/object:Gem::Version
|
532
|
-
version: '
|
535
|
+
version: '2.5'
|
533
536
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
534
537
|
requirements:
|
535
538
|
- - ">="
|