flow_object 0.1.4 → 0.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: ffa8dd6903e47060958b6623ed8a8c6b96074130
4
- data.tar.gz: 8d7772615968378288dc52f32a83eeb6bfb14db2
2
+ SHA256:
3
+ metadata.gz: cdecba76df1dc39202b7abcd32a626738447dc90ae0fc1d7cae695ca2aae876e
4
+ data.tar.gz: a6e4763933194dd419837ab96b75b22bc1e61b31473f6ccee3be052f2ac98e49
5
5
  SHA512:
6
- metadata.gz: 57215e81d52180ee8d28600be3ae0326834106e270e7c2fc00838fcd067ec5666ab21bc2696128a735e79d1a6ee1ea74dca46fa91de98d324b249bee8572d162
7
- data.tar.gz: fc71295067cbc45c298aea3fa0452f6e431ca02ed1ccbc5f370064b8fffc302fee14e66ae7d1b2a0fd63eaca9bd23aaa5dc351b2e93abf6122ae8e3850bc9600
6
+ metadata.gz: 11fe476ab5eb07624fb4629f520ee88a75b2da05e4393b72907247f84b3a569af961b1bcef5be91a86f47f03f6ebe639d305e6d2a7d80735efe9096e7a82a926
7
+ data.tar.gz: a1ae38390b9c66abb5f2a1df631eb3391b16563e5c7db1bae885802a93c50d272fa0b7388b8a2896f41fa0d924fba2b891a20bc51482168f028067c469fb222f
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- flow_object (0.1.4)
5
- mature_factory (~> 0.2.12)
4
+ flow_object (0.2.3)
5
+ mature_factory (~> 0.2.17)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -10,9 +10,8 @@ GEM
10
10
  coderay (1.1.3)
11
11
  diff-lcs (1.4.4)
12
12
  dry-inflector (0.1.2)
13
- mature_factory (0.2.12)
13
+ mature_factory (0.2.17)
14
14
  dry-inflector (~> 0.1)
15
- simple_facade (~> 0.2)
16
15
  method_source (1.0.0)
17
16
  pry (0.13.1)
18
17
  coderay (~> 1.1)
@@ -33,7 +32,6 @@ GEM
33
32
  rspec-support (3.9.3)
34
33
  rspec_vars_helper (0.1.0)
35
34
  rspec (>= 2.4)
36
- simple_facade (0.2.1)
37
35
 
38
36
  PLATFORMS
39
37
  ruby
data/flow_object.gemspec CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
37
  spec.require_paths = ['lib']
38
38
 
39
- spec.add_dependency 'mature_factory', '~> 0.2.12'
39
+ spec.add_dependency 'mature_factory', '~> 0.2.17'
40
40
 
41
41
  spec.add_development_dependency 'bundler', '~> 1.17'
42
42
  spec.add_development_dependency 'pry'
data/lib/flow_object.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  require 'mature_factory'
2
+ require 'flow_object/callbacks'
3
+ require 'flow_object/runner'
2
4
  require 'flow_object/base'
3
5
  require 'flow_object/version'
4
6
 
@@ -3,110 +3,158 @@ module FlowObject
3
3
  include MatureFactory
4
4
  include MatureFactory::Features::Assemble
5
5
 
6
- composed_of :stages, :inputs, :outputs
6
+ produces :stages, :inputs, :outputs
7
7
 
8
8
  class << self
9
- attr_accessor :in, :out, :initial_values
9
+ extend Forwardable
10
+ attr_reader :in, :out, :initial_values
11
+ def_delegators :callbacks, :after_input_initialize, :after_flow_initialize,
12
+ :after_input_check, :after_flow_check, :after_output_initialize
10
13
  end
11
14
 
12
- attr_reader :output, :given
15
+ attr_reader :output
13
16
 
