flows 0.3.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.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/{build.yml → test.yml} +5 -10
  3. data/.gitignore +1 -0
  4. data/.reek.yml +42 -0
  5. data/.rubocop.yml +20 -7
  6. data/.ruby-version +1 -1
  7. data/.yardopts +1 -0
  8. data/CHANGELOG.md +42 -0
  9. data/Gemfile +0 -6
  10. data/Gemfile.lock +139 -74
  11. data/README.md +158 -364
  12. data/Rakefile +35 -1
  13. data/bin/.rubocop.yml +5 -0
  14. data/bin/all_the_errors +47 -0
  15. data/bin/benchmark +73 -105
  16. data/bin/benchmark_cli/compare.rb +118 -0
  17. data/bin/benchmark_cli/compare/a_plus_b.rb +22 -0
  18. data/bin/benchmark_cli/compare/base.rb +45 -0
  19. data/bin/benchmark_cli/compare/command.rb +47 -0
  20. data/bin/benchmark_cli/compare/ten_steps.rb +22 -0
  21. data/bin/benchmark_cli/examples.rb +23 -0
  22. data/bin/benchmark_cli/examples/.rubocop.yml +19 -0
  23. data/bin/benchmark_cli/examples/a_plus_b/dry_do.rb +23 -0
  24. data/bin/benchmark_cli/examples/a_plus_b/dry_transaction.rb +17 -0
  25. data/bin/benchmark_cli/examples/a_plus_b/flows_do.rb +22 -0
  26. data/bin/benchmark_cli/examples/a_plus_b/flows_railway.rb +13 -0
  27. data/bin/benchmark_cli/examples/a_plus_b/flows_scp.rb +13 -0
  28. data/bin/benchmark_cli/examples/a_plus_b/flows_scp_mut.rb +13 -0
  29. data/bin/benchmark_cli/examples/a_plus_b/flows_scp_oc.rb +21 -0
  30. data/bin/benchmark_cli/examples/a_plus_b/trailblazer.rb +15 -0
  31. data/bin/benchmark_cli/examples/ten_steps/dry_do.rb +70 -0
  32. data/bin/benchmark_cli/examples/ten_steps/dry_transaction.rb +64 -0
  33. data/bin/benchmark_cli/examples/ten_steps/flows_do.rb +69 -0
  34. data/bin/benchmark_cli/examples/ten_steps/flows_railway.rb +58 -0
  35. data/bin/benchmark_cli/examples/ten_steps/flows_scp.rb +58 -0
  36. data/bin/benchmark_cli/examples/ten_steps/flows_scp_mut.rb +58 -0
  37. data/bin/benchmark_cli/examples/ten_steps/flows_scp_oc.rb +66 -0
  38. data/bin/benchmark_cli/examples/ten_steps/trailblazer.rb +60 -0
  39. data/bin/benchmark_cli/helpers.rb +12 -0
  40. data/bin/benchmark_cli/ruby.rb +15 -0
  41. data/bin/benchmark_cli/ruby/command.rb +38 -0
  42. data/bin/benchmark_cli/ruby/method_exec.rb +71 -0
  43. data/bin/benchmark_cli/ruby/self_class.rb +69 -0
  44. data/bin/benchmark_cli/ruby/structs.rb +90 -0
  45. data/bin/console +1 -0
  46. data/bin/docserver +7 -0
  47. data/bin/errors +118 -0
  48. data/bin/errors_cli/contract_error_demo.rb +49 -0
  49. data/bin/errors_cli/di_error_demo.rb +38 -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/README.md +2 -186
  56. data/docs/_sidebar.md +0 -24
  57. data/docs/index.html +1 -1
  58. data/flows.gemspec +25 -2
  59. data/forspell.dict +9 -0
  60. data/lefthook.yml +9 -0
  61. data/lib/flows.rb +11 -5
  62. data/lib/flows/contract.rb +402 -0
  63. data/lib/flows/contract/array.rb +55 -0
  64. data/lib/flows/contract/case_eq.rb +41 -0
  65. data/lib/flows/contract/compose.rb +77 -0
  66. data/lib/flows/contract/either.rb +53 -0
  67. data/lib/flows/contract/error.rb +25 -0
  68. data/lib/flows/contract/hash.rb +75 -0
  69. data/lib/flows/contract/hash_of.rb +70 -0
  70. data/lib/flows/contract/helpers.rb +22 -0
  71. data/lib/flows/contract/predicate.rb +34 -0
  72. data/lib/flows/contract/transformer.rb +50 -0
  73. data/lib/flows/contract/tuple.rb +70 -0
  74. data/lib/flows/flow.rb +75 -7
  75. data/lib/flows/flow/node.rb +131 -0
  76. data/lib/flows/flow/router.rb +25 -0
  77. data/lib/flows/flow/router/custom.rb +54 -0
  78. data/lib/flows/flow/router/errors.rb +11 -0
  79. data/lib/flows/flow/router/simple.rb +20 -0
  80. data/lib/flows/plugin.rb +13 -0
  81. data/lib/flows/plugin/dependency_injector.rb +159 -0
  82. data/lib/flows/plugin/dependency_injector/dependency.rb +24 -0
  83. data/lib/flows/plugin/dependency_injector/dependency_definition.rb +16 -0
  84. data/lib/flows/plugin/dependency_injector/dependency_list.rb +57 -0
  85. data/lib/flows/plugin/dependency_injector/errors.rb +58 -0
  86. data/lib/flows/plugin/implicit_init.rb +45 -0
  87. data/lib/flows/plugin/output_contract.rb +84 -0
  88. data/lib/flows/plugin/output_contract/dsl.rb +36 -0
  89. data/lib/flows/plugin/output_contract/errors.rb +74 -0
  90. data/lib/flows/plugin/output_contract/wrapper.rb +53 -0
  91. data/lib/flows/railway.rb +140 -37
  92. data/lib/flows/railway/dsl.rb +8 -19
  93. data/lib/flows/railway/errors.rb +8 -12
  94. data/lib/flows/railway/step.rb +24 -0
  95. data/lib/flows/railway/step_list.rb +38 -0
  96. data/lib/flows/result.rb +188 -2
  97. data/lib/flows/result/do.rb +160 -16
  98. data/lib/flows/result/err.rb +12 -6
  99. data/lib/flows/result/errors.rb +29 -17
  100. data/lib/flows/result/helpers.rb +25 -3
  101. data/lib/flows/result/ok.rb +12 -6
  102. data/lib/flows/shared_context_pipeline.rb +216 -0
  103. data/lib/flows/shared_context_pipeline/dsl.rb +63 -0
  104. data/lib/flows/shared_context_pipeline/errors.rb +17 -0
  105. data/lib/flows/shared_context_pipeline/mutation_step.rb +31 -0
  106. data/lib/flows/shared_context_pipeline/router_definition.rb +21 -0
  107. data/lib/flows/shared_context_pipeline/step.rb +46 -0
  108. data/lib/flows/shared_context_pipeline/track.rb +67 -0
  109. data/lib/flows/shared_context_pipeline/track_list.rb +46 -0
  110. data/lib/flows/util.rb +17 -0
  111. data/lib/flows/util/inheritable_singleton_vars.rb +79 -0
  112. data/lib/flows/util/inheritable_singleton_vars/dup_strategy.rb +109 -0
  113. data/lib/flows/util/inheritable_singleton_vars/isolation_strategy.rb +104 -0
  114. data/lib/flows/util/prepend_to_class.rb +145 -0
  115. data/lib/flows/version.rb +1 -1
  116. metadata +233 -37
  117. data/bin/demo +0 -66
  118. data/bin/examples.rb +0 -195
  119. data/bin/profile_10steps +0 -106
  120. data/bin/ruby_benchmarks +0 -26
  121. data/docs/CNAME +0 -1
  122. data/docs/contributing/benchmarks_profiling.md +0 -3
  123. data/docs/contributing/local_development.md +0 -3
  124. data/docs/flow/direct_usage.md +0 -3
  125. data/docs/flow/general_idea.md +0 -3
  126. data/docs/operation/basic_usage.md +0 -1
  127. data/docs/operation/inject_steps.md +0 -3
  128. data/docs/operation/lambda_steps.md +0 -3
  129. data/docs/operation/result_shapes.md +0 -3
  130. data/docs/operation/routing_tracks.md +0 -3
  131. data/docs/operation/wrapping_steps.md +0 -3
  132. data/docs/overview/performance.md +0 -336
  133. data/docs/railway/basic_usage.md +0 -232
  134. data/docs/result_objects/basic_usage.md +0 -196
  135. data/docs/result_objects/do_notation.md +0 -139
  136. data/lib/flows/implicit_build.rb +0 -16
  137. data/lib/flows/node.rb +0 -27
  138. data/lib/flows/operation.rb +0 -55
  139. data/lib/flows/operation/builder.rb +0 -130
  140. data/lib/flows/operation/builder/build_router.rb +0 -37
  141. data/lib/flows/operation/dsl.rb +0 -93
  142. data/lib/flows/operation/errors.rb +0 -75
  143. data/lib/flows/operation/executor.rb +0 -78
  144. data/lib/flows/railway/builder.rb +0 -68
  145. data/lib/flows/railway/executor.rb +0 -23
  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,118 @@
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
+
20
+ class ErrorsCLI
21
+ extend GLI::App
22
+
23
+ program_desc 'Error reporting demo'
24
+
25
+ use_openstruct true
26
+
27
+ def self.make_cmd(ctx, title, name) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
28
+ ctx.desc title
29
+ ctx.command name do |cmd|
30
+ cmd.action do |_, _, _|
31
+ puts title.green
32
+ puts(('BEGIN' + '-' * (title.length - 5)).color(:darkgray))
33
+ yield
34
+ rescue StandardError => err
35
+ puts err.message
36
+ puts(('END' + '-' * (title.length - 3)).color(:darkgray))
37
+ puts
38
+ end
39
+ end
40
+ end
41
+
42
+ make_cmd self, 'Flows::Contract error', :contract do
43
+ ContractErrorDemo.call
44
+ end
45
+
46
+ make_cmd self, 'Flows::Flow::Router::NoRouteError', :router do
47
+ FlowsRouterErrorDemo.call
48
+ end
49
+
50
+ desc 'Flows::Plugin::DependencyInjector errors'
51
+ command :di do |cmd|
52
+ make_cmd cmd, 'Missing Dependency', :missing do
53
+ DIErrorDemo.missing_dependency
54
+ end
55
+
56
+ make_cmd cmd, 'Unexpected Dependency', :unexpected do
57
+ DIErrorDemo.unexpected_dependency
58
+ end
59
+
60
+ make_cmd cmd, 'Invalid Type', :invalid_type do
61
+ DIErrorDemo.invalid_type_dependency
62
+ end
63
+
64
+ make_cmd cmd, 'Missing Default', :missing_default do
65
+ DIErrorDemo.missing_default
66
+ end
67
+ end
68
+
69
+ desc 'OutputContract plugin errors'
70
+ command :output_contract do |cmd|
71
+ make_cmd cmd, 'No Contract error', :no_contract do
72
+ OCErrorDemo.no_contract
73
+ end
74
+
75
+ make_cmd cmd, 'Contract error', :contract do
76
+ OCErrorDemo.contract_error
77
+ end
78
+
79
+ make_cmd cmd, 'Status error', :status do
80
+ OCErrorDemo.status_error
81
+ end
82
+
83
+ make_cmd cmd, 'Result type error', :result_type do
84
+ OCErrorDemo.result_type_error
85
+ end
86
+ end
87
+
88
+ desc 'Railway errors'
89
+ command :railway do |cmd|
90
+ make_cmd cmd, 'No Steps error', :no_steps do
91
+ RailwayErrorDemo.call
92
+ end
93
+ end
94
+
95
+ desc 'Result errors'
96
+ command :result do |cmd|
97
+ make_cmd cmd, 'Access error for successful result', :ok_access do
98
+ ResultErrorDemo.success_access_error
99
+ end
100
+
101
+ make_cmd cmd, 'Access error for failure result', :err_access do
102
+ ResultErrorDemo.failure_access_error
103
+ end
104
+ end
105
+
106
+ desc 'Shared Context Pipeline errors'
107
+ command :scp do |cmd|
108
+ make_cmd cmd, 'No Steps error', :no_steps do
109
+ SCPErrorDemo.no_steps
110
+ end
111
+
112
+ make_cmd cmd, 'Missing Step Implementation error', :no_step_impl do
113
+ SCPErrorDemo.no_step_impl
114
+ end
115
+ end
116
+ end
117
+
118
+ 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,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
@@ -0,0 +1,10 @@
1
+ module RailwayErrorDemo
2
+ class MyRailway < ::Flows::Railway
3
+ end
4
+
5
+ class << self
6
+ def call
7
+ MyRailway.new
8
+ end
9
+ end
10
+ end