workbook 0.8.1 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|