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