14
- def initialize(given)
15
- @given = given
16
- @output = self.class.__fo_wrap_output__
17
+ def initialize(flow, step_name = :flow)
18
+ @output = self.class.send(:__fo_wrap_output__)
19
+ self.class.link_with_delegation(@output, flow, step_name, true)
20
+ self.class.after_output_initialize.call(@output)
17
21
  end
18
22
 
19
- def self.inherited(subclass)
20
- super
21
- subclass.from(self.in)
22
- subclass.to(self.out)
23
+ def on_exception(exception = nil)
24
+ # NOOP
23
25
  end
24
26
 
25
- def self.from(input)
26
- self.in = input
27
- self
27
+ def on_failure(failed_step = nil)
28
+ # NOOP
28
29
  end
29
30
 
30
- def self.to(output)
31
- self.out = output
32
- self
31
+ def on_success
32
+ # NOOP
33
33
  end
34
34
 
35
- def self.__fo_wrap_input__
36
- return initial_values if self.in.nil?
37
- input_class = public_send(:"#{self.in}_input_class")
38
- return initial_values if input_class.nil?
39
- public_send(:"new_#{self.in}_input_instance", *initial_values)
40
- end
35
+ module ClassMethods
36
+ def inherited(subclass)
37
+ super
38
+ subclass.from(self.in)
39
+ subclass.to(self.out)
40
+ subclass.after_input_initialize(&self.after_input_initialize)
41
+ subclass.after_flow_initialize(&self.after_flow_initialize)
42
+ subclass.after_input_check(&self.after_input_check)
43
+ subclass.after_flow_check(&self.after_flow_check)
44
+ subclass.after_output_initialize(&self.after_output_initialize)
45
+ end
41
46
 
42
- def self.__fo_wrap_output__
43
- # rescue NoMethodError => ex
44
- # "You have not define output class. Please add `output :#{self.out}`"
45
- return if self.out.nil?
46
- return unless self.respond_to?(:"#{self.out}_output_class")
47
- output_class = public_send(:"#{self.out}_output_class")
48
- return if output_class.nil?
49
- public_send(:"new_#{self.out}_output_instance")
50
- end
47
+ def callbacks
48
+ @callbacks ||= Callbacks.new
49
+ end
51
50
 
52
- def self.accept(*values)
53
- self.initial_values = values
54
- self
55
- end
51
+ def from(input)
52
+ @in = input
53
+ self
54
+ end
56
55
 
57
- def self.__fo_resolve_cascade__(cascade, step, failure)
58
- new(cascade).tap do |flow|
59
- if failure
60
- __fo_notify_error__(flow, step)
61
- else
62
- __fo_notify_success__(flow)
63
- end
56
+ def to(output)
57
+ @out = output
58
+ self
64
59
  end
65
- end
66
60
 
67
- def self.__fo_notify_error__(flow, step)
68
- if flow.output.respond_to?(:"on_#{step}_failure")
69
- flow.output.public_send(:"on_#{step}_failure", flow.given)
70
- elsif flow.output.respond_to?(:on_failure)
71
- flow.output.on_failure(flow.given, step)
72
- elsif flow.respond_to?(:"on_#{step}_failure")
73
- flow.public_send(:"on_#{step}_failure")
74
- else
75
- flow.on_failure(step)
61
+ def accept(*values)
62
+ @initial_values = values
63
+ self
76
64
  end
77
- end
78
65
 
79
- def self.__fo_notify_success__(flow)
80
- if flow.output.respond_to?(:on_success)
81
- flow.output.on_success(flow.given)
82
- else
83
- flow.on_success
66
+ def call(flow: :main)
67
+ __fo_resolve__(__fo_process__(flow: flow))
84
68
  end
85
- end
86
69
 
87
- def self.call(flow: :main)
88
- failure, previous_step, object = false, :"#{self.in}_input", __fo_wrap_input__
89
- plan = public_send(:"build_#{flow}", previous_step, object)
90
- cascade = plan.call do |object, id|
91
- previous_step = id.to_sym
92
- if !object.valid?
93
- failure = true
94
- throw :halt
95
- end
96
- end
97
- __fo_resolve_cascade__(cascade, previous_step, failure)
98
- end
70
+ def flow(name = :main, &block)
71
+ wrap(name, delegate: true, on_exception: :halt, &block)
72
+ end
99
73
 
