business_flow 0.19.3 → 0.19.5

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