workbook 0.8.1 → 0.9.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/.codeclimate.yml +21 -0
- data/.gitignore +4 -1
- data/.ruby-version +1 -1
- data/.travis.yml +4 -4
- data/CHANGELOG.md +8 -0
- data/Gemfile +2 -2
- data/README.md +9 -7
- data/Rakefile +6 -6
- data/json_test.json +1 -0
- data/lib/workbook/book.rb +73 -62
- data/lib/workbook/cell.rb +58 -13
- data/lib/workbook/column.rb +31 -28
- data/lib/workbook/format.rb +23 -24
- data/lib/workbook/generatetypes.rb +4 -4
- data/lib/workbook/modules/cache.rb +6 -7
- data/lib/workbook/modules/cell.rb +77 -100
- data/lib/workbook/modules/diff_sort.rb +92 -83
- data/lib/workbook/modules/raw_objects_storage.rb +6 -8
- data/lib/workbook/modules/type_parser.rb +30 -22
- data/lib/workbook/nil_value.rb +4 -9
- data/lib/workbook/readers/csv_reader.rb +7 -10
- data/lib/workbook/readers/ods_reader.rb +51 -50
- data/lib/workbook/readers/txt_reader.rb +6 -8
- data/lib/workbook/readers/xls_reader.rb +21 -33
- data/lib/workbook/readers/xls_shared.rb +106 -117
- data/lib/workbook/readers/xlsx_reader.rb +45 -46
- data/lib/workbook/row.rb +99 -84
- data/lib/workbook/sheet.rb +47 -38
- data/lib/workbook/table.rb +96 -72
- data/lib/workbook/template.rb +12 -15
- data/lib/workbook/types/false.rb +0 -1
- data/lib/workbook/types/nil.rb +0 -1
- data/lib/workbook/types/nil_class.rb +1 -1
- data/lib/workbook/types/numeric.rb +1 -1
- data/lib/workbook/types/string.rb +1 -1
- data/lib/workbook/types/time.rb +1 -1
- data/lib/workbook/types/true.rb +0 -1
- data/lib/workbook/types/true_class.rb +1 -1
- data/lib/workbook/version.rb +2 -3
- data/lib/workbook/writers/csv_table_writer.rb +10 -13
- data/lib/workbook/writers/html_writer.rb +34 -38
- data/lib/workbook/writers/json_table_writer.rb +8 -11
- data/lib/workbook/writers/xls_writer.rb +30 -36
- data/lib/workbook/writers/xlsx_writer.rb +45 -29
- data/lib/workbook.rb +16 -15
- data/test/artifacts/currency_test.ods +0 -0
- data/test/helper.rb +6 -5
- data/test/test_book.rb +41 -38
- data/test/test_column.rb +26 -24
- data/test/test_format.rb +51 -55
- data/test/test_functional.rb +7 -8
- data/test/test_modules_cache.rb +18 -17
- data/test/test_modules_cell.rb +55 -46
- data/test/test_modules_table_diff_sort.rb +55 -64
- data/test/test_modules_type_parser.rb +61 -31
- data/test/test_readers_csv_reader.rb +48 -42
- data/test/test_readers_ods_reader.rb +36 -31
- data/test/test_readers_txt_reader.rb +21 -23
- data/test/test_readers_xls_reader.rb +20 -23
- data/test/test_readers_xls_shared.rb +2 -3
- data/test/test_readers_xlsx_reader.rb +44 -37
- data/test/test_row.rb +105 -109
- data/test/test_sheet.rb +35 -41
- data/test/test_table.rb +82 -60
- data/test/test_template.rb +16 -15
- data/test/test_types_date.rb +4 -6
- data/test/test_writers_csv_writer.rb +24 -0
- data/test/test_writers_html_writer.rb +42 -41
- data/test/test_writers_json_writer.rb +16 -9
- data/test/test_writers_xls_writer.rb +50 -35
- data/test/test_writers_xlsx_writer.rb +62 -34
- data/workbook.gemspec +25 -27
- metadata +96 -42
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
3
|
+
|
5
4
|
module Workbook
|
6
5
|
module Modules
|
7
6
|
# Adds essential diffing and comparing support, as well as diffing entire books
|
@@ -11,21 +10,22 @@ module Workbook
|
|
11
10
|
#
|
12
11
|
# @return [Workbook::Table] the empty table, linked to a book
|
13
12
|
def new_diff_template
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
13
|
+
diffbook = Workbook::Book.new
|
14
|
+
template = diffbook.template
|
15
|
+
f = template.create_or_find_format_by "destroyed"
|
16
|
+
f[:background_color] = :red
|
17
|
+
f = template.create_or_find_format_by "updated"
|
18
|
+
f[:background_color] = :yellow
|
19
|
+
f = template.create_or_find_format_by "created"
|
20
|
+
f[:background_color] = :lime
|
21
|
+
f = template.create_or_find_format_by "header"
|
22
|
+
f[:rotation] = 72
|
23
|
+
f[:font_weight] = :bold
|
24
|
+
f[:height] = 80
|
25
|
+
diffbook
|
27
26
|
end
|
28
27
|
end
|
28
|
+
|
29
29
|
def self.included(base)
|
30
30
|
base.extend(ClassMethods)
|
31
31
|
end
|
@@ -34,9 +34,9 @@ module Workbook
|
|
34
34
|
#
|
35
35
|
# @param [Workbook::Book] to_workbook to compare against
|
36
36
|
# @return [Workbook::Book] workbook with compared result
|
37
|
-
def diff to_workbook, options={:
|
37
|
+
def diff to_workbook, options = {sort: true, ignore_headers: false}
|
38
38
|
diff_template = Workbook::Book.new_diff_template
|
39
|
-
|
39
|
+
each_with_index do |from_sheet, sheet_index|
|
40
40
|
to_sheet = to_workbook[sheet_index]
|
41
41
|
if to_sheet
|
42
42
|
from_table = from_sheet.table
|
@@ -46,7 +46,7 @@ module Workbook
|
|
46
46
|
from_table.diff(to_table, options)
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
49
|
+
diff_template # the template has been filled in the meanwhile, not to use as a template anymore... :)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
@@ -55,27 +55,27 @@ module Workbook
|
|
55
55
|
# create an overview of the differences between itself with another 'previous' table, returns a book with a single sheet and table (containing the diffs)
|
56
56
|
#
|
57
57
|
# @return [Workbook::Table] the return result
|
58
|
-
def diff other, options={}
|
59
|
-
options = {:
|
58
|
+
def diff other, options = {}
|
59
|
+
options = {sort: true, ignore_headers: false}.merge(options)
|
60
60
|
|
61
61
|
aligned = align(other, options)
|
62
62
|
aself = aligned[:self]
|
63
63
|
aother = aligned[:other]
|
64
64
|
|
65
65
|
iteration_cols = []
|
66
|
-
if options[:ignore_headers]
|
67
|
-
|
66
|
+
iteration_cols = if options[:ignore_headers]
|
67
|
+
[aother.first.count, aself.first.count].max.times.collect
|
68
68
|
else
|
69
|
-
|
69
|
+
(aother.header.to_symbols + aother.header.to_symbols).uniq
|
70
70
|
end
|
71
71
|
|
72
72
|
diff_table = diff_template
|
73
|
-
maxri = (aself.count-1)
|
73
|
+
maxri = (aself.count - 1)
|
74
74
|
|
75
|
-
|
76
|
-
row = diff_table[ri] = Workbook::Row.new(nil, diff_table)
|
77
|
-
srow = aself[ri]
|
78
|
-
orow = aother[ri]
|
75
|
+
(0..maxri).each do |ri|
|
76
|
+
row = diff_table.rows[ri] = Workbook::Row.new(nil, diff_table)
|
77
|
+
srow = aself.rows[ri]
|
78
|
+
orow = aother.rows[ri]
|
79
79
|
|
80
80
|
iteration_cols.each_with_index do |ch, ci|
|
81
81
|
scell = srow[ch]
|
@@ -83,38 +83,13 @@ module Workbook
|
|
83
83
|
row[ci] = create_diff_cell(scell, ocell)
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
87
|
-
diff_table[0].format = diff_template.template.create_or_find_format_by
|
86
|
+
unless options[:ignore_headers]
|
87
|
+
diff_table[0].format = diff_template.template.create_or_find_format_by "header"
|
88
88
|
end
|
89
89
|
|
90
90
|
diff_table
|
91
91
|
end
|
92
92
|
|
93
|
-
# creates a new cell describing the difference between two cells
|
94
|
-
#
|
95
|
-
# @return [Workbook::Cell] the diff cell
|
96
|
-
def create_diff_cell(scell, ocell)
|
97
|
-
dcell = scell.nil? ? Workbook::Cell.new(nil) : scell
|
98
|
-
if (scell == ocell)
|
99
|
-
dcell.format = scell.format if scell
|
100
|
-
elsif scell.nil?
|
101
|
-
dcell = Workbook::Cell.new "(was: #{ocell.to_s})"
|
102
|
-
dcell.format = diff_template.template.create_or_find_format_by 'destroyed'
|
103
|
-
elsif ocell.nil?
|
104
|
-
dcell = scell.clone
|
105
|
-
fmt = scell.nil? ? :default : scell.format[:number_format]
|
106
|
-
f = diff_template.template.create_or_find_format_by 'created', fmt
|
107
|
-
f[:number_format] = scell.format[:number_format]
|
108
|
-
dcell.format = f
|
109
|
-
elsif scell != ocell
|
110
|
-
dcell = Workbook::Cell.new "#{scell.to_s} (was: #{ocell.to_s})"
|
111
|
-
f = diff_template.template.create_or_find_format_by 'updated'
|
112
|
-
dcell.format = f
|
113
|
-
end
|
114
|
-
|
115
|
-
dcell
|
116
|
-
end
|
117
|
-
|
118
93
|
# Return template table to write the diff result in; in case non exists a default is generated.
|
119
94
|
#
|
120
95
|
# @return [Workbook::Table] the empty table, linked to a book
|
@@ -131,71 +106,105 @@ module Workbook
|
|
131
106
|
# @param [Workbook::Table] table to diff inside
|
132
107
|
# @return [Workbook::Table] the passed table
|
133
108
|
def diff_template= table
|
134
|
-
@diff_template= table
|
109
|
+
@diff_template = table
|
135
110
|
end
|
136
111
|
|
137
112
|
# aligns itself with another table, used by diff
|
138
113
|
#
|
139
114
|
# @param [Workbook::Table] other table to align with
|
140
115
|
# @param [Hash] options default to: `{:sort=>true,:ignore_headers=>false}`
|
141
|
-
def align other, options={
|
142
|
-
|
143
|
-
options = {:sort=>true,:ignore_headers=>false}.merge(options)
|
116
|
+
def align other, options = {}
|
117
|
+
options = {sort: true, ignore_headers: false}.merge(options)
|
144
118
|
|
145
119
|
sother = other.clone.remove_empty_lines!
|
146
|
-
sself =
|
120
|
+
sself = clone.remove_empty_lines!
|
147
121
|
|
148
122
|
if options[:ignore_headers]
|
149
123
|
sother.header = false
|
150
124
|
sself.header = false
|
151
125
|
end
|
152
126
|
|
153
|
-
sother = options[:sort] ?
|
154
|
-
sself = options[:sort] ?
|
127
|
+
sother = options[:sort] ? sother.sort : sother
|
128
|
+
sself = options[:sort] ? sself.sort : sself
|
155
129
|
|
156
130
|
row_index = 0
|
157
|
-
while row_index < [sother.count,sself.count].max
|
131
|
+
while (row_index < [sother.count, sself.count].max) && (row_index < other.count + count)
|
158
132
|
row_index = align_row(sself, sother, row_index)
|
159
133
|
end
|
160
134
|
|
161
|
-
{:
|
135
|
+
{self: sself, other: sother}
|
162
136
|
end
|
163
137
|
|
138
|
+
def sort
|
139
|
+
clone.sort!
|
140
|
+
end
|
141
|
+
|
142
|
+
def sort!
|
143
|
+
header_row = @rows.delete_at(header_row_index) if header
|
144
|
+
@rows = [header_row] + @rows.sort
|
145
|
+
self
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
164
150
|
# for use in the align 'while' loop
|
165
151
|
def align_row sself, sother, row_index
|
166
152
|
asd = 0
|
167
|
-
if sself[row_index]
|
168
|
-
asd = sself[row_index].key <=> sother[row_index].key
|
169
|
-
elsif sself[row_index]
|
153
|
+
if sself.rows[row_index] && sother.rows[row_index]
|
154
|
+
asd = sself.rows[row_index].key <=> sother.rows[row_index].key
|
155
|
+
elsif sself.rows[row_index]
|
170
156
|
asd = -1
|
171
|
-
elsif sother[row_index]
|
157
|
+
elsif sother.rows[row_index]
|
172
158
|
asd = 1
|
173
159
|
end
|
174
|
-
if asd == -1
|
175
|
-
sother.insert row_index, placeholder_row
|
176
|
-
row_index -=
|
177
|
-
elsif asd == 1
|
178
|
-
sself.insert row_index, placeholder_row
|
179
|
-
row_index -=
|
160
|
+
if (asd == -1) && insert_placeholder?(sother, sself, row_index)
|
161
|
+
sother.rows.insert row_index, placeholder_row
|
162
|
+
row_index -= 2
|
163
|
+
elsif (asd == 1) && insert_placeholder?(sother, sself, row_index)
|
164
|
+
sself.rows.insert row_index, placeholder_row
|
165
|
+
row_index -= 2
|
180
166
|
end
|
181
167
|
|
182
|
-
row_index
|
168
|
+
row_index + 1
|
183
169
|
end
|
184
170
|
|
185
171
|
def insert_placeholder? sother, sself, row_index
|
186
|
-
(sother[row_index].nil?
|
187
|
-
|
172
|
+
(sother.rows[row_index].nil? || !sother.rows[row_index].placeholder?) &&
|
173
|
+
(sself.rows[row_index].nil? || !sself.rows[row_index].placeholder?)
|
188
174
|
end
|
189
175
|
|
190
176
|
# returns a placeholder row, for internal use only
|
191
177
|
def placeholder_row
|
192
|
-
if defined?(@placeholder_row)
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
178
|
+
return @placeholder_row if defined?(@placeholder_row) && !@placeholder_row.nil?
|
179
|
+
|
180
|
+
@placeholder_row = Workbook::Row.new [nil]
|
181
|
+
@placeholder_row.placeholder = true
|
182
|
+
@placeholder_row
|
183
|
+
end
|
184
|
+
|
185
|
+
# creates a new cell describing the difference between two cells
|
186
|
+
#
|
187
|
+
# @return [Workbook::Cell] the diff cell
|
188
|
+
def create_diff_cell(scell, ocell)
|
189
|
+
dcell = scell.nil? ? Workbook::Cell.new(nil) : scell
|
190
|
+
if scell == ocell
|
191
|
+
dcell.format = scell.format if scell
|
192
|
+
elsif scell.nil?
|
193
|
+
dcell = Workbook::Cell.new "(was: #{ocell})"
|
194
|
+
dcell.format = diff_template.template.create_or_find_format_by "destroyed"
|
195
|
+
elsif ocell.nil?
|
196
|
+
dcell = scell.clone
|
197
|
+
fmt = scell.nil? ? :default : scell.format[:number_format]
|
198
|
+
f = diff_template.template.create_or_find_format_by "created", fmt
|
199
|
+
f[:number_format] = scell.format[:number_format]
|
200
|
+
dcell.format = f
|
201
|
+
elsif scell != ocell
|
202
|
+
dcell = Workbook::Cell.new "#{scell} (was: #{ocell})"
|
203
|
+
f = diff_template.template.create_or_find_format_by "updated"
|
204
|
+
dcell.format = f
|
198
205
|
end
|
206
|
+
|
207
|
+
dcell
|
199
208
|
end
|
200
209
|
end
|
201
210
|
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
3
|
+
|
5
4
|
module Workbook
|
6
5
|
module Modules
|
7
6
|
# Adds support for storing raw objects, used in e.g. Format and Template
|
8
7
|
module RawObjectsStorage
|
9
|
-
|
10
8
|
# A raw is a 'raw' object, representing a workbook, or cell, or whatever... in a particular format (defined by its class)
|
11
|
-
def add_raw raw_object, options={}
|
12
|
-
class_of_obj = options[:raw_object_class]
|
13
|
-
raws[class_of_obj]=raw_object
|
9
|
+
def add_raw raw_object, options = {}
|
10
|
+
class_of_obj = options[:raw_object_class] || raw_object.class
|
11
|
+
raws[class_of_obj] = raw_object
|
14
12
|
end
|
15
13
|
|
16
14
|
# Returns true if there is a template for a certain class, otherwise false
|
@@ -21,8 +19,8 @@ module Workbook
|
|
21
19
|
# Returns raw data stored for a type of raw object (if available)
|
22
20
|
# @param [Class] raw_object_class (e.g. Spreadsheet::Format for the Spreadsheet-gem)
|
23
21
|
def return_raw_for raw_object_class
|
24
|
-
raws.each { |tc,t| return t if tc == raw_object_class}
|
25
|
-
|
22
|
+
raws.each { |tc, t| return t if tc == raw_object_class }
|
23
|
+
nil
|
26
24
|
end
|
27
25
|
|
28
26
|
# Remove all raw data references
|
@@ -1,22 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
2
|
# frozen_string_literal: true
|
3
|
+
|
5
4
|
module Workbook
|
6
5
|
module Modules
|
7
6
|
# Adds type parsing capabilities to e.g. a Cell.
|
7
|
+
#
|
8
|
+
# Cell#string_parsers can be appended with symbols referencing the
|
8
9
|
module TypeParser
|
9
|
-
|
10
10
|
# Cleans a text file from all kinds of different ways of representing new lines
|
11
11
|
# @param [String] csv_raw a raw csv string
|
12
12
|
def strip_win_chars csv_raw
|
13
|
-
csv_raw.gsub(/(\n\r|\r\n|\r)/,"\n")
|
13
|
+
csv_raw.gsub(/(\n\r|\r\n|\r)/, "\n")
|
14
14
|
end
|
15
15
|
|
16
16
|
# Return the different active string parsers
|
17
|
-
# @return [Array<Symbol>] A list of parsers
|
17
|
+
# @return [Array<Symbol>] A list of parsers, defaults to [:string_cleaner, :string_integer_converter, :string_boolean_converter]
|
18
18
|
def string_parsers
|
19
|
-
@string_parsers ||= [:string_cleaner
|
19
|
+
@string_parsers ||= [:string_cleaner, :string_integer_converter, :string_boolean_converter]
|
20
20
|
end
|
21
21
|
|
22
22
|
# Set the list of string parsers
|
@@ -29,15 +29,17 @@ module Workbook
|
|
29
29
|
# Return the different active string parsers
|
30
30
|
# @return [Array<Proc>] A list of parsers as Procs
|
31
31
|
def string_parsers_as_procs
|
32
|
-
string_parsers.collect{|c| c.is_a?(Proc) ? c :
|
32
|
+
string_parsers.collect { |c| c.is_a?(Proc) ? c : send(c) }
|
33
33
|
end
|
34
34
|
|
35
35
|
# Returns the parsed value (retrieved by calling #value)
|
36
36
|
# @return [Object] The parsed object, ideally a date or integer when found to be a such...
|
37
|
-
def parse options={}
|
38
|
-
options = {:
|
37
|
+
def parse options = {}
|
38
|
+
options = {detect_date: false, convert_empty_to_nil: true}.merge(options)
|
39
|
+
|
39
40
|
string_parsers.push :string_optimistic_date_converter if options[:detect_date]
|
40
41
|
string_parsers.push :string_nil_converter if options[:convert_empty_to_nil]
|
42
|
+
|
41
43
|
v = value
|
42
44
|
string_parsers_as_procs.each do |p|
|
43
45
|
if v.is_a? String
|
@@ -47,27 +49,30 @@ module Workbook
|
|
47
49
|
v
|
48
50
|
end
|
49
51
|
|
50
|
-
def parse! options={}
|
52
|
+
def parse! options = {}
|
51
53
|
self.value = parse(options)
|
52
54
|
end
|
53
55
|
|
54
|
-
def clean! options={}
|
56
|
+
def clean! options = {}
|
55
57
|
parse! options
|
56
58
|
end
|
57
59
|
|
60
|
+
# @return [Proc] that does some cleaning in strings
|
58
61
|
def string_cleaner
|
59
62
|
proc do |v|
|
60
63
|
v = v.strip
|
61
|
-
v.gsub(
|
64
|
+
v.gsub("mailto:", "")
|
62
65
|
end
|
63
66
|
end
|
64
67
|
|
68
|
+
# @return [Proc] that returns nil for an empty string
|
65
69
|
def string_nil_converter
|
66
70
|
proc do |v|
|
67
71
|
(v == "" ? nil : v)
|
68
72
|
end
|
69
73
|
end
|
70
74
|
|
75
|
+
# @return [Proc] that tries to distill an integer
|
71
76
|
def string_integer_converter
|
72
77
|
proc do |v|
|
73
78
|
if v.to_i.to_s == v
|
@@ -78,19 +83,20 @@ module Workbook
|
|
78
83
|
end
|
79
84
|
end
|
80
85
|
|
86
|
+
# @return [Proc] that tries to distill a date from a string
|
81
87
|
def string_optimistic_date_converter
|
82
88
|
proc do |v|
|
83
89
|
if v
|
84
90
|
rv = v
|
85
|
-
starts_with_nr = v.
|
86
|
-
no_spaced_dash = v.to_s.match(" - ")
|
87
|
-
min_two_dashes = v.to_s.scan("-").count > 1
|
88
|
-
min_two_dashes = v.to_s.scan("/").count > 1
|
91
|
+
starts_with_nr = v[0].to_i.to_s == v[0] # it should at least start with a number...
|
92
|
+
no_spaced_dash = !v.to_s.match?(" - ")
|
93
|
+
min_two_dashes = v.to_s.scan("-").count > 1
|
94
|
+
min_two_dashes = v.to_s.scan("/").count > 1 if min_two_dashes == false
|
89
95
|
|
90
96
|
normal_date_length = v.to_s.length <= 25
|
91
|
-
if no_spaced_dash
|
97
|
+
if no_spaced_dash && starts_with_nr && normal_date_length && min_two_dashes
|
92
98
|
begin
|
93
|
-
rv =
|
99
|
+
rv = v.length > 10 ? DateTime.parse(v) : Date.parse(v)
|
94
100
|
rescue ArgumentError
|
95
101
|
rv = v
|
96
102
|
end
|
@@ -104,14 +110,15 @@ module Workbook
|
|
104
110
|
end
|
105
111
|
end
|
106
112
|
|
113
|
+
# @return [Proc] that tries to distill a date from a string
|
107
114
|
def string_american_date_converter
|
108
115
|
proc do |v|
|
109
116
|
if v
|
110
117
|
rv = v
|
111
118
|
# try strptime with format 'mm/dd/yyyy'
|
112
|
-
if rv.is_a?(String) && /^\d{1,2}[\/-]\d{1,2}[\/-]\d{4}
|
119
|
+
if rv.is_a?(String) && /^\d{1,2}[\/-]\d{1,2}[\/-]\d{4}$/ =~ v
|
113
120
|
begin
|
114
|
-
rv = Date.strptime(v, "%m/%d/%Y")
|
121
|
+
rv = Date.strptime(v.tr("-", "/"), "%m/%d/%Y")
|
115
122
|
rescue ArgumentError
|
116
123
|
end
|
117
124
|
end
|
@@ -120,13 +127,14 @@ module Workbook
|
|
120
127
|
end
|
121
128
|
end
|
122
129
|
|
130
|
+
# @return [Proc] that tries to distill a date from a string
|
123
131
|
def string_non_american_date_converter
|
124
132
|
proc do |v|
|
125
133
|
rv = v
|
126
134
|
# try strptime with format 'mm/dd/yyyy'
|
127
|
-
if rv.is_a?(String) && /^\d{1,2}[
|
135
|
+
if rv.is_a?(String) && /^\d{1,2}[\/\-.]\d{1,2}[\/\-.]\d{4}$/ =~ v
|
128
136
|
begin
|
129
|
-
rv = Date.strptime(v, "%m/%
|
137
|
+
rv = Date.strptime(v.gsub(/[-.]/, "/"), "%d/%m/%Y")
|
130
138
|
rescue ArgumentError
|
131
139
|
end
|
132
140
|
end
|
data/lib/workbook/nil_value.rb
CHANGED
@@ -1,14 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Workbook
|
4
|
-
|
5
4
|
# Used in cases col or rowspans are used
|
6
5
|
class NilValue
|
7
|
-
|
8
6
|
# initialize this special nilvalue with a reason
|
9
7
|
# @param [String] reason (currently only :covered, in case this cell is coverd because an adjecant cell spans over it)
|
10
8
|
def initialize reason
|
11
|
-
self.reason= reason
|
9
|
+
self.reason = reason
|
12
10
|
end
|
13
11
|
|
14
12
|
# returns the value of itself (nil)
|
@@ -17,13 +15,11 @@ module Workbook
|
|
17
15
|
nil
|
18
16
|
end
|
19
17
|
|
20
|
-
def <=>
|
21
|
-
value <=>
|
18
|
+
def <=> other
|
19
|
+
value <=> other
|
22
20
|
end
|
23
21
|
|
24
|
-
|
25
|
-
@reason
|
26
|
-
end
|
22
|
+
attr_reader :reason
|
27
23
|
|
28
24
|
# set the reason why this value is nil
|
29
25
|
def reason= reason
|
@@ -33,6 +29,5 @@ module Workbook
|
|
33
29
|
raise "invalid reason given"
|
34
30
|
end
|
35
31
|
end
|
36
|
-
|
37
32
|
end
|
38
33
|
end
|
@@ -1,20 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# -*- encoding : utf-8 -*-
|
4
|
-
|
5
3
|
module Workbook
|
6
4
|
module Readers
|
7
5
|
module CsvReader
|
8
|
-
def load_csv text, options={}
|
6
|
+
def load_csv text, options = {}
|
9
7
|
csv = text
|
10
8
|
parse_csv csv, options
|
11
9
|
end
|
12
10
|
|
13
11
|
def csv_lib
|
14
|
-
|
12
|
+
CSV
|
15
13
|
end
|
16
14
|
|
17
|
-
def parse_csv csv_raw, options={}
|
15
|
+
def parse_csv csv_raw, options = {}
|
18
16
|
optimistic_date_converter = Workbook::Cell.new.string_optimistic_date_converter
|
19
17
|
options = {
|
20
18
|
converters: [optimistic_date_converter, :all]
|
@@ -23,20 +21,19 @@ module Workbook
|
|
23
21
|
csv = nil
|
24
22
|
|
25
23
|
begin
|
26
|
-
csv = CSV.parse(csv_raw, options)
|
24
|
+
csv = CSV.parse(csv_raw, **options)
|
27
25
|
rescue CSV::MalformedCSVError
|
28
|
-
csv_excel = CSV.parse(csv_raw,options.merge({:
|
26
|
+
csv_excel = CSV.parse(csv_raw, **options.merge({col_sep: ";"}))
|
29
27
|
csv = csv_excel if csv_excel[0].count > 1
|
30
28
|
end
|
31
29
|
|
32
|
-
if csv
|
33
|
-
csv_excel = CSV.parse(csv_raw,options.merge({:
|
30
|
+
if csv.nil? || (csv[0].count == 1)
|
31
|
+
csv_excel = CSV.parse(csv_raw, **options.merge({col_sep: ";"}))
|
34
32
|
csv = csv_excel if csv_excel[0].count > 1
|
35
33
|
end
|
36
34
|
|
37
35
|
self[0] = Workbook::Sheet.new(csv, self) unless sheet.has_contents?
|
38
36
|
end
|
39
|
-
|
40
37
|
end
|
41
38
|
end
|
42
39
|
end
|