roo 2.8.1 → 2.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/.github/workflows/ruby.yml +34 -0
- data/CHANGELOG.md +26 -0
- data/Gemfile +1 -0
- data/README.md +15 -3
- data/lib/roo/base.rb +1 -1
- data/lib/roo/csv.rb +10 -4
- data/lib/roo/excelx/cell/number.rb +2 -1
- data/lib/roo/excelx/cell/time.rb +1 -1
- data/lib/roo/excelx/relationships.rb +9 -1
- data/lib/roo/excelx/sheet_doc.rb +12 -13
- data/lib/roo/excelx.rb +13 -7
- data/lib/roo/spreadsheet.rb +8 -2
- data/lib/roo/utils.rb +22 -1
- data/lib/roo/version.rb +1 -1
- data/roo.gemspec +10 -3
- data/spec/lib/roo/excelx/cell/time_spec.rb +15 -0
- data/spec/lib/roo/excelx/relationships_spec.rb +43 -0
- data/spec/lib/roo/excelx_spec.rb +34 -1
- data/spec/lib/roo/spreadsheet_spec.rb +1 -1
- data/spec/lib/roo/utils_spec.rb +13 -9
- data/test/excelx/cell/test_attr_reader_default.rb +1 -1
- data/test/excelx/cell/test_number.rb +2 -0
- data/test/roo/test_excelx.rb +27 -1
- data/test/roo/test_open_office.rb +1 -1
- metadata +32 -17
- data/.travis.yml +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae372e5e7ed6c045de6911c323a805fa4f60c68c2e8cd96358db03a01ff3beef
|
|
4
|
+
data.tar.gz: 6a2f09854519bd5d1b233aafcd1cf58d29343dc48e3cc735498ea2696785fd24
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5dae710a3f90d9d7038b0c4813ac0b400e6c587c2cf00be9239e27294f60046b2748b090207fce2ebaa3139a3adc681d0063bec9c1e6ee7c91cde51de1ae5861
|
|
7
|
+
data.tar.gz: 34691a95ee37cf9af6640c2090d2542db2a84558829a42b4ecab13870e2d9e73ee1d0c243cb01d536d5709158cb746bf69b1e0d0a0888226f5906bf41566e542
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: Ruby
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- master
|
|
6
|
+
pull_request:
|
|
7
|
+
branches:
|
|
8
|
+
- master
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
ruby:
|
|
16
|
+
- '2.7'
|
|
17
|
+
- '3.0'
|
|
18
|
+
- '3.1'
|
|
19
|
+
- ruby-head
|
|
20
|
+
- jruby-9.3.3.0
|
|
21
|
+
include:
|
|
22
|
+
- ruby: ruby-head
|
|
23
|
+
env:
|
|
24
|
+
RUBYOPT: '--jit'
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v2
|
|
27
|
+
- uses: ruby/setup-ruby@v1
|
|
28
|
+
with:
|
|
29
|
+
ruby-version: ${{ matrix.ruby }}
|
|
30
|
+
bundler-cache: true
|
|
31
|
+
- run: bundle exec rake
|
|
32
|
+
env:
|
|
33
|
+
LONG_RUN: true
|
|
34
|
+
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
## Unreleased
|
|
2
2
|
|
|
3
|
+
## [2.9.0] 2022-03-19
|
|
4
|
+
|
|
5
|
+
### Changed/Added
|
|
6
|
+
- Ruby 3.x Support [555](https://github.com/roo-rb/roo/pull/555)
|
|
7
|
+
- Ignore all richdata at 'xl/richData' of XSLX [552](https://github.com/roo-rb/roo/pull/552)
|
|
8
|
+
- Only copy if cell is present when `expand_merged_ranges: true` [557](https://github.com/roo-rb/roo/pull/557)
|
|
9
|
+
- Fixes issue where the contents of hidden sheet was returned when parsing visible sheets only. [536](https://github.com/roo-rb/roo/pull/536)
|
|
10
|
+
- Add formats [525](https://github.com/roo-rb/roo/pull/525)
|
|
11
|
+
- Fix warnings caused by Ruby 2.7 update [530](https://github.com/roo-rb/roo/pull/530)
|
|
12
|
+
- Add formats [525](https://github.com/roo-rb/roo/pull/525)
|
|
13
|
+
|
|
14
|
+
### Removed
|
|
15
|
+
- Support for ruby 2.4, 2.5, 2.6(excluded jRuby)
|
|
16
|
+
|
|
17
|
+
## [2.8.3] 2020-02-03
|
|
18
|
+
### Changed/Added
|
|
19
|
+
- Updated rubyzip version. Now minimal version is 1.3.0 [515](https://github.com/roo-rb/roo/pull/515) - [CVE-2019-16892](https://github.com/rubyzip/rubyzip/pull/403)
|
|
20
|
+
|
|
21
|
+
## [2.8.2] 2019-02-01
|
|
22
|
+
### Changed/Added
|
|
23
|
+
- Support range cell for Excelx's links [490](https://github.com/roo-rb/roo/pull/490)
|
|
24
|
+
- Skip `extract_hyperlinks` if not required [488](https://github.com/roo-rb/roo/pull/488)
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
- Fixed error for invalid link [492](https://github.com/roo-rb/roo/pull/492)
|
|
28
|
+
|
|
3
29
|
## [2.8.1] 2019-01-21
|
|
4
30
|
### Fixed
|
|
5
31
|
- Fixed error if excelx's cell have empty children [487](https://github.com/roo-rb/roo/pull/487)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Install as a gem
|
|
|
18
18
|
Or add it to your Gemfile
|
|
19
19
|
|
|
20
20
|
```ruby
|
|
21
|
-
gem "roo", "~> 2.
|
|
21
|
+
gem "roo", "~> 2.8.0"
|
|
22
22
|
```
|
|
23
23
|
## Usage
|
|
24
24
|
|
|
@@ -249,7 +249,7 @@ ods.formula('A', 2)
|
|
|
249
249
|
csv = Roo::CSV.new("mycsv.csv")
|
|
250
250
|
```
|
|
251
251
|
|
|
252
|
-
Because Roo uses the
|
|
252
|
+
Because Roo uses the standard CSV library, you can use options available to that library to parse csv files. You can pass options using the ``csv_options`` key.
|
|
253
253
|
|
|
254
254
|
For instance, you can load tab-delimited files (``.tsv``), and you can use a particular encoding when opening the file.
|
|
255
255
|
|
|
@@ -262,6 +262,18 @@ csv = Roo::CSV.new("mytsv.tsv", csv_options: {col_sep: "\t"})
|
|
|
262
262
|
csv = Roo::CSV.new("mycsv.csv", csv_options: {encoding: Encoding::ISO_8859_1})
|
|
263
263
|
```
|
|
264
264
|
|
|
265
|
+
You can also open csv files through the Roo::Spreadsheet class (useful if you accept both CSV and Excel types from a user file upload, for example).
|
|
266
|
+
|
|
267
|
+
```ruby
|
|
268
|
+
# Load a spreadsheet from a file path
|
|
269
|
+
# Roo figures out the right parser based on file extension
|
|
270
|
+
spreadsheet = Roo::Spreadsheet.open(csv_or_xlsx_file)
|
|
271
|
+
|
|
272
|
+
# Load a csv and auto-strip the BOM (byte order mark)
|
|
273
|
+
# csv files saved from MS Excel typically have the BOM marker at the beginning of the file
|
|
274
|
+
spreadsheet = Roo::Spreadsheet.open("mycsv.csv", { csv_options: { encoding: 'bom|utf-8' } })
|
|
275
|
+
```
|
|
276
|
+
|
|
265
277
|
## Upgrading from Roo 1.13.x
|
|
266
278
|
If you use ``.xls`` or Google spreadsheets, you will need to install ``roo-xls`` or ``roo-google`` to continue using that functionality.
|
|
267
279
|
|
|
@@ -271,7 +283,7 @@ Roo's public methods have stayed relatively consistent between 1.13.x and 2.0.0,
|
|
|
271
283
|
|
|
272
284
|
## Contributing
|
|
273
285
|
### Features
|
|
274
|
-
1. Fork it ( https://github.com/
|
|
286
|
+
1. Fork it ( https://github.com/roo-rb/roo/fork )
|
|
275
287
|
2. Install it (`bundle install --with local_development`)
|
|
276
288
|
3. Create your feature branch (`git checkout -b my-new-feature`)
|
|
277
289
|
4. Commit your changes (`git commit -am 'My new feature'`)
|
data/lib/roo/base.rb
CHANGED
|
@@ -544,7 +544,7 @@ class Roo::Base
|
|
|
544
544
|
tempfilename = File.join(tmpdir, find_basename(uri))
|
|
545
545
|
begin
|
|
546
546
|
File.open(tempfilename, "wb") do |file|
|
|
547
|
-
open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") do |net|
|
|
547
|
+
URI.open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") do |net|
|
|
548
548
|
file.write(net.read)
|
|
549
549
|
end
|
|
550
550
|
end
|
data/lib/roo/csv.rb
CHANGED
|
@@ -90,17 +90,23 @@ module Roo
|
|
|
90
90
|
def each_row(options, &block)
|
|
91
91
|
if uri?(filename)
|
|
92
92
|
each_row_using_tempdir(options, &block)
|
|
93
|
-
elsif is_stream?(filename_or_stream)
|
|
94
|
-
::CSV.new(filename_or_stream, options).each(&block)
|
|
95
93
|
else
|
|
96
|
-
|
|
94
|
+
csv_foreach(filename_or_stream, options, &block)
|
|
97
95
|
end
|
|
98
96
|
end
|
|
99
97
|
|
|
100
98
|
def each_row_using_tempdir(options, &block)
|
|
101
99
|
::Dir.mktmpdir(Roo::TEMP_PREFIX, ENV["ROO_TMP"]) do |tmpdir|
|
|
102
100
|
tmp_filename = download_uri(filename, tmpdir)
|
|
103
|
-
|
|
101
|
+
csv_foreach(tmp_filename, options, &block)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def csv_foreach(path_or_io, options, &block)
|
|
106
|
+
if is_stream?(path_or_io)
|
|
107
|
+
::CSV.new(path_or_io, **options).each(&block)
|
|
108
|
+
else
|
|
109
|
+
::CSV.foreach(path_or_io, **options, &block)
|
|
104
110
|
end
|
|
105
111
|
end
|
|
106
112
|
|
|
@@ -48,7 +48,7 @@ module Roo
|
|
|
48
48
|
when /^(0+)$/ then "%0#{$1.size}d"
|
|
49
49
|
when /^0\.(0+)$/ then "%.#{$1.size}f"
|
|
50
50
|
when '#,##0' then number_format('%.0f')
|
|
51
|
-
when
|
|
51
|
+
when /^#,##0.(0+)$/ then number_format("%.#{$1.size}f")
|
|
52
52
|
when '0%'
|
|
53
53
|
proc do |number|
|
|
54
54
|
Kernel.format('%d%%', number.to_f * 100)
|
|
@@ -64,6 +64,7 @@ module Roo
|
|
|
64
64
|
when '#,##0.00;[Red](#,##0.00)' then number_format('%.2f', '[Red](%.2f)')
|
|
65
65
|
# FIXME: not quite sure what the format should look like in this case.
|
|
66
66
|
when '##0.0E+0' then '%.1E'
|
|
67
|
+
when "_-* #,##0.00\\ _€_-;\\-* #,##0.00\\ _€_-;_-* \"-\"??\\ _€_-;_-@_-" then number_format('%.2f', '-%.2f')
|
|
67
68
|
when '@' then proc { |number| number }
|
|
68
69
|
else
|
|
69
70
|
raise "Unknown format: #{format.inspect}"
|
data/lib/roo/excelx/cell/time.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Roo
|
|
|
13
13
|
super
|
|
14
14
|
@format = excelx_type.last
|
|
15
15
|
@datetime = create_datetime(base_date, value)
|
|
16
|
-
@value = link ? Roo::Link.new(link, value) : (value.to_f * 86_400).to_i
|
|
16
|
+
@value = link ? Roo::Link.new(link, value) : (value.to_f * 86_400).round.to_i
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def formatted_value
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require 'roo/excelx/extractor'
|
|
2
4
|
|
|
3
5
|
module Roo
|
|
@@ -11,10 +13,16 @@ module Roo
|
|
|
11
13
|
@relationships ||= extract_relationships
|
|
12
14
|
end
|
|
13
15
|
|
|
16
|
+
def include_type?(type)
|
|
17
|
+
to_a.any? do |_, rel|
|
|
18
|
+
rel["Type"]&.include? type
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
14
22
|
private
|
|
15
23
|
|
|
16
24
|
def extract_relationships
|
|
17
|
-
return
|
|
25
|
+
return {} unless doc_exists?
|
|
18
26
|
|
|
19
27
|
doc.xpath('/Relationships/Relationship').each_with_object({}) do |rel, hash|
|
|
20
28
|
hash[rel['Id']] = rel
|
data/lib/roo/excelx/sheet_doc.rb
CHANGED
|
@@ -22,7 +22,7 @@ module Roo
|
|
|
22
22
|
|
|
23
23
|
def hyperlinks(relationships)
|
|
24
24
|
# If you're sure you're not going to need this hyperlinks you can discard it
|
|
25
|
-
@hyperlinks ||= if @options[:no_hyperlinks]
|
|
25
|
+
@hyperlinks ||= if @options[:no_hyperlinks] || !relationships.include_type?("hyperlink")
|
|
26
26
|
{}
|
|
27
27
|
else
|
|
28
28
|
extract_hyperlinks(relationships)
|
|
@@ -101,12 +101,7 @@ module Roo
|
|
|
101
101
|
cell_xml_children.each do |cell|
|
|
102
102
|
case cell.name
|
|
103
103
|
when 'is'
|
|
104
|
-
content =
|
|
105
|
-
cell.children.each do |inline_str|
|
|
106
|
-
if inline_str.name == 't'
|
|
107
|
-
content << inline_str.content
|
|
108
|
-
end
|
|
109
|
-
end
|
|
104
|
+
content = cell.search('t').map(&:content).join
|
|
110
105
|
unless content.empty?
|
|
111
106
|
return Excelx::Cell.cell_class(:string).new(content, formula, style, hyperlink, coordinate)
|
|
112
107
|
end
|
|
@@ -185,7 +180,10 @@ module Roo
|
|
|
185
180
|
if relationship = relationships[hyperlink['id']]
|
|
186
181
|
target_link = relationship['Target']
|
|
187
182
|
target_link += "##{hyperlink['location']}" if hyperlink['location']
|
|
188
|
-
|
|
183
|
+
|
|
184
|
+
Roo::Utils.coordinates_in_range(hyperlink["ref"].to_s) do |coord|
|
|
185
|
+
hash[coord] = target_link
|
|
186
|
+
end
|
|
189
187
|
end
|
|
190
188
|
end
|
|
191
189
|
end
|
|
@@ -194,11 +192,12 @@ module Roo
|
|
|
194
192
|
# Extract merged ranges from xml
|
|
195
193
|
merges = {}
|
|
196
194
|
doc.xpath('/worksheet/mergeCells/mergeCell').each do |mergecell_xml|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
195
|
+
src, dst = mergecell_xml["ref"].split(/:/).map { |ref| ::Roo::Utils.ref_to_key(ref) }
|
|
196
|
+
next unless cells[src]
|
|
197
|
+
for row in src[0]..dst[0] do
|
|
198
|
+
for col in src[1]..dst[1] do
|
|
199
|
+
next if row == src[0] && col == src[1]
|
|
200
|
+
merges[[row, col]] = src
|
|
202
201
|
end
|
|
203
202
|
end
|
|
204
203
|
end
|
data/lib/roo/excelx.rb
CHANGED
|
@@ -60,15 +60,16 @@ module Roo
|
|
|
60
60
|
@filename = local_filename(filename_or_stream, @tmpdir, packed)
|
|
61
61
|
process_zipfile(@filename || filename_or_stream)
|
|
62
62
|
|
|
63
|
-
@sheet_names =
|
|
64
|
-
unless options[:only_visible_sheets] && sheet['state'] == 'hidden'
|
|
65
|
-
sheet['name']
|
|
66
|
-
end
|
|
67
|
-
end.compact
|
|
63
|
+
@sheet_names = []
|
|
68
64
|
@sheets = []
|
|
69
65
|
@sheets_by_name = {}
|
|
70
|
-
|
|
71
|
-
|
|
66
|
+
|
|
67
|
+
workbook.sheets.each_with_index do |sheet, index|
|
|
68
|
+
next if options[:only_visible_sheets] && sheet['state'] == 'hidden'
|
|
69
|
+
|
|
70
|
+
sheet_name = sheet['name']
|
|
71
|
+
@sheet_names << sheet_name
|
|
72
|
+
@sheets_by_name[sheet_name] = @sheets[index] = Sheet.new(sheet_name, @shared, index, sheet_options)
|
|
72
73
|
end
|
|
73
74
|
|
|
74
75
|
if cell_max
|
|
@@ -428,6 +429,11 @@ module Roo
|
|
|
428
429
|
entries.each do |entry|
|
|
429
430
|
path =
|
|
430
431
|
case entry.name.downcase
|
|
432
|
+
when /richdata/
|
|
433
|
+
# FIXME: Ignore richData as parsing is not implemented yet and can cause
|
|
434
|
+
# Zip::DestinationFileExistsError when including a second "styles.xml" entry
|
|
435
|
+
# see http://schemas.microsoft.com/office/spreadsheetml/2017/richdata2
|
|
436
|
+
nil
|
|
431
437
|
when /sharedstrings.xml$/
|
|
432
438
|
"#{@tmpdir}/roo_sharedStrings.xml"
|
|
433
439
|
when /styles.xml$/
|
data/lib/roo/spreadsheet.rb
CHANGED
|
@@ -24,8 +24,14 @@ module Roo
|
|
|
24
24
|
options[:file_warning] = :ignore
|
|
25
25
|
extension.tr('.', '').downcase.to_sym
|
|
26
26
|
else
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
parsed_path =
|
|
28
|
+
if path =~ /\A#{::URI::DEFAULT_PARSER.make_regexp}\z/
|
|
29
|
+
# path is 7th match
|
|
30
|
+
Regexp.last_match[7]
|
|
31
|
+
else
|
|
32
|
+
path
|
|
33
|
+
end
|
|
34
|
+
::File.extname(parsed_path).tr('.', '').downcase.to_sym
|
|
29
35
|
end
|
|
30
36
|
end
|
|
31
37
|
end
|
data/lib/roo/utils.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module Roo
|
|
2
4
|
module Utils
|
|
3
5
|
extend self
|
|
@@ -41,7 +43,7 @@ module Roo
|
|
|
41
43
|
|
|
42
44
|
# convert a number to something like 'AB' (1 => 'A', 2 => 'B', ...)
|
|
43
45
|
def number_to_letter(num)
|
|
44
|
-
result = ""
|
|
46
|
+
result = +""
|
|
45
47
|
|
|
46
48
|
until num.zero?
|
|
47
49
|
num, index = (num - 1).divmod(26)
|
|
@@ -73,6 +75,25 @@ module Roo
|
|
|
73
75
|
(x2 - (x1 - 1)) * (y2 - (y1 - 1))
|
|
74
76
|
end
|
|
75
77
|
|
|
78
|
+
def coordinates_in_range(str)
|
|
79
|
+
return to_enum(:coordinates_in_range, str) unless block_given?
|
|
80
|
+
coordinates = str.split(":", 2).map! { |s| extract_coordinate s }
|
|
81
|
+
|
|
82
|
+
case coordinates.size
|
|
83
|
+
when 1
|
|
84
|
+
yield coordinates[0]
|
|
85
|
+
when 2
|
|
86
|
+
tl, br = coordinates
|
|
87
|
+
rows = tl.row..br.row
|
|
88
|
+
cols = tl.column..br.column
|
|
89
|
+
rows.each do |row|
|
|
90
|
+
cols.each do |column|
|
|
91
|
+
yield Excelx::Coordinate.new(row, column)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
76
97
|
def load_xml(path)
|
|
77
98
|
::File.open(path, 'rb') do |file|
|
|
78
99
|
::Nokogiri::XML(file)
|
data/lib/roo/version.rb
CHANGED
data/roo.gemspec
CHANGED
|
@@ -17,12 +17,19 @@ Gem::Specification.new do |spec|
|
|
|
17
17
|
spec.files.reject! { |fn| fn.include?('test/files') }
|
|
18
18
|
spec.require_paths = ['lib']
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
|
|
21
|
+
spec.required_ruby_version = ">= 2.6.0"
|
|
22
|
+
else
|
|
23
|
+
spec.required_ruby_version = ">= 2.7.0"
|
|
24
|
+
end
|
|
21
25
|
|
|
22
26
|
spec.add_dependency 'nokogiri', '~> 1'
|
|
23
|
-
spec.add_dependency 'rubyzip', '>= 1.
|
|
27
|
+
spec.add_dependency 'rubyzip', '>= 1.3.0', '< 3.0.0'
|
|
24
28
|
|
|
25
|
-
spec.add_development_dependency 'rake'
|
|
29
|
+
spec.add_development_dependency 'rake'
|
|
26
30
|
spec.add_development_dependency 'minitest', '~> 5.4', '>= 5.4.3'
|
|
27
31
|
spec.add_development_dependency 'rack', '~> 1.6', '< 2.0.0'
|
|
32
|
+
if RUBY_VERSION >= '3.0.0'
|
|
33
|
+
spec.add_development_dependency 'matrix'
|
|
34
|
+
end
|
|
28
35
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe Roo::Excelx::Cell::Time do
|
|
4
|
+
it "should set the cell value to the correct number of seconds" do
|
|
5
|
+
value = 0.05513888888888888 # '1:19:24'
|
|
6
|
+
excelx_type = [:numeric_or_formula, "h:mm:ss"]
|
|
7
|
+
base_timestamp = Date.new(1899, 12, 30).to_time.to_i
|
|
8
|
+
time_cell = Roo::Excelx::Cell::Time.new(value, nil, excelx_type, 1, nil, base_timestamp, nil)
|
|
9
|
+
expect(time_cell.value).to eq(1*60*60 + 19*60 + 24) # '1:19:24' in seconds
|
|
10
|
+
# use case from https://github.com/roo-rb/roo/issues/310
|
|
11
|
+
value = 0.523761574074074 # '12:34:13' in seconds
|
|
12
|
+
time_cell = Roo::Excelx::Cell::Time.new(value, nil, excelx_type, 1, nil, base_timestamp, nil)
|
|
13
|
+
expect(time_cell.value).to eq(12*60*60 + 34*60 + 13) # 12:34:13 in seconds
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
describe Roo::Excelx::Relationships do
|
|
6
|
+
subject(:relationships) { Roo::Excelx::Relationships.new Roo::Excelx.new(path).rels_files[0] }
|
|
7
|
+
|
|
8
|
+
describe "#include_type?" do
|
|
9
|
+
[
|
|
10
|
+
["with hyperlink type", "test/files/link.xlsx", true, false],
|
|
11
|
+
["with nil path", "test/files/Bibelbund.xlsx", false, false],
|
|
12
|
+
["with comments type", "test/files/comments-google.xlsx", false, true],
|
|
13
|
+
].each do |context_desc, file_path, hyperlink_value, comments_value|
|
|
14
|
+
context context_desc do
|
|
15
|
+
let(:path) { file_path }
|
|
16
|
+
|
|
17
|
+
it "should return #{hyperlink_value} for hyperlink" do
|
|
18
|
+
expect(subject.include_type?("hyperlink")).to be hyperlink_value
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should return #{hyperlink_value} for link" do
|
|
22
|
+
expect(subject.include_type?("link")).to be hyperlink_value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "should return false for hypelink" do
|
|
26
|
+
expect(subject.include_type?("hypelink")).to be false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "should return false for coment" do
|
|
30
|
+
expect(subject.include_type?("coment")).to be false
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should return #{comments_value} for comments" do
|
|
34
|
+
expect(subject.include_type?("comments")).to be comments_value
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should return #{comments_value} for comment" do
|
|
38
|
+
expect(subject.include_type?("comment")).to be comments_value
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
data/spec/lib/roo/excelx_spec.rb
CHANGED
|
@@ -86,6 +86,14 @@ describe Roo::Excelx do
|
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
|
|
89
|
+
describe 'for a workbook with hidden sheets' do
|
|
90
|
+
let(:path) { 'test/files/hidden_sheets.xlsx' }
|
|
91
|
+
|
|
92
|
+
it 'returns the cell contents from the visible sheet' do
|
|
93
|
+
expect(Roo::Excelx.new(path, only_visible_sheets: true).cell('A', 1)).to eq "visible sheet 1"
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
89
97
|
describe '#parse' do
|
|
90
98
|
let(:path) { 'test/files/numeric-link.xlsx' }
|
|
91
99
|
|
|
@@ -379,9 +387,34 @@ describe Roo::Excelx do
|
|
|
379
387
|
expect(subject.hyperlink?(1, 1)).to eq true
|
|
380
388
|
expect(subject.hyperlink?(1, 2)).to eq false
|
|
381
389
|
end
|
|
390
|
+
|
|
391
|
+
context 'defined on cell range' do
|
|
392
|
+
let(:path) { 'test/files/cell-range-link.xlsx' }
|
|
393
|
+
|
|
394
|
+
it 'returns the expected result' do
|
|
395
|
+
[[false]*3, *[[true, true, false]]*4, [false]*3].each.with_index(1) do |row, row_index|
|
|
396
|
+
row.each.with_index(1) do |value, col_index|
|
|
397
|
+
expect(subject.hyperlink?(row_index, col_index)).to eq(value)
|
|
398
|
+
end
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
end
|
|
382
402
|
end
|
|
383
403
|
|
|
384
404
|
describe '#hyperlink' do
|
|
405
|
+
context 'defined on cell range' do
|
|
406
|
+
let(:path) { 'test/files/cell-range-link.xlsx' }
|
|
407
|
+
|
|
408
|
+
it 'returns the expected result' do
|
|
409
|
+
link = "http://www.google.com"
|
|
410
|
+
[[nil]*3, *[[link, link, nil]]*4, [nil]*3].each.with_index(1) do |row, row_index|
|
|
411
|
+
row.each.with_index(1) do |value, col_index|
|
|
412
|
+
expect(subject.hyperlink(row_index, col_index)).to eq(value)
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
end
|
|
416
|
+
end
|
|
417
|
+
|
|
385
418
|
context 'without location' do
|
|
386
419
|
let(:path) { 'test/files/link.xlsx' }
|
|
387
420
|
|
|
@@ -628,4 +661,4 @@ describe 'Roo::Excelx with options set' do
|
|
|
628
661
|
end
|
|
629
662
|
end
|
|
630
663
|
end
|
|
631
|
-
end
|
|
664
|
+
end
|
|
@@ -25,7 +25,7 @@ describe Roo::Spreadsheet do
|
|
|
25
25
|
let(:filename) { tempfile.path }
|
|
26
26
|
|
|
27
27
|
it 'loads the proper type' do
|
|
28
|
-
expect(Roo::CSV).to receive(:new).with(filename, file_warning: :ignore).and_call_original
|
|
28
|
+
expect(Roo::CSV).to receive(:new).with(filename, {file_warning: :ignore}).and_call_original
|
|
29
29
|
expect(Roo::Spreadsheet.open(tempfile, extension: :csv)).to be_a(Roo::CSV)
|
|
30
30
|
end
|
|
31
31
|
end
|
data/spec/lib/roo/utils_spec.rb
CHANGED
|
@@ -43,15 +43,6 @@ RSpec.describe ::Roo::Utils do
|
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
-
context '.split_coordinate' do
|
|
47
|
-
it "returns the expected result" do
|
|
48
|
-
expect(described_class.split_coordinate('A1')).to eq [1, 1]
|
|
49
|
-
expect(described_class.split_coordinate('B2')).to eq [2, 2]
|
|
50
|
-
expect(described_class.split_coordinate('R2')).to eq [2, 18]
|
|
51
|
-
expect(described_class.split_coordinate('AR31')).to eq [31, 18 + 26]
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
46
|
context '.extract_coordinate' do
|
|
56
47
|
it "returns the expected result" do
|
|
57
48
|
expect(described_class.extract_coordinate('A1')).to eq [1, 1]
|
|
@@ -90,6 +81,19 @@ RSpec.describe ::Roo::Utils do
|
|
|
90
81
|
end
|
|
91
82
|
end
|
|
92
83
|
|
|
84
|
+
context '.coordinates_in_range' do
|
|
85
|
+
it "returns the expected result" do
|
|
86
|
+
expect(described_class.coordinates_in_range('').to_a).to eq []
|
|
87
|
+
expect(described_class.coordinates_in_range('B2').to_a).to eq [[2, 2]]
|
|
88
|
+
expect(described_class.coordinates_in_range('D2:G3').to_a).to eq [[2, 4], [2, 5], [2, 6], [2, 7], [3, 4], [3, 5], [3, 6], [3, 7]]
|
|
89
|
+
expect(described_class.coordinates_in_range('G3:D2').to_a).to eq []
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "raises an error when appropriate" do
|
|
93
|
+
expect { described_class.coordinates_in_range('D2:G3:I5').to_a }.to raise_error(ArgumentError)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
93
97
|
context '.load_xml' do
|
|
94
98
|
it 'returns the expected result' do
|
|
95
99
|
expect(described_class.load_xml('test/files/sheet1.xml')).to be_a(Nokogiri::XML::Document)
|
|
@@ -66,6 +66,7 @@ class TestRooExcelxCellNumber < Minitest::Test
|
|
|
66
66
|
['0.000000000', '1042.000000000'],
|
|
67
67
|
['#,##0', '1,042'],
|
|
68
68
|
['#,##0.00', '1,042.00'],
|
|
69
|
+
['#,##0.000', '1,042.000'],
|
|
69
70
|
['0%', '104200%'],
|
|
70
71
|
['0.00%', '104200.00%'],
|
|
71
72
|
['0.00E+00', '1.04E+03'],
|
|
@@ -74,6 +75,7 @@ class TestRooExcelxCellNumber < Minitest::Test
|
|
|
74
75
|
['#,##0.00;(#,##0.00)', '1,042.00'],
|
|
75
76
|
['#,##0.00;[Red](#,##0.00)', '1,042.00'],
|
|
76
77
|
['##0.0E+0', '1.0E+03'],
|
|
78
|
+
["_-* #,##0.00\\ _€_-;\\-* #,##0.00\\ _€_-;_-* \"-\"??\\ _€_-;_-@_-", '1,042.00'],
|
|
77
79
|
['@', '1042']
|
|
78
80
|
].each do |style_format, result|
|
|
79
81
|
cell = Roo::Excelx::Cell::Number.new '1042', nil, [style_format], nil, nil, nil
|
data/test/roo/test_excelx.rb
CHANGED
|
@@ -3,7 +3,7 @@ require "test_helper"
|
|
|
3
3
|
class TestRworkbookExcelx < Minitest::Test
|
|
4
4
|
def test_download_uri_with_invalid_host
|
|
5
5
|
assert_raises(RuntimeError) do
|
|
6
|
-
Roo::Excelx.new("http://
|
|
6
|
+
Roo::Excelx.new("http://examples.com/file.xlsx")
|
|
7
7
|
end
|
|
8
8
|
end
|
|
9
9
|
|
|
@@ -133,6 +133,20 @@ class TestRworkbookExcelx < Minitest::Test
|
|
|
133
133
|
end
|
|
134
134
|
end
|
|
135
135
|
|
|
136
|
+
def test_expand_merged_range_doesnt_insert_nil_values
|
|
137
|
+
options = { expand_merged_ranges: true }
|
|
138
|
+
xlsx = roo_class.new(File.join(TESTDIR, "merged_ranges.xlsx"), options)
|
|
139
|
+
|
|
140
|
+
refute_includes xlsx.sheet_for(0).cells.values, nil, "`nil` was copied into the cells hash from an empty merged range"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def test_expand_merged_range_doesnt_raise_issue_506
|
|
144
|
+
# Issue 506 sent an example test.xlsx file that would raise an error upon parsing.
|
|
145
|
+
xl = Roo::Spreadsheet.open(File.join(TESTDIR, "expand_merged_ranges_issue_506.xlsx"), expand_merged_ranges: true)
|
|
146
|
+
data = xl.parse(one: /one/i, two: /two/i, clean: true)
|
|
147
|
+
assert_equal [{:one=>"John", :two=>"Johnson"}, {:one=>"Sam", :two=>nil}, {:one=>"Dave", :two=>nil}], data
|
|
148
|
+
end
|
|
149
|
+
|
|
136
150
|
def test_noexpand_merged_range
|
|
137
151
|
xlsx = roo_class.new(File.join(TESTDIR, "merged_ranges.xlsx"))
|
|
138
152
|
|
|
@@ -302,6 +316,11 @@ class TestRworkbookExcelx < Minitest::Test
|
|
|
302
316
|
end
|
|
303
317
|
end
|
|
304
318
|
|
|
319
|
+
def test_handles_link_without_hyperlink
|
|
320
|
+
workbook = Roo::Spreadsheet.open(File.join(TESTDIR, "bad_link.xlsx"))
|
|
321
|
+
assert_equal "Test", workbook.cell(1, 1)
|
|
322
|
+
end
|
|
323
|
+
|
|
305
324
|
# Excel has two base date formats one from 1900 and the other from 1904.
|
|
306
325
|
# see #test_base_dates_in_excel
|
|
307
326
|
def test_base_dates_in_excelx
|
|
@@ -315,6 +334,13 @@ class TestRworkbookExcelx < Minitest::Test
|
|
|
315
334
|
end
|
|
316
335
|
end
|
|
317
336
|
|
|
337
|
+
def test_parsing_xlsx_with_richtext
|
|
338
|
+
xlsx = roo_class.new(File.join(TESTDIR, "richtext_example.xlsx"))
|
|
339
|
+
|
|
340
|
+
assert_equal "Example richtext", xlsx.cell("a", 1)
|
|
341
|
+
assert_equal "Example richtext", xlsx.cell("b", 1)
|
|
342
|
+
end
|
|
343
|
+
|
|
318
344
|
def roo_class
|
|
319
345
|
Roo::Excelx
|
|
320
346
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: roo
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Thomas Preymesser
|
|
@@ -10,10 +10,10 @@ authors:
|
|
|
10
10
|
- Oleksandr Simonov
|
|
11
11
|
- Steven Daniels
|
|
12
12
|
- Anmol Chopra
|
|
13
|
-
autorequire:
|
|
13
|
+
autorequire:
|
|
14
14
|
bindir: bin
|
|
15
15
|
cert_chain: []
|
|
16
|
-
date:
|
|
16
|
+
date: 2022-03-19 00:00:00.000000000 Z
|
|
17
17
|
dependencies:
|
|
18
18
|
- !ruby/object:Gem::Dependency
|
|
19
19
|
name: nokogiri
|
|
@@ -35,34 +35,34 @@ dependencies:
|
|
|
35
35
|
requirements:
|
|
36
36
|
- - ">="
|
|
37
37
|
- !ruby/object:Gem::Version
|
|
38
|
-
version: 1.
|
|
38
|
+
version: 1.3.0
|
|
39
39
|
- - "<"
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
|
-
version:
|
|
41
|
+
version: 3.0.0
|
|
42
42
|
type: :runtime
|
|
43
43
|
prerelease: false
|
|
44
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
45
45
|
requirements:
|
|
46
46
|
- - ">="
|
|
47
47
|
- !ruby/object:Gem::Version
|
|
48
|
-
version: 1.
|
|
48
|
+
version: 1.3.0
|
|
49
49
|
- - "<"
|
|
50
50
|
- !ruby/object:Gem::Version
|
|
51
|
-
version:
|
|
51
|
+
version: 3.0.0
|
|
52
52
|
- !ruby/object:Gem::Dependency
|
|
53
53
|
name: rake
|
|
54
54
|
requirement: !ruby/object:Gem::Requirement
|
|
55
55
|
requirements:
|
|
56
|
-
- - "
|
|
56
|
+
- - ">="
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
|
-
version: '
|
|
58
|
+
version: '0'
|
|
59
59
|
type: :development
|
|
60
60
|
prerelease: false
|
|
61
61
|
version_requirements: !ruby/object:Gem::Requirement
|
|
62
62
|
requirements:
|
|
63
|
-
- - "
|
|
63
|
+
- - ">="
|
|
64
64
|
- !ruby/object:Gem::Version
|
|
65
|
-
version: '
|
|
65
|
+
version: '0'
|
|
66
66
|
- !ruby/object:Gem::Dependency
|
|
67
67
|
name: minitest
|
|
68
68
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -103,6 +103,20 @@ dependencies:
|
|
|
103
103
|
- - "<"
|
|
104
104
|
- !ruby/object:Gem::Version
|
|
105
105
|
version: 2.0.0
|
|
106
|
+
- !ruby/object:Gem::Dependency
|
|
107
|
+
name: matrix
|
|
108
|
+
requirement: !ruby/object:Gem::Requirement
|
|
109
|
+
requirements:
|
|
110
|
+
- - ">="
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: '0'
|
|
113
|
+
type: :development
|
|
114
|
+
prerelease: false
|
|
115
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
116
|
+
requirements:
|
|
117
|
+
- - ">="
|
|
118
|
+
- !ruby/object:Gem::Version
|
|
119
|
+
version: '0'
|
|
106
120
|
description: |-
|
|
107
121
|
Roo can access the contents of various spreadsheet files. It can handle
|
|
108
122
|
* OpenOffice
|
|
@@ -119,10 +133,10 @@ files:
|
|
|
119
133
|
- ".codeclimate.yml"
|
|
120
134
|
- ".github/issue_template.md"
|
|
121
135
|
- ".github/pull_request_template.md"
|
|
136
|
+
- ".github/workflows/ruby.yml"
|
|
122
137
|
- ".gitignore"
|
|
123
138
|
- ".rubocop.yml"
|
|
124
139
|
- ".simplecov"
|
|
125
|
-
- ".travis.yml"
|
|
126
140
|
- CHANGELOG.md
|
|
127
141
|
- Gemfile
|
|
128
142
|
- Guardfile
|
|
@@ -181,7 +195,9 @@ files:
|
|
|
181
195
|
- spec/helpers.rb
|
|
182
196
|
- spec/lib/roo/base_spec.rb
|
|
183
197
|
- spec/lib/roo/csv_spec.rb
|
|
198
|
+
- spec/lib/roo/excelx/cell/time_spec.rb
|
|
184
199
|
- spec/lib/roo/excelx/format_spec.rb
|
|
200
|
+
- spec/lib/roo/excelx/relationships_spec.rb
|
|
185
201
|
- spec/lib/roo/excelx/sheet_doc_spec.rb
|
|
186
202
|
- spec/lib/roo/excelx_spec.rb
|
|
187
203
|
- spec/lib/roo/libreoffice_spec.rb
|
|
@@ -224,7 +240,7 @@ homepage: https://github.com/roo-rb/roo
|
|
|
224
240
|
licenses:
|
|
225
241
|
- MIT
|
|
226
242
|
metadata: {}
|
|
227
|
-
post_install_message:
|
|
243
|
+
post_install_message:
|
|
228
244
|
rdoc_options: []
|
|
229
245
|
require_paths:
|
|
230
246
|
- lib
|
|
@@ -232,16 +248,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
232
248
|
requirements:
|
|
233
249
|
- - ">="
|
|
234
250
|
- !ruby/object:Gem::Version
|
|
235
|
-
version: 2.
|
|
251
|
+
version: 2.7.0
|
|
236
252
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
237
253
|
requirements:
|
|
238
254
|
- - ">="
|
|
239
255
|
- !ruby/object:Gem::Version
|
|
240
256
|
version: '0'
|
|
241
257
|
requirements: []
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
signing_key:
|
|
258
|
+
rubygems_version: 3.3.3
|
|
259
|
+
signing_key:
|
|
245
260
|
specification_version: 4
|
|
246
261
|
summary: Roo can access the contents of various spreadsheet files.
|
|
247
262
|
test_files: []
|
data/.travis.yml
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
language: ruby
|
|
2
|
-
rvm:
|
|
3
|
-
- 2.3
|
|
4
|
-
- 2.4
|
|
5
|
-
- 2.5
|
|
6
|
-
- 2.6
|
|
7
|
-
- ruby-head
|
|
8
|
-
- jruby-9.1.6.0
|
|
9
|
-
env:
|
|
10
|
-
- LONG_RUN=true
|
|
11
|
-
matrix:
|
|
12
|
-
include:
|
|
13
|
-
- rvm: 2.6
|
|
14
|
-
env: RUBYOPT=--jit LONG_RUN=true
|
|
15
|
-
- rvm: ruby-head
|
|
16
|
-
env: RUBYOPT=--jit LONG_RUN=true
|
|
17
|
-
allow_failures:
|
|
18
|
-
- rvm: ruby-head
|
|
19
|
-
- rvm: ruby-head
|
|
20
|
-
env: RUBYOPT=--jit LONG_RUN=true
|
|
21
|
-
- rvm: jruby-9.1.6.0
|
|
22
|
-
bundler_args: --without local_development
|