100
- def self.flow(name = 'main', &block)
101
- wrap(name, delegate: true, &block)
102
- end
74
+ def link_with_delegation(target, object, accessor, delegate)
75
+ MatureFactory::Features::Assemble::AbstractBuilder
76
+ .link_with_delegation(target, object, accessor, delegate)
77
+ end
103
78
 
104
- def on_failure(failed_step = nil)
105
- # NOOP
106
- end
79
+ private
107
80
 
108
- def on_success
109
- # NOOP
81
+ def halt_flow?(object, id)
82
+ false
83
+ end
84
+
85
+ def __fo_process__(flow: :main)
86
+ plan = __fo_build_flow__(flow, self.in, :input, __fo_wrap_input__)
87
+ Runner.new(plan, callbacks, method(:halt_flow?)).execute_plan
88
+ end
89
+
90
+ def __fo_build_flow__(flow, step_name, group, object)
91
+ public_send(:"build_#{flow}", title: step_name, group: group, object: object)
92
+ end
93
+
94
+ def __fo_wrap_input__
95
+ return initial_values if self.in.nil?
96
+ input_class = public_send(:"#{self.in}_input_class")
97
+ return initial_values if input_class.nil?
98
+ public_send(:"new_#{self.in}_input_instance", *initial_values)
99
+ end
100
+
101
+ def __fo_wrap_output__
102
+ # rescue NoMethodError => ex
103
+ # "You have not define output class. Please add `output :#{self.out}`"
104
+ return if self.out.nil?
105
+ return unless self.respond_to?(:"#{self.out}_output_class")
106
+ output_class = public_send(:"#{self.out}_output_class")
107
+ return if output_class.nil?
108
+ public_send(:"new_#{self.out}_output_instance")
109
+ end
110
+
111
+ def __fo_resolve__(runner)
112
+ new(runner.flow.public_send(runner.step_name), runner.step_name).tap do |handler|
113
+ if runner.flow.exceptional?
114
+ __fo_notify_exception__(handler, runner.flow.exception)
115
+ elsif runner.failure
116
+ __fo_notify_error__(handler, runner.step_name)
117
+ else
118
+ __fo_notify_success__(handler)
119
+ end
120
+ end
121
+ end
122
+
123
+ def __fo_notify_exception__(handler, exception)
124
+ step = exception.step_id.title
125
+ if handler.output.respond_to?(:"on_#{step}_exception")
126
+ handler.output.public_send(:"on_#{step}_exception", exception)
127
+ elsif handler.output.respond_to?(:on_exception)
128
+ handler.output.on_exception(exception)
129
+ elsif handler.respond_to?(:"on_#{step}_exception")
130
+ handler.public_send(:"on_#{step}_exception", exception)
131
+ else
132
+ handler.on_exception(exception)
133
+ end
134
+ __fo_notify_error__(handler, exception.step_id.title)
135
+ end
136
+
137
+ def __fo_notify_error__(handler, step)
138
+ if handler.output.respond_to?(:"on_#{step}_failure")
139
+ handler.output.public_send(:"on_#{step}_failure")
140
+ elsif handler.output.respond_to?(:on_failure)
141
+ handler.output.on_failure(step)
142
+ elsif handler.respond_to?(:"on_#{step}_failure")
143
+ handler.public_send(:"on_#{step}_failure")
144
+ else
145
+ handler.on_failure(step)
146
+ end
147
+ end
148
+
149
+ def __fo_notify_success__(handler)
150
+ if handler.output.respond_to?(:on_success)
151
+ handler.output.on_success
152
+ else
153
+ handler.on_success
154
+ end
155
+ end
110
156
  end
157
+
158
+ extend ClassMethods
111
159
  end
112
160
  end
