roo 2.7.0 → 2.8.3
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 +5 -5
- data/.github/issue_template.md +16 -0
- data/.github/pull_request_template.md +14 -0
- data/.rubocop.yml +186 -0
- data/.travis.yml +12 -7
- data/CHANGELOG.md +53 -2
- data/LICENSE +2 -0
- data/README.md +29 -13
- data/lib/roo/base.rb +69 -61
- data/lib/roo/constants.rb +5 -3
- data/lib/roo/csv.rb +20 -12
- data/lib/roo/excelx/cell/base.rb +26 -12
- data/lib/roo/excelx/cell/boolean.rb +9 -6
- data/lib/roo/excelx/cell/date.rb +7 -7
- data/lib/roo/excelx/cell/datetime.rb +14 -18
- data/lib/roo/excelx/cell/empty.rb +3 -2
- data/lib/roo/excelx/cell/number.rb +35 -34
- data/lib/roo/excelx/cell/string.rb +3 -3
- data/lib/roo/excelx/cell/time.rb +4 -3
- data/lib/roo/excelx/cell.rb +10 -6
- data/lib/roo/excelx/comments.rb +3 -3
- data/lib/roo/excelx/coordinate.rb +11 -4
- data/lib/roo/excelx/extractor.rb +21 -3
- data/lib/roo/excelx/format.rb +38 -31
- data/lib/roo/excelx/images.rb +26 -0
- data/lib/roo/excelx/relationships.rb +12 -4
- data/lib/roo/excelx/shared.rb +10 -3
- data/lib/roo/excelx/shared_strings.rb +9 -15
- data/lib/roo/excelx/sheet.rb +49 -10
- data/lib/roo/excelx/sheet_doc.rb +89 -48
- data/lib/roo/excelx/styles.rb +3 -3
- data/lib/roo/excelx/workbook.rb +7 -3
- data/lib/roo/excelx.rb +42 -16
- data/lib/roo/helpers/default_attr_reader.rb +20 -0
- data/lib/roo/helpers/weak_instance_cache.rb +41 -0
- data/lib/roo/open_office.rb +8 -6
- data/lib/roo/spreadsheet.rb +1 -1
- data/lib/roo/utils.rb +70 -20
- data/lib/roo/version.rb +1 -1
- data/lib/roo.rb +4 -1
- data/roo.gemspec +13 -11
- data/spec/lib/roo/base_spec.rb +45 -3
- data/spec/lib/roo/excelx/relationships_spec.rb +43 -0
- data/spec/lib/roo/excelx/sheet_doc_spec.rb +11 -0
- data/spec/lib/roo/excelx_spec.rb +150 -31
- data/spec/lib/roo/strict_spec.rb +43 -0
- data/spec/lib/roo/utils_spec.rb +25 -3
- data/spec/lib/roo/weak_instance_cache_spec.rb +92 -0
- data/spec/lib/roo_spec.rb +0 -0
- data/spec/spec_helper.rb +1 -1
- data/test/excelx/cell/test_attr_reader_default.rb +72 -0
- data/test/excelx/cell/test_base.rb +5 -0
- data/test/excelx/cell/test_datetime.rb +6 -6
- data/test/excelx/cell/test_empty.rb +11 -0
- data/test/excelx/cell/test_number.rb +9 -0
- data/test/excelx/cell/test_string.rb +20 -0
- data/test/excelx/cell/test_time.rb +4 -4
- data/test/excelx/test_coordinate.rb +51 -0
- data/test/formatters/test_csv.rb +19 -2
- data/test/formatters/test_xml.rb +13 -9
- data/test/helpers/test_accessing_files.rb +60 -0
- data/test/helpers/test_comments.rb +43 -0
- data/test/helpers/test_formulas.rb +9 -0
- data/test/helpers/test_labels.rb +103 -0
- data/test/helpers/test_sheets.rb +55 -0
- data/test/helpers/test_styles.rb +62 -0
- data/test/roo/test_base.rb +182 -0
- data/test/roo/test_csv.rb +37 -1
- data/test/roo/test_excelx.rb +157 -13
- data/test/roo/test_open_office.rb +196 -33
- data/test/test_helper.rb +66 -22
- data/test/test_roo.rb +32 -881
- metadata +32 -14
- data/.github/ISSUE_TEMPLATE +0 -10
- data/Gemfile_ruby2 +0 -30
data/lib/roo/base.rb
CHANGED
@@ -1,9 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require 'nokogiri'
|
6
|
-
require 'roo/utils'
|
1
|
+
require "tmpdir"
|
2
|
+
require "stringio"
|
3
|
+
require "nokogiri"
|
4
|
+
require "roo/utils"
|
7
5
|
require "roo/formatters/base"
|
8
6
|
require "roo/formatters/csv"
|
9
7
|
require "roo/formatters/matrix"
|
@@ -19,8 +17,8 @@ class Roo::Base
|
|
19
17
|
include Roo::Formatters::XML
|
20
18
|
include Roo::Formatters::YAML
|
21
19
|
|
22
|
-
MAX_ROW_COL = 999_999
|
23
|
-
MIN_ROW_COL = 0
|
20
|
+
MAX_ROW_COL = 999_999
|
21
|
+
MIN_ROW_COL = 0
|
24
22
|
|
25
23
|
attr_reader :headers
|
26
24
|
|
@@ -28,7 +26,7 @@ class Roo::Base
|
|
28
26
|
attr_accessor :header_line
|
29
27
|
|
30
28
|
def self.TEMP_PREFIX
|
31
|
-
warn
|
29
|
+
warn "[DEPRECATION] please access TEMP_PREFIX via Roo::TEMP_PREFIX"
|
32
30
|
Roo::TEMP_PREFIX
|
33
31
|
end
|
34
32
|
|
@@ -56,6 +54,11 @@ class Roo::Base
|
|
56
54
|
if self.class.respond_to?(:finalize_tempdirs)
|
57
55
|
self.class.finalize_tempdirs(object_id)
|
58
56
|
end
|
57
|
+
|
58
|
+
instance_variables.each do |instance_variable|
|
59
|
+
instance_variable_set(instance_variable, nil)
|
60
|
+
end
|
61
|
+
|
59
62
|
nil
|
60
63
|
end
|
61
64
|
|
@@ -64,10 +67,10 @@ class Roo::Base
|
|
64
67
|
end
|
65
68
|
|
66
69
|
# sets the working sheet in the document
|
67
|
-
# 'sheet' can be a number (
|
70
|
+
# 'sheet' can be a number (0 = first sheet) or the name of a sheet.
|
68
71
|
def default_sheet=(sheet)
|
69
72
|
validate_sheet!(sheet)
|
70
|
-
@default_sheet = sheet
|
73
|
+
@default_sheet = sheet.is_a?(String) ? sheet : sheets[sheet]
|
71
74
|
@first_row[sheet] = @last_row[sheet] = @first_column[sheet] = @last_column[sheet] = nil
|
72
75
|
@cells_read[sheet] = false
|
73
76
|
end
|
@@ -100,7 +103,7 @@ class Roo::Base
|
|
100
103
|
def collect_last_row_col_for_sheet(sheet)
|
101
104
|
first_row = first_column = MAX_ROW_COL
|
102
105
|
last_row = last_column = MIN_ROW_COL
|
103
|
-
@cell[sheet].each_pair do|key, value|
|
106
|
+
@cell[sheet].each_pair do |key, value|
|
104
107
|
next unless value
|
105
108
|
first_row = [first_row, key.first.to_i].min
|
106
109
|
last_row = [last_row, key.first.to_i].max
|
@@ -110,13 +113,12 @@ class Roo::Base
|
|
110
113
|
{ first_row: first_row, first_column: first_column, last_row: last_row, last_column: last_column }
|
111
114
|
end
|
112
115
|
|
113
|
-
%
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
EOS
|
116
|
+
%i(first_row last_row first_column last_column).each do |key|
|
117
|
+
ivar = "@#{key}".to_sym
|
118
|
+
define_method(key) do |sheet = default_sheet|
|
119
|
+
read_cells(sheet)
|
120
|
+
instance_variable_get(ivar)[sheet] ||= first_last_row_col_for_sheet(sheet)[key]
|
121
|
+
end
|
120
122
|
end
|
121
123
|
|
122
124
|
def inspect
|
@@ -203,16 +205,16 @@ class Roo::Base
|
|
203
205
|
"Number of sheets: #{sheets.size}\n"\
|
204
206
|
"Sheets: #{sheets.join(', ')}\n"
|
205
207
|
n = 1
|
206
|
-
sheets.each do|sheet|
|
208
|
+
sheets.each do |sheet|
|
207
209
|
self.default_sheet = sheet
|
208
|
-
result <<
|
210
|
+
result << "Sheet " + n.to_s + ":\n"
|
209
211
|
if first_row
|
210
212
|
result << " First row: #{first_row}\n"
|
211
213
|
result << " Last row: #{last_row}\n"
|
212
214
|
result << " First column: #{::Roo::Utils.number_to_letter(first_column)}\n"
|
213
215
|
result << " Last column: #{::Roo::Utils.number_to_letter(last_column)}"
|
214
216
|
else
|
215
|
-
result <<
|
217
|
+
result << " - empty -"
|
216
218
|
end
|
217
219
|
result << "\n" if sheet != sheets.last
|
218
220
|
n += 1
|
@@ -286,39 +288,42 @@ class Roo::Base
|
|
286
288
|
clean_sheet_if_need(options)
|
287
289
|
search_or_set_header(options)
|
288
290
|
headers = @headers ||
|
289
|
-
|
290
|
-
[cell(@header_line, col)
|
291
|
-
end
|
291
|
+
(first_column..last_column).each_with_object({}) do |col, hash|
|
292
|
+
hash[cell(@header_line, col)] = col
|
293
|
+
end
|
292
294
|
|
293
295
|
@header_line.upto(last_row) do |line|
|
294
|
-
yield(
|
296
|
+
yield(headers.each_with_object({}) { |(k, v), hash| hash[k] = cell(line, v) })
|
295
297
|
end
|
296
298
|
end
|
297
299
|
end
|
298
300
|
|
299
301
|
def parse(options = {})
|
300
|
-
|
301
|
-
|
302
|
-
yield(row) if block_given?
|
303
|
-
ary << row
|
302
|
+
results = each(options).map do |row|
|
303
|
+
block_given? ? yield(row) : row
|
304
304
|
end
|
305
|
-
|
305
|
+
|
306
|
+
options[:headers] == true ? results : results.drop(1)
|
306
307
|
end
|
307
308
|
|
308
309
|
def row_with(query, return_headers = false)
|
309
310
|
line_no = 0
|
311
|
+
closest_mismatched_headers = []
|
310
312
|
each do |row|
|
311
313
|
line_no += 1
|
312
314
|
headers = query.map { |q| row.grep(q)[0] }.compact
|
313
|
-
|
314
315
|
if headers.length == query.length
|
315
316
|
@header_line = line_no
|
316
317
|
return return_headers ? headers : line_no
|
317
|
-
|
318
|
-
|
318
|
+
else
|
319
|
+
closest_mismatched_headers = headers if headers.length > closest_mismatched_headers.length
|
320
|
+
if line_no > 100
|
321
|
+
break
|
322
|
+
end
|
319
323
|
end
|
320
324
|
end
|
321
|
-
|
325
|
+
missing_headers = query.select { |q| closest_mismatched_headers.grep(q).empty? }
|
326
|
+
raise Roo::HeaderRowNotFoundError, missing_headers
|
322
327
|
end
|
323
328
|
|
324
329
|
protected
|
@@ -331,7 +336,7 @@ class Roo::Base
|
|
331
336
|
filename = File.basename(filename, File.extname(filename))
|
332
337
|
end
|
333
338
|
|
334
|
-
if uri?(filename) && (qs_begin = filename.rindex(
|
339
|
+
if uri?(filename) && (qs_begin = filename.rindex("?"))
|
335
340
|
filename = filename[0..qs_begin - 1]
|
336
341
|
end
|
337
342
|
exts = Array(exts)
|
@@ -357,7 +362,7 @@ class Roo::Base
|
|
357
362
|
# Diese Methode ist eine temp. Loesung, um zu erforschen, ob der
|
358
363
|
# Zugriff mit numerischen Keys schneller ist.
|
359
364
|
def key_to_num(str)
|
360
|
-
r, c = str.split(
|
365
|
+
r, c = str.split(",")
|
361
366
|
[r.to_i, c.to_i]
|
362
367
|
end
|
363
368
|
|
@@ -419,9 +424,9 @@ class Roo::Base
|
|
419
424
|
|
420
425
|
def find_by_conditions(options)
|
421
426
|
rows = first_row.upto(last_row)
|
422
|
-
header_for =
|
423
|
-
[col
|
424
|
-
end
|
427
|
+
header_for = 1.upto(last_column).each_with_object({}) do |col, hash|
|
428
|
+
hash[col] = cell(@header_line, col)
|
429
|
+
end
|
425
430
|
|
426
431
|
# are all conditions met?
|
427
432
|
conditions = options[:conditions]
|
@@ -436,9 +441,9 @@ class Roo::Base
|
|
436
441
|
rows.map { |i| row(i) }
|
437
442
|
else
|
438
443
|
rows.map do |i|
|
439
|
-
|
440
|
-
[header_for.fetch(j)
|
441
|
-
end
|
444
|
+
1.upto(row(i).size).each_with_object({}) do |j, hash|
|
445
|
+
hash[header_for.fetch(j)] = cell(i, j)
|
446
|
+
end
|
442
447
|
end
|
443
448
|
end
|
444
449
|
end
|
@@ -456,7 +461,7 @@ class Roo::Base
|
|
456
461
|
|
457
462
|
def find_basename(filename)
|
458
463
|
if uri?(filename)
|
459
|
-
require
|
464
|
+
require "uri"
|
460
465
|
uri = URI.parse filename
|
461
466
|
File.basename(uri.path)
|
462
467
|
elsif !is_stream?(filename)
|
@@ -465,9 +470,9 @@ class Roo::Base
|
|
465
470
|
end
|
466
471
|
|
467
472
|
def make_tmpdir(prefix = nil, root = nil, &block)
|
468
|
-
warn
|
473
|
+
warn "[DEPRECATION] extend Roo::Tempdir and use its .make_tempdir instead"
|
469
474
|
prefix = "#{Roo::TEMP_PREFIX}#{prefix}"
|
470
|
-
root ||= ENV[
|
475
|
+
root ||= ENV["ROO_TMP"]
|
471
476
|
|
472
477
|
if block_given?
|
473
478
|
# folder is deleted at end of block
|
@@ -486,14 +491,17 @@ class Roo::Base
|
|
486
491
|
end
|
487
492
|
|
488
493
|
def sanitize_value(v)
|
489
|
-
v.gsub(/[[:cntrl:]]|^[\p{Space}]+|[\p{Space}]+$/,
|
494
|
+
v.gsub(/[[:cntrl:]]|^[\p{Space}]+|[\p{Space}]+$/, "")
|
490
495
|
end
|
491
496
|
|
492
497
|
def set_headers(hash = {})
|
493
498
|
# try to find header row with all values or give an error
|
494
499
|
# then create new hash by indexing strings and keeping integers for header array
|
495
|
-
|
496
|
-
@headers =
|
500
|
+
header_row = row_with(hash.values, true)
|
501
|
+
@headers = {}
|
502
|
+
hash.each_with_index do |(key, _), index|
|
503
|
+
@headers[key] = header_index(header_row[index])
|
504
|
+
end
|
497
505
|
end
|
498
506
|
|
499
507
|
def header_index(query)
|
@@ -526,17 +534,17 @@ class Roo::Base
|
|
526
534
|
end
|
527
535
|
|
528
536
|
def uri?(filename)
|
529
|
-
filename.start_with?(
|
537
|
+
filename.start_with?("http://", "https://", "ftp://")
|
530
538
|
rescue
|
531
539
|
false
|
532
540
|
end
|
533
541
|
|
534
542
|
def download_uri(uri, tmpdir)
|
535
|
-
require
|
543
|
+
require "open-uri"
|
536
544
|
tempfilename = File.join(tmpdir, find_basename(uri))
|
537
545
|
begin
|
538
|
-
File.open(tempfilename,
|
539
|
-
open(uri,
|
546
|
+
File.open(tempfilename, "wb") do |file|
|
547
|
+
open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") do |net|
|
540
548
|
file.write(net.read)
|
541
549
|
end
|
542
550
|
end
|
@@ -547,15 +555,15 @@ class Roo::Base
|
|
547
555
|
end
|
548
556
|
|
549
557
|
def open_from_stream(stream, tmpdir)
|
550
|
-
tempfilename = File.join(tmpdir,
|
551
|
-
File.open(tempfilename,
|
558
|
+
tempfilename = File.join(tmpdir, "spreadsheet")
|
559
|
+
File.open(tempfilename, "wb") do |file|
|
552
560
|
file.write(stream[7..-1])
|
553
561
|
end
|
554
|
-
File.join(tmpdir,
|
562
|
+
File.join(tmpdir, "spreadsheet")
|
555
563
|
end
|
556
564
|
|
557
565
|
def unzip(filename, tmpdir)
|
558
|
-
require
|
566
|
+
require "zip/filesystem"
|
559
567
|
|
560
568
|
Zip::File.open(filename) do |zip|
|
561
569
|
process_zipfile_packed(zip, tmpdir)
|
@@ -568,7 +576,7 @@ class Roo::Base
|
|
568
576
|
when nil
|
569
577
|
fail ArgumentError, "Error: sheet 'nil' not valid"
|
570
578
|
when Integer
|
571
|
-
sheets.fetch(sheet
|
579
|
+
sheets.fetch(sheet) do
|
572
580
|
fail RangeError, "sheet index #{sheet} not found"
|
573
581
|
end
|
574
582
|
when String
|
@@ -580,16 +588,16 @@ class Roo::Base
|
|
580
588
|
end
|
581
589
|
end
|
582
590
|
|
583
|
-
def process_zipfile_packed(zip, tmpdir, path =
|
591
|
+
def process_zipfile_packed(zip, tmpdir, path = "")
|
584
592
|
if zip.file.file? path
|
585
593
|
# extract and return filename
|
586
|
-
File.open(File.join(tmpdir, path),
|
594
|
+
File.open(File.join(tmpdir, path), "wb") do |file|
|
587
595
|
file.write(zip.read(path))
|
588
596
|
end
|
589
597
|
File.join(tmpdir, path)
|
590
598
|
else
|
591
599
|
ret = nil
|
592
|
-
path +=
|
600
|
+
path += "/" unless path.empty?
|
593
601
|
zip.dir.foreach(path) do |filename|
|
594
602
|
ret = process_zipfile_packed(zip, tmpdir, path + filename)
|
595
603
|
end
|
data/lib/roo/constants.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roo
|
2
|
-
ROO_EXCEL_NOTICE = "Excel support has been extracted to roo-xls due to its dependency on the GPL'd spreadsheet gem. Install roo-xls to use Roo::Excel."
|
3
|
-
ROO_EXCELML_NOTICE = "Excel SpreadsheetML support has been extracted to roo-xls. Install roo-xls to use Roo::Excel2003XML."
|
4
|
-
ROO_GOOGLE_NOTICE = "Google support has been extracted to roo-google. Install roo-google to use Roo::Google."
|
4
|
+
ROO_EXCEL_NOTICE = "Excel support has been extracted to roo-xls due to its dependency on the GPL'd spreadsheet gem. Install roo-xls to use Roo::Excel."
|
5
|
+
ROO_EXCELML_NOTICE = "Excel SpreadsheetML support has been extracted to roo-xls. Install roo-xls to use Roo::Excel2003XML."
|
6
|
+
ROO_GOOGLE_NOTICE = "Google support has been extracted to roo-google. Install roo-google to use Roo::Google."
|
5
7
|
end
|
data/lib/roo/csv.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "csv"
|
2
4
|
require "time"
|
3
5
|
|
@@ -63,25 +65,31 @@ module Roo
|
|
63
65
|
def read_cells(sheet = default_sheet)
|
64
66
|
sheet ||= default_sheet
|
65
67
|
return if @cells_read[sheet]
|
66
|
-
|
67
|
-
|
68
|
-
row_num = 1
|
68
|
+
row_num = 0
|
69
|
+
max_col_num = 0
|
69
70
|
|
70
71
|
each_row csv_options do |row|
|
71
|
-
|
72
|
-
|
72
|
+
row_num += 1
|
73
|
+
col_num = 0
|
74
|
+
|
75
|
+
row.each do |elem|
|
76
|
+
col_num += 1
|
77
|
+
coordinate = [row_num, col_num]
|
73
78
|
@cell[coordinate] = elem
|
74
79
|
@cell_type[coordinate] = celltype_class(elem)
|
75
80
|
end
|
76
|
-
|
81
|
+
|
82
|
+
max_col_num = col_num if col_num > max_col_num
|
77
83
|
end
|
78
84
|
|
85
|
+
set_row_count(sheet, row_num)
|
86
|
+
set_column_count(sheet, max_col_num)
|
79
87
|
@cells_read[sheet] = true
|
80
88
|
end
|
81
89
|
|
82
90
|
def each_row(options, &block)
|
83
91
|
if uri?(filename)
|
84
|
-
|
92
|
+
each_row_using_tempdir(options, &block)
|
85
93
|
elsif is_stream?(filename_or_stream)
|
86
94
|
::CSV.new(filename_or_stream, options).each(&block)
|
87
95
|
else
|
@@ -89,24 +97,24 @@ module Roo
|
|
89
97
|
end
|
90
98
|
end
|
91
99
|
|
92
|
-
def each_row_using_tempdir
|
100
|
+
def each_row_using_tempdir(options, &block)
|
93
101
|
::Dir.mktmpdir(Roo::TEMP_PREFIX, ENV["ROO_TMP"]) do |tmpdir|
|
94
102
|
tmp_filename = download_uri(filename, tmpdir)
|
95
103
|
::CSV.foreach(tmp_filename, options, &block)
|
96
104
|
end
|
97
105
|
end
|
98
106
|
|
99
|
-
def set_row_count(sheet)
|
107
|
+
def set_row_count(sheet, last_row)
|
100
108
|
@first_row[sheet] = 1
|
101
|
-
@last_row[sheet] =
|
109
|
+
@last_row[sheet] = last_row
|
102
110
|
@last_row[sheet] = @first_row[sheet] if @last_row[sheet].zero?
|
103
111
|
|
104
112
|
nil
|
105
113
|
end
|
106
114
|
|
107
|
-
def set_column_count(sheet)
|
115
|
+
def set_column_count(sheet, last_col)
|
108
116
|
@first_column[sheet] = 1
|
109
|
-
@last_column[sheet] =
|
117
|
+
@last_column[sheet] = last_col
|
110
118
|
@last_column[sheet] = @first_column[sheet] if @last_column[sheet].zero?
|
111
119
|
|
112
120
|
nil
|
data/lib/roo/excelx/cell/base.rb
CHANGED
@@ -1,13 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "roo/helpers/default_attr_reader"
|
4
|
+
|
1
5
|
module Roo
|
2
6
|
class Excelx
|
3
7
|
class Cell
|
4
8
|
class Base
|
9
|
+
extend Roo::Helpers::DefaultAttrReader
|
5
10
|
attr_reader :cell_type, :cell_value, :value
|
6
11
|
|
7
12
|
# FIXME: I think style should be deprecated. Having a style attribute
|
8
13
|
# for a cell doesn't really accomplish much. It seems to be used
|
9
14
|
# when you want to export to excelx.
|
10
|
-
|
15
|
+
attr_reader_with_default default_type: :base, style: 1
|
11
16
|
|
12
17
|
|
13
18
|
# FIXME: Updating a cell's value should be able tochange the cell's type,
|
@@ -34,14 +39,12 @@ module Roo
|
|
34
39
|
attr_writer :value
|
35
40
|
|
36
41
|
def initialize(value, formula, excelx_type, style, link, coordinate)
|
37
|
-
@link = !!link
|
38
42
|
@cell_value = value
|
39
|
-
@cell_type = excelx_type
|
40
|
-
@formula = formula
|
41
|
-
@style = style
|
43
|
+
@cell_type = excelx_type if excelx_type
|
44
|
+
@formula = formula if formula
|
45
|
+
@style = style unless style == 1
|
42
46
|
@coordinate = coordinate
|
43
|
-
@
|
44
|
-
@value = link? ? Roo::Link.new(link, value) : value
|
47
|
+
@value = link ? Roo::Link.new(link, value) : value
|
45
48
|
end
|
46
49
|
|
47
50
|
def type
|
@@ -50,16 +53,16 @@ module Roo
|
|
50
53
|
elsif link?
|
51
54
|
:link
|
52
55
|
else
|
53
|
-
|
56
|
+
default_type
|
54
57
|
end
|
55
58
|
end
|
56
59
|
|
57
60
|
def formula?
|
58
|
-
|
61
|
+
!!(defined?(@formula) && @formula)
|
59
62
|
end
|
60
63
|
|
61
64
|
def link?
|
62
|
-
|
65
|
+
Roo::Link === @value
|
63
66
|
end
|
64
67
|
|
65
68
|
alias_method :formatted_value, :value
|
@@ -68,9 +71,16 @@ module Roo
|
|
68
71
|
formatted_value
|
69
72
|
end
|
70
73
|
|
71
|
-
# DEPRECATED: Please use link instead.
|
74
|
+
# DEPRECATED: Please use link? instead.
|
72
75
|
def hyperlink
|
73
|
-
warn '[DEPRECATION] `hyperlink` is deprecated. Please use `link
|
76
|
+
warn '[DEPRECATION] `hyperlink` is deprecated. Please use `link?` instead.'
|
77
|
+
link?
|
78
|
+
end
|
79
|
+
|
80
|
+
# DEPRECATED: Please use link? instead.
|
81
|
+
def link
|
82
|
+
warn '[DEPRECATION] `link` is deprecated. Please use `link?` instead.'
|
83
|
+
link?
|
74
84
|
end
|
75
85
|
|
76
86
|
# DEPRECATED: Please use cell_value instead.
|
@@ -88,6 +98,10 @@ module Roo
|
|
88
98
|
def empty?
|
89
99
|
false
|
90
100
|
end
|
101
|
+
|
102
|
+
def presence
|
103
|
+
empty? ? nil : self
|
104
|
+
end
|
91
105
|
end
|
92
106
|
end
|
93
107
|
end
|
@@ -1,17 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Roo
|
2
4
|
class Excelx
|
3
5
|
class Cell
|
4
6
|
class Boolean < Cell::Base
|
5
|
-
attr_reader :value, :formula, :format, :
|
7
|
+
attr_reader :value, :formula, :format, :cell_value, :coordinate
|
8
|
+
|
9
|
+
attr_reader_with_default default_type: :boolean, cell_type: :boolean
|
6
10
|
|
7
11
|
def initialize(value, formula, style, link, coordinate)
|
8
|
-
super(value, formula, nil, style,
|
9
|
-
@
|
10
|
-
@value = link? ? Roo::Link.new(link, value) : create_boolean(value)
|
12
|
+
super(value, formula, nil, style, nil, coordinate)
|
13
|
+
@value = link ? Roo::Link.new(link, value) : create_boolean(value)
|
11
14
|
end
|
12
15
|
|
13
16
|
def formatted_value
|
14
|
-
value ? 'TRUE'
|
17
|
+
value ? 'TRUE' : 'FALSE'
|
15
18
|
end
|
16
19
|
|
17
20
|
private
|
@@ -19,7 +22,7 @@ module Roo
|
|
19
22
|
def create_boolean(value)
|
20
23
|
# FIXME: Using a boolean will cause methods like Base#to_csv to fail.
|
21
24
|
# Roo is using some method to ignore false/nil values.
|
22
|
-
value.to_i == 1
|
25
|
+
value.to_i == 1
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
data/lib/roo/excelx/cell/date.rb
CHANGED
@@ -4,23 +4,23 @@ module Roo
|
|
4
4
|
class Excelx
|
5
5
|
class Cell
|
6
6
|
class Date < Roo::Excelx::Cell::DateTime
|
7
|
-
attr_reader :value, :formula, :format, :cell_type, :cell_value, :
|
7
|
+
attr_reader :value, :formula, :format, :cell_type, :cell_value, :coordinate
|
8
|
+
|
9
|
+
attr_reader_with_default default_type: :date
|
8
10
|
|
9
11
|
def initialize(value, formula, excelx_type, style, link, base_date, coordinate)
|
10
12
|
# NOTE: Pass all arguments to the parent class, DateTime.
|
11
13
|
super
|
12
|
-
@type = :date
|
13
14
|
@format = excelx_type.last
|
14
|
-
@value = link
|
15
|
+
@value = link ? Roo::Link.new(link, value) : create_date(base_date, value)
|
15
16
|
end
|
16
17
|
|
17
18
|
private
|
18
19
|
|
19
|
-
def
|
20
|
-
date = base_date + value.to_i
|
21
|
-
yyyy, mm, dd = date.strftime('%Y-%m-%d').split('-')
|
20
|
+
def create_datetime(_,_); end
|
22
21
|
|
23
|
-
|
22
|
+
def create_date(base_date, value)
|
23
|
+
base_date + value.to_i
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -1,16 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'date'
|
2
4
|
|
3
5
|
module Roo
|
4
6
|
class Excelx
|
5
7
|
class Cell
|
6
8
|
class DateTime < Cell::Base
|
7
|
-
|
9
|
+
SECONDS_IN_DAY = 60 * 60 * 24
|
10
|
+
|
11
|
+
attr_reader :value, :formula, :format, :cell_value, :coordinate
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
|
13
|
+
attr_reader_with_default default_type: :datetime
|
14
|
+
|
15
|
+
def initialize(value, formula, excelx_type, style, link, base_timestamp, coordinate)
|
16
|
+
super(value, formula, excelx_type, style, nil, coordinate)
|
12
17
|
@format = excelx_type.last
|
13
|
-
@value = link
|
18
|
+
@value = link ? Roo::Link.new(link, value) : create_datetime(base_timestamp, value)
|
14
19
|
end
|
15
20
|
|
16
21
|
# Public: Returns formatted value for a datetime. Format's can be an
|
@@ -78,7 +83,7 @@ module Roo
|
|
78
83
|
|
79
84
|
TIME_FORMATS = {
|
80
85
|
'hh' => '%H', # Hour (24): 01
|
81
|
-
'h' => '%-k'
|
86
|
+
'h' => '%-k', # Hour (24): 1
|
82
87
|
# 'hh'.freeze => '%I'.freeze, # Hour (12): 08
|
83
88
|
# 'h'.freeze => '%-l'.freeze, # Hour (12): 8
|
84
89
|
'mm' => '%M', # Minute: 01
|
@@ -92,18 +97,9 @@ module Roo
|
|
92
97
|
'0' => '%1N' # Fractional Seconds: tenths.
|
93
98
|
}
|
94
99
|
|
95
|
-
def create_datetime(
|
96
|
-
|
97
|
-
|
98
|
-
t = round_datetime(datetime_string)
|
99
|
-
|
100
|
-
::DateTime.civil(t.year, t.month, t.day, t.hour, t.min, t.sec)
|
101
|
-
end
|
102
|
-
|
103
|
-
def round_datetime(datetime_string)
|
104
|
-
/(?<yyyy>\d+)-(?<mm>\d+)-(?<dd>\d+) (?<hh>\d+):(?<mi>\d+):(?<ss>\d+.\d+)/ =~ datetime_string
|
105
|
-
|
106
|
-
::Time.new(yyyy, mm, dd, hh, mi, ss.to_r).round(0)
|
100
|
+
def create_datetime(base_timestamp, value)
|
101
|
+
timestamp = (base_timestamp + (value.to_f.round(6) * SECONDS_IN_DAY)).round(0)
|
102
|
+
::Time.at(timestamp).utc.to_datetime
|
107
103
|
end
|
108
104
|
end
|
109
105
|
end
|
@@ -3,10 +3,11 @@ module Roo
|
|
3
3
|
class Excelx
|
4
4
|
class Cell
|
5
5
|
class Empty < Cell::Base
|
6
|
-
attr_reader :value, :formula, :format, :cell_type, :cell_value, :
|
6
|
+
attr_reader :value, :formula, :format, :cell_type, :cell_value, :coordinate
|
7
|
+
|
8
|
+
attr_reader_with_default default_type: nil, style: nil
|
7
9
|
|
8
10
|
def initialize(coordinate)
|
9
|
-
@value = @formula = @format = @cell_type = @cell_value = @hyperlink = nil
|
10
11
|
@coordinate = coordinate
|
11
12
|
end
|
12
13
|
|