flows 0.2.0 → 0.6.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 (166) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/{build.yml → test.yml} +5 -10
  3. data/.gitignore +9 -1
  4. data/.mdlrc +1 -1
  5. data/.reek.yml +54 -0
  6. data/.rubocop.yml +26 -7
  7. data/.rubocop_todo.yml +27 -0
  8. data/.ruby-version +1 -1
  9. data/.yardopts +1 -0
  10. data/CHANGELOG.md +81 -0
  11. data/Gemfile +0 -6
  12. data/README.md +167 -363
  13. data/Rakefile +35 -1
  14. data/bin/.rubocop.yml +5 -0
  15. data/bin/all_the_errors +55 -0
  16. data/bin/benchmark +73 -105
  17. data/bin/benchmark_cli/compare.rb +118 -0
  18. data/bin/benchmark_cli/compare/a_plus_b.rb +22 -0
  19. data/bin/benchmark_cli/compare/base.rb +45 -0
  20. data/bin/benchmark_cli/compare/command.rb +47 -0
  21. data/bin/benchmark_cli/compare/ten_steps.rb +22 -0
  22. data/bin/benchmark_cli/examples.rb +23 -0
  23. data/bin/benchmark_cli/examples/.rubocop.yml +22 -0
  24. data/bin/benchmark_cli/examples/a_plus_b/dry_do.rb +23 -0
  25. data/bin/benchmark_cli/examples/a_plus_b/dry_transaction.rb +17 -0
  26. data/bin/benchmark_cli/examples/a_plus_b/flows_do.rb +22 -0
  27. data/bin/benchmark_cli/examples/a_plus_b/flows_railway.rb +13 -0
  28. data/bin/benchmark_cli/examples/a_plus_b/flows_scp.rb +13 -0
  29. data/bin/benchmark_cli/examples/a_plus_b/flows_scp_mut.rb +13 -0
  30. data/bin/benchmark_cli/examples/a_plus_b/flows_scp_oc.rb +21 -0
  31. data/bin/benchmark_cli/examples/a_plus_b/trailblazer.rb +15 -0
  32. data/bin/benchmark_cli/examples/ten_steps/dry_do.rb +70 -0
  33. data/bin/benchmark_cli/examples/ten_steps/dry_transaction.rb +64 -0
  34. data/bin/benchmark_cli/examples/ten_steps/flows_do.rb +69 -0
  35. data/bin/benchmark_cli/examples/ten_steps/flows_railway.rb +58 -0
  36. data/bin/benchmark_cli/examples/ten_steps/flows_scp.rb +58 -0
  37. data/bin/benchmark_cli/examples/ten_steps/flows_scp_mut.rb +58 -0
  38. data/bin/benchmark_cli/examples/ten_steps/flows_scp_oc.rb +66 -0
  39. data/bin/benchmark_cli/examples/ten_steps/trailblazer.rb +60 -0
  40. data/bin/benchmark_cli/helpers.rb +12 -0
  41. data/bin/benchmark_cli/ruby.rb +15 -0
  42. data/bin/benchmark_cli/ruby/command.rb +38 -0
  43. data/bin/benchmark_cli/ruby/method_exec.rb +71 -0
  44. data/bin/benchmark_cli/ruby/self_class.rb +69 -0
  45. data/bin/benchmark_cli/ruby/structs.rb +90 -0
  46. data/bin/console +1 -0
  47. data/bin/docserver +7 -0
  48. data/bin/errors +138 -0
  49. data/bin/errors_cli/contract_error_demo.rb +49 -0
  50. data/bin/errors_cli/di_error_demo.rb +38 -0
  51. data/bin/errors_cli/flow_error_demo.rb +22 -0
  52. data/bin/errors_cli/flows_router_error_demo.rb +15 -0
  53. data/bin/errors_cli/interface_error_demo.rb +17 -0
  54. data/bin/errors_cli/oc_error_demo.rb +40 -0
  55. data/bin/errors_cli/railway_error_demo.rb +10 -0
  56. data/bin/errors_cli/result_error_demo.rb +13 -0
  57. data/bin/errors_cli/scp_error_demo.rb +17 -0
  58. data/docs/README.md +3 -187
  59. data/docs/_sidebar.md +0 -24
  60. data/docs/index.html +1 -1
  61. data/flows.gemspec +27 -2
  62. data/forspell.dict +9 -0
  63. data/lefthook.yml +9 -0
  64. data/lib/flows.rb +11 -5
  65. data/lib/flows/contract.rb +402 -0
  66. data/lib/flows/contract/array.rb +55 -0
  67. data/lib/flows/contract/case_eq.rb +43 -0
  68. data/lib/flows/contract/compose.rb +77 -0
  69. data/lib/flows/contract/either.rb +53 -0
  70. data/lib/flows/contract/error.rb +24 -0
  71. data/lib/flows/contract/hash.rb +75 -0
  72. data/lib/flows/contract/hash_of.rb +70 -0
  73. data/lib/flows/contract/helpers.rb +22 -0
  74. data/lib/flows/contract/predicate.rb +34 -0
  75. data/lib/flows/contract/transformer.rb +50 -0
  76. data/lib/flows/contract/tuple.rb +70 -0
  77. data/lib/flows/flow.rb +96 -7
  78. data/lib/flows/flow/errors.rb +29 -0
  79. data/lib/flows/flow/node.rb +132 -0
  80. data/lib/flows/flow/router.rb +29 -0
  81. data/lib/flows/flow/router/custom.rb +59 -0
  82. data/lib/flows/flow/router/errors.rb +11 -0
  83. data/lib/flows/flow/router/simple.rb +25 -0
  84. data/lib/flows/plugin.rb +15 -0
  85. data/lib/flows/plugin/dependency_injector.rb +170 -0
  86. data/lib/flows/plugin/dependency_injector/dependency.rb +24 -0
  87. data/lib/flows/plugin/dependency_injector/dependency_definition.rb +16 -0
  88. data/lib/flows/plugin/dependency_injector/dependency_list.rb +55 -0
  89. data/lib/flows/plugin/dependency_injector/errors.rb +58 -0
  90. data/lib/flows/plugin/implicit_init.rb +45 -0
  91. data/lib/flows/plugin/interface.rb +84 -0
  92. data/lib/flows/plugin/output_contract.rb +85 -0
  93. data/lib/flows/plugin/output_contract/dsl.rb +48 -0
  94. data/lib/flows/plugin/output_contract/errors.rb +74 -0
  95. data/lib/flows/plugin/output_contract/wrapper.rb +55 -0
  96. data/lib/flows/plugin/profiler.rb +114 -0
  97. data/lib/flows/plugin/profiler/injector.rb +35 -0
  98. data/lib/flows/plugin/profiler/report.rb +48 -0
  99. data/lib/flows/plugin/profiler/report/events.rb +43 -0
  100. data/lib/flows/plugin/profiler/report/flat.rb +41 -0
  101. data/lib/flows/plugin/profiler/report/flat/method_report.rb +80 -0
  102. data/lib/flows/plugin/profiler/report/raw.rb +15 -0
  103. data/lib/flows/plugin/profiler/report/tree.rb +98 -0
  104. data/lib/flows/plugin/profiler/report/tree/calculated_node.rb +116 -0
  105. data/lib/flows/plugin/profiler/report/tree/node.rb +34 -0
  106. data/lib/flows/plugin/profiler/wrapper.rb +53 -0
  107. data/lib/flows/railway.rb +140 -34
  108. data/lib/flows/railway/dsl.rb +8 -18
  109. data/lib/flows/railway/errors.rb +8 -12
  110. data/lib/flows/railway/step.rb +24 -0
  111. data/lib/flows/railway/step_list.rb +38 -0
  112. data/lib/flows/result.rb +188 -2
  113. data/lib/flows/result/do.rb +158 -16
  114. data/lib/flows/result/err.rb +12 -6
  115. data/lib/flows/result/errors.rb +29 -17
  116. data/lib/flows/result/helpers.rb +25 -3
  117. data/lib/flows/result/ok.rb +12 -6
  118. data/lib/flows/shared_context_pipeline.rb +342 -0
  119. data/lib/flows/shared_context_pipeline/dsl.rb +12 -0
  120. data/lib/flows/shared_context_pipeline/dsl/callbacks.rb +35 -0
  121. data/lib/flows/shared_context_pipeline/dsl/tracks.rb +52 -0
  122. data/lib/flows/shared_context_pipeline/errors.rb +17 -0
  123. data/lib/flows/shared_context_pipeline/mutation_step.rb +30 -0
  124. data/lib/flows/shared_context_pipeline/router_definition.rb +21 -0
  125. data/lib/flows/shared_context_pipeline/step.rb +55 -0
  126. data/lib/flows/shared_context_pipeline/track.rb +54 -0
  127. data/lib/flows/shared_context_pipeline/track_list.rb +51 -0
  128. data/lib/flows/shared_context_pipeline/wrap.rb +73 -0
  129. data/lib/flows/util.rb +17 -0
  130. data/lib/flows/util/inheritable_singleton_vars.rb +86 -0
  131. data/lib/flows/util/inheritable_singleton_vars/dup_strategy.rb +100 -0
  132. data/lib/flows/util/inheritable_singleton_vars/isolation_strategy.rb +91 -0
  133. data/lib/flows/util/prepend_to_class.rb +191 -0
  134. data/lib/flows/version.rb +1 -1
  135. metadata +253 -38
  136. data/Gemfile.lock +0 -174
  137. data/bin/demo +0 -66
  138. data/bin/examples.rb +0 -195
  139. data/bin/profile_10steps +0 -106
  140. data/bin/ruby_benchmarks +0 -26
  141. data/docs/CNAME +0 -1
  142. data/docs/contributing/benchmarks_profiling.md +0 -3
  143. data/docs/contributing/local_development.md +0 -3
  144. data/docs/flow/direct_usage.md +0 -3
  145. data/docs/flow/general_idea.md +0 -3
  146. data/docs/operation/basic_usage.md +0 -1
  147. data/docs/operation/inject_steps.md +0 -3
  148. data/docs/operation/lambda_steps.md +0 -3
  149. data/docs/operation/result_shapes.md +0 -3
  150. data/docs/operation/routing_tracks.md +0 -3
  151. data/docs/operation/wrapping_steps.md +0 -3
  152. data/docs/overview/performance.md +0 -336
  153. data/docs/railway/basic_usage.md +0 -232
  154. data/docs/result_objects/basic_usage.md +0 -196
  155. data/docs/result_objects/do_notation.md +0 -139
  156. data/lib/flows/node.rb +0 -27
  157. data/lib/flows/operation.rb +0 -52
  158. data/lib/flows/operation/builder.rb +0 -130
  159. data/lib/flows/operation/builder/build_router.rb +0 -37
  160. data/lib/flows/operation/dsl.rb +0 -93
  161. data/lib/flows/operation/errors.rb +0 -75
  162. data/lib/flows/operation/executor.rb +0 -78
  163. data/lib/flows/railway/builder.rb +0 -68
  164. data/lib/flows/railway/executor.rb +0 -23
  165. data/lib/flows/result_router.rb +0 -14
  166. data/lib/flows/router.rb +0 -22