@@ -0,0 +1,29 @@
1
+ module FlowObject
2
+ class Callbacks
3
+ SUPPORTED = %i[
4
+ after_input_initialize
5
+ after_flow_initialize
6
+ after_input_check
7
+ after_flow_check
8
+ after_output_initialize
9
+ ].freeze
10
+
11
+ NOOP = proc {}.freeze
12
+
13
+ def initialize
14
+ @callbacks = Hash.new { |hash, key| hash[key] = NOOP }
15
+ end
16
+
17
+ def method_missing(name, *_attrs, &block)
18
+ if SUPPORTED.include?(name)
19
+ block_given? ? @callbacks[name] = block : @callbacks[name]
20
+ else
21
+ super
22
+ end
23
+ end
24
+
25
+ def respond_to_missing?(name, *)
26
+ SUPPORTED.include?(name)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,67 @@
1
+ module FlowObject
2
+ class Runner
3
+ attr_reader :step_name, :failure, :flow
4
+
5
+ def initialize(plan, callbacks, halt_if_proc)
6
+ @plan = plan
7
+ @flow = flow
8
+ @failure = false
9
+ @step_name = nil
10
+ @callbacks = callbacks
11
+ @step_index = 0
12
+ @halt_if_proc = halt_if_proc
13
+ end
14
+
15
+ def execute_plan
16
+ @flow = call_flow_builder
17
+ after_flow_check(flow.public_send(@step_name))
18
+ self
19
+ end
20
+
21
+ private
22
+
23
+ def call_flow_builder
24
+ @plan.call do |object, id|
25
+ handle_step(object, id) { throw :halt }
26
+ end
27
+ end
28
+
29
+ def after_flow_check(object)
30
+ @callbacks.after_flow_check.call(object)
31
+ end
32
+
33
+ def after_input_initialize(object)
34
+ @callbacks.after_input_initialize.call(object)
35
+ end
36
+
37
+ def after_flow_initialize(object)
38
+ @callbacks.after_flow_initialize.call(object)
39
+ end
40
+
41
+ def after_input_check(object)
42
+ @callbacks.after_input_check.call(object)
43
+ end
44
+
45
+ def second_step?
46
+ @step_index == 1
47
+ end
48
+
49
+ def input_step?(id)
50
+ id.group == :input
51
+ end
52
+
53
+ def flow_step?(id)
54
+ id.group == :stage
55
+ end
56
+
57
+ def handle_step(object, id)
58
+ after_input_initialize(object) if input_step?(id)
59
+ after_flow_initialize(object) if second_step? && flow_step?(id)
60
+ @step_name = id.title
61
+ @step_index += 1
62
+ yield if @failure = @halt_if_proc.call(object, id)
63
+ after_input_check(object) if input_step?(id)
64
+ end
65
+
66
+ end
67
+ end
@@ -1,3 +1,3 @@
1
1
  module FlowObject
2
- VERSION = '0.1.4'.freeze
2
+ VERSION = '0.2.3'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flow_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrii Baran
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-01-08 00:00:00.000000000 Z
11
+ date: 2021-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mature_factory
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: 0.2.12
19
+ version: 0.2.17
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: 0.2.12
26
+ version: 0.2.17
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -116,6 +116,8 @@ files:
116
116
  - flow_object.gemspec
117
117
  - lib/flow_object.rb
118
118
  - lib/flow_object/base.rb
119
+ - lib/flow_object/callbacks.rb
120
+ - lib/flow_object/runner.rb
119
121
  - lib/flow_object/version.rb
120
122
  homepage: https://github.com/andriy-baran/flow_object
121
123
  licenses:
@@ -139,8 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
141
  - !ruby/object:Gem::Version
140
142
  version: '0'
141
143
  requirements: []
142
- rubyforge_project:
143
- rubygems_version: 2.5.1
144
+ rubygems_version: 3.2.16
144
145
  signing_key:
145
146
  specification_version: 4
146
147
  summary: Create objects for storing application flows