business_flow 0.19.3 → 0.19.5

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
2
  SHA256:
3
- metadata.gz: 0f141ad60cea86b41612d48091f29916ed512b95136f665a0e99fce1b9cddf60
4
- data.tar.gz: b2342e16e41780165029b2605fe545ff940939903a85c7f749704e3af443a126
3
+ metadata.gz: 82c431371d59045db43a3e6a53b1f5be3169396eb684cd3dd57360c13e66de93
4
+ data.tar.gz: 7af7df17705aba80a4c27099a72a122413029bf95f73490d87de2ae66336dd4d
5
5
  SHA512:
6
- metadata.gz: b48a9c480de3bbb78c0fe1f2bdadb7b05e8f93068eac08d5b9aa21999d5c6f54b97febee0366de7c49ea4dafd8a3e87d362a6d70e0e2dc3997ee0a25eda1deb2
7
- data.tar.gz: cef0b142c7f352dc83cf786a5a2df98a37101c58f8b7c75fda2fa0cc113211531657aaeb7813f88b8738ea6bd8d7ce49e2b9aeb00adf88766f31b16e8ec7012b
6
+ metadata.gz: 27e674b0357b3312991ad8d65c91b95e0fed8481259512bdee9e3e2a262e9841af6a1d2b30de250781de36e4aa7544a5d17482ee75013067c9f59c837603958d
7
+ data.tar.gz: 8c3fe93115e9ac88c71812c1392e9a88702a410ce904f12b2982640a115066a93b1b676fc671be99ef9675073f5e90454d231409e2c13c67ded91f595aa588ae
data/.reek.yml ADDED
@@ -0,0 +1,13 @@
1
+ # Auto generated by Reeks --todo flag
2
+ ---
3
+ detectors:
4
+ FeatureEnvy:
5
+ exclude:
6
+ - BusinessFlow::ClusterLock::ClassMethods::LockFailure#add_to
7
+ LongParameterList:
8
+ exclude:
9
+ - BusinessFlow#self.add_error
10
+ UncommunicativeVariableName:
11
+ # N.B. If we want to enable this, we need to tweak the RuboCop config. In particular, RuboCop
12
+ # prefers `e` for exceptions.
13
+ enabled: false
data/.rubocop.yml ADDED
@@ -0,0 +1,84 @@
1
+ require:
2
+ - rubocop-rspec
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 2.7
6
+ NewCops: enable
7
+ Exclude:
8
+ - coverage/**/*
9
+
10
+ # Excluding specs here because of RSpec's tendency to look at the line-number info on a backtrace to
11
+ # decide what to show you when a matcher fails. I.E. a very long line may be needed to ensure you
12
+ # get good diagnostic info on a test failure.
13
+ Layout/LineLength:
14
+ Max: 100
15
+ Exclude:
16
+ - spec/**/*
17
+
18
+ RSpec/MultipleMemoizedHelpers:
19
+ Enabled: false
20
+
21
+ RSpec/IndexedLet:
22
+ # We have specs that are describing process steps, so... numbers are kinda the best way to describe that.
23
+ Enabled: false
24
+
25
+ RSpec/NestedGroups:
26
+ Max: 4
27
+
28
+ RSpec/LeakyConstantDeclaration:
29
+ # This effectively duplicates Lint/ConstantDefinitionInBlock.
30
+ Enabled: false
31
+
32
+ Lint/ConstantDefinitionInBlock:
33
+ Exclude:
34
+ - spec/**/*
35
+
36
+ Naming/MemoizedInstanceVariableName:
37
+ # This conflicts with Reek.
38
+ Enabled: false
39
+
40
+ # Explicit is bettr than implicit.
41
+ Style/EmptyElse:
42
+ Enabled: false
43
+
44
+ Style/RescueModifier:
45
+ Exclude:
46
+ - spec/**/*
47
+
48
+ Style/DocumentDynamicEvalDefinition:
49
+ Enabled: false
50
+
51
+ # Explicit is bettr than implicit.
52
+ FactoryBot/SyntaxMethods:
53
+ Enabled: false
54
+
55
+ # For `match(hash_including(...))`, in specs, this rule would make things pretty unreadable.
56
+ Layout/ClosingParenthesisIndentation:
57
+ Exclude:
58
+ - spec/**/*
59
+
60
+ # This makes things pretty unreadable in a lot of cases, including but not limited to
61
+ # `match(hash_including(...))` in specs.
62
+ Layout/FirstArgumentIndentation:
63
+ Enabled: false
64
+
65
+ Bundler/OrderedGems:
66
+ Exclude:
67
+ - 'Gemfile'
68
+
69
+ Lint/EmptyBlock:
70
+ Enabled: false
71
+
72
+ # OpenStruct is unwise for actual application code (esp. in light of potentially using yjit in the
73
+ # future), but the flexibility is handy for specs.
74
+ Style/OpenStructUse:
75
+ Exclude:
76
+ - spec/**/*
77
+
78
+ # Disabling this because the "preferred" way requires allocating a Range which is stupid and wrong.
79
+ Style/RandomWithOffset:
80
+ Enabled: false
81
+
82
+ # What, exactly, does the Ruby community have against the Truthiness Operator?!
83
+ Style/DoubleNegation:
84
+ Enabled: false
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ business_flow
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.7.4
data/Gemfile CHANGED
@@ -1,6 +1,18 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
6
 
5
7
  # Specify your gem's dependencies in business_flow.gemspec
6
8
  gemspec