@@ -0,0 +1,85 @@
1
+ require_relative 'output_contract/errors'
2
+ require_relative 'output_contract/dsl'
3
+ require_relative 'output_contract/wrapper'
4
+
5
+ module Flows
6
+ module Plugin
7
+ # Allows to make a contract check and transformation for `#call` method execution in any class.
8
+ #
9
+ # Plugin applies a wrapper to a `#call` instance method.
10
+ # This wrapper will do the following:
11
+ #
12
+ # * check that {Result} instance is returned by `#call`
13
+ # * check that returned {Result#status} is expected
14
+ # * check that returned result data conforms {Contract} assigned
15
+ # to a particular result type and status
16
+ # * applies contract transform to the returned data
17
+ # * returns {Result} with the same status and type,
18
+ # wraps transformed data inside.
19
+ #
20
+ # Plugin provides DSL to express expected result statuses and assigned contracts.
21
+ # Contracts definition reuses {Contract.make} to execute block and get a contract.
22
+ #
23
+ # * `success_with(status, &block)` - defines contract for a successful result with status `status`.
24
+ # * `failure_with(status, &block)` - defines contract for a failure result with status `status`.
25
+ # * `skip_output_contract` - disables contract check and transformation for current class and children.
26
+ #
27
+ # @example with one possible output contract
28
+ # class DoJob
29
+ # include Flows::Result::Helpers
30
+ # include Flows::Plugin::OutputContract
31
+ #
32
+ # success_with :ok do
33
+ # Integer
34
+ # end
35
+ #
36
+ # def call(a, b)
37
+ # ok_data(a + b)
38
+ # end
39
+ # end
40
+ #
41
+ # DoJob.new.call(1, 2).unwrap
42
+ # # => 3
43
+ #
44
+ # DoJob.new.call('a', 'b')
45
+ # # Flows::Contract::Error exception raised
46
+ #
47
+ # @example with multiple contracts
48
+ # class DoJob
49
+ # include Flows::Result::Helpers
50
+ # include Flows::Plugin::OutputContract
51
+ #
52
+ # success_with :int_sum do
53
+ # Integer
54
+ # end
55
+ #
56
+ # success_with :float_sum do
57
+ # Float
58
+ # end
59
+ #
60
+ # failure_with :err do
61
+ # hash_of(
62
+ # key: Symbol,
63
+ # msg: String
64
+ # )
65
+ # end
66
+ #
67
+ # def call(a, b)
68
+ # if a.is_a?(Float) || b.is_a?(Float)
69
+ # ok_data(a + b, status: :float_sum)
70
+ # elsif a.is_a?(Integer) && b.is_a?(Integer)
71
+ # ok_data(a + b, status: :int_sum)
72
+ # else
73
+ # err(key: :unexpected_type, msg: "Unexpected argument types")
74
+ # end
75
+ # end
76
+ # end
77
+ module OutputContract
78
+ # @api private
79
+ def self.included(mod)
80
+ mod.extend(DSL)
81
+ mod.prepend(Wrapper)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,48 @@
1
+ module Flows
2
+ module Plugin
3
+ module OutputContract
4
+ # DSL for OutputContract plugin.
5
+ module DSL
6
+ # Hash of contracts for successful results.
7
+ attr_reader :success_contracts
8
+
9
+ # Hash of contracts for failure results.
10
+ attr_reader :failure_contracts
11
+
12
+ # Is contract check and transformation disabled
13
+ attr_reader :skip_output_contract_flag
14
+
15
+ SingletonVarsSetup = Flows::Util::InheritableSingletonVars::DupStrategy.make_module(
16
+ '@success_contracts' => {},
17
+ '@failure_contracts' => {},
18
+ '@skip_output_contract_flag' => false
19
+ )
20
+
21
+ include SingletonVarsSetup
22
+
23
+ # Defines a contract for a successful result with specific status.
24
+ #
25
+ # @param status [Symbol] Corresponding result status.
26
+ # @param contract_block [Proc] This block will be passed to {Contract.make} to get a contract.
27
+ def success_with(status, &contract_block)
28
+ success_contracts[status] = Flows::Contract.make(&contract_block)
29
+ end
30
+
31
+ # Defines a contract for a failure result with specific status.
32
+ #
33
+ # @param status [Symbol] Corresponding result status.
34
+ # @param contract_block [Proc] This block will be passed to {Contract.make} to get a contract.
35
+ def failure_with(status, &contract_block)
36
+ failure_contracts[status] = Flows::Contract.make(&contract_block)
37
+ end
38
+
39
+ # Disables contract check and transformation for current class and children.
40
+ #
41
+ # @param enable [Boolean] if true - contracts are disabled
42
+ def skip_output_contract(enable: true)
43
+ @skip_output_contract_flag = enable
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,74 @@
1
+ module Flows
2
+ module Plugin
3
+ module OutputContract
4
+ # Base error class for output contract errors.
5
+ class Error < StandardError; end
6
+
7
+ # Raised when no single contract for successful results is defined
8
+ class NoContractError < Error
9
+ def initialize(klass)
10
+ @klass = klass
11
+ end
12
+
13
+ def message
14
+ "No single success contract defined for #{@klass}"
15
+ end
16
+ end
17
+
18
+ # Raised when result's data violates contract
19
+ class ContractError < Error
20
+ def initialize(klass, result, error)
21
+ @klass = klass
22
+ @result = result
23
+ @error = error
24
+ end
25
+
26
+ def message
27
+ shifted_error = @error.split("\n").map { |str| " #{str}" }.join("\n")
28
+
29
+ "Output contract for #{@klass} is violated.\n" \
30
+ "Result:\n" \
31
+ " `#{@result.inspect}`\n" \
32
+ "Contract Error:\n" \
33
+ "#{shifted_error}"
34
+ end
35
+ end
36
+
37
+ # Raised when no contract found for result
38
+ class StatusError < Error
39
+ def initialize(klass, result, allowed_statuses)
40
+ @klass = klass
41
+ @result = result
42
+ @allowed_statuses = allowed_statuses
43
+ end
44
+
45
+ def message
46
+ allowed_statuses_str = @allowed_statuses.map { |st| "`#{st.inspect}`" }.join(', ')
47
+
48
+ "Output contract for #{@klass} is violated.\n" \
49
+ "Result:\n" \
50
+ " `#{@result.inspect}`\n" \
51
+ "Contract Error:\n" \
52
+ " has unexpected status `#{@result.status.inspect}`\n" \
53
+ " allowed statuses for `#{@result.class}` are: #{allowed_statuses_str}"
54
+ end
55
+ end
56
+
57
+ # Raised when not a result object returned
58
+ class ResultTypeError < Error
59
+ def initialize(klass, result)
60
+ @klass = klass
61
+ @result = result
62
+ end
63
+
64
+ def message
65
+ "Output contract for #{@klass} is violated.\n" \
66
+ "Result:\n" \
67
+ " `#{@result.inspect}`\n" \
68
+ "Contract Error:\n" \
69
+ ' result must be instance of `Flows::Result`'
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,55 @@
1
+ module Flows
2
+ module Plugin
3
+ module OutputContract
4
+ # Contains wrappers for initializer and `#call` methods.
5
+ #
6
+ # @api private
7
+ module Wrapper
8
+ def initialize(*args, &block)
9
+ super(*args, &block)
10
+ klass = self.class
11
+ raise NoContractError, klass if klass.success_contracts.empty? && !klass.skip_output_contract_flag
12
+ end
13
+
14
+ def call(*args, &block)
15
+ result = super(*args, &block)
16
+ klass = self.class
17
+
18
+ return result if klass.skip_output_contract_flag
19
+
20
+ Util.transform_result(klass, result)
21
+
22
+ result
23
+ end
24
+
25
+ # Helper methods for {Wrapper} are extracted to this
26
+ # module as singleton methods to not pollute user classes.
27
+ #
28
+ # @api private
29
+ module Util
30
+ class << self
31
+ def transform_result(klass, result)
32
+ contract = Util.contract_for(klass, result)
33
+
34
+ data = result.send(:data)
35
+
36
+ transformed_result = contract.transform(data)
37
+ raise ContractError.new(klass, result, transformed_result.error) if transformed_result.err?
38
+
39
+ result.send(:'data=', transformed_result.unwrap)
40
+ end
41
+
42
+ def contract_for(klass, result)
43
+ raise ResultTypeError.new(klass, result) unless result.is_a?(Flows::Result)
44
+
45
+ status = result.status
46
+ contracts = result.ok? ? klass.success_contracts : klass.failure_contracts
47
+
48
+ contracts[status] || raise(StatusError.new(klass, result, contracts.keys))
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,114 @@
1
+ require_relative 'profiler/report'
2
+ require_relative 'profiler/injector'
3
+ require_relative 'profiler/wrapper'
4
+
5
+ module Flows
6
+ module Plugin
7
+ # Allows to record execution count and time of particular method on class or singleton class.
8
+ #
9
+ # Recorded data can be displayed in a different ways.
10
+ # See {Profiler::Report} implementations for possible options.
11
+ #
12
+ # To do a measurement you have call your classes inside {.profile} block.
13
+ #
14
+ # @note even without calling {.profile} using this module has some performance
15
+ # impact. Don't left this module used in production environments.
16
+ #
17
+ # @example
18
+ # class MyClass
19
+ # CallProfiler = Flows::Plugin::Profiler.for_method(:call)
20
+ # include CallProfiler
21
+ #
22
+ # def call(a, b)
23
+ # # some work here
24
+ # end
25
+ # end
26
+ #
27
+ # class AnotherClass
28
+ # CallProfiler = Flows::Plugin::Profiler.for_method(:perform)
29
+ # extend CallProfiler
30
+ #
31
+ # def self.perform(x)
32
+ # MyClass.new.call(x, x)
33
+ # end
34
+ # end
35
+ #
36
+ # last_result = Flows::Plugin::Profiler.profile do
37
+ # AnotherClass.perform(2)
38
+ # AnotherClass.perform(6)
39
+ # end
40
+ #
41
+ # Profiler.last_report.to_a
42
+ # # => [
43
+ # # [:started, AnotherClass, :singleton, :perform, nil],
44
+ # # [:started, MyClass, :instance, :call, nil],
45
+ # # [:finished, MyClass, :instance, :call, 7.3],
46
+ # # [:finished, AnotherClass, :singleton, :perform, 10.5],
47
+ # # [:started, AnotherClass, :singleton, :perform, nil],
48
+ # # [:started, MyClass, :instance, :call, nil],
49
+ # # [:finished, MyClass, :instance, :call, 8.8],
50
+ # # [:finished, AnotherClass, :singleton, :perform, 14.2]
51
+ # # ]
52
+ module Profiler
53
+ THREAD_VAR_FLAG = :flows_profiler_flag
54
+ THREAD_VAR_REPORT = :flows_profiler_report
55
+
56
+ class << self
57
+ # Generates profiler module for a particular method.
58
+ #
59
+ # Use `include` for instance methods and `extend` for singleton ones.
60
+ #
61
+ # @param method_name [Symbol] method to wrap with profiling.
62
+ # @return [Module] module to include or extend.
63
+ def for_method(method_name)
64
+ Module.new.tap do |mod|
65
+ injector_mod = Injector.make_module(method_name)
66
+ mod.const_set(:Injector, injector_mod)
67
+ mod.extend injector_mod
68
+ end
69
+ end
70
+
71
+ # Profiles a block execution.
72
+ #
73
+ # @param report [Report, Symbol]
74
+ # desired {Report} to be used.
75
+ # In case of symbol `:some_name` the `Flows::Plugin::Profiler::Report::SomeName.new` will be used.
76
+ # @yield code to profile
77
+ # @return block result
78
+ def profile(report = :raw)
79
+ thread = Thread.current
80
+
81
+ thread[THREAD_VAR_FLAG] = true
82
+ thread[THREAD_VAR_REPORT] = make_report(report)
83
+
84
+ yield
85
+ ensure
86
+ thread[THREAD_VAR_FLAG] = false
87
+ end
88
+
89
+ # Resets thread-local variables used for reporting.
90
+ def reset
91
+ thread = Thread.current
92
+ thread[THREAD_VAR_FLAG] = false
93
+ thread[THREAD_VAR_REPORT] = nil
94
+ end
95
+
96
+ # @return [Report, nil] last generated report if some.
97
+ def last_report
98
+ Thread.current[THREAD_VAR_REPORT]
99
+ end
100
+
101
+ private
102
+
103
+ def make_report(report_or_sym)
104
+ case report_or_sym
105
+ when Report then report_or_sym
106
+ when Symbol
107
+ const_name = report_or_sym.to_s.split('_').map(&:capitalize).join
108
+ Report.const_get(const_name).new
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,35 @@
1
+ module Flows
2
+ module Plugin
3
+ module Profiler
4
+ # @api private
5
+ module Injector
6
+ class << self
7
+ def make_module(method_name)
8
+ Module.new.tap do |mod|
9
+ add_included(mod, method_name)
10
+ add_extended(mod, method_name)
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def add_included(mod, method_name)
17
+ mod.define_method(:included) do |target|
18
+ raise 'must be included into class' unless target.is_a?(Class)
19
+
20
+ target.prepend Wrapper.make_instance_wrapper(method_name)
21
+ end
22
+ end
23
+
24
+ def add_extended(mod, method_name)
25
+ mod.define_method(:extended) do |target|
26
+ raise 'must be extended into class' unless target.is_a?(Class)
27
+
28
+ target.singleton_class.prepend(Wrapper.make_singleton_wrapper(method_name))
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,48 @@
1
+ require_relative 'report/events'
2
+ require_relative 'report/raw'
3
+ require_relative 'report/tree'
4
+ require_relative 'report/flat'
5
+
6
+ module Flows
7
+ module Plugin
8
+ module Profiler
9
+ # Base class for {Profiler} reports.
10
+ #
11
+ # @!method to_s
12
+ # @abstract
13
+ # @return [String] human-readable representation.
14
+ class Report
15
+ # @return [Array<Array>] raw profiler events
16
+ attr_reader :raw_data
17
+
18
+ def initialize
19
+ @raw_data = []
20
+ end
21
+
22
+ # Add event to profile report.
23
+ #
24
+ # @param event_type [:started, :finished] event type
25
+ # @param klass [Class] class where called method is placed
26
+ # @param method_type [:instance, :singleton] method type
27
+ # @param method_name [Symbol] name of the called method
28
+ # @param data [nil, Float] event data, time represented as
29
+ # a Float microseconds value.
30
+ def add(*args)
31
+ raw_data << args
32
+ end
33
+
34
+ # @return [Array<Event>] array of events
35
+ def events
36
+ raw_data.map do |raw_event|
37
+ klass = case raw_event.first
38
+ when :started then StartEvent
39
+ when :finished then FinishEvent
40
+ end
41
+
42
+ klass.new(*raw_event[1..-1])
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end