burner 1.0.0.pre.alpha.6 → 1.0.0.pre.alpha.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -0
- data/README.md +22 -18
- data/lib/burner/job.rb +4 -6
- data/lib/burner/job_with_register.rb +24 -0
- data/lib/burner/library.rb +3 -1
- data/lib/burner/library/collection/arrays_to_objects.rb +4 -6
- data/lib/burner/library/collection/graph.rb +5 -7
- data/lib/burner/library/collection/objects_to_arrays.rb +4 -6
- data/lib/burner/library/collection/shift.rb +4 -6
- data/lib/burner/library/collection/transform.rb +5 -7
- data/lib/burner/library/collection/unpivot.rb +15 -9
- data/lib/burner/library/collection/validate.rb +89 -0
- data/lib/burner/library/collection/values.rb +7 -9
- data/lib/burner/library/deserialize/csv.rb +2 -4
- data/lib/burner/library/deserialize/json.rb +2 -4
- data/lib/burner/library/deserialize/yaml.rb +5 -5
- data/lib/burner/library/dummy.rb +1 -3
- data/lib/burner/library/echo.rb +0 -2
- data/lib/burner/library/io/base.rb +3 -3
- data/lib/burner/library/io/exist.rb +8 -8
- data/lib/burner/library/io/read.rb +3 -5
- data/lib/burner/library/io/write.rb +3 -5
- data/lib/burner/library/serialize/csv.rb +3 -5
- data/lib/burner/library/serialize/json.rb +2 -4
- data/lib/burner/library/serialize/yaml.rb +2 -4
- data/lib/burner/library/set_value.rb +4 -6
- data/lib/burner/library/sleep.rb +0 -2
- data/lib/burner/modeling.rb +1 -0
- data/lib/burner/modeling/validations.rb +23 -0
- data/lib/burner/modeling/validations/base.rb +35 -0
- data/lib/burner/modeling/validations/blank.rb +31 -0
- data/lib/burner/modeling/validations/present.rb +31 -0
- data/lib/burner/payload.rb +39 -5
- data/lib/burner/pipeline.rb +3 -3
- data/lib/burner/step.rb +1 -5
- data/lib/burner/util.rb +1 -0
- data/lib/burner/util/string_template.rb +42 -0
- data/lib/burner/version.rb +1 -1
- metadata +9 -3
- data/lib/burner/string_template.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8cb851b5c317d3566c1b3b77c9c904e26970de8e0ce4329e2c8b83336c372b02
|
4
|
+
data.tar.gz: 0ad28e56c8b52ceede4ed321812e45edfaef2bcd4000428738c348e5e849092a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf5bc810ffa5dba106e6538dbab2f44e6763f5ad073da2b645e46eff3e976e61f9a0d551ae4d5ad9998c5c1d87b5e2913b902901020ad77f20b4c29800321df5
|
7
|
+
data.tar.gz: ef83de8173fbad28c2cc07c44f101175ebe9c60d5a9275d2e7280ba1b621a8c51082504ae5d5c917916d398a7a89d06ca7416dd08ba7148ebebb87cd42dd7b05
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -233,39 +233,43 @@ This library only ships with very basic, rudimentary jobs that are meant to just
|
|
233
233
|
|
234
234
|
#### Collection
|
235
235
|
|
236
|
-
* **collection/arrays_to_objects** [mappings]: Convert an array of arrays to an array of objects.
|
237
|
-
* **collection/graph** [config, key]: Use [Hashematics](https://github.com/bluemarblepayroll/hashematics) to turn a flat array of objects into a deeply nested object tree.
|
238
|
-
* **collection/objects_to_arrays** [mappings]: Convert an array of objects to an array of arrays.
|
239
|
-
* **collection/shift** [amount]: Remove the first N number of elements from an array.
|
240
|
-
* **collection/transform** [attributes, exclusive, separator]: Iterate over all objects and transform each key per the attribute transformers specifications. If exclusive is set to false then the current object will be overridden/merged. Separator can also be set for key path support. This job uses [Realize](https://github.com/bluemarblepayroll/realize), which provides its own extendable value-transformation pipeline.
|
241
|
-
* **collection/unpivot** [pivot_set]: Take an array of objects and unpivot specific sets of keys into rows. Under the hood it uses [HashMath's Unpivot class](https://github.com/bluemarblepayroll/hash_math#unpivot-hash-key-coalescence-and-row-extrapolation).
|
242
|
-
* **collection/
|
236
|
+
* **collection/arrays_to_objects** [mappings, register]: Convert an array of arrays to an array of objects.
|
237
|
+
* **collection/graph** [config, key, register]: Use [Hashematics](https://github.com/bluemarblepayroll/hashematics) to turn a flat array of objects into a deeply nested object tree.
|
238
|
+
* **collection/objects_to_arrays** [mappings, register]: Convert an array of objects to an array of arrays.
|
239
|
+
* **collection/shift** [amount, register]: Remove the first N number of elements from an array.
|
240
|
+
* **collection/transform** [attributes, exclusive, separator, register]: Iterate over all objects and transform each key per the attribute transformers specifications. If exclusive is set to false then the current object will be overridden/merged. Separator can also be set for key path support. This job uses [Realize](https://github.com/bluemarblepayroll/realize), which provides its own extendable value-transformation pipeline.
|
241
|
+
* **collection/unpivot** [pivot_set, register]: Take an array of objects and unpivot specific sets of keys into rows. Under the hood it uses [HashMath's Unpivot class](https://github.com/bluemarblepayroll/hash_math#unpivot-hash-key-coalescence-and-row-extrapolation).
|
242
|
+
* **collection/validate** [invalid_register, join_char, message_key, register, separator, validations]: Take an array of objects, run it through each declared validator, and split the objects into two registers. The valid objects will be split into the current register while the invalid ones will go into the invalid_register as declared. Optional arguments, join_char and message_key, help determine the compiled error messages. The separator option can be utilized to use dot-notation for validating keys. See each validation's options by viewing their classes within the `lib/modeling/validations` directory.
|
243
|
+
* **collection/values** [include_keys, register]: Take an array of objects and call `#values` on each object. If include_keys is true (it is false by default), then call `#keys` on the first object and inject that as a "header" object.
|
243
244
|
|
244
245
|
#### De-serialization
|
245
246
|
|
246
|
-
* **deserialize/csv** []: Take a CSV string and de-serialize into object(s). Currently it will return an array of arrays, with each nested array representing one row.
|
247
|
-
* **deserialize/json** []: Treat input as a string and de-serialize it to JSON.
|
248
|
-
* **deserialize/yaml** [safe]: Treat input as a string and de-serialize it to YAML. By default it will try and [safely de-serialize](https://ruby-doc.org/stdlib-2.6.1/libdoc/psych/rdoc/Psych.html#method-c-safe_load) it (only using core classes). If you wish to de-serialize it to any class type, pass in `safe: false`
|
247
|
+
* **deserialize/csv** [register]: Take a CSV string and de-serialize into object(s). Currently it will return an array of arrays, with each nested array representing one row.
|
248
|
+
* **deserialize/json** [register]: Treat input as a string and de-serialize it to JSON.
|
249
|
+
* **deserialize/yaml** [register, safe]: Treat input as a string and de-serialize it to YAML. By default it will try and [safely de-serialize](https://ruby-doc.org/stdlib-2.6.1/libdoc/psych/rdoc/Psych.html#method-c-safe_load) it (only using core classes). If you wish to de-serialize it to any class type, pass in `safe: false`
|
249
250
|
|
250
251
|
#### IO
|
251
252
|
|
252
253
|
* **io/exist** [path, short_circuit]: Check to see if a file exists. The path parameter can be interpolated using `Payload#params`. If short_circuit was set to true (defaults to false) and the file does not exist then the pipeline will be short-circuited.
|
253
|
-
* **io/read** [binary, path]: Read in a local file. The path parameter can be interpolated using `Payload#params`. If the contents are binary, pass in `binary: true` to open it up in binary+read mode.
|
254
|
-
* **io/write** [binary, path]: Write to a local file. The path parameter can be interpolated using `Payload#params`. If the contents are binary, pass in `binary: true` to open it up in binary+write mode.
|
254
|
+
* **io/read** [binary, path, register]: Read in a local file. The path parameter can be interpolated using `Payload#params`. If the contents are binary, pass in `binary: true` to open it up in binary+read mode.
|
255
|
+
* **io/write** [binary, path, register]: Write to a local file. The path parameter can be interpolated using `Payload#params`. If the contents are binary, pass in `binary: true` to open it up in binary+write mode.
|
255
256
|
|
256
257
|
#### Serialization
|
257
258
|
|
258
|
-
* **serialize/csv** []: Take an array of arrays and create a CSV.
|
259
|
-
* **serialize/json** []: Convert value to JSON.
|
260
|
-
* **serialize/yaml** []: Convert value to YAML.
|
259
|
+
* **serialize/csv** [register]: Take an array of arrays and create a CSV.
|
260
|
+
* **serialize/json** [register]: Convert value to JSON.
|
261
|
+
* **serialize/yaml** [register]: Convert value to YAML.
|
261
262
|
|
262
263
|
#### General
|
263
264
|
|
264
265
|
* **dummy** []: Do nothing
|
265
266
|
* **echo** [message]: Write a message to the output. The message parameter can be interpolated using `Payload#params`.
|
266
|
-
* **set** [value]: Set the value to any arbitrary value.
|
267
|
+
* **set** [register, value]: Set the value to any arbitrary value.
|
267
268
|
* **sleep** [seconds]: Sleep the thread for X number of seconds.
|
268
269
|
|
270
|
+
Notes:
|
271
|
+
|
272
|
+
* If you see that a job accepts a 'register' attribute/argument, that indicates a job will access and/or mutate the payload. The register indicates which part of the payload the job will interact with. This allows jobs to be placed into 'lanes'. If register is not specified, then the default register is used.
|
269
273
|
|
270
274
|
### Adding & Registering Jobs
|
271
275
|
|
@@ -274,9 +278,9 @@ Where this library shines is when additional jobs are plugged in. Burner uses i
|
|
274
278
|
Let's say we would like to register a job to parse a CSV:
|
275
279
|
|
276
280
|
````ruby
|
277
|
-
class ParseCsv < Burner::
|
281
|
+
class ParseCsv < Burner::JobWithRegister
|
278
282
|
def perform(output, payload)
|
279
|
-
payload
|
283
|
+
payload[register] = CSV.parse(payload[register], headers: true).map(&:to_h)
|
280
284
|
|
281
285
|
nil
|
282
286
|
end
|
data/lib/burner/job.rb
CHANGED
@@ -7,11 +7,9 @@
|
|
7
7
|
# LICENSE file in the root directory of this source tree.
|
8
8
|
#
|
9
9
|
|
10
|
-
require_relative 'string_template'
|
11
|
-
|
12
10
|
module Burner
|
13
11
|
# Abstract base class for all job subclasses. The only public method a subclass needs to
|
14
|
-
# implement #perform(
|
12
|
+
# implement #perform(output, payload) and then you can register it for use using
|
15
13
|
# the Burner::Jobs factory class method #register. An example of a registration:
|
16
14
|
# Burner::Jobs.register('your_class', YourClass)
|
17
15
|
class Job
|
@@ -26,7 +24,7 @@ module Burner
|
|
26
24
|
@name = name.to_s
|
27
25
|
end
|
28
26
|
|
29
|
-
# There are only
|
27
|
+
# There are only a few requirements to be considered a valid Burner Job:
|
30
28
|
# 1. The class responds to #name
|
31
29
|
# 2. The class responds to #perform(output, payload)
|
32
30
|
#
|
@@ -49,9 +47,9 @@ module Burner
|
|
49
47
|
protected
|
50
48
|
|
51
49
|
def job_string_template(expression, output, payload)
|
52
|
-
templatable_params = payload.params.merge(__id: output.id, __value: payload
|
50
|
+
templatable_params = payload.params.merge(__id: output.id, __value: payload[''])
|
53
51
|
|
54
|
-
StringTemplate.instance.evaluate(expression, templatable_params)
|
52
|
+
Util::StringTemplate.instance.evaluate(expression, templatable_params)
|
55
53
|
end
|
56
54
|
end
|
57
55
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require_relative 'job'
|
11
|
+
|
12
|
+
module Burner
|
13
|
+
# Add on a register attribute to the configuration for a job. This indicates that a job
|
14
|
+
# either accesses and/or mutates the payload's registers.
|
15
|
+
class JobWithRegister < Job
|
16
|
+
attr_reader :register
|
17
|
+
|
18
|
+
def initialize(name:, register: '')
|
19
|
+
super(name: name)
|
20
|
+
|
21
|
+
@register = register.to_s
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/burner/library.rb
CHANGED
@@ -7,13 +7,15 @@
|
|
7
7
|
# LICENSE file in the root directory of this source tree.
|
8
8
|
#
|
9
9
|
|
10
|
-
require_relative '
|
10
|
+
require_relative 'job_with_register'
|
11
|
+
|
11
12
|
require_relative 'library/collection/arrays_to_objects'
|
12
13
|
require_relative 'library/collection/graph'
|
13
14
|
require_relative 'library/collection/objects_to_arrays'
|
14
15
|
require_relative 'library/collection/shift'
|
15
16
|
require_relative 'library/collection/transform'
|
16
17
|
require_relative 'library/collection/unpivot'
|
18
|
+
require_relative 'library/collection/validate'
|
17
19
|
require_relative 'library/collection/values'
|
18
20
|
require_relative 'library/deserialize/csv'
|
19
21
|
require_relative 'library/deserialize/json'
|
@@ -47,11 +47,11 @@ module Burner
|
|
47
47
|
# }
|
48
48
|
#
|
49
49
|
# Burner::Pipeline.make(config).execute
|
50
|
-
class ArraysToObjects <
|
50
|
+
class ArraysToObjects < JobWithRegister
|
51
51
|
attr_reader :mappings
|
52
52
|
|
53
|
-
def initialize(name:, mappings: [])
|
54
|
-
super(name: name)
|
53
|
+
def initialize(name:, mappings: [], register: '')
|
54
|
+
super(name: name, register: register)
|
55
55
|
|
56
56
|
@mappings = Modeling::KeyIndexMapping.array(mappings)
|
57
57
|
|
@@ -59,9 +59,7 @@ module Burner
|
|
59
59
|
end
|
60
60
|
|
61
61
|
def perform(_output, payload)
|
62
|
-
payload
|
63
|
-
|
64
|
-
nil
|
62
|
+
payload[register] = array(payload[register]).map { |array| index_to_key_map(array) }
|
65
63
|
end
|
66
64
|
|
67
65
|
private
|
@@ -15,11 +15,11 @@ module Burner
|
|
15
15
|
#
|
16
16
|
# Expected Payload#value input: array of objects.
|
17
17
|
# Payload#value output: An array of objects.
|
18
|
-
class Graph <
|
18
|
+
class Graph < JobWithRegister
|
19
19
|
attr_reader :key, :groups
|
20
20
|
|
21
|
-
def initialize(name:, key:, config: Hashematics::Configuration.new)
|
22
|
-
super(name: name)
|
21
|
+
def initialize(name:, key:, config: Hashematics::Configuration.new, register: '')
|
22
|
+
super(name: name, register: register)
|
23
23
|
|
24
24
|
raise ArgumentError, 'key is required' if key.to_s.empty?
|
25
25
|
|
@@ -30,13 +30,11 @@ module Burner
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def perform(output, payload)
|
33
|
-
graph = Hashematics::Graph.new(groups).add(array(payload
|
33
|
+
graph = Hashematics::Graph.new(groups).add(array(payload[register]))
|
34
34
|
|
35
35
|
output.detail("Graphing: #{key}")
|
36
36
|
|
37
|
-
payload
|
38
|
-
|
39
|
-
nil
|
37
|
+
payload[register] = graph.data(key)
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
@@ -48,7 +48,7 @@ module Burner
|
|
48
48
|
# }
|
49
49
|
#
|
50
50
|
# Burner::Pipeline.make(config).execute
|
51
|
-
class ObjectsToArrays <
|
51
|
+
class ObjectsToArrays < JobWithRegister
|
52
52
|
attr_reader :mappings
|
53
53
|
|
54
54
|
# If you wish to support nested objects you can pass in a string to use as a
|
@@ -56,8 +56,8 @@ module Burner
|
|
56
56
|
# nested hashes then set separator to '.'. For more information, see the underlying
|
57
57
|
# library that supports this dot-notation concept:
|
58
58
|
# https://github.com/bluemarblepayroll/objectable
|
59
|
-
def initialize(name:, mappings: [], separator: '')
|
60
|
-
super(name: name)
|
59
|
+
def initialize(name:, mappings: [], register: '', separator: '')
|
60
|
+
super(name: name, register: register)
|
61
61
|
|
62
62
|
@mappings = Modeling::KeyIndexMapping.array(mappings)
|
63
63
|
@resolver = Objectable.resolver(separator: separator.to_s)
|
@@ -66,9 +66,7 @@ module Burner
|
|
66
66
|
end
|
67
67
|
|
68
68
|
def perform(_output, payload)
|
69
|
-
payload
|
70
|
-
|
71
|
-
nil
|
69
|
+
payload[register] = array(payload[register]).map { |object| key_to_index_map(object) }
|
72
70
|
end
|
73
71
|
|
74
72
|
private
|
@@ -16,15 +16,15 @@ module Burner
|
|
16
16
|
#
|
17
17
|
# Expected Payload#value input: nothing.
|
18
18
|
# Payload#value output: An array with N beginning elements removed.
|
19
|
-
class Shift <
|
19
|
+
class Shift < JobWithRegister
|
20
20
|
DEFAULT_AMOUNT = 0
|
21
21
|
|
22
22
|
private_constant :DEFAULT_AMOUNT
|
23
23
|
|
24
24
|
attr_reader :amount
|
25
25
|
|
26
|
-
def initialize(name:, amount: DEFAULT_AMOUNT)
|
27
|
-
super(name: name)
|
26
|
+
def initialize(name:, amount: DEFAULT_AMOUNT, register: '')
|
27
|
+
super(name: name, register: register)
|
28
28
|
|
29
29
|
@amount = amount.to_i
|
30
30
|
|
@@ -34,9 +34,7 @@ module Burner
|
|
34
34
|
def perform(output, payload)
|
35
35
|
output.detail("Shifting #{amount} entries.")
|
36
36
|
|
37
|
-
payload
|
38
|
-
|
39
|
-
nil
|
37
|
+
payload[register] = array(payload[register]).slice(amount..-1)
|
40
38
|
end
|
41
39
|
end
|
42
40
|
end
|
@@ -20,15 +20,15 @@ module Burner
|
|
20
20
|
#
|
21
21
|
# Expected Payload#value input: array of objects.
|
22
22
|
# Payload#value output: An array of objects.
|
23
|
-
class Transform <
|
23
|
+
class Transform < JobWithRegister
|
24
24
|
BLANK = ''
|
25
25
|
|
26
26
|
attr_reader :attribute_renderers,
|
27
27
|
:exclusive,
|
28
28
|
:resolver
|
29
29
|
|
30
|
-
def initialize(name:, attributes: [], exclusive: false, separator: BLANK)
|
31
|
-
super(name: name)
|
30
|
+
def initialize(name:, attributes: [], exclusive: false, register: '', separator: BLANK)
|
31
|
+
super(name: name, register: register)
|
32
32
|
|
33
33
|
@resolver = Objectable.resolver(separator: separator)
|
34
34
|
@exclusive = exclusive || false
|
@@ -41,14 +41,12 @@ module Burner
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def perform(output, payload)
|
44
|
-
payload
|
44
|
+
payload[register] = array(payload[register]).map { |row| transform(row, payload.time) }
|
45
45
|
|
46
46
|
attr_count = attribute_renderers.length
|
47
|
-
row_count = payload.
|
47
|
+
row_count = payload[register].length
|
48
48
|
|
49
49
|
output.detail("Transformed #{attr_count} attributes(s) for #{row_count} row(s)")
|
50
|
-
|
51
|
-
nil
|
52
50
|
end
|
53
51
|
|
54
52
|
private
|
@@ -16,11 +16,11 @@ module Burner
|
|
16
16
|
#
|
17
17
|
# Expected Payload#value input: array of objects.
|
18
18
|
# Payload#value output: An array of objects.
|
19
|
-
class Unpivot <
|
19
|
+
class Unpivot < JobWithRegister
|
20
20
|
attr_reader :unpivot
|
21
21
|
|
22
|
-
def initialize(name:, pivot_set: HashMath::Unpivot::PivotSet.new)
|
23
|
-
super(name: name)
|
22
|
+
def initialize(name:, pivot_set: HashMath::Unpivot::PivotSet.new, register: '')
|
23
|
+
super(name: name, register: register)
|
24
24
|
|
25
25
|
@unpivot = HashMath::Unpivot.new(pivot_set)
|
26
26
|
|
@@ -28,18 +28,24 @@ module Burner
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def perform(output, payload)
|
31
|
-
|
32
|
-
|
33
|
-
payload.value = array(payload.value)
|
34
|
-
object_count = payload.value.length || 0
|
31
|
+
payload[register] = array(payload[register])
|
32
|
+
object_count = payload[register].length || 0
|
35
33
|
|
36
34
|
message = "#{pivot_count} Pivots, Key(s): #{key_count} key(s), #{object_count} objects(s)"
|
37
35
|
|
38
36
|
output.detail(message)
|
39
37
|
|
40
|
-
payload
|
38
|
+
payload[register] = payload[register].flat_map { |object| unpivot.expand(object) }
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def pivot_count
|
44
|
+
unpivot.pivot_set.pivots.length
|
45
|
+
end
|
41
46
|
|
42
|
-
|
47
|
+
def key_count
|
48
|
+
unpivot.pivot_set.pivots.map { |p| p.keys.length }.sum
|
43
49
|
end
|
44
50
|
end
|
45
51
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Burner
|
11
|
+
module Library
|
12
|
+
module Collection
|
13
|
+
# Process each object in an array and see if its attribute values match a given set
|
14
|
+
# of validations. The main register will include the valid objects and the invalid_register
|
15
|
+
# will contain the invalid objects.
|
16
|
+
#
|
17
|
+
# Expected Payload#value input: array of objects.
|
18
|
+
# Payload#value output: An array of objects.
|
19
|
+
class Validate < JobWithRegister
|
20
|
+
DEFAULT_INVALID_REGISTER = 'invalid'
|
21
|
+
DEFAULT_JOIN_CHAR = ', '
|
22
|
+
DEFAULT_MESSAGE_KEY = 'errors'
|
23
|
+
|
24
|
+
attr_reader :invalid_register,
|
25
|
+
:join_char,
|
26
|
+
:message_key,
|
27
|
+
:resolver,
|
28
|
+
:validations
|
29
|
+
|
30
|
+
def initialize(
|
31
|
+
name:,
|
32
|
+
invalid_register: DEFAULT_INVALID_REGISTER,
|
33
|
+
join_char: DEFAULT_JOIN_CHAR,
|
34
|
+
message_key: DEFAULT_MESSAGE_KEY,
|
35
|
+
register: '',
|
36
|
+
separator: '',
|
37
|
+
validations: []
|
38
|
+
)
|
39
|
+
super(name: name, register: register)
|
40
|
+
|
41
|
+
@invalid_register = invalid_register.to_s
|
42
|
+
@join_char = join_char.to_s
|
43
|
+
@message_key = message_key.to_s
|
44
|
+
@resolver = Objectable.resolver(separator: separator)
|
45
|
+
@validations = Modeling::Validations.array(validations)
|
46
|
+
|
47
|
+
freeze
|
48
|
+
end
|
49
|
+
|
50
|
+
def perform(output, payload)
|
51
|
+
valid = []
|
52
|
+
invalid = []
|
53
|
+
|
54
|
+
(payload[register] || []).each do |object|
|
55
|
+
errors = validate(object)
|
56
|
+
|
57
|
+
if errors.empty?
|
58
|
+
valid << object
|
59
|
+
else
|
60
|
+
invalid << make_in_error(object, errors)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
output.detail("Valid count: #{valid.length}")
|
65
|
+
output.detail("Invalid count: #{invalid.length}")
|
66
|
+
|
67
|
+
payload[register] = valid
|
68
|
+
payload[invalid_register] = invalid
|
69
|
+
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def validate(object)
|
76
|
+
validations.each_with_object([]) do |validation, memo|
|
77
|
+
next if validation.valid?(object, resolver)
|
78
|
+
|
79
|
+
memo << validation.message
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def make_in_error(object, errors)
|
84
|
+
resolver.set(object, message_key, errors.join(join_char))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -16,11 +16,11 @@ module Burner
|
|
16
16
|
#
|
17
17
|
# Expected Payload#value input: array of objects.
|
18
18
|
# Payload#value output: An array of arrays.
|
19
|
-
class Values <
|
19
|
+
class Values < JobWithRegister
|
20
20
|
attr_reader :include_keys
|
21
21
|
|
22
|
-
def initialize(name:, include_keys: false)
|
23
|
-
super(name: name)
|
22
|
+
def initialize(name:, include_keys: false, register: '')
|
23
|
+
super(name: name, register: register)
|
24
24
|
|
25
25
|
@include_keys = include_keys || false
|
26
26
|
|
@@ -28,12 +28,10 @@ module Burner
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def perform(_output, payload)
|
31
|
-
payload
|
32
|
-
keys
|
33
|
-
values
|
34
|
-
payload
|
35
|
-
|
36
|
-
nil
|
31
|
+
payload[register] = array(payload[register])
|
32
|
+
keys = include_keys ? [keys(payload[register].first)] : []
|
33
|
+
values = payload[register].map { |object| values(object) }
|
34
|
+
payload[register] = keys + values
|
37
35
|
end
|
38
36
|
|
39
37
|
private
|
@@ -14,14 +14,12 @@ module Burner
|
|
14
14
|
#
|
15
15
|
# Expected Payload#value input: nothing.
|
16
16
|
# Payload#value output: an array of arrays. Each inner array represents one data row.
|
17
|
-
class Csv <
|
17
|
+
class Csv < JobWithRegister
|
18
18
|
# This currently only supports returning an array of arrays, including the header row.
|
19
19
|
# In the future this could be extended to offer more customizable options, such as
|
20
20
|
# making it return an array of hashes with the columns mapped, etc.)
|
21
21
|
def perform(_output, payload)
|
22
|
-
payload
|
23
|
-
|
24
|
-
nil
|
22
|
+
payload[register] = CSV.new(payload[register], headers: false).to_a
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
@@ -14,11 +14,9 @@ module Burner
|
|
14
14
|
#
|
15
15
|
# Expected Payload#value input: string of JSON data.
|
16
16
|
# Payload#value output: anything, as specified by the JSON de-serializer.
|
17
|
-
class Json <
|
17
|
+
class Json < JobWithRegister
|
18
18
|
def perform(_output, payload)
|
19
|
-
payload
|
20
|
-
|
21
|
-
nil
|
19
|
+
payload[register] = JSON.parse(payload[register])
|
22
20
|
end
|
23
21
|
end
|
24
22
|
end
|
@@ -17,11 +17,11 @@ module Burner
|
|
17
17
|
#
|
18
18
|
# Expected Payload#value input: string of YAML data.
|
19
19
|
# Payload#value output: anything as specified by the YAML de-serializer.
|
20
|
-
class Yaml <
|
20
|
+
class Yaml < JobWithRegister
|
21
21
|
attr_reader :safe
|
22
22
|
|
23
|
-
def initialize(name:, safe: true)
|
24
|
-
super(name: name)
|
23
|
+
def initialize(name:, register: '', safe: true)
|
24
|
+
super(name: name, register: register)
|
25
25
|
|
26
26
|
@safe = safe
|
27
27
|
|
@@ -36,9 +36,9 @@ module Burner
|
|
36
36
|
def perform(output, payload)
|
37
37
|
output.detail('Warning: loading YAML not using safe_load.') unless safe
|
38
38
|
|
39
|
-
|
39
|
+
value = payload[register]
|
40
40
|
|
41
|
-
|
41
|
+
payload[register] = safe ? YAML.safe_load(value) : YAML.load(value)
|
42
42
|
end
|
43
43
|
# rubocop:enable Security/YAMLLoad
|
44
44
|
end
|
data/lib/burner/library/dummy.rb
CHANGED
data/lib/burner/library/echo.rb
CHANGED
@@ -11,11 +11,11 @@ module Burner
|
|
11
11
|
module Library
|
12
12
|
module IO
|
13
13
|
# Common configuration/code for all IO Job subclasses.
|
14
|
-
class Base <
|
14
|
+
class Base < JobWithRegister
|
15
15
|
attr_reader :path
|
16
16
|
|
17
|
-
def initialize(name:, path:)
|
18
|
-
super(name: name)
|
17
|
+
def initialize(name:, path:, register: '')
|
18
|
+
super(name: name, register: register)
|
19
19
|
|
20
20
|
raise ArgumentError, 'path is required' if path.to_s.empty?
|
21
21
|
|
@@ -16,15 +16,16 @@ module Burner
|
|
16
16
|
# does not exist then the job will return false and short circuit the pipeline.
|
17
17
|
#
|
18
18
|
# Note: this does not use Payload#value.
|
19
|
-
class Exist <
|
20
|
-
attr_reader :short_circuit
|
19
|
+
class Exist < Job
|
20
|
+
attr_reader :path, :short_circuit
|
21
21
|
|
22
22
|
def initialize(name:, path:, short_circuit: false)
|
23
|
-
super(name: name
|
23
|
+
super(name: name)
|
24
24
|
|
25
|
-
|
25
|
+
raise ArgumentError, 'path is required' if path.to_s.empty?
|
26
26
|
|
27
|
-
|
27
|
+
@path = path.to_s
|
28
|
+
@short_circuit = short_circuit || false
|
28
29
|
end
|
29
30
|
|
30
31
|
def perform(output, payload)
|
@@ -35,9 +36,8 @@ module Burner
|
|
35
36
|
|
36
37
|
output.detail("The path: #{compiled_path} #{verb} exist")
|
37
38
|
|
38
|
-
# if anything but false is returned then the pipeline will not short circuit.
|
39
|
-
|
40
|
-
short_circuit && !exists ? false : nil
|
39
|
+
# if anything but false is returned then the pipeline will not short circuit.
|
40
|
+
payload.halt_pipeline if short_circuit && !exists
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -19,8 +19,8 @@ module Burner
|
|
19
19
|
class Read < Base
|
20
20
|
attr_reader :binary
|
21
21
|
|
22
|
-
def initialize(name:, path:, binary: false)
|
23
|
-
super(name: name, path: path)
|
22
|
+
def initialize(name:, path:, binary: false, register: '')
|
23
|
+
super(name: name, path: path, register: register)
|
24
24
|
|
25
25
|
@binary = binary || false
|
26
26
|
|
@@ -32,9 +32,7 @@ module Burner
|
|
32
32
|
|
33
33
|
output.detail("Reading: #{compiled_path}")
|
34
34
|
|
35
|
-
payload
|
36
|
-
|
37
|
-
nil
|
35
|
+
payload[register] = File.open(compiled_path, mode, &:read)
|
38
36
|
end
|
39
37
|
|
40
38
|
private
|
@@ -19,8 +19,8 @@ module Burner
|
|
19
19
|
class Write < Base
|
20
20
|
attr_reader :binary
|
21
21
|
|
22
|
-
def initialize(name:, path:, binary: false)
|
23
|
-
super(name: name, path: path)
|
22
|
+
def initialize(name:, path:, binary: false, register: '')
|
23
|
+
super(name: name, path: path, register: register)
|
24
24
|
|
25
25
|
@binary = binary || false
|
26
26
|
|
@@ -35,7 +35,7 @@ module Burner
|
|
35
35
|
output.detail("Writing: #{compiled_path}")
|
36
36
|
|
37
37
|
time_in_seconds = Benchmark.measure do
|
38
|
-
File.open(compiled_path, mode) { |io| io.write(payload
|
38
|
+
File.open(compiled_path, mode) { |io| io.write(payload[register]) }
|
39
39
|
end.real
|
40
40
|
|
41
41
|
side_effect = SideEffects::WrittenFile.new(
|
@@ -45,8 +45,6 @@ module Burner
|
|
45
45
|
)
|
46
46
|
|
47
47
|
payload.add_side_effect(side_effect)
|
48
|
-
|
49
|
-
nil
|
50
48
|
end
|
51
49
|
|
52
50
|
private
|
@@ -14,15 +14,13 @@ module Burner
|
|
14
14
|
#
|
15
15
|
# Expected Payload#value input: array of arrays.
|
16
16
|
# Payload#value output: a serialized CSV string.
|
17
|
-
class Csv <
|
17
|
+
class Csv < JobWithRegister
|
18
18
|
def perform(_output, payload)
|
19
|
-
payload
|
20
|
-
array(payload
|
19
|
+
payload[register] = CSV.generate(options) do |csv|
|
20
|
+
array(payload[register]).each do |row|
|
21
21
|
csv << row
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
25
|
-
nil
|
26
24
|
end
|
27
25
|
|
28
26
|
private
|
@@ -14,11 +14,9 @@ module Burner
|
|
14
14
|
#
|
15
15
|
# Expected Payload#value input: anything.
|
16
16
|
# Payload#value output: string representing the output of the JSON serializer.
|
17
|
-
class Json <
|
17
|
+
class Json < JobWithRegister
|
18
18
|
def perform(_output, payload)
|
19
|
-
payload
|
20
|
-
|
21
|
-
nil
|
19
|
+
payload[register] = payload[register].to_json
|
22
20
|
end
|
23
21
|
end
|
24
22
|
end
|
@@ -14,11 +14,9 @@ module Burner
|
|
14
14
|
#
|
15
15
|
# Expected Payload#value input: anything.
|
16
16
|
# Payload#value output: string representing the output of the YAML serializer.
|
17
|
-
class Yaml <
|
17
|
+
class Yaml < JobWithRegister
|
18
18
|
def perform(_output, payload)
|
19
|
-
payload
|
20
|
-
|
21
|
-
nil
|
19
|
+
payload[register] = payload[register].to_yaml
|
22
20
|
end
|
23
21
|
end
|
24
22
|
end
|
@@ -13,11 +13,11 @@ module Burner
|
|
13
13
|
#
|
14
14
|
# Expected Payload#value input: anything.
|
15
15
|
# Payload#value output: whatever value was specified in this job.
|
16
|
-
class SetValue <
|
16
|
+
class SetValue < JobWithRegister
|
17
17
|
attr_reader :value
|
18
18
|
|
19
|
-
def initialize(name:, value: nil)
|
20
|
-
super(name: name)
|
19
|
+
def initialize(name:, register: '', value: nil)
|
20
|
+
super(name: name, register: register)
|
21
21
|
|
22
22
|
@value = value
|
23
23
|
|
@@ -25,9 +25,7 @@ module Burner
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def perform(_output, payload)
|
28
|
-
payload
|
29
|
-
|
30
|
-
nil
|
28
|
+
payload[register] = value
|
31
29
|
end
|
32
30
|
end
|
33
31
|
end
|
data/lib/burner/library/sleep.rb
CHANGED
data/lib/burner/modeling.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require_relative 'validations/blank'
|
11
|
+
require_relative 'validations/present'
|
12
|
+
|
13
|
+
module Burner
|
14
|
+
module Modeling
|
15
|
+
# Factory for building sub-classes that can validate an individual object and field value.
|
16
|
+
class Validations
|
17
|
+
acts_as_hashable_factory
|
18
|
+
|
19
|
+
register 'blank', Validations::Blank
|
20
|
+
register 'present', Validations::Present
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Burner
|
11
|
+
module Modeling
|
12
|
+
class Validations
|
13
|
+
# Common logic shared among all Validation subclasses.
|
14
|
+
# This class is an abstract class, make sure to implement:
|
15
|
+
# - #valid?(object, resolver)
|
16
|
+
# - #default_message
|
17
|
+
class Base
|
18
|
+
acts_as_hashable
|
19
|
+
|
20
|
+
attr_reader :key
|
21
|
+
|
22
|
+
def initialize(key:, message: '')
|
23
|
+
raise ArgumentError, 'key is required' if key.to_s.empty?
|
24
|
+
|
25
|
+
@key = key.to_s
|
26
|
+
@message = message.to_s
|
27
|
+
end
|
28
|
+
|
29
|
+
def message
|
30
|
+
@message.to_s.empty? ? "#{key}#{default_message}" : @message.to_s
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require_relative 'base'
|
11
|
+
|
12
|
+
module Burner
|
13
|
+
module Modeling
|
14
|
+
class Validations
|
15
|
+
# Check if a value is blank, if it is not blank then it is not valid.
|
16
|
+
class Blank < Base
|
17
|
+
acts_as_hashable
|
18
|
+
|
19
|
+
def valid?(object, resolver)
|
20
|
+
resolver.get(object, key).to_s.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def default_message
|
26
|
+
' must be blank'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
require_relative 'base'
|
11
|
+
|
12
|
+
module Burner
|
13
|
+
module Modeling
|
14
|
+
class Validations
|
15
|
+
# Check if a value is present. If it is blank (null or empty) then it is invalid.
|
16
|
+
class Present < Base
|
17
|
+
acts_as_hashable
|
18
|
+
|
19
|
+
def valid?(object_value, resolver)
|
20
|
+
!resolver.get(object_value, key).to_s.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def default_message
|
26
|
+
' is required'
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/burner/payload.rb
CHANGED
@@ -19,26 +19,60 @@ module Burner
|
|
19
19
|
# report back the files it has written in a more structured data way (as opposed to simply
|
20
20
|
# writing some information to the output.)
|
21
21
|
class Payload
|
22
|
-
attr_accessor :value
|
23
|
-
|
24
22
|
attr_reader :params,
|
23
|
+
:registers,
|
25
24
|
:side_effects,
|
26
25
|
:time
|
27
26
|
|
28
27
|
def initialize(
|
29
28
|
params: {},
|
29
|
+
registers: {},
|
30
30
|
side_effects: [],
|
31
|
-
time: Time.now.utc
|
32
|
-
value: nil
|
31
|
+
time: Time.now.utc
|
33
32
|
)
|
34
33
|
@params = params || {}
|
34
|
+
@registers = {}
|
35
35
|
@side_effects = side_effects || []
|
36
36
|
@time = time || Time.now.utc
|
37
|
-
|
37
|
+
|
38
|
+
add_registers(registers)
|
38
39
|
end
|
39
40
|
|
41
|
+
# Add a side effect of a job. This helps to keep track of things jobs do outside of its
|
42
|
+
# register mutations.
|
40
43
|
def add_side_effect(side_effect)
|
41
44
|
tap { side_effects << side_effect }
|
42
45
|
end
|
46
|
+
|
47
|
+
# Set a register's value.
|
48
|
+
def []=(key, value)
|
49
|
+
set(key, value)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Retrieve a register's value.
|
53
|
+
def [](key)
|
54
|
+
registers[key.to_s]
|
55
|
+
end
|
56
|
+
|
57
|
+
# Set halt_pipeline to true. This will indicate to the pipeline to stop all
|
58
|
+
# subsequent processing.
|
59
|
+
def halt_pipeline
|
60
|
+
@halt_pipeline = true
|
61
|
+
end
|
62
|
+
|
63
|
+
# Check and see if halt_pipeline was called.
|
64
|
+
def halt_pipeline?
|
65
|
+
@halt_pipeline || false
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def set(key, value)
|
71
|
+
registers[key.to_s] = value
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_registers(registers)
|
75
|
+
(registers || {}).each { |k, v| set(k, v) }
|
76
|
+
end
|
43
77
|
end
|
44
78
|
end
|
data/lib/burner/pipeline.rb
CHANGED
@@ -48,10 +48,10 @@ module Burner
|
|
48
48
|
|
49
49
|
time_in_seconds = Benchmark.measure do
|
50
50
|
steps.each do |step|
|
51
|
-
|
51
|
+
step.perform(output, payload)
|
52
52
|
|
53
|
-
if
|
54
|
-
output.detail('
|
53
|
+
if payload.halt_pipeline?
|
54
|
+
output.detail('Payload was halted, ending pipeline.')
|
55
55
|
break
|
56
56
|
end
|
57
57
|
end
|
data/lib/burner/step.rb
CHANGED
@@ -29,17 +29,13 @@ module Burner
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def perform(output, payload)
|
32
|
-
return_value = nil
|
33
|
-
|
34
32
|
output.title("#{job.class.name}#{SEPARATOR}#{job.name}")
|
35
33
|
|
36
34
|
time_in_seconds = Benchmark.measure do
|
37
|
-
|
35
|
+
job.perform(output, payload)
|
38
36
|
end.real.round(3)
|
39
37
|
|
40
38
|
output.complete(time_in_seconds)
|
41
|
-
|
42
|
-
return_value
|
43
39
|
end
|
44
40
|
end
|
45
41
|
end
|
data/lib/burner/util.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
#
|
4
|
+
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
+
#
|
6
|
+
# This source code is licensed under the MIT license found in the
|
7
|
+
# LICENSE file in the root directory of this source tree.
|
8
|
+
#
|
9
|
+
|
10
|
+
module Burner
|
11
|
+
module Util
|
12
|
+
# Can take in a string and an object and use the object for formatting string interpolations
|
13
|
+
# using tokens of form: {attribute_name}. This templating class does not understand nested
|
14
|
+
# structures, so input should be a flat object/hash in the form of key-value pairs.
|
15
|
+
# A benefit of using Objectable for resolution is that it can understand almost any type of
|
16
|
+
# object: Hash, Struct, OpenStruct, custom objects, etc.
|
17
|
+
# For more information see underlying libraries:
|
18
|
+
# * Stringento: https://github.com/bluemarblepayroll/stringento
|
19
|
+
# * Objectable: https://github.com/bluemarblepayroll/objectable
|
20
|
+
class StringTemplate
|
21
|
+
include Singleton
|
22
|
+
|
23
|
+
attr_reader :resolver
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@resolver = Objectable.resolver(separator: '')
|
27
|
+
|
28
|
+
freeze
|
29
|
+
end
|
30
|
+
|
31
|
+
# For general consumption
|
32
|
+
def evaluate(expression, input)
|
33
|
+
Stringento.evaluate(expression, input, resolver: self)
|
34
|
+
end
|
35
|
+
|
36
|
+
# For Stringento consumption
|
37
|
+
def resolve(value, input)
|
38
|
+
resolver.get(input, value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/burner/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: burner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.pre.alpha.
|
4
|
+
version: 1.0.0.pre.alpha.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Ruggio
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts_as_hashable
|
@@ -220,6 +220,7 @@ files:
|
|
220
220
|
- lib/burner.rb
|
221
221
|
- lib/burner/cli.rb
|
222
222
|
- lib/burner/job.rb
|
223
|
+
- lib/burner/job_with_register.rb
|
223
224
|
- lib/burner/jobs.rb
|
224
225
|
- lib/burner/library.rb
|
225
226
|
- lib/burner/library/collection/arrays_to_objects.rb
|
@@ -228,6 +229,7 @@ files:
|
|
228
229
|
- lib/burner/library/collection/shift.rb
|
229
230
|
- lib/burner/library/collection/transform.rb
|
230
231
|
- lib/burner/library/collection/unpivot.rb
|
232
|
+
- lib/burner/library/collection/validate.rb
|
231
233
|
- lib/burner/library/collection/values.rb
|
232
234
|
- lib/burner/library/deserialize/csv.rb
|
233
235
|
- lib/burner/library/deserialize/json.rb
|
@@ -247,15 +249,19 @@ files:
|
|
247
249
|
- lib/burner/modeling/attribute.rb
|
248
250
|
- lib/burner/modeling/attribute_renderer.rb
|
249
251
|
- lib/burner/modeling/key_index_mapping.rb
|
252
|
+
- lib/burner/modeling/validations.rb
|
253
|
+
- lib/burner/modeling/validations/base.rb
|
254
|
+
- lib/burner/modeling/validations/blank.rb
|
255
|
+
- lib/burner/modeling/validations/present.rb
|
250
256
|
- lib/burner/output.rb
|
251
257
|
- lib/burner/payload.rb
|
252
258
|
- lib/burner/pipeline.rb
|
253
259
|
- lib/burner/side_effects.rb
|
254
260
|
- lib/burner/side_effects/written_file.rb
|
255
261
|
- lib/burner/step.rb
|
256
|
-
- lib/burner/string_template.rb
|
257
262
|
- lib/burner/util.rb
|
258
263
|
- lib/burner/util/arrayable.rb
|
264
|
+
- lib/burner/util/string_template.rb
|
259
265
|
- lib/burner/version.rb
|
260
266
|
homepage: https://github.com/bluemarblepayroll/burner
|
261
267
|
licenses:
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
#
|
4
|
-
# Copyright (c) 2020-present, Blue Marble Payroll, LLC
|
5
|
-
#
|
6
|
-
# This source code is licensed under the MIT license found in the
|
7
|
-
# LICENSE file in the root directory of this source tree.
|
8
|
-
#
|
9
|
-
|
10
|
-
module Burner
|
11
|
-
# Can take in a string and an object and use the object for formatting string interpolations
|
12
|
-
# using tokens of form: {attribute_name}. This templating class does not understand nested
|
13
|
-
# structures, so input should be a flat object/hash in the form of key-value pairs. A benefit of
|
14
|
-
# using Objectable for resolution is that it can understand almost any type of
|
15
|
-
# object: Hash, Struct, OpenStruct, custom objects, etc.
|
16
|
-
# For more information see underlying libraries:
|
17
|
-
# * Stringento: https://github.com/bluemarblepayroll/stringento
|
18
|
-
# * Objectable: https://github.com/bluemarblepayroll/objectable
|
19
|
-
class StringTemplate
|
20
|
-
include Singleton
|
21
|
-
|
22
|
-
attr_reader :resolver
|
23
|
-
|
24
|
-
def initialize
|
25
|
-
@resolver = Objectable.resolver(separator: '')
|
26
|
-
|
27
|
-
freeze
|
28
|
-
end
|
29
|
-
|
30
|
-
# For general consumption
|
31
|
-
def evaluate(expression, input)
|
32
|
-
Stringento.evaluate(expression, input, resolver: self)
|
33
|
-
end
|
34
|
-
|
35
|
-
# For Stringento consumption
|
36
|
-
def resolve(value, input)
|
37
|
-
resolver.get(input, value)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|