portable 1.0.0.pre.alpha → 1.0.0.pre.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +101 -36
- data/lib/portable.rb +5 -1
- data/lib/portable/csv/byte_order_mark.rb +27 -0
- data/lib/portable/csv/document.rb +34 -0
- data/lib/portable/csv/options.rb +32 -0
- data/lib/portable/csv/writer.rb +109 -0
- data/lib/portable/{export.rb → data_table.rb} +13 -13
- data/lib/portable/document.rb +35 -0
- data/lib/portable/transformer.rb +0 -2
- data/lib/portable/version.rb +1 -1
- data/lib/portable/writers.rb +10 -0
- metadata +9 -4
- data/lib/portable/writer.rb +0 -82
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 112f223aca7d26dda5b4e9c93b1e83174885e941806de503c2d15be37047cdc1
|
4
|
+
data.tar.gz: 7d9764151388559dd0ac999b69fa4bed16ff9d02fdb796944ff4d22b30b5056d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0bb98a4e53e669c13fbf361d2b3e5be4572ce2b42ab99e43b555ecc8db7c89c25cd28b653b61bc1b3ab2ace6688886ba0f1d45f04d4d1bcb3b178d7183adad6a
|
7
|
+
data.tar.gz: 14ac7eebf7b0af0b6553317e1d9f1f51757554ad43b9f0827a036ed12ff9ff9b67c5e2feb5db03566cce6ce43783ad8a24e0aed42a2a5367e306283531cb0214
|
data/README.md
CHANGED
@@ -31,7 +31,7 @@ bundle add portable
|
|
31
31
|
|
32
32
|
## Examples
|
33
33
|
|
34
|
-
### Getting Started
|
34
|
+
### Getting Started Writing CSV Files
|
35
35
|
|
36
36
|
Consider the following data set as an array of hashes:
|
37
37
|
|
@@ -45,26 +45,24 @@ patients = [
|
|
45
45
|
We could configure an export like so:
|
46
46
|
|
47
47
|
````ruby
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
48
|
+
document = {
|
49
|
+
data_table: {
|
50
|
+
columns: [
|
51
|
+
{ header: :first },
|
52
|
+
{ header: :last },
|
53
|
+
{ header: :dob }
|
54
|
+
]
|
55
|
+
}
|
54
56
|
}
|
55
57
|
````
|
56
58
|
|
57
59
|
And execute the export against the example dataset in order to generate a CSV file:
|
58
60
|
|
59
61
|
````ruby
|
60
|
-
writer = Portable::Writer.new(export)
|
62
|
+
writer = Portable::Csv::Writer.new(export)
|
61
63
|
filename = File.join('tmp', 'patients.csv')
|
62
64
|
|
63
|
-
writer.open(filename)
|
64
|
-
patients.each do |patient|
|
65
|
-
writer.write(object: patient)
|
66
|
-
end
|
67
|
-
end
|
65
|
+
writer.open(filename) { |writer| writer.write_all(patients) }
|
68
66
|
````
|
69
67
|
|
70
68
|
We should now have a CSV file at tmp/patients.csv that looks like this:
|
@@ -78,31 +76,33 @@ Frank | Rizzo | 1930-09-22
|
|
78
76
|
|
79
77
|
This library uses Realize under the hood, so you have the option of configuring any transformation pipeline for each column. Reviewing [Realize's list of transformers](https://github.com/bluemarblepayroll/realize#transformer-gallery) is recommended to see what is available.
|
80
78
|
|
81
|
-
Let's expand our example above with different headers and date formatting:
|
79
|
+
Let's expand our CSV example above with different headers and date formatting:
|
82
80
|
|
83
81
|
````ruby
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
82
|
+
document = {
|
83
|
+
data_table: {
|
84
|
+
columns: [
|
85
|
+
{
|
86
|
+
header: 'First Name',
|
87
|
+
transformers: [
|
88
|
+
{ type: 'r/value/resolve', key: :first }
|
89
|
+
]
|
90
|
+
},
|
91
|
+
{
|
92
|
+
header: 'Last Name',
|
93
|
+
transformers: [
|
94
|
+
{ type: 'r/value/resolve', key: :last }
|
95
|
+
]
|
96
|
+
},
|
97
|
+
{
|
98
|
+
header: 'Date of Birth',
|
99
|
+
transformers: [
|
100
|
+
{ type: 'r/value/resolve', key: :dob },
|
101
|
+
{ type: 'r/format/date', output_format: '%m/%d/%Y' },
|
102
|
+
]
|
103
|
+
}
|
104
|
+
]
|
105
|
+
}
|
106
106
|
}
|
107
107
|
````
|
108
108
|
|
@@ -115,6 +115,71 @@ Frank | Rizzo | 09/22/1930
|
|
115
115
|
|
116
116
|
Realize is also [pluggable](https://github.com/bluemarblepayroll/realize#plugging-in-transformers), so you are able to create your own and plug them directly into Realize.
|
117
117
|
|
118
|
+
### Options
|
119
|
+
|
120
|
+
Each writer can have its own set of options.
|
121
|
+
|
122
|
+
#### CSV Options
|
123
|
+
|
124
|
+
The following options are available for customizing CSV documents:
|
125
|
+
|
126
|
+
* byte_order_mark: (optional, default is nothing): This option will write out a byte order mark identifying the encoding for the file. This is useful for ensuring applications like Microsoft Excel open CSV files properly. See Portable::Csv::ByteOrderMark constants for acceptable values.
|
127
|
+
|
128
|
+
### Custom Header/Footer Rows
|
129
|
+
|
130
|
+
The main document model can also include statically defined rows to place either at the header (above data table) or footer (below data table) locations. For example:
|
131
|
+
|
132
|
+
````ruby
|
133
|
+
document = {
|
134
|
+
data_table: {
|
135
|
+
columns: [
|
136
|
+
{
|
137
|
+
header: 'First Name',
|
138
|
+
transformers: [
|
139
|
+
{ type: 'r/value/resolve', key: :first }
|
140
|
+
]
|
141
|
+
},
|
142
|
+
{
|
143
|
+
header: 'Last Name',
|
144
|
+
transformers: [
|
145
|
+
{ type: 'r/value/resolve', key: :last }
|
146
|
+
]
|
147
|
+
},
|
148
|
+
{
|
149
|
+
header: 'Date of Birth',
|
150
|
+
transformers: [
|
151
|
+
{ type: 'r/value/resolve', key: :dob },
|
152
|
+
{ type: 'r/format/date', output_format: '%m/%d/%Y' },
|
153
|
+
]
|
154
|
+
}
|
155
|
+
]
|
156
|
+
},
|
157
|
+
header_rows: [
|
158
|
+
[ 'Run Date', '04/05/2000' ],
|
159
|
+
[ 'Run By', 'Hops the Bunny' ],
|
160
|
+
[],
|
161
|
+
[ 'BEGIN' ]
|
162
|
+
],
|
163
|
+
header_rows: [
|
164
|
+
[ 'END' ]
|
165
|
+
],
|
166
|
+
}
|
167
|
+
````
|
168
|
+
|
169
|
+
Using this document configuration would yield a CSV with four "header rows" at the top, one "data table header row", two data rows, and one "footer row". This is not easily illustrated in Markdown, but this would be the result:
|
170
|
+
|
171
|
+
````
|
172
|
+
Run Date | 04/05/2000
|
173
|
+
Run By | Hops the Bunny
|
174
|
+
|
175
|
+
BEGIN
|
176
|
+
First Name | Last Name | Date of Birth
|
177
|
+
---------- | --------- | -------------
|
178
|
+
Marky | Mark | 04/05/2000
|
179
|
+
Frank | Rizzo | 09/22/1930
|
180
|
+
END
|
181
|
+
````
|
182
|
+
|
118
183
|
## Contributing
|
119
184
|
|
120
185
|
### Development Environment Configuration
|
data/lib/portable.rb
CHANGED
@@ -10,8 +10,12 @@
|
|
10
10
|
require 'acts_as_hashable'
|
11
11
|
require 'csv'
|
12
12
|
require 'fileutils'
|
13
|
+
require 'forwardable'
|
13
14
|
require 'objectable'
|
14
15
|
require 'realize'
|
15
16
|
require 'time'
|
16
17
|
|
17
|
-
require_relative 'portable/
|
18
|
+
require_relative 'portable/data_table'
|
19
|
+
require_relative 'portable/document'
|
20
|
+
require_relative 'portable/transformer'
|
21
|
+
require_relative 'portable/writers'
|
@@ -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 Portable
|
11
|
+
module Csv
|
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
|
@@ -0,0 +1,34 @@
|
|
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 'options'
|
11
|
+
|
12
|
+
module Portable
|
13
|
+
module Csv
|
14
|
+
# Defines all the options for an export including static header rows, footer rows, and how
|
15
|
+
# to draw the data table.
|
16
|
+
class Document < Portable::Document
|
17
|
+
attr_reader :options
|
18
|
+
|
19
|
+
def_delegators :options,
|
20
|
+
:byte_order_mark,
|
21
|
+
:byte_order_mark?
|
22
|
+
|
23
|
+
def initialize(data_table: {}, footer_rows: [], header_rows: [], options: {})
|
24
|
+
@options = Options.make(options)
|
25
|
+
|
26
|
+
super(
|
27
|
+
data_table: data_table,
|
28
|
+
footer_rows: footer_rows,
|
29
|
+
header_rows: header_rows
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,32 @@
|
|
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 'byte_order_mark'
|
11
|
+
|
12
|
+
module Portable
|
13
|
+
module Csv
|
14
|
+
# Defines all the options for an export including static header rows, footer rows, and how
|
15
|
+
# to draw the data table.
|
16
|
+
class Options
|
17
|
+
acts_as_hashable
|
18
|
+
|
19
|
+
attr_reader :byte_order_mark
|
20
|
+
|
21
|
+
def initialize(byte_order_mark: nil)
|
22
|
+
@byte_order_mark = ByteOrderMark.resolve(byte_order_mark)
|
23
|
+
|
24
|
+
freeze
|
25
|
+
end
|
26
|
+
|
27
|
+
def byte_order_mark?
|
28
|
+
!byte_order_mark.nil?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,109 @@
|
|
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 'document'
|
11
|
+
|
12
|
+
module Portable
|
13
|
+
module Csv
|
14
|
+
# Main API for writing files. There are two main patterns to choose from:
|
15
|
+
# 1. calling #open, #write, and #close manually.
|
16
|
+
# 2. calling #open and passing a block and having #close automatically called.
|
17
|
+
class Writer
|
18
|
+
class AlreadyOpenError < StandardError; end
|
19
|
+
class NotOpenError < StandardError; end
|
20
|
+
|
21
|
+
attr_reader :csv, :document, :time, :transformer
|
22
|
+
|
23
|
+
def initialize(document, resolver: Objectable.resolver, time: Time.now.utc)
|
24
|
+
@document = Document.make(document, nullable: false)
|
25
|
+
@time = time || Time.now.utc
|
26
|
+
@transformer = Transformer.new(@document.columns, resolver: resolver)
|
27
|
+
end
|
28
|
+
|
29
|
+
def open?
|
30
|
+
!csv.nil?
|
31
|
+
end
|
32
|
+
|
33
|
+
# Will raise a AlreadyOpenError exception if a writer has already been opened but
|
34
|
+
# not yet closed.
|
35
|
+
def open(filename)
|
36
|
+
raise AlreadyOpenError, 'writer is already open' if open?
|
37
|
+
|
38
|
+
initialize_csv(filename)
|
39
|
+
write_head
|
40
|
+
|
41
|
+
if block_given?
|
42
|
+
yield self
|
43
|
+
close
|
44
|
+
end
|
45
|
+
|
46
|
+
self
|
47
|
+
end
|
48
|
+
|
49
|
+
# Will raise a NotOpenError exception if a writer has not yet been opened.
|
50
|
+
def write_all(objects = [])
|
51
|
+
raise NotOpenError, 'writer is not open' unless open?
|
52
|
+
|
53
|
+
objects.each { |o| write(o) }
|
54
|
+
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
# Will raise a NotOpenError exception if a writer has not yet been opened.
|
59
|
+
def write(object = {})
|
60
|
+
raise NotOpenError, 'writer is not open' unless open?
|
61
|
+
|
62
|
+
csv << transformer.transform(object, time).values
|
63
|
+
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
# Will raise a NotOpenError exception if a writer has not yet been opened.
|
68
|
+
def close
|
69
|
+
raise NotOpenError, 'writer is not open' unless open?
|
70
|
+
|
71
|
+
write_foot
|
72
|
+
|
73
|
+
@csv.close
|
74
|
+
@csv = nil
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def ensure_directory_exists(filename)
|
81
|
+
path = File.dirname(filename)
|
82
|
+
|
83
|
+
FileUtils.mkdir_p(path) unless File.exist?(path)
|
84
|
+
end
|
85
|
+
|
86
|
+
def initialize_csv(filename)
|
87
|
+
ensure_directory_exists(filename)
|
88
|
+
|
89
|
+
@csv = CSV.open(filename, 'w')
|
90
|
+
|
91
|
+
csv.to_io.write(document.byte_order_mark) if document.byte_order_mark?
|
92
|
+
end
|
93
|
+
|
94
|
+
def write_head
|
95
|
+
raw_write(document.header_rows)
|
96
|
+
|
97
|
+
csv << document.headers if document.include_headers?
|
98
|
+
end
|
99
|
+
|
100
|
+
def write_foot
|
101
|
+
raw_write(document.footer_rows)
|
102
|
+
end
|
103
|
+
|
104
|
+
def raw_write(rows)
|
105
|
+
rows.each { |row| csv << row }
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -10,30 +10,30 @@
|
|
10
10
|
require_relative 'column'
|
11
11
|
|
12
12
|
module Portable
|
13
|
-
# Defines all the options for an export like columns, whether or not
|
14
|
-
# headers, and more.
|
15
|
-
class
|
13
|
+
# Defines all the options for the data grid within an export like columns, whether or not
|
14
|
+
# you want to include headers, and more.
|
15
|
+
class Datagrid
|
16
16
|
acts_as_hashable
|
17
17
|
|
18
|
-
|
19
|
-
UTF8 = "\uFEFF"
|
20
|
-
end
|
21
|
-
include Bom
|
22
|
-
|
23
|
-
attr_reader :bom, :columns, :include_headers
|
18
|
+
attr_reader :columns
|
24
19
|
|
25
|
-
|
26
|
-
|
27
|
-
def initialize(bom: nil, columns: [], include_headers: true)
|
28
|
-
@bom = bom ? Bom.const_get(bom.to_s.upcase.to_sym) : nil
|
20
|
+
def initialize(columns: [], include_headers: true)
|
29
21
|
@columns = Column.array(columns)
|
30
22
|
@include_headers = include_headers || false
|
31
23
|
|
32
24
|
freeze
|
33
25
|
end
|
34
26
|
|
27
|
+
def include_headers?
|
28
|
+
include_headers
|
29
|
+
end
|
30
|
+
|
35
31
|
def headers
|
36
32
|
columns.map(&:header)
|
37
33
|
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
attr_reader :include_headers
|
38
38
|
end
|
39
39
|
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 Portable
|
11
|
+
# Base document object model defining what all documents should include.
|
12
|
+
class Document
|
13
|
+
acts_as_hashable
|
14
|
+
extend Forwardable
|
15
|
+
|
16
|
+
attr_reader :data_table,
|
17
|
+
:footer_rows,
|
18
|
+
:header_rows
|
19
|
+
|
20
|
+
def_delegators :data_table,
|
21
|
+
:columns,
|
22
|
+
:headers,
|
23
|
+
:include_headers?,
|
24
|
+
:headers,
|
25
|
+
:transform
|
26
|
+
|
27
|
+
def initialize(data_table: {}, footer_rows: [], header_rows: [])
|
28
|
+
@data_table = Datagrid.make(data_table)
|
29
|
+
@footer_rows = footer_rows || []
|
30
|
+
@header_rows = header_rows || []
|
31
|
+
|
32
|
+
freeze
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/portable/transformer.rb
CHANGED
data/lib/portable/version.rb
CHANGED
@@ -0,0 +1,10 @@
|
|
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 'csv/writer'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: portable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0.pre.alpha
|
4
|
+
version: 1.0.0.pre.alpha.1
|
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-08-
|
11
|
+
date: 2020-08-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts_as_hashable
|
@@ -174,10 +174,15 @@ files:
|
|
174
174
|
- exe/.gitkeep
|
175
175
|
- lib/portable.rb
|
176
176
|
- lib/portable/column.rb
|
177
|
-
- lib/portable/
|
177
|
+
- lib/portable/csv/byte_order_mark.rb
|
178
|
+
- lib/portable/csv/document.rb
|
179
|
+
- lib/portable/csv/options.rb
|
180
|
+
- lib/portable/csv/writer.rb
|
181
|
+
- lib/portable/data_table.rb
|
182
|
+
- lib/portable/document.rb
|
178
183
|
- lib/portable/transformer.rb
|
179
184
|
- lib/portable/version.rb
|
180
|
-
- lib/portable/
|
185
|
+
- lib/portable/writers.rb
|
181
186
|
- portable.gemspec
|
182
187
|
homepage: https://github.com/bluemarblepayroll/portable
|
183
188
|
licenses:
|
data/lib/portable/writer.rb
DELETED
@@ -1,82 +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
|
-
require_relative 'export'
|
11
|
-
require_relative 'transformer'
|
12
|
-
|
13
|
-
module Portable
|
14
|
-
# Main API for writing files. There are two main patterns to choose from:
|
15
|
-
# 1. calling #open, #write, and #close manually.
|
16
|
-
# 2. calling #open and passing a block and having #close automatically called.
|
17
|
-
class Writer
|
18
|
-
class AlreadyOpenError < StandardError; end
|
19
|
-
class NotOpenError < StandardError; end
|
20
|
-
|
21
|
-
attr_reader :csv, :export, :transformer
|
22
|
-
|
23
|
-
def initialize(export, resolver: Objectable.resolver)
|
24
|
-
@export = Export.make(export, nullable: false)
|
25
|
-
@transformer = Transformer.new(@export.columns, resolver: resolver)
|
26
|
-
end
|
27
|
-
|
28
|
-
def open?
|
29
|
-
!csv.nil?
|
30
|
-
end
|
31
|
-
|
32
|
-
# Will raise a AlreadyOpenError exception if a writer has already been opened but
|
33
|
-
# not yet closed.
|
34
|
-
def open(filename)
|
35
|
-
raise AlreadyOpenError, 'writer is already open' if open?
|
36
|
-
|
37
|
-
initialize_csv(filename)
|
38
|
-
|
39
|
-
if block_given?
|
40
|
-
yield self
|
41
|
-
close
|
42
|
-
end
|
43
|
-
|
44
|
-
self
|
45
|
-
end
|
46
|
-
|
47
|
-
# Will raise a NotOpenError exception if a writer has not yet been opened.
|
48
|
-
def write(object: {}, time: Time.now.utc)
|
49
|
-
raise NotOpenError, 'writer is not open' unless open?
|
50
|
-
|
51
|
-
csv << transformer.transform(object, time).values
|
52
|
-
|
53
|
-
self
|
54
|
-
end
|
55
|
-
|
56
|
-
# Will raise a NotOpenError exception if a writer has not yet been opened.
|
57
|
-
def close
|
58
|
-
raise NotOpenError, 'writer is not open' unless open?
|
59
|
-
|
60
|
-
@csv.close
|
61
|
-
@csv = nil
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def ensure_directory_exists(filename)
|
68
|
-
path = File.dirname(filename)
|
69
|
-
|
70
|
-
FileUtils.mkdir_p(path) unless File.exist?(path)
|
71
|
-
end
|
72
|
-
|
73
|
-
def initialize_csv(filename)
|
74
|
-
ensure_directory_exists(filename)
|
75
|
-
|
76
|
-
@csv = CSV.open(filename, 'w')
|
77
|
-
|
78
|
-
csv.to_io.write(export.bom) if export.bom
|
79
|
-
csv << export.headers if export.include_headers?
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|