burner 1.3.0 → 1.4.0.pre.alpha
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +6 -1
- data/burner.gemspec +1 -0
- data/lib/burner.rb +1 -0
- data/lib/burner/jobs.rb +3 -0
- data/lib/burner/library.rb +3 -0
- data/lib/burner/library/compress/row_reader.rb +102 -0
- data/lib/burner/library/io/row_reader.rb +119 -0
- data/lib/burner/library/serialize/csv.rb +15 -2
- data/lib/burner/modeling.rb +1 -0
- data/lib/burner/modeling/byte_order_mark.rb +27 -0
- data/lib/burner/version.rb +1 -1
- metadata +21 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e4694264d232ea9b8c353973096b144283967676421524aa7aa2b9582f73469f
|
4
|
+
data.tar.gz: 1730498b8d7b18a1fee81a51b16817cb17e69f78bcd3091be7152b3139955806
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1c473531a5422691fb36e14f5fbf7d7421fd19abe889d08e84e14265c146616f5761acbc3458c8cdd656ac784755dc96ec68370637234f260dbac16b0b8486b6
|
7
|
+
data.tar.gz: 88bce907acfcbb8fcec5c39d4be5ba8876fb630583ed55b268d96c3eca65c66412d15439f5abe4af8c29505099b54796dd4e9cdcb898a707d5e32a3e4dc0d838
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -228,6 +228,10 @@ This library only ships with very basic, rudimentary jobs that are meant to just
|
|
228
228
|
* **b/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.
|
229
229
|
* **b/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.
|
230
230
|
|
231
|
+
#### Compression
|
232
|
+
|
233
|
+
* **b/compress/row_reader** [data_key, ignore_blank_path, ignore_blank_data, path_key, register, separator]: Iterates over an array of objects, extracts a path and data in each object, and creates a zip file.
|
234
|
+
|
231
235
|
#### De-serialization
|
232
236
|
|
233
237
|
* **b/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.
|
@@ -240,11 +244,12 @@ By default all jobs will use the `Burner::Disks::Local` disk for its persistence
|
|
240
244
|
|
241
245
|
* **b/io/exist** [disk, 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.
|
242
246
|
* **b/io/read** [binary, disk, 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.
|
247
|
+
* **b/io/row_reader** [data_key, disk, ignore_blank_path, ignore_file_not_found, path_key, register, separator]: Iterates over an array of objects, extracts a filepath from a key in each object, and attempts to load the file's content for each record. The file's content will be stored at the specified data_key. By default missing paths or files will be treated as hard errors. If you wish to ignore these then pass in true for ignore_blank_path and/or ignore_file_not_found.
|
243
248
|
* **b/io/write** [binary, disk, 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.
|
244
249
|
|
245
250
|
#### Serialization
|
246
251
|
|
247
|
-
* **b/serialize/csv** [register]: Take an array of arrays and create a CSV.
|
252
|
+
* **b/serialize/csv** [byte_order_mark, register]: Take an array of arrays and create a CSV. You can optionally pre-pend a byte order mark, see Burner::Modeling::ByteOrderMark for acceptable options.
|
248
253
|
* **b/serialize/json** [register]: Convert value to JSON.
|
249
254
|
* **b/serialize/yaml** [register]: Convert value to YAML.
|
250
255
|
|
data/burner.gemspec
CHANGED
@@ -33,6 +33,7 @@ Gem::Specification.new do |s|
|
|
33
33
|
s.add_dependency('hash_math', '~>1.2')
|
34
34
|
s.add_dependency('objectable', '~>1.0')
|
35
35
|
s.add_dependency('realize', '~>1.3')
|
36
|
+
s.add_dependency('rubyzip', '~>1.2')
|
36
37
|
s.add_dependency('stringento', '~>2.1')
|
37
38
|
|
38
39
|
s.add_development_dependency('guard-rspec', '~>4.7')
|
data/lib/burner.rb
CHANGED
data/lib/burner/jobs.rb
CHANGED
@@ -35,12 +35,15 @@ module Burner
|
|
35
35
|
register 'b/collection/values', Library::Collection::Values
|
36
36
|
register 'b/collection/validate', Library::Collection::Validate
|
37
37
|
|
38
|
+
register 'b/compress/row_reader', Library::Compress::RowReader
|
39
|
+
|
38
40
|
register 'b/deserialize/csv', Library::Deserialize::Csv
|
39
41
|
register 'b/deserialize/json', Library::Deserialize::Json
|
40
42
|
register 'b/deserialize/yaml', Library::Deserialize::Yaml
|
41
43
|
|
42
44
|
register 'b/io/exist', Library::IO::Exist
|
43
45
|
register 'b/io/read', Library::IO::Read
|
46
|
+
register 'b/io/row_reader', Library::IO::RowReader
|
44
47
|
register 'b/io/write', Library::IO::Write
|
45
48
|
|
46
49
|
register 'b/serialize/csv', Library::Serialize::Csv
|
data/lib/burner/library.rb
CHANGED
@@ -26,12 +26,15 @@ require_relative 'library/collection/unpivot'
|
|
26
26
|
require_relative 'library/collection/validate'
|
27
27
|
require_relative 'library/collection/values'
|
28
28
|
|
29
|
+
require_relative 'library/compress/row_reader'
|
30
|
+
|
29
31
|
require_relative 'library/deserialize/csv'
|
30
32
|
require_relative 'library/deserialize/json'
|
31
33
|
require_relative 'library/deserialize/yaml'
|
32
34
|
|
33
35
|
require_relative 'library/io/exist'
|
34
36
|
require_relative 'library/io/read'
|
37
|
+
require_relative 'library/io/row_reader'
|
35
38
|
require_relative 'library/io/write'
|
36
39
|
|
37
40
|
require_relative 'library/serialize/csv'
|
@@ -0,0 +1,102 @@
|
|
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 Compress
|
13
|
+
# Iterates over an array of objects, extracts a path and data in each object, and
|
14
|
+
# creates a zip file. By default, if a path is blank then an ArgumentError will be raised.
|
15
|
+
# If this is undesirable then you can set ignore_blank_path to true and the record will be
|
16
|
+
# skipped. You also have the option to supress blank files being added by configuring
|
17
|
+
# ignore_blank_data as true.
|
18
|
+
#
|
19
|
+
# Expected Payload[register] input: array of objects.
|
20
|
+
# Payload[register] output: compressed binary zip file contents.
|
21
|
+
class RowReader < JobWithRegister
|
22
|
+
Content = Struct.new(:path, :data)
|
23
|
+
|
24
|
+
private_constant :Content
|
25
|
+
|
26
|
+
DEFAULT_DATA_KEY = 'data'
|
27
|
+
DEFAULT_PATH_KEY = 'path'
|
28
|
+
|
29
|
+
attr_reader :data_key,
|
30
|
+
:ignore_blank_data,
|
31
|
+
:ignore_blank_path,
|
32
|
+
:path_key,
|
33
|
+
:resolver
|
34
|
+
|
35
|
+
def initialize(
|
36
|
+
name:,
|
37
|
+
data_key: DEFAULT_DATA_KEY,
|
38
|
+
ignore_blank_data: false,
|
39
|
+
ignore_blank_path: false,
|
40
|
+
path_key: DEFAULT_PATH_KEY,
|
41
|
+
register: DEFAULT_REGISTER,
|
42
|
+
separator: ''
|
43
|
+
)
|
44
|
+
super(name: name, register: register)
|
45
|
+
|
46
|
+
@data_key = data_key.to_s
|
47
|
+
@ignore_blank_data = ignore_blank_data || false
|
48
|
+
@ignore_blank_path = ignore_blank_path || false
|
49
|
+
@path_key = path_key.to_s
|
50
|
+
@resolver = Objectable.resolver(separator: separator)
|
51
|
+
|
52
|
+
freeze
|
53
|
+
end
|
54
|
+
|
55
|
+
def perform(output, payload)
|
56
|
+
payload[register] = Zip::OutputStream.write_buffer do |zip|
|
57
|
+
array(payload[register]).each.with_index(1) do |record, index|
|
58
|
+
content = extract_path_and_data(record, index, output)
|
59
|
+
|
60
|
+
next unless content
|
61
|
+
|
62
|
+
zip.put_next_entry(content.path)
|
63
|
+
zip.write(content.data)
|
64
|
+
end
|
65
|
+
end.string
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def extract_path_and_data(record, index, output)
|
71
|
+
path = strip_leading_separator(resolver.get(record, path_key))
|
72
|
+
data = resolver.get(record, data_key)
|
73
|
+
|
74
|
+
return if assert_and_skip_missing_path?(path, index, output)
|
75
|
+
return if skip_missing_data?(data, index, output)
|
76
|
+
|
77
|
+
Content.new(path, data)
|
78
|
+
end
|
79
|
+
|
80
|
+
def strip_leading_separator(path)
|
81
|
+
path.to_s.start_with?(File::SEPARATOR) ? path.to_s[1..-1] : path.to_s
|
82
|
+
end
|
83
|
+
|
84
|
+
def assert_and_skip_missing_path?(path, index, output)
|
85
|
+
if ignore_blank_path && path.to_s.empty?
|
86
|
+
output.detail("Skipping record #{index} because of blank path")
|
87
|
+
true
|
88
|
+
elsif path.to_s.empty?
|
89
|
+
raise ArgumentError, "Record #{index} is missing a path at key: #{path_key}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def skip_missing_data?(data, index, output)
|
94
|
+
return false unless ignore_blank_data && data.to_s.empty?
|
95
|
+
|
96
|
+
output.detail("Skipping record #{index} because of blank data")
|
97
|
+
true
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,119 @@
|
|
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 'open_file_base'
|
11
|
+
|
12
|
+
module Burner
|
13
|
+
module Library
|
14
|
+
module IO
|
15
|
+
# Iterates over an array of objects, extracts a filepath from a key in each object,
|
16
|
+
# and attempts to load the file's content for each record. The file's content will be
|
17
|
+
# stored at the specified data_key. By default missing paths or files will be
|
18
|
+
# treated as hard errors. If you wish to ignore these then pass in true for
|
19
|
+
# ignore_blank_path and/or ignore_file_not_found.
|
20
|
+
#
|
21
|
+
# Expected Payload[register] input: array of objects.
|
22
|
+
# Payload[register] output: array of objects.
|
23
|
+
class RowReader < JobWithRegister
|
24
|
+
class FileNotFoundError < StandardError; end
|
25
|
+
|
26
|
+
DEFAULT_DATA_KEY = 'data'
|
27
|
+
DEFAULT_PATH_KEY = 'path'
|
28
|
+
|
29
|
+
attr_reader :binary,
|
30
|
+
:data_key,
|
31
|
+
:disk,
|
32
|
+
:ignore_blank_path,
|
33
|
+
:ignore_file_not_found,
|
34
|
+
:path_key,
|
35
|
+
:resolver
|
36
|
+
|
37
|
+
def initialize(
|
38
|
+
name:,
|
39
|
+
binary: false,
|
40
|
+
data_key: DEFAULT_DATA_KEY,
|
41
|
+
disk: {},
|
42
|
+
ignore_blank_path: false,
|
43
|
+
ignore_file_not_found: false,
|
44
|
+
path_key: DEFAULT_PATH_KEY,
|
45
|
+
register: DEFAULT_REGISTER,
|
46
|
+
separator: ''
|
47
|
+
)
|
48
|
+
super(name: name, register: register)
|
49
|
+
|
50
|
+
@binary = binary || false
|
51
|
+
@data_key = data_key.to_s
|
52
|
+
@disk = Disks.make(disk)
|
53
|
+
@ignore_blank_path = ignore_blank_path || false
|
54
|
+
@ignore_file_not_found = ignore_file_not_found || false
|
55
|
+
@path_key = path_key.to_s
|
56
|
+
@resolver = Objectable.resolver(separator: separator)
|
57
|
+
|
58
|
+
freeze
|
59
|
+
end
|
60
|
+
|
61
|
+
def perform(output, payload)
|
62
|
+
records = array(payload[register])
|
63
|
+
|
64
|
+
output.detail("Reading path_key: #{path_key} for #{payload[register].length} records(s)")
|
65
|
+
output.detail("Storing read data in: #{path_key}")
|
66
|
+
|
67
|
+
payload[register] = records.map.with_index(1) do |object, index|
|
68
|
+
load_data(object, index, output)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def assert_and_skip_missing_path?(path, index, output)
|
75
|
+
missing_path = path.to_s.empty?
|
76
|
+
blank_path_raises_error = !ignore_blank_path
|
77
|
+
|
78
|
+
if missing_path && blank_path_raises_error
|
79
|
+
output.detail("Record #{index} is missing a path, raising error")
|
80
|
+
|
81
|
+
raise ArgumentError, "Record #{index} is missing a path"
|
82
|
+
elsif missing_path
|
83
|
+
output.detail("Record #{index} is missing a path")
|
84
|
+
|
85
|
+
true
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def assert_and_skip_file_not_found?(path, index, output)
|
90
|
+
does_not_exist = !disk.exist?(path)
|
91
|
+
file_not_found_raises_error = !ignore_file_not_found
|
92
|
+
|
93
|
+
if file_not_found_raises_error && does_not_exist
|
94
|
+
output.detail("Record #{index} path: '#{path}' does not exist, raising error")
|
95
|
+
|
96
|
+
raise FileNotFoundError, "#{path} does not exist"
|
97
|
+
elsif does_not_exist
|
98
|
+
output.detail("Record #{index} path: '#{path}' does not exist, skipping")
|
99
|
+
|
100
|
+
true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def load_data(object, index, output)
|
105
|
+
path = resolver.get(object, path_key)
|
106
|
+
|
107
|
+
return object if assert_and_skip_missing_path?(path, index, output)
|
108
|
+
return object if assert_and_skip_file_not_found?(path, index, output)
|
109
|
+
|
110
|
+
data = disk.read(path, binary: binary)
|
111
|
+
|
112
|
+
resolver.set(object, data_key, data)
|
113
|
+
|
114
|
+
object
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -10,17 +10,30 @@
|
|
10
10
|
module Burner
|
11
11
|
module Library
|
12
12
|
module Serialize
|
13
|
-
# Take an array of arrays and create a CSV.
|
13
|
+
# Take an array of arrays and create a CSV. You can optionally pre-pend a byte order mark,
|
14
|
+
# see Burner::Modeling::ByteOrderMark for acceptable options.
|
14
15
|
#
|
15
16
|
# Expected Payload[register] input: array of arrays.
|
16
17
|
# Payload[register] output: a serialized CSV string.
|
17
18
|
class Csv < JobWithRegister
|
19
|
+
attr_reader :byte_order_mark
|
20
|
+
|
21
|
+
def initialize(name:, byte_order_mark: nil, register: DEFAULT_REGISTER)
|
22
|
+
super(name: name, register: register)
|
23
|
+
|
24
|
+
@byte_order_mark = Modeling::ByteOrderMark.resolve(byte_order_mark)
|
25
|
+
|
26
|
+
freeze
|
27
|
+
end
|
28
|
+
|
18
29
|
def perform(_output, payload)
|
19
|
-
|
30
|
+
serialized_rows = CSV.generate(options) do |csv|
|
20
31
|
array(payload[register]).each do |row|
|
21
32
|
csv << row
|
22
33
|
end
|
23
34
|
end
|
35
|
+
|
36
|
+
payload[register] = "#{byte_order_mark}#{serialized_rows}"
|
24
37
|
end
|
25
38
|
|
26
39
|
private
|
data/lib/burner/modeling.rb
CHANGED
@@ -9,6 +9,7 @@
|
|
9
9
|
|
10
10
|
require_relative 'modeling/attribute'
|
11
11
|
require_relative 'modeling/attribute_renderer'
|
12
|
+
require_relative 'modeling/byte_order_mark'
|
12
13
|
require_relative 'modeling/key_index_mapping'
|
13
14
|
require_relative 'modeling/key_mapping'
|
14
15
|
require_relative 'modeling/validations'
|
@@ -0,0 +1,27 @@
|
|
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
|
+
# Define all acceptable byte order mark values.
|
13
|
+
module ByteOrderMark
|
14
|
+
UTF_8 = "\xEF\xBB\xBF"
|
15
|
+
UTF_16BE = "\xFE\xFF"
|
16
|
+
UTF_16LE = "\xFF\xFE"
|
17
|
+
UTF_32BE = "\x00\x00\xFE\xFF"
|
18
|
+
UTF_32LE = "\xFE\xFF\x00\x00"
|
19
|
+
|
20
|
+
class << self
|
21
|
+
def resolve(value)
|
22
|
+
value ? const_get(value.to_s.upcase.to_sym) : nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
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.
|
4
|
+
version: 1.4.0.pre.alpha
|
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-12-
|
11
|
+
date: 2020-12-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts_as_hashable
|
@@ -80,6 +80,20 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.3'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubyzip
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.2'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '1.2'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
98
|
name: stringento
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -238,6 +252,7 @@ files:
|
|
238
252
|
- lib/burner/library/collection/unpivot.rb
|
239
253
|
- lib/burner/library/collection/validate.rb
|
240
254
|
- lib/burner/library/collection/values.rb
|
255
|
+
- lib/burner/library/compress/row_reader.rb
|
241
256
|
- lib/burner/library/deserialize/csv.rb
|
242
257
|
- lib/burner/library/deserialize/json.rb
|
243
258
|
- lib/burner/library/deserialize/yaml.rb
|
@@ -245,6 +260,7 @@ files:
|
|
245
260
|
- lib/burner/library/io/exist.rb
|
246
261
|
- lib/burner/library/io/open_file_base.rb
|
247
262
|
- lib/burner/library/io/read.rb
|
263
|
+
- lib/burner/library/io/row_reader.rb
|
248
264
|
- lib/burner/library/io/write.rb
|
249
265
|
- lib/burner/library/nothing.rb
|
250
266
|
- lib/burner/library/serialize/csv.rb
|
@@ -256,6 +272,7 @@ files:
|
|
256
272
|
- lib/burner/modeling.rb
|
257
273
|
- lib/burner/modeling/attribute.rb
|
258
274
|
- lib/burner/modeling/attribute_renderer.rb
|
275
|
+
- lib/burner/modeling/byte_order_mark.rb
|
259
276
|
- lib/burner/modeling/key_index_mapping.rb
|
260
277
|
- lib/burner/modeling/key_mapping.rb
|
261
278
|
- lib/burner/modeling/validations.rb
|
@@ -292,9 +309,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
292
309
|
version: '2.5'
|
293
310
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
294
311
|
requirements:
|
295
|
-
- - "
|
312
|
+
- - ">"
|
296
313
|
- !ruby/object:Gem::Version
|
297
|
-
version:
|
314
|
+
version: 1.3.1
|
298
315
|
requirements: []
|
299
316
|
rubygems_version: 3.0.3
|
300
317
|
signing_key:
|