business_flow 0.6.0 → 0.7.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -6
- data/lib/business_flow/cacheable.rb +7 -2
- data/lib/business_flow/dsl.rb +78 -22
- data/lib/business_flow/not_nil_validator.rb +1 -2
- data/lib/business_flow/step.rb +20 -4
- data/lib/business_flow/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa83401ab6f440779738905d43a9b7114ed03e68
|
4
|
+
data.tar.gz: 5af8dbff7edf19b183a8201f418ef3555aadd54a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9d44e6d0dd4d71e140fe4f4fff24b1243295355cd71c4e128585a08c0abab3cb93f5da9ea28db39cdd25a7088fa8e03c53ca4fe35623fe63b2c7dbd45df71cd2
|
7
|
+
data.tar.gz: f16efd204e218ffd86a0850cefa452b338171164d7fb1ded0bb157745637459e9c49a843acfb4ee5366a8bddc7f370dab3252df8fe7d7abd7762702d8c35da7f
|
data/Gemfile.lock
CHANGED
@@ -1,18 +1,18 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
business_flow (0.
|
4
|
+
business_flow (0.7.0)
|
5
5
|
activemodel (>= 3.0)
|
6
6
|
activesupport (>= 3.0)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: https://rubygems.org/
|
10
10
|
specs:
|
11
|
-
activemodel (5.1.
|
12
|
-
activesupport (= 5.1.
|
13
|
-
activesupport (5.1.
|
11
|
+
activemodel (5.1.6)
|
12
|
+
activesupport (= 5.1.6)
|
13
|
+
activesupport (5.1.6)
|
14
14
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
-
i18n (
|
15
|
+
i18n (>= 0.7, < 2)
|
16
16
|
minitest (~> 5.1)
|
17
17
|
tzinfo (~> 1.1)
|
18
18
|
ast (2.4.0)
|
@@ -30,7 +30,7 @@ GEM
|
|
30
30
|
diff-lcs (1.3)
|
31
31
|
docile (1.1.5)
|
32
32
|
equalizer (0.0.11)
|
33
|
-
i18n (0.
|
33
|
+
i18n (1.0.0)
|
34
34
|
concurrent-ruby (~> 1.0)
|
35
35
|
ice_nine (0.11.2)
|
36
36
|
json (2.1.0)
|
@@ -7,7 +7,8 @@ module BusinessFlow
|
|
7
7
|
|
8
8
|
def cache_key
|
9
9
|
klass = self.class
|
10
|
-
|
10
|
+
key = Digest::SHA256.hexdigest(klass.cache_key.call(self, nil).to_s)
|
11
|
+
"#{klass.name.underscore}/#{key}"
|
11
12
|
end
|
12
13
|
|
13
14
|
# DSL Methods
|
@@ -16,7 +17,11 @@ module BusinessFlow
|
|
16
17
|
if store
|
17
18
|
@cache_store = store
|
18
19
|
else
|
19
|
-
@cache_store ||=
|
20
|
+
@cache_store ||= if defined?(Rails)
|
21
|
+
Rails.cache
|
22
|
+
else
|
23
|
+
ActiveSupport::Cache::MemoryStore.new
|
24
|
+
end
|
20
25
|
end
|
21
26
|
end
|
22
27
|
|
data/lib/business_flow/dsl.rb
CHANGED
@@ -8,8 +8,6 @@ module BusinessFlow
|
|
8
8
|
# was initialized with. The provided .call will instantiate the including
|
9
9
|
# class with a parameter_object as the only argument.
|
10
10
|
module ClassMethods
|
11
|
-
attr_reader :requirements
|
12
|
-
|
13
11
|
# Requires that a field be retrievable from the initialization parameters
|
14
12
|
#
|
15
13
|
# This will only require that the field is not nil. The field may still
|
@@ -17,25 +15,26 @@ module BusinessFlow
|
|
17
15
|
#
|
18
16
|
# @param fields The fields required from the initialization parameters
|
19
17
|
def needs(*fields)
|
20
|
-
@
|
21
|
-
@
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
# Allows a field to be retrieved from the initialiaztoin parameters
|
26
|
-
#
|
27
|
-
# Unlike needs, this applies no validation to the field. It may
|
28
|
-
# be nil.
|
29
|
-
#
|
30
|
-
# @param (see #needs)
|
31
|
-
def wants(*fields)
|
18
|
+
@needs ||= []
|
19
|
+
return @needs if fields.blank?
|
20
|
+
@needs.push(*fields)
|
32
21
|
fields.each do |field|
|
33
22
|
PrivateHelpers.create_parameter_field(self, field)
|
34
23
|
end
|
35
24
|
end
|
36
25
|
|
26
|
+
# Allows a field to be retrieved from the initialiaztion parameters
|
27
|
+
def wants(field, default = proc { nil }, opts = {})
|
28
|
+
internal_name = "wants_#{field}".to_sym
|
29
|
+
uses(internal_name, default, opts)
|
30
|
+
PrivateHelpers.create_parameter_field(self, field, internal_name)
|
31
|
+
end
|
32
|
+
|
37
33
|
# Declares that you will expose a field to the outside world.
|
38
34
|
def provides(*fields)
|
35
|
+
@provides ||= []
|
36
|
+
return @provides if fields.blank?
|
37
|
+
@provides.push(*fields)
|
39
38
|
fields.each { |field| PrivateHelpers.create_field(self, field) }
|
40
39
|
end
|
41
40
|
|
@@ -44,7 +43,14 @@ module BusinessFlow
|
|
44
43
|
# validations.
|
45
44
|
def expects(field, options = {})
|
46
45
|
validates field, options.merge(on: field)
|
47
|
-
|
46
|
+
PrivateHelpers.create_field(self, field)
|
47
|
+
end
|
48
|
+
|
49
|
+
def uses(field, klass, opts = {})
|
50
|
+
callable = Callable.new(klass, self)
|
51
|
+
step = Step.new(callable, opts)
|
52
|
+
PrivateHelpers.create_memoized_field(self, field, step)
|
53
|
+
private field
|
48
54
|
end
|
49
55
|
|
50
56
|
def step(klass, opts = {})
|
@@ -53,7 +59,9 @@ module BusinessFlow
|
|
53
59
|
condition: PrivateHelpers.create_conditional_callable(self, opts)
|
54
60
|
)
|
55
61
|
step_queue << step = Step.new(callable, opts)
|
56
|
-
|
62
|
+
step.outputs.values.each do |field|
|
63
|
+
PrivateHelpers.create_field(self, field)
|
64
|
+
end
|
57
65
|
end
|
58
66
|
|
59
67
|
def call(parameter_object)
|
@@ -115,15 +123,30 @@ module BusinessFlow
|
|
115
123
|
end
|
116
124
|
end
|
117
125
|
|
118
|
-
def self.create_parameter_field(klass, field)
|
119
|
-
klass.send(:define_method, field)
|
126
|
+
def self.create_parameter_field(klass, field, fallback = nil)
|
127
|
+
klass.send(:define_method, field, ¶meter_proc(field, fallback))
|
128
|
+
klass.send(:private, field)
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.read_from_parameter_object(field)
|
132
|
+
proc do
|
120
133
|
if parameter_object.is_a?(Hash) && parameter_object.key?(field)
|
121
134
|
parameter_object[field]
|
122
135
|
else
|
123
136
|
parameter_object.public_send(field)
|
124
137
|
end
|
125
138
|
end
|
126
|
-
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.parameter_proc(field, fallback)
|
142
|
+
read = read_from_parameter_object(field)
|
143
|
+
proc do
|
144
|
+
begin
|
145
|
+
instance_exec(&read)
|
146
|
+
rescue NoMethodError
|
147
|
+
nil
|
148
|
+
end || (fallback && send(fallback))
|
149
|
+
end
|
127
150
|
end
|
128
151
|
|
129
152
|
def self.create_conditional_callable(klass, opts)
|
@@ -139,21 +162,54 @@ module BusinessFlow
|
|
139
162
|
|
140
163
|
def self.create_field(klass, field)
|
141
164
|
return unless field.is_a?(Symbol)
|
142
|
-
klass
|
165
|
+
define_getter(klass, field)
|
143
166
|
setter_name = "#{field}=".to_sym
|
144
167
|
define_setter(klass, setter_name, field)
|
145
168
|
klass.send(:private, setter_name)
|
146
169
|
end
|
147
170
|
|
171
|
+
def self.define_getter(klass, field)
|
172
|
+
return if klass.method_defined?(field) ||
|
173
|
+
klass.private_method_defined?(field)
|
174
|
+
klass.send(:attr_reader, field)
|
175
|
+
end
|
176
|
+
|
148
177
|
def self.define_setter(klass, setter_name, field)
|
149
178
|
return if klass.method_defined?(setter_name) ||
|
150
179
|
klass.private_method_defined?(setter_name)
|
151
|
-
klass.send(:define_method, setter_name
|
152
|
-
|
180
|
+
klass.send(:define_method, setter_name,
|
181
|
+
&setter_proc("@#{field}", field))
|
182
|
+
end
|
183
|
+
|
184
|
+
def self.safe_ivar_name(field)
|
185
|
+
ivar_name = "@business_flow_dsl_#{field}"
|
186
|
+
if ivar_name.end_with?('?')
|
187
|
+
ivar_name.sub!(/\?$/, '_query')
|
188
|
+
elsif ivar_name.end_with?('!')
|
189
|
+
ivar_name.sub!(/\!$/, '_bang')
|
190
|
+
end
|
191
|
+
ivar_name.to_sym
|
192
|
+
end
|
193
|
+
|
194
|
+
def self.setter_proc(ivar_name, field)
|
195
|
+
proc do |new_value|
|
196
|
+
instance_variable_set(ivar_name, new_value)
|
153
197
|
throw :halt_step unless valid?(field)
|
154
198
|
new_value
|
155
199
|
end
|
156
200
|
end
|
201
|
+
|
202
|
+
def self.create_memoized_field(klass, field, step)
|
203
|
+
ivar_name = safe_ivar_name(field)
|
204
|
+
setter_proc = self.setter_proc(ivar_name, field)
|
205
|
+
klass.send(:define_method, field) do
|
206
|
+
if instance_variable_defined?(ivar_name)
|
207
|
+
instance_variable_get(ivar_name)
|
208
|
+
else
|
209
|
+
instance_exec(step.call(self).output, &setter_proc)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
157
213
|
end
|
158
214
|
end
|
159
215
|
end
|
@@ -5,8 +5,7 @@ module BusinessFlow
|
|
5
5
|
# Dear reek -- I didn't decided the ActiveModel Validator API, I just
|
6
6
|
# have to live with it.
|
7
7
|
def validate(record)
|
8
|
-
|
9
|
-
requirements.each do |attribute|
|
8
|
+
record.class.needs.each do |attribute|
|
10
9
|
value = record.read_attribute_for_validation(attribute)
|
11
10
|
record.errors[attribute] << 'must not be nil' if value.nil?
|
12
11
|
end
|
data/lib/business_flow/step.rb
CHANGED
@@ -35,9 +35,10 @@ module BusinessFlow
|
|
35
35
|
# Represents the result of a step, and allows setting response values on
|
36
36
|
# an object, and merging error data into the same object.
|
37
37
|
class Result
|
38
|
-
def initialize(result, output_map)
|
38
|
+
def initialize(result, output_map, output_callable)
|
39
39
|
@result = result
|
40
40
|
@output_map = output_map
|
41
|
+
@output_callable = output_callable
|
41
42
|
@result_errors = begin
|
42
43
|
result.errors
|
43
44
|
rescue NoMethodError
|
@@ -58,6 +59,10 @@ module BusinessFlow
|
|
58
59
|
@result_errors.present?
|
59
60
|
end
|
60
61
|
|
62
|
+
def output
|
63
|
+
@output_callable.call(@result)
|
64
|
+
end
|
65
|
+
|
61
66
|
def self.process_output(object, output, output_setter)
|
62
67
|
case output_setter
|
63
68
|
when Symbol
|
@@ -99,19 +104,26 @@ module BusinessFlow
|
|
99
104
|
def merge_into(_object); end
|
100
105
|
end
|
101
106
|
|
102
|
-
|
107
|
+
# Manage creating results for our step
|
108
|
+
ResultFactory = Struct.new(:outputs, :output_callable) do
|
109
|
+
def result(step_result)
|
110
|
+
Result.new(step_result, outputs, output_callable)
|
111
|
+
end
|
112
|
+
end
|
103
113
|
|
104
114
|
def initialize(callable, opts)
|
105
115
|
@callable = callable
|
106
116
|
@input_object = Inputs.new(opts[:inputs] || {})
|
107
|
-
|
117
|
+
outputs = opts[:outputs] || {}
|
118
|
+
output = opts[:output] || ->(result) { result }
|
119
|
+
@result_factory = ResultFactory.new(outputs, output)
|
108
120
|
@condition = opts[:condition] || proc { true }
|
109
121
|
end
|
110
122
|
|
111
123
|
def call(parameter_source)
|
112
124
|
parameters = @input_object.parameters_from_source(parameter_source)
|
113
125
|
if @condition.call(parameter_source, parameters)
|
114
|
-
|
126
|
+
@result_factory.result(@callable.call(parameter_source, parameters))
|
115
127
|
else
|
116
128
|
ConditionFailedResult.new
|
117
129
|
end
|
@@ -121,6 +133,10 @@ module BusinessFlow
|
|
121
133
|
@input_object.inputs
|
122
134
|
end
|
123
135
|
|
136
|
+
def outputs
|
137
|
+
@result_factory.outputs
|
138
|
+
end
|
139
|
+
|
124
140
|
def to_s
|
125
141
|
@callable.to_s
|
126
142
|
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.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Scarborough
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|