9
+
10
+ gem 'pry', '~> 0.14.2'
11
+ gem 'rake', '~> 13.0'
12
+ gem 'reek', '~> 6.1'
13
+ gem 'retryable', '~> 3.0.4'
14
+ gem 'rspec', '~> 3.0'
15
+ gem 'rubocop', '~> 1.59.0'
16
+ gem 'rubocop-rspec', '~> 2.29.1'
17
+ gem 'simplecov', '~> 0.22.0'
18
+ gem 'timecop', '~> 0.9.1'
data/Gemfile.lock CHANGED
@@ -1,84 +1,120 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- business_flow (0.19.3)
4
+ business_flow (0.19.5)
5
5
  activemodel (>= 4.2, < 8)
6
6
  activesupport (>= 4.2, < 8)
7
7
 
8
8
  GEM
9
9
  remote: https://rubygems.org/
10
10
  specs:
11
- activemodel (7.0.4)
12
- activesupport (= 7.0.4)
13
- activesupport (7.0.4)
11
+ activemodel (7.1.3.2)
12
+ activesupport (= 7.1.3.2)
13
+ activesupport (7.1.3.2)
14
+ base64
15
+ bigdecimal
14
16
  concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ connection_pool (>= 2.2.5)
18
+ drb
15
19
  i18n (>= 1.6, < 2)
16
20
  minitest (>= 5.1)
21
+ mutex_m
17
22
  tzinfo (~> 2.0)
18
23
  ast (2.4.2)
19
- concurrent-ruby (1.1.10)
20
- diff-lcs (1.5.0)
24
+ base64 (0.2.0)
25
+ bigdecimal (3.1.7)
26
+ coderay (1.1.3)
27
+ concurrent-ruby (1.2.3)
28
+ connection_pool (2.4.1)
29
+ diff-lcs (1.5.1)
21
30
  docile (1.4.0)
22
- i18n (1.12.0)
31
+ drb (2.2.1)
32
+ i18n (1.14.4)
23
33
  concurrent-ruby (~> 1.0)
24
- jaro_winkler (1.5.4)
34
+ json (2.7.2)
25
35
  kwalify (0.7.2)
26
- minitest (5.16.3)
27
- parallel (1.22.1)
28
- parser (3.2.2.1)
36
+ language_server-protocol (3.17.0.3)
37
+ method_source (1.1.0)
38
+ minitest (5.22.3)
39
+ mutex_m (0.2.0)
40
+ parallel (1.24.0)
41
+ parser (3.2.2.4)
29
42
  ast (~> 2.4.1)
43
+ racc
44
+ pry (0.14.2)
45
+ coderay (~> 1.1)
46
+ method_source (~> 1.0)
47
+ racc (1.7.3)
30
48
  rainbow (3.1.1)
31
- rake (10.5.0)
49
+ rake (13.2.1)
32
50
  reek (6.1.4)
33
51
  kwalify (~> 0.7.0)
34
52
  parser (~> 3.2.0)
35
53
  rainbow (>= 2.0, < 4.0)
54
+ regexp_parser (2.9.0)
36
55
  retryable (3.0.5)
37
- rspec (3.12.0)
38
- rspec-core (~> 3.12.0)
39
- rspec-expectations (~> 3.12.0)
40
- rspec-mocks (~> 3.12.0)
41
- rspec-core (3.12.0)
42
- rspec-support (~> 3.12.0)
43
- rspec-expectations (3.12.0)
56
+ rexml (3.2.6)
57
+ rspec (3.13.0)
58
+ rspec-core (~> 3.13.0)
59
+ rspec-expectations (~> 3.13.0)
60
+ rspec-mocks (~> 3.13.0)
61
+ rspec-core (3.13.0)
62
+ rspec-support (~> 3.13.0)
63
+ rspec-expectations (3.13.0)
44
64
  diff-lcs (>= 1.2.0, < 2.0)
45
- rspec-support (~> 3.12.0)
46
- rspec-mocks (3.12.0)
65
+ rspec-support (~> 3.13.0)
66
+ rspec-mocks (3.13.0)
47
67
  diff-lcs (>= 1.2.0, < 2.0)
48
- rspec-support (~> 3.12.0)
49
- rspec-support (3.12.0)
50
- rubocop (0.68.1)
51
- jaro_winkler (~> 1.5.1)
68
+ rspec-support (~> 3.13.0)
69
+ rspec-support (3.13.1)
70
+ rubocop (1.59.0)
71
+ json (~> 2.3)
72
+ language_server-protocol (>= 3.17.0)
52
73
  parallel (~> 1.10)
53
- parser (>= 2.5, != 2.5.1.1)
74
+ parser (>= 3.2.2.4)
54
75
  rainbow (>= 2.2.2, < 4.0)
76
+ regexp_parser (>= 1.8, < 3.0)
77
+ rexml (>= 3.2.5, < 4.0)
78
+ rubocop-ast (>= 1.30.0, < 2.0)
55
79
  ruby-progressbar (~> 1.7)
