flows 0.1.0 → 0.5.1

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.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +38 -0
  3. data/.gitignore +9 -1
  4. data/.mdlrc +1 -0
  5. data/.reek.yml +54 -0
  6. data/.rubocop.yml +44 -2
  7. data/.ruby-version +1 -1
  8. data/.yardopts +1 -0
  9. data/CHANGELOG.md +65 -0
  10. data/README.md +186 -256
  11. data/Rakefile +35 -1
  12. data/bin/.rubocop.yml +5 -0
  13. data/bin/all_the_errors +55 -0
  14. data/bin/benchmark +69 -78
  15. data/bin/benchmark_cli/compare.rb +118 -0
  16. data/bin/benchmark_cli/compare/a_plus_b.rb +22 -0
  17. data/bin/benchmark_cli/compare/base.rb +45 -0
  18. data/bin/benchmark_cli/compare/command.rb +47 -0
  19. data/bin/benchmark_cli/compare/ten_steps.rb +22 -0
  20. data/bin/benchmark_cli/examples.rb +23 -0
  21. data/bin/benchmark_cli/examples/.rubocop.yml +19 -0
  22. data/bin/benchmark_cli/examples/a_plus_b/dry_do.rb +23 -0
  23. data/bin/benchmark_cli/examples/a_plus_b/dry_transaction.rb +17 -0
  24. data/bin/benchmark_cli/examples/a_plus_b/flows_do.rb +22 -0
  25. data/bin/benchmark_cli/examples/a_plus_b/flows_railway.rb +13 -0
  26. data/bin/benchmark_cli/examples/a_plus_b/flows_scp.rb +13 -0
  27. data/bin/benchmark_cli/examples/a_plus_b/flows_scp_mut.rb +13 -0
  28. data/bin/benchmark_cli/examples/a_plus_b/flows_scp_oc.rb +21 -0
  29. data/bin/benchmark_cli/examples/a_plus_b/trailblazer.rb +15 -0
  30. data/bin/benchmark_cli/examples/ten_steps/dry_do.rb +70 -0
  31. data/bin/benchmark_cli/examples/ten_steps/dry_transaction.rb +64 -0
  32. data/bin/benchmark_cli/examples/ten_steps/flows_do.rb +69 -0
  33. data/bin/benchmark_cli/examples/ten_steps/flows_railway.rb +58 -0
  34. data/bin/benchmark_cli/examples/ten_steps/flows_scp.rb +58 -0
  35. data/bin/benchmark_cli/examples/ten_steps/flows_scp_mut.rb +58 -0
  36. data/bin/benchmark_cli/examples/ten_steps/flows_scp_oc.rb +66 -0
  37. data/bin/benchmark_cli/examples/ten_steps/trailblazer.rb +60 -0
  38. data/bin/benchmark_cli/helpers.rb +12 -0
  39. data/bin/benchmark_cli/ruby.rb +15 -0
  40. data/bin/benchmark_cli/ruby/command.rb +38 -0
  41. data/bin/benchmark_cli/ruby/method_exec.rb +71 -0
  42. data/bin/benchmark_cli/ruby/self_class.rb +69 -0
  43. data/bin/benchmark_cli/ruby/structs.rb +90 -0
  44. data/bin/console +1 -0
  45. data/bin/docserver +7 -0
  46. data/bin/errors +130 -0
  47. data/bin/errors_cli/contract_error_demo.rb +49 -0
  48. data/bin/errors_cli/di_error_demo.rb +38 -0
  49. data/bin/errors_cli/flow_error_demo.rb +22 -0
  50. data/bin/errors_cli/flows_router_error_demo.rb +15 -0
  51. data/bin/errors_cli/oc_error_demo.rb +40 -0
  52. data/bin/errors_cli/railway_error_demo.rb +10 -0
  53. data/bin/errors_cli/result_error_demo.rb +13 -0
  54. data/bin/errors_cli/scp_error_demo.rb +17 -0
  55. data/docs/.nojekyll +0 -0
  56. data/docs/README.md +13 -0
  57. data/docs/_sidebar.md +2 -0
  58. data/docs/index.html +30 -0
  59. data/flows.gemspec +27 -2
  60. data/forspell.dict +17 -0
  61. data/lefthook.yml +21 -0
  62. data/lib/flows.rb +13 -5
  63. data/lib/flows/contract.rb +402 -0
  64. data/lib/flows/contract/array.rb +55 -0
  65. data/lib/flows/contract/case_eq.rb +43 -0
  66. data/lib/flows/contract/compose.rb +77 -0
  67. data/lib/flows/contract/either.rb +53 -0
  68. data/lib/flows/contract/error.rb +25 -0
  69. data/lib/flows/contract/hash.rb +75 -0
  70. data/lib/flows/contract/hash_of.rb +70 -0
  71. data/lib/flows/contract/helpers.rb +22 -0
  72. data/lib/flows/contract/predicate.rb +34 -0
  73. data/lib/flows/contract/transformer.rb +50 -0
  74. data/lib/flows/contract/tuple.rb +70 -0
  75. data/lib/flows/flow.rb +96 -7
  76. data/lib/flows/flow/errors.rb +29 -0
  77. data/lib/flows/flow/node.rb +132 -0
  78. data/lib/flows/flow/router.rb +29 -0
  79. data/lib/flows/flow/router/custom.rb +59 -0
  80. data/lib/flows/flow/router/errors.rb +11 -0
  81. data/lib/flows/flow/router/simple.rb +25 -0
  82. data/lib/flows/plugin.rb +14 -0
  83. data/lib/flows/plugin/dependency_injector.rb +159 -0
  84. data/lib/flows/plugin/dependency_injector/dependency.rb +24 -0
  85. data/lib/flows/plugin/dependency_injector/dependency_definition.rb +16 -0
  86. data/lib/flows/plugin/dependency_injector/dependency_list.rb +57 -0
  87. data/lib/flows/plugin/dependency_injector/errors.rb +58 -0
  88. data/lib/flows/plugin/implicit_init.rb +45 -0
  89. data/lib/flows/plugin/output_contract.rb +85 -0
  90. data/lib/flows/plugin/output_contract/dsl.rb +48 -0
  91. data/lib/flows/plugin/output_contract/errors.rb +74 -0
  92. data/lib/flows/plugin/output_contract/wrapper.rb +55 -0
  93. data/lib/flows/plugin/profiler.rb +114 -0
  94. data/lib/flows/plugin/profiler/injector.rb +35 -0
  95. data/lib/flows/plugin/profiler/report.rb +48 -0
  96. data/lib/flows/plugin/profiler/report/events.rb +43 -0
  97. data/lib/flows/plugin/profiler/report/flat.rb +41 -0
  98. data/lib/flows/plugin/profiler/report/flat/method_report.rb +81 -0
  99. data/lib/flows/plugin/profiler/report/raw.rb +15 -0
  100. data/lib/flows/plugin/profiler/report/tree.rb +98 -0
  101. data/lib/flows/plugin/profiler/report/tree/calculated_node.rb +116 -0
  102. data/lib/flows/plugin/profiler/report/tree/node.rb +35 -0
  103. data/lib/flows/plugin/profiler/wrapper.rb +53 -0
  104. data/lib/flows/railway.rb +154 -0
  105. data/lib/flows/railway/dsl.rb +18 -0
  106. data/lib/flows/railway/errors.rb +17 -0
  107. data/lib/flows/railway/step.rb +24 -0
  108. data/lib/flows/railway/step_list.rb +38 -0
  109. data/lib/flows/result.rb +189 -2
  110. data/lib/flows/result/do.rb +172 -0
  111. data/lib/flows/result/err.rb +12 -6
  112. data/lib/flows/result/errors.rb +29 -17
  113. data/lib/flows/result/helpers.rb +25 -3
  114. data/lib/flows/result/ok.rb +12 -6
  115. data/lib/flows/shared_context_pipeline.rb +299 -0
  116. data/lib/flows/shared_context_pipeline/dsl.rb +12 -0
  117. data/lib/flows/shared_context_pipeline/dsl/callbacks.rb +38 -0
  118. data/lib/flows/shared_context_pipeline/dsl/tracks.rb +52 -0
  119. data/lib/flows/shared_context_pipeline/errors.rb +17 -0
  120. data/lib/flows/shared_context_pipeline/mutation_step.rb +29 -0
  121. data/lib/flows/shared_context_pipeline/router_definition.rb +21 -0
  122. data/lib/flows/shared_context_pipeline/step.rb +44 -0
  123. data/lib/flows/shared_context_pipeline/track.rb +54 -0
  124. data/lib/flows/shared_context_pipeline/track_list.rb +51 -0
  125. data/lib/flows/shared_context_pipeline/wrap.rb +74 -0
  126. data/lib/flows/util.rb +17 -0
  127. data/lib/flows/util/inheritable_singleton_vars.rb +86 -0
  128. data/lib/flows/util/inheritable_singleton_vars/dup_strategy.rb +98 -0
  129. data/lib/flows/util/inheritable_singleton_vars/isolation_strategy.rb +91 -0
  130. data/lib/flows/util/prepend_to_class.rb +179 -0
  131. data/lib/flows/version.rb +1 -1
  132. metadata +288 -20
  133. data/.travis.yml +0 -8
  134. data/Gemfile.lock +0 -119
  135. data/bin/demo +0 -66
  136. data/bin/examples.rb +0 -159
  137. data/bin/profile_10steps +0 -64
  138. data/bin/ruby_benchmarks +0 -26
  139. data/lib/flows/node.rb +0 -27
  140. data/lib/flows/operation.rb +0 -54
  141. data/lib/flows/operation/builder.rb +0 -130
  142. data/lib/flows/operation/builder/build_router.rb +0 -37
  143. data/lib/flows/operation/dsl.rb +0 -72
  144. data/lib/flows/operation/errors.rb +0 -75
  145. data/lib/flows/operation/executor.rb +0 -78
  146. data/lib/flows/result_router.rb +0 -14
  147. data/lib/flows/router.rb +0 -22
