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,69 @@
1
+ class BenchmarkCLI
2
+ module Ruby
3
+ class SelfClass
4
+ include Helpers
5
+
6
+ def call
7
+ header 'Check if repeatative `self.class` impacts performance'
8
+
9
+ Benchmark.ips do |benchmark|
10
+ benchmark.config(stats: :bootstrap, confidence: 95)
11
+
12
+ run_benchmarks(benchmark)
13
+
14
+ benchmark.compare!
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def run_benchmarks(benchmark)
21
+ report_self_class(benchmark)
22
+ report_klass(benchmark)
23
+ end
24
+
25
+ def report_self_class(benchmark)
26
+ benchmark.report '[self.class, ... 10 times]' do
27
+ self_class_10_times
28
+ end
29
+ end
30
+
31
+ def self_class_10_times # rubocop:disable Metrics/MethodLength
32
+ [
33
+ self.class,
34
+ self.class,
35
+ self.class,
36
+ self.class,
37
+ self.class,
38
+ self.class,
39
+ self.class,
40
+ self.class,
41
+ self.class,
42
+ self.class
43
+ ]
44
+ end
45
+
46
+ def report_klass(benchmark)
47
+ benchmark.report 'klass = self.class; [klass, ... 10 times]' do
48
+ klass_10_times
49
+ end
50
+ end
51
+
52
+ def klass_10_times # rubocop:disable Metrics/MethodLength
53
+ klass = self.class
54
+ [
55
+ klass,
56
+ klass,
57
+ klass,
58
+ klass,
59
+ klass,
60
+ klass,
61
+ klass,
62
+ klass,
63
+ klass,
64
+ klass
65
+ ]
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,90 @@
1
+ require 'ostruct'
2
+
3
+ class BenchmarkCLI
4
+ module Ruby
5
+ class Structs
6
+ include Helpers
7
+
8
+ def call
9
+ header 'Creates a struct with 3 random number fields and calculates the sum of the fields'
10
+
11
+ Benchmark.ips do |benchmark|
12
+ benchmark.config(stats: :bootstrap, confidence: 95)
13
+
14
+ run_benchmarks(benchmark)
15
+
16
+ benchmark.compare!
17
+ end
18
+ end
19
+
20
+ RubyStruct = Struct.new(:a, :b, :c, keyword_init: true)
21
+
22
+ class CustomStruct
23
+ attr_reader :a, :b, :c
24
+
25
+ def initialize(a:, b:, c:) # rubocop:disable Naming/MethodParameterName
26
+ @a = a
27
+ @b = b
28
+ @c = c
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def run_benchmarks(benchmark)
35
+ report_hash(benchmark)
36
+ report_ruby_struct(benchmark)
37
+ report_custom_class(benchmark)
38
+ report_ostruct(benchmark)
39
+ end
40
+
41
+ def report_hash(benchmark)
42
+ benchmark.report 'Hash' do
43
+ hash = {
44
+ a: rand(10),
45
+ b: rand(20),
46
+ c: rand(30)
47
+ }
48
+
49
+ hash[:a] + hash[:b] + hash[:c]
50
+ end
51
+ end
52
+
53
+ def report_ruby_struct(benchmark)
54
+ benchmark.report 'Ruby Struct' do
55
+ rstruct = RubyStruct.new(
56
+ a: rand(10),
57
+ b: rand(20),
58
+ c: rand(30)
59
+ )
60
+
61
+ rstruct.a + rstruct.b + rstruct.c
62
+ end
63
+ end
64
+
65
+ def report_custom_class(benchmark)
66
+ benchmark.report 'Custom Class' do
67
+ custom_struct = CustomStruct.new(
68
+ a: rand(10),
69
+ b: rand(10),
70
+ c: rand(10)
71
+ )
72
+
73
+ custom_struct.a + custom_struct.b + custom_struct.c
74
+ end
75
+ end
76
+
77
+ def report_ostruct(benchmark)
78
+ benchmark.report 'Open Struct' do
79
+ ostruct = OpenStruct.new(
80
+ a: rand(10),
81
+ b: rand(10),
82
+ c: rand(10)
83
+ )
84
+
85
+ ostruct.a + ostruct.b + ostruct.c
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -6,5 +6,6 @@ require 'flows'
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
+ require 'awesome_print'
9
10
  require 'pry'