56
- unicode-display_width (>= 1.4.0, < 1.6)
57
- rubocop-rspec (1.24.0)
58
- rubocop (>= 0.53.0)
59
- ruby-progressbar (1.11.0)
80
+ unicode-display_width (>= 2.4.0, < 3.0)
81
+ rubocop-ast (1.30.0)
82
+ parser (>= 3.2.1.0)
83
+ rubocop-capybara (2.20.0)
84
+ rubocop (~> 1.41)
85
+ rubocop-factory_bot (2.25.1)
86
+ rubocop (~> 1.41)
87
+ rubocop-rspec (2.29.2)
88
+ rubocop (~> 1.40)
89
+ rubocop-capybara (~> 2.17)
90
+ rubocop-factory_bot (~> 2.22)
91
+ rubocop-rspec_rails (~> 2.28)
92
+ rubocop-rspec_rails (2.28.3)
93
+ rubocop (~> 1.40)
94
+ ruby-progressbar (1.13.0)
60
95
  simplecov (0.22.0)
61
96
  docile (~> 1.1)
62
97
  simplecov-html (~> 0.11)
63
98
  simplecov_json_formatter (~> 0.1)
64
99
  simplecov-html (0.12.3)
65
100
  simplecov_json_formatter (0.1.4)
66
- timecop (0.9.6)
67
- tzinfo (2.0.5)
101
+ timecop (0.9.8)
102
+ tzinfo (2.0.6)
68
103
  concurrent-ruby (~> 1.0)
69
- unicode-display_width (1.5.0)
104
+ unicode-display_width (2.5.0)
70
105
 
71
106
  PLATFORMS
72
107
  ruby
73
108
 
74
109
  DEPENDENCIES
75
110
  business_flow!
76
- rake (~> 10.0)
111
+ pry (~> 0.14.2)
112
+ rake (~> 13.0)
77
113
  reek (~> 6.1)
78
114
  retryable (~> 3.0.4)
79
115
  rspec (~> 3.0)
80
- rubocop (~> 0.53)
81
- rubocop-rspec (~> 1.24.0)
116
+ rubocop (~> 1.59.0)
117
+ rubocop-rspec (~> 2.29.1)
82
118
  simplecov (~> 0.22.0)
83
119
  timecop (~> 0.9.1)
84
120
 
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
 
data/bin/console CHANGED
@@ -1,5 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ # frozen_string_literal: true
4
+
3
5
  require 'bundler/setup'
4
6
  require 'business_flow'
5
7
 
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
 
2
3
  lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
@@ -23,12 +24,7 @@ Gem::Specification.new do |spec|
23
24
  spec.add_dependency 'activemodel', '>= 4.2', '< 8'
24
25
  spec.add_dependency 'activesupport', '>= 4.2', '< 8'
25
26
 
26
- spec.add_development_dependency 'rake', '~> 10.0'
27
- spec.add_development_dependency 'reek', '~> 6.1'
28
- spec.add_development_dependency 'retryable', '~> 3.0.4'
29
- spec.add_development_dependency 'rspec', '~> 3.0'
30
- spec.add_development_dependency 'rubocop', '~> 0.53'
31
- spec.add_development_dependency 'rubocop-rspec', '~> 1.24.0'
32
- spec.add_development_dependency 'simplecov', '~> 0.22.0'
33
- spec.add_development_dependency 'timecop', '~> 0.9.1'
27
+ spec.metadata['rubygems_mfa_required'] = 'true'
28
+
29
+ spec.required_ruby_version = '>= 2.7.0'
34
30
  end
@@ -68,13 +68,14 @@ module BusinessFlow
68
68
 
69
69
  def clear_cache(parameter_object = {})
70
70
  clear_cache!(parameter_object)
71
- rescue FlowFailedException => exc
72
- exc.flow
71
+ rescue FlowFailedException => e
72
+ e.flow
73
73
  end
74
74
 
75
75
  def clear_cache!(parameter_object = {})
76
76
  flow = build(parameter_object)
77
77
  raise FlowFailedException, result_from(flow) if flow.errors?
78
+
78
79
  ClassMethods.clear_cache(flow)
79
80
  end
80
81
 
@@ -91,8 +92,8 @@ module BusinessFlow
91
92
  with_cache(flow) do
92
93
  super(flow)._business_flow_cacheable_finalize(flow.cache_key)
93
94
  end
94
- rescue FlowFailedException => exc
95
- exc.flow
95
+ rescue FlowFailedException => e
96
+ e.flow
96
97
  end
97
98
 
98
99
  def with_cache(flow, &blk)
@@ -117,11 +118,13 @@ module BusinessFlow
117
118
  RESULT_FINALIZE = proc do |cache_key|
118
119
  @cache_key = cache_key
119
120
  raise FlowFailedException, self if errors?
121
+
120
122
  self
121
123
  end
122
124
 
123
125
  def add_cache_key_to_result_class
124
126
  return if @cache_key_added
127
+
125
128
  result_class = const_get(:Result)
126
129
  DSL::PublicField.new(:cache_key).add_to(result_class)
