flows 0.1.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
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