10
11
  Pry.start
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ rm -rf .yardoc/ && bundle exec yard server --reload
7
+ rm -rf .yardoc/
@@ -0,0 +1,130 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'flows'
5
+
6
+ require 'pry'
7
+ require 'gli'
8
+
9
+ require 'rainbow/refinement'
10
+ using Rainbow
11
+
12
+ require_relative 'errors_cli/contract_error_demo'
13
+ require_relative 'errors_cli/flows_router_error_demo'
14
+ require_relative 'errors_cli/di_error_demo'
15
+ require_relative 'errors_cli/oc_error_demo'
16
+ require_relative 'errors_cli/railway_error_demo'
17
+ require_relative 'errors_cli/result_error_demo'
18
+ require_relative 'errors_cli/scp_error_demo'
19
+ require_relative 'errors_cli/flow_error_demo'
20
+
21
+ class ErrorsCLI
22
+ extend GLI::App
23
+
24
+ program_desc 'Error reporting demo'
25
+
26
+ use_openstruct true
27
+
28
+ def self.make_cmd(ctx, title, name) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
29
+ ctx.desc title
30
+ ctx.command name do |cmd|
31
+ cmd.action do |_, _, _|
32
+ puts title.green
33
+ puts(('BEGIN' + '-' * (title.length - 5)).color(:darkgray))
34
+ yield
35
+ rescue StandardError => err
36
+ puts err.message
37
+ puts(('END' + '-' * (title.length - 3)).color(:darkgray))
38
+ puts
39
+ end
40
+ end
41
+ end
42
+
43
+ make_cmd self, 'Flows::Contract error', :contract do
44
+ ContractErrorDemo.call
45
+ end
46
+
47
+ make_cmd self, 'Flows::Flow::Router::NoRouteError', :router do
48
+ FlowsRouterErrorDemo.call
49
+ end
50
+
51
+ desc 'Flows::Plugin::DependencyInjector errors'
52
+ command :di do |cmd|
53
+ make_cmd cmd, 'Missing Dependency', :missing do
54
+ DIErrorDemo.missing_dependency
55
+ end
56
+
57
+ make_cmd cmd, 'Unexpected Dependency', :unexpected do
58
+ DIErrorDemo.unexpected_dependency
59
+ end
60
+
61
+ make_cmd cmd, 'Invalid Type', :invalid_type do
62
+ DIErrorDemo.invalid_type_dependency
63
+ end
64
+
65
+ make_cmd cmd, 'Missing Default', :missing_default do
66
+ DIErrorDemo.missing_default
67
+ end
68
+ end
69
+
70
+ desc 'OutputContract plugin errors'
71
+ command :output_contract do |cmd|
72
+ make_cmd cmd, 'No Contract error', :no_contract do
73
+ OCErrorDemo.no_contract
74
+ end
75
+
76
+ make_cmd cmd, 'Contract error', :contract do
77
+ OCErrorDemo.contract_error
78
+ end
79
+
80
+ make_cmd cmd, 'Status error', :status do
81
+ OCErrorDemo.status_error
82
+ end
83
+
84
+ make_cmd cmd, 'Result type error', :result_type do
85
+ OCErrorDemo.result_type_error
86
+ end
87
+ end
88
+
89
+ desc 'Railway errors'
90
+ command :railway do |cmd|
91
+ make_cmd cmd, 'No Steps error', :no_steps do
92
+ RailwayErrorDemo.call
93
+ end
94
+ end
95
+
96
+ desc 'Result errors'
97
+ command :result do |cmd|
98
+ make_cmd cmd, 'Access error for successful result', :ok_access do
99
+ ResultErrorDemo.success_access_error
100
+ end
101
+
102
+ make_cmd cmd, 'Access error for failure result', :err_access do
103
+ ResultErrorDemo.failure_access_error
104
+ end
105
+ end
106
+
107
+ desc 'Shared Context Pipeline errors'
108
+ command :scp do |cmd|
109
+ make_cmd cmd, 'No Steps error', :no_steps do
110
+ SCPErrorDemo.no_steps
111
+ end
112
+
113
+ make_cmd cmd, 'Missing Step Implementation error', :no_step_impl do
114
+ SCPErrorDemo.no_step_impl
115
+ end
116
+ end
117
+
118
+ desc 'Flow errors'
119
+ command :flow do |cmd|
120
+ make_cmd cmd, 'No first node', :no_first_node do
121
+ FlowErrorDemo.no_first_node
122
+ end
123
+
124
+ make_cmd cmd, 'Invalid Node route', :invalid_node_route do
125
+ FlowErrorDemo.invalid_node_route
126
+ end
127
+ end
128
+ end
129
+
130
+ exit ErrorsCLI.run(ARGV)
@@ -0,0 +1,49 @@
1
+ module ContractErrorDemo
2
+ class << self
3
+ def call
4
+ contract.transform!(invalid_data)
5
+ end
6
+
7
+ private
8
+
9
+ def invalid_data # rubocop:disable Metrics/MethodLength
10
+ {
11
+ str_array_field: ['aaa', 'bbb', :ccc],
12
+ hash_array_field: [
13
+ {
14
+ x: 1,
15
+ y: 2
16
+ },
17
+ {
18
+ 'x' => 1,
19
+ 'y' => 2
20
+ }
21
+ ],
22
+ array_compose_predicate: ['aaaa', 'bbbb', 'a', :xxx],
23
+ int_field: '10',
24
+ array_either: ['a', :a, 1],
25
+ tuple: [1, 1]
26
+ }
27
+ end
28
+
29
+ def contract # rubocop:disable Metrics/MethodLength
30
+ Flows::Contract.make do
31
+ hash_of(
32
+ str_array_field: array(String),
33
+ hash_array_field: array(
34
+ hash(Symbol, String)
35
+ ),
36
+ array_compose_predicate: array(
37
+ compose(String, predicate('must be longer that 3') { |str| str.size > 3 })
38
+ ),
39
+ int_field: Integer,
40
+ array_either: array(
41
+ either(String, Symbol)
42
+ ),
43
+ tuple: tuple(Float, Float),
44
+ field_to_be_missed: String
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,38 @@
1
+ module DIErrorDemo
2
+ class WithDI
3
+ include Flows::Plugin::DependencyInjector
4
+
5
+ dependency :req_str_dep, required: true, type: String
6
+
7
+ def call
8
+ 'Hi!'
9
+ end
10
+ end
11
+
12
+ class WithEmptyDI
13
+ include Flows::Plugin::DependencyInjector
14
+ end
15
+
16
+ class << self
17
+ def missing_dependency
18
+ WithDI.new
19
+ end
20
+
21
+ def unexpected_dependency
22
+ WithDI.new(dependencies: {
23
+ req_str_dep: 'AAA',
24
+ my_extra_dependency: 'III'
25
+ })
26
+ end
27
+
28
+ def invalid_type_dependency
29
+ WithDI.new(dependencies: {
30
+ req_str_dep: :AAA
31
+ })
32
+ end
33
+
34
+ def missing_default
35
+ WithEmptyDI.dependency :my_opt_dep
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,22 @@
1
+ module FlowErrorDemo
2
+ class << self
3
+ def no_first_node
4
+ Flows::Flow.new(
5
+ start_node: :first,
6
+ node_map: {}
7
+ )
8
+ end
9
+
10
+ def invalid_node_route
11
+ Flows::Flow.new(
12
+ start_node: :first,
13
+ node_map: {
14
+ first: Flows::Flow::Node.new(
15
+ body: ->(_) {},
16
+ router: Flows::Flow::Router::Custom.new(a: :b)
17
+ )
18
+ }
19
+ )
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ module FlowsRouterErrorDemo
2
+ class << self
3
+ include Flows::Result::Helpers
4
+
5
+ def call
6
+ router.call(ok(some: :data))
7
+ end
8
+
9
+ private
10
+
11
+ def router
12
+ Flows::Flow::Router::Custom.new(match_err => :end)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,40 @@
1
+ module OCErrorDemo
2
+ class WithoutContract
3
+ include Flows::Plugin::OutputContract
4
+ end
5
+
6
+ class WithContract
7
+ include Flows::Plugin::OutputContract
8
+
9
+ success_with :ok do
10
+ hash_of(
11
+ x: Integer,
12
+ y: Integer
13
+ )
14
+ end
15
+
16
+ def call(result)
17
+ result
18
+ end
19
+ end
20
+
21
+ class << self
22
+ include Flows::Result::Helpers
23
+
24
+ def no_contract
25
+ WithoutContract.new
26
+ end
27
+
28
+ def contract_error
29
+ WithContract.new.call(ok(z: 100))
30
+ end
31
+
32
+ def status_error
33
+ WithContract.new.call(ok(:unexpeted_status, x: 1, y: 2))
34
+ end
35
+
36
+ def result_type_error
37
+ WithContract.new.call(z: 100)
38
+ end
39
+ end
40
+ end