127
130
  result_class.send(:define_method, :_business_flow_cacheable_finalize,
@@ -98,11 +98,9 @@ module BusinessFlow
98
98
  def lookup_callable(first_instance)
99
99
  constant_name = @callable.to_s.camelcase
100
100
  first_instance.class.module_parents.each do |parent|
101
- begin
102
- return parent.const_get(constant_name)
103
- rescue NameError
104
- next
105
- end
101
+ return parent.const_get(constant_name)
102
+ rescue NameError
103
+ next
106
104
  end
107
105
  nil
108
106
  end
@@ -20,23 +20,24 @@ module BusinessFlow
20
20
  end
21
21
 
22
22
  def self.default_servers=(servers)
23
- if servers.is_a?(String)
24
- @default_servers = proc { servers }
25
- elsif servers
26
- @default_servers = Callable.new(servers)
27
- else
28
- @default_servers = nil
29
- end
23
+ @default_servers = if servers.is_a?(String)
24
+ proc { servers }
25
+ elsif servers
26
+ Callable.new(servers)
27
+ else
28
+ nil
29
+ end
30
30
  end
31
31
 
32
32
  def self.default_servers
33
- @default_servers ||= proc { nil }
33
+ @default_servers ||= proc {}
34
34
  end
35
35
 
36
36
  def assert_cluster_lock!
37
- @_business_flow_cluster_lock.assert! if !BusinessFlow::ClusterLock.disabled?
38
- rescue ZK::Exceptions::ZKError => exc
39
- errors.add(:cluster_lock, :assert_failed, message: exc.message)
37
+ @_business_flow_cluster_lock.assert! unless BusinessFlow::ClusterLock.disabled?
38
+ rescue ZK::Exceptions::ZKError => e
39
+ BusinessFlow.add_error(errors, :cluster_lock, :assert_failed, e.message)
40
+
40
41
  raise
41
42
  end
42
43
 
@@ -49,10 +50,11 @@ module BusinessFlow
49
50
  end
50
51
 
51
52
  # DSL Methods
52
- module ClassMethods
53
+ module ClassMethods # rubocop:disable Metrics/ModuleLength
53
54
  # Error raised when there is an internal issue with acquiring a lock.
54
55
  class LockFailure < StandardError
55
56
  attr_reader :error_type
57
+
56
58
  def initialize(error_type, message)
57
59
  @error_type = error_type
58
60
  super(message)
@@ -60,7 +62,9 @@ module BusinessFlow
60
62
 
61
63
  def add_to(flow)
62
64
  errors = flow.errors
63
- errors.add(:cluster_lock, error_type, message: message) if !errors.key?(:cluster_lock)
65
+ unless errors.key?(:cluster_lock)
66
+ BusinessFlow.add_error(errors, :cluster_lock, error_type, message)
67
+ end
64
68
  flow
65
69
  end
66
70
  end
@@ -114,8 +118,8 @@ module BusinessFlow
114
118
  ClassMethods.with_lock(flow, lock_info) do
115
119
  super(flow)._business_flow_cluster_lock_finalize(lock_info)
116
120
  end
117
- rescue LockFailure => exc
118
- return result_from(exc.add_to(flow))._business_flow_cluster_lock_finalize(lock_info)
121
+ rescue LockFailure => e
122
+ result_from(e.add_to(flow))._business_flow_cluster_lock_finalize(lock_info)
119
123
  end
120
124
 
121
125
  RESULT_FINALIZE = proc do |cluster_lock_info|
@@ -125,6 +129,7 @@ module BusinessFlow
125
129
 
126
130
  def add_cluster_luck_info_to_result_class
127
131
  return if @cluster_lock_info_added
132
+
128
133
  result_class = const_get(:Result)
129
134
  DSL::PublicField.new(:cluster_lock_info).add_to(result_class)
130
135
  result_class.send(:define_method, :_business_flow_cluster_lock_finalize,
@@ -134,19 +139,23 @@ module BusinessFlow
134
139
 
135
140
  # :reek:NilCheck
136
141
  def self.zookeeper_server_list(flow)
137
- servers = catch(:halt_step) { flow.class.with_zookeeper_servers.call(flow)&.merge_into(flow)&.to_s }
138
- if servers.nil? || servers.length == 0
142
+ servers =
143
+ catch(:halt_step) { flow.class.with_zookeeper_servers.call(flow)&.merge_into(flow)&.to_s }
144
+ if servers.nil? || servers.empty?
139
145
  raise LockFailure.new(:no_servers, 'no zookeeper servers provided')
140
146
  end
147
+
141
148
  servers
142
149
  end
143
150
 
144
151
  # :reek:NilCheck
145
152
  def self.lock_name(flow)
146
- lock_name = catch(:halt_step) { flow.class.with_cluster_lock.call(flow)&.merge_into(flow)&.to_s }
147
- if lock_name.nil? || lock_name.length == 0
153
+ lock_name =
154
+ catch(:halt_step) { flow.class.with_cluster_lock.call(flow)&.merge_into(flow)&.to_s }
155
+ if lock_name.nil? || lock_name.empty?
148
156
  raise LockFailure.new(:no_lock_name, 'no lock name provided')
149
157
  end
158
+
150
159
  lock_name
151
160
  end
152
161
 
@@ -169,7 +178,7 @@ module BusinessFlow
169
178
  def self.inner_acquire_lock(zk_connection, lock, payload)
170
179
  lock_held = lock.lock(wait: false)
171
180
  payload[:lock_acquired] = lock_held if payload
172
- if !lock_held
181
+ unless lock_held
173
182
  zk_connection.close!
174
183
  raise LockFailure.new(:lock_unavailable, 'the lock was not available')
175
184
  end
@@ -178,11 +187,11 @@ module BusinessFlow
178
187
 
179
188
  def self.cleanup(lock, zk_connection)
180
189
  begin
181
- lock.unlock if lock
190
+ lock&.unlock
182
191
  rescue ZK::Exceptions::OperationTimeOut
183
192
  # Just let the connection close handle this.
184
193
  end
185
- zk_connection.close! if zk_connection
194
+ zk_connection&.close!
186
195
  end
187
196
 
188
197
  # :reek:ControlParameter
@@ -199,16 +208,16 @@ module BusinessFlow
199
208
  end
200
209
  end
201
210
 
202
- def self.with_lock(flow, lock_info, &blk)
203
- zk_connection, lock =
204
- if !BusinessFlow::ClusterLock.disabled?
211
+ def self.with_lock(flow, lock_info, &_blk)
212
+ unless BusinessFlow::ClusterLock.disabled?
213
+ zk_connection, lock =
205
214
  instrumented_acquire_lock(flow, lock_info)
206
- end
215
+ end
207
216
  yield lock_info
208
- rescue ZK::Exceptions::LockAssertionFailedError, ZK::Exceptions::OperationTimeOut => exc
217
+ rescue ZK::Exceptions::LockAssertionFailedError, ZK::Exceptions::OperationTimeOut => e
209
218
  # This would occur if we asserted a cluster lock while executing the flow.
210
219
  # This will have set an error on the flow, so we can carry on.
211
- raise LockFailure.new(exception_to_error_type(exc), exc.message)
220
+ raise LockFailure.new(exception_to_error_type(e), e.message)
212
221
  ensure
213
222
  cleanup(lock, zk_connection)
214
223
  end
@@ -3,7 +3,7 @@
3
3
  module BusinessFlow
4
4
  # Provides compatibility for ActiveSupport/Model 4.x through 7.x
5
5
  module Compat
6
- if !Module.instance_methods.include?(:module_parents)
6
+ unless Module.instance_methods.include?(:module_parents)
7
7
  # ActiveSupport 5 removed #parents in favor of #module_parents.
8
8
  class ::Module
9
9
  def module_parents
@@ -12,13 +12,16 @@ module BusinessFlow
12
12
  end
13
13
  end
14
14
 
15
- if !ActiveModel::Errors.instance_methods.include?(:merge!)
15
+ unless ActiveModel::Errors.instance_methods.include?(:merge!)
16
16
  # ActiveModel 5 added details (which we do not use here) and #merge!
17
17
  # :reek:MissingSafeMethod Look it's the API.
18
- class ::ActiveModel::Errors
19
- def merge!(other)
20
- other.each do |attribute, message|
21
- self[attribute] << message
18
+ module ::ActiveModel
19
+ # Amend the errors class with a convenience method.
20
+ class Errors
21
+ def merge!(other)
22
+ other.each do |attribute, message|
23
+ self[attribute] << message
24
+ end
22
25
  end
23
26
  end
24
27
  end
@@ -13,6 +13,7 @@ module BusinessFlow
13
13
  def call
14
14
  @step_queue.each do |step|
15
15
  break if @flow.errors?
16
+
16
17
  execute_step(step)
17
18
  end
18
19
  end
@@ -5,7 +5,7 @@ module BusinessFlow
5
5
  # ClassMethods.
6
6
  module DSL
7
7
  # Contains the DSL for BusinessFlow
8
- module ClassMethods
8
+ module ClassMethods # rubocop:disable Metrics/ModuleLength
9
9
  # Holds metadata about inputs to a flow
10
10
  class Inputs
11
11
  attr_reader :all, :needs, :optionals
@@ -56,17 +56,18 @@ module BusinessFlow
56
56
  # without having to check for whether or not the wants can be executed.
57
57
  #
58
58
  # :reek:NilCheck This is one of the places where we eliminate nil.
59
- def lookup(field, by:, with:)
59
+ # :reek:LongParameterList Deal with it
60
+ def lookup(field, by:, with:, inputs: nil, output: nil)
60
61
  by = Array.wrap(by)
61
62
  optional(*by)
62
63
  wants field, with, unless: -> { by.any? { |input| send(input).nil? } },
63
- default_output: field
64
+ default_output: field, inputs: inputs, output: output
64
65
  end
65
66
 
66
67
  # Allows a field to be retrieved from the initialiaztion parameters
67
68
  def wants(field, default = nil, opts = {}, &blk)
68
- internal_name = "wants_#{field}".to_sym
69
- default = proc { nil } unless default || block_given?
69
+ internal_name = :"wants_#{field}"
70
+ default = proc {} unless default || block_given?
70
71
  uses(internal_name, default, opts, &blk)
71
72
  inputs.add_wants(ParameterField.new(field, internal_name))
72
73
  end
@@ -105,6 +106,7 @@ module BusinessFlow
105
106
  def call(parameter_object = {})
106
107
  flow = build(parameter_object)
107
108
  return result_from(flow) if flow.errors?
109
+
108
110
  execute(flow)
109
111
  end
110
112
 
@@ -127,6 +129,7 @@ module BusinessFlow
127
129
  def call!(*args)
128
130
  flow = call(*args)
129
131
  raise FlowFailedException, flow if flow.errors?
132
+
130
133
  flow
131
134
  end
132
135
 
@@ -136,9 +139,9 @@ module BusinessFlow
136
139
 
137
140
  def step_executor(executor_class = nil)
138
141
  if executor_class
139
- @executor_class = executor_class
142
+ @step_executor = executor_class
140
143
  else
141
- @executor_class ||= ::BusinessFlow::DefaultStepExecutor
144
+ @step_executor ||= ::BusinessFlow::DefaultStepExecutor
142
145
  end
143
146
  end
144
147
 
@@ -158,22 +161,32 @@ module BusinessFlow
158
161
 
159
162
  def finalize_result_provider
160
163
  return if @finalized_result_provider || !@result_copy
164
+
161
165
  const_get(:Result).class_eval "#{@result_copy}\nend", __FILE__, __LINE__
162
166
  @finalized_result_provider = true
163
167
  end
164
168
 
165
- def needs_code
169
+ def needs_code # rubocop:disable Metrics/MethodLength
166
170
  needs.map do |need|
167
- %(if #{need}.nil?
168
- errors.add(:#{need}, :invalid, message: 'must not be nil')
169
- throw :halt_step
170
- end
171
- )
171
+ if BusinessFlow.active_model5?
172
+ %(if #{need}.nil?
173
+ errors.add(:#{need}, :invalid, message: 'must not be nil')
174
+ throw :halt_step
175
+ end
176
+ )
177
+ else
178
+ %(if #{need}.nil?
179
+ errors.add(:#{need}, 'must not be nil')
180
+ throw :halt_step
181
+ end
182
+ )
183
+ end
172
184
  end.join("\n")
173
185
  end
174
186
 
175
187
  def finalize_initializer
176
188
  return if @finalized_initializer
189
+
177
190
  class_eval %{
178
191
  private def _business_flow_dsl_initialize(parameter_object)
179
192
  @parameter_object = parameter_object
@@ -188,7 +201,7 @@ module BusinessFlow
188
201
  FROM_FLOW_PREAMBLE = %(
189
202
  def from_flow(flow)
190
203
  return if errors?
191
- ).freeze
204
+ )
192
205
 
193
206
  RESULT_DEF = %(
194
207
  class Result
@@ -216,7 +229,7 @@ module BusinessFlow
216
229
  !valid?(context)
217
230
  end
218
231
  end
219
- ).freeze
232
+ )
220
233
 
221
234
  # Provides the minimum necessary methods to support the use of
222
235
  # ActiveModel::Errors
@@ -235,13 +248,16 @@ module BusinessFlow
235
248
  end
236
249
 
237
250
  # :reek:ManualDispatch I have no need to actually call human_attribute_name,
251
+ # :reek:TooManyStatements Breaking this up would add complexity.
238
252
  # I just need to know if I have to provide my own.
239
253
  def self.included(klass)
240
254
  klass.extend(ClassMethods)
241
255
  klass.class_eval RESULT_DEF, __FILE__, __LINE__
242
256
  klass.extend(ErrorSupport) unless klass.respond_to?(:human_attribute_name)
243
257
  klass.extend(ActiveModel::Naming)
244
- klass.include(ErrorSupport::InstanceMethods) unless klass.respond_to?(:read_attribute_for_validation)
258
+ return if klass.respond_to?(:read_attribute_for_validation)
259
+
260
+ klass.include(ErrorSupport::InstanceMethods)
245
261
  end
246
262
 
247
263
  attr_reader :parameter_object
@@ -249,6 +265,7 @@ module BusinessFlow
249
265
 
250
266
  def call
251
267
  return if invalid?
268
+
252
269
  klass = self.class
253
270
  klass.step_executor.new(klass.step_queue, self).call
254
271
  end
@@ -261,7 +278,7 @@ module BusinessFlow
261
278
  @parameter_object = parameter_object
262
279
  needs.each do |need|
263
280
  if send(need).nil?
264
- errors.add(need, :invalid, message: 'must not be nil')
281
+ BusinessFlow.add_error(need, :invalid, error_type, 'must not be nil')
265
282
  throw :halt_step
266
283
  end
267
284
  end
@@ -274,6 +291,7 @@ module BusinessFlow
274
291
  # We only want to fall back to a default if we were
275
292
  # given nil. Other falsy vlues should be directly used.
276
293
  return yield if value.nil? && block_given?
294
+
277
295
  value
278
296
  end
279
297
 
@@ -288,11 +306,8 @@ module BusinessFlow
288
306
  end
289
307
 
290
308
  private def _business_flow_dsl_parameters
291
- @_business_flow_dsl_parameters ||= Hash[
292
- self.class.inputs.all.map do |input|
293
- [input, _business_flow_parameter_inner_fetch(input)]
294
- end
295
- ]
309
+ @_business_flow_dsl_parameters ||=
310
+ self.class.inputs.all.to_h { |input| [input, _business_flow_parameter_inner_fetch(input)] }
296
311
  end
297
312
 
298
313
  def errors
@@ -302,7 +317,7 @@ module BusinessFlow
302
317
  def errors?
303
318
  # We're explicitly using the instance variable here so that if no
304
319
  # errors have been created, we don't initialize the error object.
305
- @errors && @errors.present?
320
+ @errors&.present?
306
321
  end
307
322
 
308
323
  def valid?(_context = nil)
@@ -363,6 +378,7 @@ module BusinessFlow
363
378
  def self.eval_method(klass, name, str)
364
379
  return if klass.method_defined?(name) ||
365
380
  klass.private_method_defined?(name)
381
+
366
382
  unsafe_eval_method(klass, name, str)
367
383
  end
368
384
 
@@ -443,12 +459,10 @@ module BusinessFlow
443
459
  end
444
460
 
445
461
  def safe_ivar_name
446
- @safe_ivar_name ||= begin
447
- "@business_flow_dsl_#{field}"
448
- .sub(/\?$/, '_query')
449
- .sub(/\!$/, '_bang')
450
- .to_sym
451
- end
462
+ @safe_ivar_name ||= "@business_flow_dsl_#{field}"
463
+ .sub(/\?$/, '_query')
464
+ .sub(/!$/, '_bang')
465
+ .to_sym
452
466
  end
453
467
  end
454
468
 
@@ -475,7 +489,7 @@ module BusinessFlow
475
489
 
476
490
  def retriever_method_name
477
491
  @retriever_method_name ||=
478
- "_business_flow_dsl_execute_step_for_#{@name}".to_sym
492
+ :"_business_flow_dsl_execute_step_for_#{@name}"
479
493
  end
480
494
  end
481
495
 
@@ -11,7 +11,7 @@ module BusinessFlow
11
11
 
12
12
  # Contains methods that we add to the DSL
13
13
  module ClassMethods
14
- INSTRUMENTATION_PREFIX = 'business_flow'.freeze
14
+ INSTRUMENTATION_PREFIX = 'business_flow'
15
15
 
16
16
  def instrument(name, flow)
17
17
  payload = { flow: flow }
@@ -33,7 +33,7 @@ module BusinessFlow
33
33
 
34
34
  def event_name
35
35
  @event_name ||=
36
- "#{INSTRUMENTATION_PREFIX}.flow.#{instrumentation_name}".freeze
36
+ "#{INSTRUMENTATION_PREFIX}.flow.#{instrumentation_name}"
37
37
  end
38
38
  end
39
39
  end
@@ -16,7 +16,8 @@ module BusinessFlow
16
16
 
17
17
  def notify_errors(name, payload)
18
18
  return unless flow.errors?
19
- ActiveSupport::Notifications.publish(name + '.error', payload)
19
+
20
+ ActiveSupport::Notifications.publish("#{name}.error", payload)
20
21
  end
21
22
 
22
23
  def flow_name
@@ -3,7 +3,7 @@
3
3
  begin
4
4
  require 'retryable'
5
5
  rescue LoadError
6
- STDERR.puts 'BusinessFlow::Retryable requires the retryable gem'
6
+ warn 'BusinessFlow::Retryable requires the retryable gem'
7
7
  raise
8
8
  end
9
9
 
@@ -14,12 +14,13 @@ module BusinessFlow
14
14
 
15
15
  def parameters_from_source(source)
16
16
  return source if inputs.blank?
17
- Hash[inputs.map do |input_name, input_value|
18
- [
19
- input_name,
20
- Inputs.process_input(source, input_value)
21
- ]
22
- end]
17
+
18
+ inputs.to_h do |input_name, input_value| # rubocop:disable Style/HashTransformValues
19
+ [
20
+ input_name,
21
+ Inputs.process_input(source, input_value)
22
+ ]
23
+ end
23
24
  end
24
25
 
25
26
  def self.process_input(source, input_value)
@@ -133,7 +134,7 @@ module BusinessFlow
133
134
  Result.new(step_result, outputs, output)
134
135
  end
135
136
 
136
- private
137
+ private
137
138
 
138
139
  # :reek:ManualDispatch This is faster.
139
140
  def callable_for(step_result)
@@ -160,10 +161,9 @@ module BusinessFlow
160
161
 
161
162
  def to_unless(cond)
162
163
  if_stmt = Callable.new(cond)
163
- unless_stmt = proc do |instance, input|
164
+ proc do |instance, input|
164
165
  !if_stmt.call(instance, input)
165
166
  end
166
- Callable.new(unless_stmt)
167
167
  end
168
168
  end
169
169
 
@@ -184,9 +184,7 @@ module BusinessFlow
184
184
  opts.fetch(:condition) do
185
185
  if_stmts = opts[:if]
186
186
  unless_stmts = opts[:unless]
187
- if if_stmts.present? || unless_stmts.present?
188
- ConditionList.new(if_stmts, unless_stmts)
189
- end
187
+ ConditionList.new(if_stmts, unless_stmts) if if_stmts.present? || unless_stmts.present?
190
188
  end
191
189
  end
192
190
  end
@@ -223,6 +221,7 @@ module BusinessFlow
223
221
 
224
222
  def output_fields
225
223
  return [] unless outputs
224
+
226
225
  outputs.values.select { |field| field.is_a?(Symbol) }
227
226
  end
228
227
 
@@ -232,20 +231,20 @@ module BusinessFlow
232
231
 
233
232
  private
234
233
 
235
- PARAMETERS_NO_INPUT = 'parameter_source'.freeze
234
+ PARAMETERS_NO_INPUT = 'parameter_source'
236
235
  PARAMETERS_WITH_INPUT =
237
- '@input_object.parameters_from_source(parameter_source)'.freeze
236
+ '@input_object.parameters_from_source(parameter_source)'
238
237
  WITHOUT_CONDITION = %(
239
238
  @result_factory.result(@callable.call(parameter_source, parameters),
240
239
  parameter_source)
241
- ).freeze
240
+ )
242
241
  WITH_CONDITION = %(
243
242
  if @condition.call(parameter_source, parameters)
244
243
  #{WITHOUT_CONDITION}
245
244
  else
246
245
  CONDITION_FAILED
247
246
  end
248
- ).freeze
247
+ )
249
248
 
250
249
  def update_call_method
251
250
  params = @input_object ? PARAMETERS_WITH_INPUT : PARAMETERS_NO_INPUT
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BusinessFlow
4
- VERSION = '0.19.3'.freeze
4
+ VERSION = '0.19.5'
5
5
  end
data/lib/business_flow.rb CHANGED
@@ -18,4 +18,15 @@ require 'business_flow/instrument'
18
18
 
19
19
  # Makes the magic happen.
20
20
  module BusinessFlow
21
+ def self.active_model5?
22
+ @active_model5_in_use ||= ActiveModel.version >= Gem::Version.new('5.0.0')
23
+ end
24
+
25
+ def self.add_error(errors, field, error_type, message)
26
+ if active_model5?
27
+ errors.add(field, error_type, message: message)
28
+ else
29
+ errors.add(field, message)
30
+ end
31
+ end
21
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: business_flow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.19.3
4
+ version: 0.19.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Scarborough
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-06-07 00:00:00.000000000 Z
11
+ date: 2024-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -50,118 +50,6 @@ dependencies:
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
52
  version: '8'
53
- - !ruby/object:Gem::Dependency
54
- name: rake
55
- requirement: !ruby/object:Gem::Requirement
56
- requirements:
57
- - - "~>"
58
- - !ruby/object:Gem::Version
59
- version: '10.0'
60
- type: :development
61
- prerelease: false
62
- version_requirements: !ruby/object:Gem::Requirement
63
- requirements:
64
- - - "~>"
65
- - !ruby/object:Gem::Version
66
- version: '10.0'
67
- - !ruby/object:Gem::Dependency
68
- name: reek
69
- requirement: !ruby/object:Gem::Requirement
70
- requirements:
71
- - - "~>"
72
- - !ruby/object:Gem::Version
73
- version: '6.1'
74
- type: :development
75
- prerelease: false
76
- version_requirements: !ruby/object:Gem::Requirement
77
- requirements:
78
- - - "~>"
79
- - !ruby/object:Gem::Version
80
- version: '6.1'
81
- - !ruby/object:Gem::Dependency
82
- name: retryable
83
- requirement: !ruby/object:Gem::Requirement
84
- requirements:
85
- - - "~>"
86
- - !ruby/object:Gem::Version
87
- version: 3.0.4
88
- type: :development
89
- prerelease: false
90
- version_requirements: !ruby/object:Gem::Requirement
91
- requirements:
92
- - - "~>"
93
- - !ruby/object:Gem::Version
94
- version: 3.0.4
95
- - !ruby/object:Gem::Dependency
96
- name: rspec
97
- requirement: !ruby/object:Gem::Requirement
98
- requirements:
99
- - - "~>"
100
- - !ruby/object:Gem::Version
101
- version: '3.0'
102
- type: :development
103
- prerelease: false
104
- version_requirements: !ruby/object:Gem::Requirement
105
- requirements:
106
- - - "~>"
107
- - !ruby/object:Gem::Version
108
- version: '3.0'
109
- - !ruby/object:Gem::Dependency
110
- name: rubocop
111
- requirement: !ruby/object:Gem::Requirement
112
- requirements:
113
- - - "~>"
114
- - !ruby/object:Gem::Version
115
- version: '0.53'
116
- type: :development
117
- prerelease: false
118
- version_requirements: !ruby/object:Gem::Requirement
119
- requirements:
120
- - - "~>"
121
- - !ruby/object:Gem::Version
122
- version: '0.53'
123
- - !ruby/object:Gem::Dependency
124
- name: rubocop-rspec
125
- requirement: !ruby/object:Gem::Requirement
126
- requirements:
127
- - - "~>"
128
- - !ruby/object:Gem::Version
129
- version: 1.24.0
130
- type: :development
131
- prerelease: false
132
- version_requirements: !ruby/object:Gem::Requirement
133
- requirements:
134
- - - "~>"
135
- - !ruby/object:Gem::Version
136
- version: 1.24.0
137
- - !ruby/object:Gem::Dependency
138
- name: simplecov
139
- requirement: !ruby/object:Gem::Requirement
140
- requirements:
141
- - - "~>"
142
- - !ruby/object:Gem::Version
143
- version: 0.22.0
144
- type: :development
145
- prerelease: false
146
- version_requirements: !ruby/object:Gem::Requirement
147
- requirements:
148
- - - "~>"
149
- - !ruby/object:Gem::Version
150
- version: 0.22.0
151
- - !ruby/object:Gem::Dependency
152
- name: timecop
153
- requirement: !ruby/object:Gem::Requirement
154
- requirements:
155
- - - "~>"
156
- - !ruby/object:Gem::Version
157
- version: 0.9.1
158
- type: :development
159
- prerelease: false
160
- version_requirements: !ruby/object:Gem::Requirement
161
- requirements:
162
- - - "~>"
163
- - !ruby/object:Gem::Version
164
- version: 0.9.1
165
53
  description:
166
54
  email:
167
55
  - alex@teak.io
@@ -170,7 +58,11 @@ extensions: []
170
58
  extra_rdoc_files: []
171
59
  files:
172
60
  - ".gitignore"
61
+ - ".reek.yml"
173
62
  - ".rspec"
63
+ - ".rubocop.yml"
64
+ - ".ruby-gemset"
65
+ - ".ruby-version"
174
66
  - ".travis.yml"
175
67
  - Gemfile
176
68
  - Gemfile.lock
@@ -199,7 +91,8 @@ files:
199
91
  homepage: https://teak.io
200
92
  licenses:
201
93
  - MIT
202
- metadata: {}
94
+ metadata:
95
+ rubygems_mfa_required: 'true'
203
96
  post_install_message:
204
97
  rdoc_options: []
205
98
  require_paths:
@@ -208,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
208
101
  requirements:
209
102
  - - ">="
210
103
  - !ruby/object:Gem::Version
211
- version: '0'
104
+ version: 2.7.0
212
105
  required_rubygems_version: !ruby/object:Gem::Requirement
213
106
  requirements:
214
107
  - - ">="