@@ -0,0 +1,12 @@
1
+ require_relative 'dsl/tracks'
2
+ require_relative 'dsl/callbacks'
3
+
4
+ module Flows
5
+ class SharedContextPipeline
6
+ # @api private
7
+ module DSL
8
+ include Tracks
9
+ include Callbacks
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,38 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ module DSL
4
+ # @api private
5
+ module Callbacks
6
+ SingletonVarsSetup = Flows::Util::InheritableSingletonVars::DupStrategy.make_module(
7
+ '@before_all_callbacks' => [],
8
+ '@after_all_callbacks' => [],
9
+ '@before_each_callbacks' => [],
10
+ '@after_each_callbacks' => []
11
+ )
12
+
13
+ include SingletonVarsSetup
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
19
+
20
+ def before_all(&callback)
21
+ before_all_callbacks << callback
22
+ end
23
+
24
+ def after_all(&callback)
25
+ after_all_callbacks << callback
26
+ end
27
+
28
+ def before_each(&callback)
29
+ before_each_callbacks << callback
30
+ end
31
+
32
+ def after_each(&callback)
33
+ after_each_callbacks << callback
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,52 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ module DSL
4
+ # @api private
5
+ module Tracks
6
+ DEFAULT_ROUTER_DEF = RouterDefinition.new(
7
+ Flows::Result::Ok => :next,
8
+ Flows::Result::Err => :end
9
+ )
10
+
11
+ SingletonVarsSetup = Flows::Util::InheritableSingletonVars::DupStrategy.make_module(
12
+ '@tracks' => TrackList.new
13
+ )
14
+
15
+ include SingletonVarsSetup
16
+
17
+ attr_reader :tracks
18
+
19
+ def step(name, router_def = DEFAULT_ROUTER_DEF, &lambda)
20
+ tracks.add_step(
21
+ Step.new(name: name, lambda: lambda, router_def: router_def)
22
+ )
23
+ end
24
+
25
+ def mut_step(name, router_def = DEFAULT_ROUTER_DEF, &lambda)
26
+ tracks.add_step(
27
+ MutationStep.new(name: name, lambda: lambda, router_def: router_def)
28
+ )
29
+ end
30
+
31
+ def wrap(name, router_def = DEFAULT_ROUTER_DEF, &tracks_definitions)
32
+ tracks.add_step(
33
+ Wrap.new(method_name: name, router_def: router_def, &tracks_definitions)
34
+ )
35
+ end
36
+
37
+ def track(name, &block)
38
+ track_before = tracks.current_track
39
+
40
+ tracks.switch_track(name)
41
+ instance_exec(&block)
42
+ tracks.switch_track(track_before)
43
+ end
44
+
45
+ # :reek:UtilityFunction is allowed here
46
+ def routes(routes_def)
47
+ RouterDefinition.new(routes_def)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,17 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ # Base error class for {SharedContextPipeline} errors.
4
+ class Error < StandardError; end
5
+
6
+ # Raised when initializing {SharedContextPipeline} with no steps.
7
+ class NoStepsError < Error
8
+ def initialize(klass)
9
+ @klass = klass
10
+ end
11
+
12
+ def message
13
+ "No steps defined for main track in #{@klass}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ EMPTY_HASH = {}.freeze
4
+ EMPTY_OK = Flows::Result::Ok.new({}.freeze).freeze
5
+ EMPTY_ERR = Flows::Result::Err.new({}.freeze).freeze
6
+
7
+ # @api private
8
+ class MutationStep < Step
9
+ NODE_PREPROCESSOR = lambda do |_input, context, node_meta|
10
+ context[:class].before_each_callbacks.each do |callback|
11
+ callback.call(context[:class], node_meta[:name], context[:data], context[:meta])
12
+ end
13
+
14
+ [[context[:data]], EMPTY_HASH]
15
+ end
16
+
17
+ NODE_POSTPROCESSOR = lambda do |output, context, node_meta|
18
+ case output
19
+ when Flows::Result then output
20
+ else output ? EMPTY_OK : EMPTY_ERR
21
+ end.tap do |result|
22
+ context[:class].after_each_callbacks.each do |callback|
23
+ callback.call(context[:class], node_meta[:name], result, context[:data], context[:meta])
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ # @api private
4
+ class RouterDefinition
5
+ def initialize(routes = {})
6
+ @routes = routes
7
+ end
8
+
9
+ # :reek:ControlParameter is false positive here
10
+ def to_router(next_step)
11
+ final_routes = @routes.transform_values do |route|
12
+ next route unless route == :next
13
+
14
+ next_step || :end
15
+ end
16
+
17
+ ::Flows::Flow::Router::Custom.new(final_routes)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,44 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ EMPTY_ARRAY = [].freeze
4
+
5
+ # @api private
6
+ Step = Struct.new(:name, :lambda, :router_def, :next_step, keyword_init: true) do
7
+ def to_node(pipeline_class)
8
+ klass = self.class
9
+
10
+ Flows::Flow::Node.new(
11
+ body: lambda || pipeline_class.method(name),
12
+ router: router_def.to_router(next_step),
13
+ meta: { name: name },
14
+ preprocessor: klass::NODE_PREPROCESSOR,
15
+ postprocessor: klass::NODE_POSTPROCESSOR
16
+ )
17
+ end
18
+ end
19
+
20
+ Step.const_set(
21
+ :NODE_PREPROCESSOR,
22
+ lambda do |_input, context, node_meta|
23
+ context[:class].before_each_callbacks.each do |callback|
24
+ callback.call(context[:class], node_meta[:name], context[:data], context[:meta])
25
+ end
26
+
27
+ [EMPTY_ARRAY, context[:data]]
28
+ end
29
+ )
30
+
31
+ Step.const_set(
32
+ :NODE_POSTPROCESSOR,
33
+ lambda do |result, context, node_meta|
34
+ context[:data].merge!(result.instance_variable_get(:@data))
35
+
36
+ context[:class].after_each_callbacks.each do |callback|
37
+ callback.call(context[:class], node_meta[:name], result, context[:data], context[:meta])
38
+ end
39
+
40
+ result
41
+ end
42
+ )
43
+ end
44
+ end
@@ -0,0 +1,54 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ # @api private
4
+ class Track
5
+ TRACK_ENTRY_ROUTER_DEF = RouterDefinition.new(
6
+ Flows::Result::Ok => :next,
7
+ Flows::Result::Err => :end
8
+ )
9
+
10
+ def initialize(name)
11
+ @name = name
12
+ @step_list = []
13
+ end
14
+
15
+ def initialize_dup(_other)
16
+ @step_list = @step_list.map(&:dup)
17
+ end
18
+
19
+ def add_step(step)
20
+ last_step = @step_list.last
21
+ last_step.next_step = step.name if last_step
22
+
23
+ @step_list << step
24
+
25
+ self
26
+ end
27
+
28
+ def first_step_name
29
+ @step_list.first.name
30
+ end
31
+
32
+ def empty?
33
+ @step_list.empty?
34
+ end
35
+
36
+ def to_node_map(method_source)
37
+ @step_list.each_with_object(@name => make_track_entry_node) do |step, node_map|
38
+ node_map[step.name] = step.to_node(method_source)
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def make_track_entry_node
45
+ MutationStep.new(
46
+ name: @name,
47
+ lambda: proc { true },
48
+ router_def: TRACK_ENTRY_ROUTER_DEF,
49
+ next_step: first_step_name
50
+ ).to_node(nil)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,51 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ # @api private
4
+ class TrackList
5
+ attr_reader :current_track
6
+
7
+ def initialize
8
+ @tracks = { main: Track.new(:main) }
9
+ @current_track = :main
10
+ end
11
+
12
+ def initialize_dup(_other)
13
+ @tracks = @tracks.transform_values(&:dup)
14
+ end
15
+
16
+ def switch_track(track_name)
17
+ @tracks[track_name] ||= Track.new(track_name)
18
+ @current_track = track_name
19
+ end
20
+
21
+ def add_step(step)
22
+ @tracks[@current_track].add_step(step)
23
+ end
24
+
25
+ def first_step_name
26
+ @tracks[:main].first_step_name
27
+ end
28
+
29
+ def main_track_empty?
30
+ @tracks[:main].empty?
31
+ end
32
+
33
+ def to_node_map(method_source)
34
+ @tracks.reduce({}) do |node_map, (_, track)|
35
+ node_map.merge!(
36
+ track.to_node_map(method_source)
37
+ )
38
+ end
39
+ end
40
+
41
+ def to_flow(method_source)
42
+ raise NoStepsError, method_source if main_track_empty?
43
+
44
+ Flows::Flow.new(
45
+ start_node: first_step_name,
46
+ node_map: to_node_map(method_source)
47
+ )
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,74 @@
1
+ module Flows
2
+ class SharedContextPipeline
3
+ # @api private
4
+ class Wrap
5
+ attr_reader :router_def
6
+ attr_reader :tracks_definitions
7
+
8
+ # :reek:Attribute
9
+ attr_accessor :next_step
10
+
11
+ EMPTY_HASH = {}.freeze
12
+
13
+ NODE_PREPROCESSOR = lambda do |_input, context, _node_meta|
14
+ [[context], EMPTY_HASH]
15
+ end
16
+
17
+ NODE_POSTPROCESSOR = lambda do |result, context, _node_meta|
18
+ context[:data].merge!(result.instance_variable_get(:@data))
19
+
20
+ result
21
+ end
22
+
23
+ def initialize(method_name:, router_def:, &tracks_definitions)
24
+ @method_name = method_name
25
+ @router_def = router_def
26
+ @tracks_definitions = tracks_definitions
27
+
28
+ singleton_class.extend DSL::Tracks
29
+ singleton_class.extend Result::Helpers
30
+
31
+ singleton_class.instance_exec(&tracks_definitions)
32
+ end
33
+
34
+ # on `#dup` we're getting new empty singleton class
35
+ # so we need to initialize it like original one
36
+ def initialize_dup(other)
37
+ singleton_class.extend DSL::Tracks
38
+ singleton_class.extend Result::Helpers
39
+ singleton_class.instance_exec(&other.tracks_definitions)
40
+ end
41
+
42
+ def name
43
+ singleton_class.tracks.first_step_name
44
+ end
45
+
46
+ def to_node(method_source)
47
+ Flows::Flow::Node.new(
48
+ body: make_body(method_source),
49
+ router: router_def.to_router(next_step),
50
+ meta: { wrap_name: @method_name },
51
+ preprocessor: NODE_PREPROCESSOR,
52
+ postprocessor: NODE_POSTPROCESSOR
53
+ )
54
+ end
55
+
56
+ private
57
+
58
+ def make_flow(method_source)
59
+ singleton_class.tracks.to_flow(method_source)
60
+ end
61
+
62
+ def make_body(method_source)
63
+ flow = make_flow(method_source)
64
+ wrapper = method_source.method(@method_name)
65
+
66
+ lambda do |context|
67
+ wrapper.call(context[:data], context[:meta]) do
68
+ flow.call(nil, context: context)
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,17 @@
1
+ module Flows
2
+ # Namespace for low-level purely technical OOP helpers.
3
+ #
4
+ # Implementations here are relatively complex and require
5
+ # advanced understanding of Ruby's OOP and runtime.
6
+ #
7
+ # This module implements "hidden complexity" approach:
8
+ # hide most non-trivial parts of implementation inside
9
+ # small well-documented classes and modules.
10
+ #
11
+ # @since 0.4.0
12
+ module Util
13
+ end
14
+ end
15
+
16
+ require_relative 'util/prepend_to_class'
17
+ require_relative 'util/inheritable_singleton_vars'
@@ -0,0 +1,86 @@
1
+ module Flows
2
+ module Util
3
+ # Namespace for utility classes which allows you to define specific behaviour for
4
+ # [singleton variables](https://medium.com/@leo_hetsch/demystifying-singleton-classes-in-ruby-caf3fa4c9d91)
5
+ # in the context of inheritance.
6
+ #
7
+ # When you're writing some abstraction in Ruby one of the ways is to provide some base class and
8
+ # allow child classes to configure behaviour through class-level DSL. Something like that:
9
+ #
10
+ # class UserModel < BaseModel
11
+ # field :name
12
+ # field :username
13
+ # end
14
+ #
15
+ # The first problem here is where to store configuration values?
16
+ # In the most cases of such DSL it's singleton variables.
17
+ #
18
+ # But what will happen if we do something like this:
19
+ #
20
+ # class AdminModel < UserModel
21
+ # field :pgp_key
22
+ # end
23
+ #
24
+ # Which fields are defined for admin? `:name`, `:username` and `:pgp_key`?
25
+ # Or `:pgp_key` only? Both options are possible and can be implemented.
26
+ # But working with singleton variables is confusing and related code is confusing also.
27
+ # So, it's better to implement set of utility modules to define expected behaviour
28
+ # in a human-friendly format.
29
+ #
30
+ # The second problem is default values for singleton variables.
31
+ # In case of instance variables everything is simple:
32
+ # you have a constructor (`#initializer`) and it's the right place to set instance variables defaults.
33
+ # In case of singleton variables you can do it in `.extended` or `.included` callbacks.
34
+ # But this callback will not be executed on child classes. So, we have to add `.inherited` callback to the mix.
35
+ # Confusing? Yes. So, it's better to not think about it each time and
36
+ # use some helpers to explicitly define behaviour.
37
+ #
38
+ # Modules under this namespace provide helpers for defining defaults and inheritance strategy for your
39
+ # singleton variables.
40
+ #
41
+ # Each strategy here is using following way of injecting into yours abstract classes:
42
+ #
43
+ # class BaseSomething
44
+ # SingletonVarsSetup = Flows::Util::InheritableSingletonVars::SomeStrategy.make_module(
45
+ # **options_here
46
+ # )
47
+ #
48
+ # include SingeltonVarsSetup # extend also will work
49
+ # end
50
+ #
51
+ # In case of extensions and mixins:
52
+ #
53
+ # module MyExtension
54
+ # SingletonVarsSetup = Flows::Util::InheritableSingletonVars::SomeStrategy.make_module(
55
+ # **options_here
56
+ # )
57
+ #
58
+ # include SingeltonVarsSetup # extend also will work
59
+ # end
60
+ #
61
+ # class SomethingA
62
+ # extend MyExtension
63
+ # end
64
+ #
65
+ # module MyMixin
66
+ # SingletonVarsSetup = Flows::Util::InheritableSingletonVars::SomeStrategy.make_module(
67
+ # **options_here
68
+ # )
69
+ #
70
+ # include SingeltonVarsSetup # extend also will work
71
+ # end
72
+ #
73
+ # class SomethingB
74
+ # include MyMixin
75
+ # end
76
+ #
77
+ # Moreover, you can use multiple strategies in the same class.
78
+ #
79
+ # @since 0.4.0
80
+ module InheritableSingletonVars
81
+ end
82
+ end
83
+ end
84
+
85
+ require_relative './inheritable_singleton_vars/dup_strategy'
86
+ require_relative './inheritable_singleton_vars/isolation_strategy'