roo 2.8.3 → 2.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1e41bf12228c4a168e8df0a0cbf5b94eceaa89a1f5d174f3a3588a1a965d49f4
4
- data.tar.gz: 69d749c2667ba4efbdcd7257550ba380d6ba0250633d439ae738673e6d2b5924
3
+ metadata.gz: d43d60129a4ccbb82fe7438993aab2d6c0d7818be11c0dc28f96b76bdaedd960
4
+ data.tar.gz: 2fce78021ad19c23a840dff9647c227a917b6537591df6c1c249c62d2045356b
5
5
  SHA512:
6
- metadata.gz: 14c8d1e69b31e1be16c8845c686e596c108e9c4251e4d5ee75471dd8ea325c2aacdcf1fa4b10f6262cd840bd063de5b11432439a9bce1b82b4c350566981bb48
7
- data.tar.gz: 7a01fefbe77485af0252384dcd20770e0c993c29b916be55736a86fcdc8de710d99709fb09d95f4d628a2b3819069c3aba5df28f3488a5f519753b854c82cd48
6
+ metadata.gz: df1b92404e2835b8265c0dfded00d0fc57502e87cea3fec2798adced13bf0b4cbf04732404371ea534071740cc60f4db2b6f5c110da8006d44ad41fc47b4d728
7
+ data.tar.gz: b6062d76dafda4cd64870ef100803e61ac8e32f565a5f3a0ffafee7a674e7dfada71e6e243fe7f37545efb7457be99a39a5c035498df85a8dbd02151dffca593
@@ -0,0 +1,15 @@
1
+ name: Changelog
2
+
3
+ on:
4
+ pull_request:
5
+ types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled]
6
+
7
+ jobs:
8
+ changelog:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v2
12
+ - uses: amoniacou/changelog-enforcer@v1.4.0
13
+ with:
14
+ changeLogPath: 'CHANGELOG.md'
15
+ skipLabel: 'Skip-Changelog'
@@ -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,28 @@
1
1
  ## Unreleased
2
2
 
3
+ ### Changed/Added
4
+
5
+ ## [2.10.0] 2023-02-07
6
+
7
+ ### Changed/Added
8
+ - Fix gsub! usage for open office documents on a frozen string [581](https://github.com/roo-rb/roo/pull/581)
9
+ - Add support for boolean values in open office files that were generated via Google Sheets [580](https://github.com/roo-rb/roo/pull/580)
10
+ - Roo::Base#each_with_pagename returns Enumerator Object [576](https://github.com/roo-rb/roo/pull/576)
11
+
12
+ ## [2.9.0] 2022-03-19
13
+
14
+ ### Changed/Added
15
+ - Ruby 3.x Support [555](https://github.com/roo-rb/roo/pull/555)
16
+ - Ignore all richdata at 'xl/richData' of XSLX [552](https://github.com/roo-rb/roo/pull/552)
17
+ - Only copy if cell is present when `expand_merged_ranges: true` [557](https://github.com/roo-rb/roo/pull/557)
18
+ - Fixes issue where the contents of hidden sheet was returned when parsing visible sheets only. [536](https://github.com/roo-rb/roo/pull/536)
19
+ - Add formats [525](https://github.com/roo-rb/roo/pull/525)
20
+ - Fix warnings caused by Ruby 2.7 update [530](https://github.com/roo-rb/roo/pull/530)
21
+ - Add formats [525](https://github.com/roo-rb/roo/pull/525)
22
+
23
+ ### Removed
24
+ - Support for ruby 2.4, 2.5, 2.6(excluded jRuby)
25
+
3
26
  ## [2.8.3] 2020-02-03
4
27
  ### Changed/Added
5
28
  - 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)
data/Gemfile CHANGED
@@ -10,6 +10,7 @@ group :test do
10
10
  gem 'simplecov', '>= 0.9.0', require: false
11
11
  gem 'coveralls', require: false
12
12
  gem "minitest-reporters"
13
+ gem 'webrick' if RUBY_VERSION >= '3.0.0'
13
14
  end
14
15
 
15
16
  group :local_development do
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.8.0"
21
+ gem "roo", "~> 2.10.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 [standard CSV library](), you can use options available to that library to parse csv files. You can pass options using the ``csv_options`` key.
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/[my-github-username]/roo/fork )
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
@@ -250,8 +250,10 @@ class Roo::Base
250
250
 
251
251
  # iterate through all worksheets of a document
252
252
  def each_with_pagename
253
- sheets.each do |s|
254
- yield sheet(s, true)
253
+ Enumerator.new do |yielder|
254
+ sheets.each do |s|
255
+ yielder << sheet(s, true)
256
+ end
255
257
  end
256
258
  end
257
259
 
@@ -544,7 +546,7 @@ class Roo::Base
544
546
  tempfilename = File.join(tmpdir, find_basename(uri))
545
547
  begin
546
548
  File.open(tempfilename, "wb") do |file|
547
- open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") do |net|
549
+ URI.open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") do |net|
548
550
  file.write(net.read)
549
551
  end
550
552
  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
- ::CSV.foreach(filename, options, &block)
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
- ::CSV.foreach(tmp_filename, options, &block)
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 '#,##0.00' then number_format('%.2f')
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,7 +64,18 @@ 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 }
69
+ when /^(?:_\()?"([^"]*)"(?:\* )?([^_]+)/
70
+ proc do |number|
71
+ formatted_number = generate_formatter($2).call(number)
72
+ "#{$1}#{formatted_number}"
73
+ end
74
+ when /^_[- \(]\[\$([^-]*)[^#@]+([^_]+)/
75
+ proc do |number|
76
+ formatted_number = generate_formatter($2).call(number)
77
+ "#{$1}#{formatted_number}"
78
+ end
68
79
  else
69
80
  raise "Unknown format: #{format.inspect}"
70
81
  end
@@ -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
@@ -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
@@ -197,11 +192,12 @@ module Roo
197
192
  # Extract merged ranges from xml
198
193
  merges = {}
199
194
  doc.xpath('/worksheet/mergeCells/mergeCell').each do |mergecell_xml|
200
- tl, br = mergecell_xml["ref"].split(/:/).map { |ref| ::Roo::Utils.ref_to_key(ref) }
201
- for row in tl[0]..br[0] do
202
- for col in tl[1]..br[1] do
203
- next if row == tl[0] && col == tl[1]
204
- merges[[row, col]] = tl
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
205
201
  end
206
202
  end
207
203
  end
@@ -215,10 +211,19 @@ module Roo
215
211
  extracted_cells = {}
216
212
  empty_cell = @options[:empty_cell]
217
213
 
218
- doc.xpath('/worksheet/sheetData/row/c').each do |cell_xml|
219
- coordinate = ::Roo::Utils.extract_coordinate(cell_xml["r"])
220
- cell = cell_from_xml(cell_xml, hyperlinks(relationships)[coordinate], coordinate, empty_cell)
221
- extracted_cells[coordinate] = cell if cell
214
+ doc.xpath('/worksheet/sheetData/row').each.with_index(1) do |row_xml, ycoord|
215
+ row_xml.xpath('c').each.with_index(1) do |cell_xml, xcoord|
216
+ r = cell_xml['r']
217
+ coordinate =
218
+ if r.nil?
219
+ ::Roo::Excelx::Coordinate.new(ycoord, xcoord)
220
+ else
221
+ ::Roo::Utils.extract_coordinate(r)
222
+ end
223
+
224
+ cell = cell_from_xml(cell_xml, hyperlinks(relationships)[coordinate], coordinate, empty_cell)
225
+ extracted_cells[coordinate] = cell if cell
226
+ end
222
227
  end
223
228
 
224
229
  expand_merged_ranges(extracted_cells) if @options[:expand_merged_ranges]
@@ -32,6 +32,7 @@ module Roo
32
32
  doc.xpath('//definedName').each_with_object({}) do |defined_name, hash|
33
33
  # "Sheet1!$C$5"
34
34
  sheet, coordinates = defined_name.text.split('!$', 2)
35
+ next unless coordinates
35
36
  col, row = coordinates.split('$')
36
37
  name = defined_name['name']
37
38
  hash[name] = Label.new(name, sheet, row, col)
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 = workbook.sheets.map do |sheet|
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
- @sheet_names.each_with_index do |sheet_name, n|
71
- @sheets_by_name[sheet_name] = @sheets[n] = Sheet.new(sheet_name, @shared, n, sheet_options)
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$/
@@ -423,7 +423,10 @@ module Roo
423
423
  @style[sheet][key] = style_name
424
424
  case @cell_type[sheet][key]
425
425
  when :float
426
- @cell[sheet][key] = (table_cell.attributes['value'].to_s.include?(".") || table_cell.children.first.text.include?(".")) ? v.to_f : v.to_i
426
+ value = (table_cell.attributes['value'].to_s.include?(".") || table_cell.children.first.text.include?(".")) ? v.to_f : v.to_i
427
+ value = 'true' if formula == '=TRUE()'
428
+ value = 'false' if formula == '=FALSE()'
429
+ @cell[sheet][key] = value
427
430
  when :percentage
428
431
  @cell[sheet][key] = v.to_f
429
432
  when :string
@@ -517,7 +520,7 @@ module Roo
517
520
  str_v += child.content #.text
518
521
  end
519
522
  end
520
- str_v.gsub!(/&apos;/, "'") # special case not supported by unescapeHTML
523
+ str_v = str_v.gsub(/&apos;/, "'") # special case not supported by unescapeHTML
521
524
  str_v = CGI.unescapeHTML(str_v)
522
525
  end # == 'p'
523
526
  end
@@ -24,8 +24,14 @@ module Roo
24
24
  options[:file_warning] = :ignore
25
25
  extension.tr('.', '').downcase.to_sym
26
26
  else
27
- res = ::File.extname((path =~ /\A#{::URI::DEFAULT_PARSER.make_regexp}\z/) ? ::URI.parse(::URI.encode(path)).path : path)
28
- res.tr('.', '').downcase.to_sym
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/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Roo
2
- VERSION = "2.8.3"
2
+ VERSION = "2.10.0"
3
3
  end
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
- spec.required_ruby_version = ">= 2.3.0"
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
27
  spec.add_dependency 'rubyzip', '>= 1.3.0', '< 3.0.0'
24
28
 
25
- spec.add_development_dependency 'rake', '~> 10.1'
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
@@ -182,6 +182,14 @@ describe Roo::Base do
182
182
  end
183
183
  end
184
184
 
185
+ describe '#each_with_pagename' do
186
+ it 'should return an enumerator with all the rows' do
187
+ each_with_pagename = spreadsheet.each_with_pagename
188
+ expect(each_with_pagename).to be_a(Enumerator)
189
+ expect(each_with_pagename.to_a.last).to eq([spreadsheet.default_sheet, spreadsheet])
190
+ end
191
+ end
192
+
185
193
  describe '#each' do
186
194
  it 'should return an enumerator with all the rows' do
187
195
  each = spreadsheet.each
@@ -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
@@ -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
 
@@ -318,6 +326,30 @@ describe Roo::Excelx do
318
326
  expect(subject.formatted_value(4, 1)).to eq '05010'
319
327
  end
320
328
  end
329
+
330
+ context 'contains US currency' do
331
+ let(:path) { 'test/files/currency-us.xlsx' }
332
+
333
+ it 'returns a zero-padded number' do
334
+ expect(subject.formatted_value(4, 1)).to eq '$20.51'
335
+ end
336
+ end
337
+
338
+ context 'contains euro currency' do
339
+ let(:path) { 'test/files/currency-euro.xlsx' }
340
+
341
+ it 'returns a zero-padded number' do
342
+ expect(subject.formatted_value(4, 1)).to eq '€20.51'
343
+ end
344
+ end
345
+
346
+ context 'contains uk currency' do
347
+ let(:path) { 'test/files/currency-uk.xlsx' }
348
+
349
+ it 'returns a zero-padded number' do
350
+ expect(subject.formatted_value(4, 1)).to eq '£20.51'
351
+ end
352
+ end
321
353
  end
322
354
 
323
355
  describe '#row' do
@@ -601,6 +633,17 @@ describe Roo::Excelx do
601
633
  end
602
634
  end
603
635
 
636
+ describe 'opening a file with filters' do
637
+ let(:path) { 'test/files/wrong_coordinates.xlsx' }
638
+ subject(:xlsx) do
639
+ Roo::Spreadsheet.open(path)
640
+ end
641
+
642
+ it 'should properly extract defined_names' do
643
+ expect(subject.sheet(0).workbook.defined_names.length).to eq(1)
644
+ end
645
+ end
646
+
604
647
  describe 'images' do
605
648
  let(:path) { 'test/files/images.xlsx' }
606
649
 
@@ -653,4 +696,4 @@ describe 'Roo::Excelx with options set' do
653
696
  end
654
697
  end
655
698
  end
656
- end
699
+ 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
@@ -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]
@@ -60,7 +60,7 @@ class TestAttrReaderDefault < Minitest::Test
60
60
  object.instance_variable_defined?(attr_name) ? object.instance_variable_get(attr_name) : nil
61
61
  else
62
62
  object.public_send(attr_name)
63
- end
63
+ end
64
64
 
65
65
  if expected_value
66
66
  assert_equal expected_value, value
@@ -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
@@ -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
 
@@ -320,6 +334,22 @@ class TestRworkbookExcelx < Minitest::Test
320
334
  end
321
335
  end
322
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
+
344
+ def test_implicit_coordinates
345
+ xlsx = roo_class.new(File.join(TESTDIR, 'implicit_coordinates.xlsx'))
346
+
347
+ assert_equal 'Test', xlsx.cell('a', 1)
348
+ assert_equal 'A2', xlsx.cell('a', 2)
349
+ assert_equal 'B2', xlsx.cell(2, 2)
350
+ assert_equal 'C2', xlsx.cell('c', 2)
351
+ end
352
+
323
353
  def roo_class
324
354
  Roo::Excelx
325
355
  end
data/test/test_roo.rb CHANGED
@@ -274,6 +274,24 @@ class TestRoo < Minitest::Test
274
274
  end
275
275
  end
276
276
 
277
+ def test_cell_boolean_from_google_sheets
278
+ with_each_spreadsheet(:name=>'boolean-from-google-sheets', :format=>[:openoffice, :excelx]) do |oo|
279
+ if oo.class == Roo::Excelx
280
+ assert_equal true, oo.cell(1, 1), "failure in #{oo.class}"
281
+ assert_equal false, oo.cell(2, 1), "failure in #{oo.class}"
282
+
283
+ cell = oo.sheet_for(oo.default_sheet).cells[[1, 1,]]
284
+ assert_equal 'TRUE', cell.formatted_value
285
+
286
+ cell = oo.sheet_for(oo.default_sheet).cells[[2, 1,]]
287
+ assert_equal 'FALSE', cell.formatted_value
288
+ else
289
+ assert_equal "true", oo.cell(1,1), "failure in #{oo.class}"
290
+ assert_equal "false", oo.cell(2,1), "failure in #{oo.class}"
291
+ end
292
+ end
293
+ end
294
+
277
295
  def test_cell_multiline
278
296
  with_each_spreadsheet(:name=>'paragraph', :format=>[:openoffice, :excelx]) do |oo|
279
297
  assert_equal "This is a test\nof a multiline\nCell", oo.cell(1,1)
@@ -282,6 +300,18 @@ class TestRoo < Minitest::Test
282
300
  end
283
301
  end
284
302
 
303
+ def test_apostrophe_replacement
304
+ with_each_spreadsheet(:name=>'apostrophe', :format=>[:openoffice]) do |oo|
305
+ assert_equal "'", oo.cell(1,1)
306
+ end
307
+ end
308
+
309
+ def test_frozen_string_usage
310
+ with_each_spreadsheet(:name=>'frozen_string', :format=>[:openoffice]) do |oo|
311
+ assert_equal "", oo.cell(1,1)
312
+ end
313
+ end
314
+
285
315
  def test_row_whitespace
286
316
  # auf dieses Dokument habe ich keinen Zugriff TODO:
287
317
  # TODO: No access to document whitespace?
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.8.3
4
+ version: 2.10.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: 2020-02-03 00:00:00.000000000 Z
16
+ date: 2023-02-07 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: nokogiri
@@ -53,16 +53,16 @@ dependencies:
53
53
  name: rake
54
54
  requirement: !ruby/object:Gem::Requirement
55
55
  requirements:
56
- - - "~>"
56
+ - - ">="
57
57
  - !ruby/object:Gem::Version
58
- version: '10.1'
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: '10.1'
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,11 @@ files:
119
133
  - ".codeclimate.yml"
120
134
  - ".github/issue_template.md"
121
135
  - ".github/pull_request_template.md"
136
+ - ".github/workflows/pull-request.yml"
137
+ - ".github/workflows/ruby.yml"
122
138
  - ".gitignore"
123
139
  - ".rubocop.yml"
124
140
  - ".simplecov"
125
- - ".travis.yml"
126
141
  - CHANGELOG.md
127
142
  - Gemfile
128
143
  - Guardfile
@@ -181,6 +196,7 @@ files:
181
196
  - spec/helpers.rb
182
197
  - spec/lib/roo/base_spec.rb
183
198
  - spec/lib/roo/csv_spec.rb
199
+ - spec/lib/roo/excelx/cell/time_spec.rb
184
200
  - spec/lib/roo/excelx/format_spec.rb
185
201
  - spec/lib/roo/excelx/relationships_spec.rb
186
202
  - spec/lib/roo/excelx/sheet_doc_spec.rb
@@ -225,7 +241,7 @@ homepage: https://github.com/roo-rb/roo
225
241
  licenses:
226
242
  - MIT
227
243
  metadata: {}
228
- post_install_message:
244
+ post_install_message:
229
245
  rdoc_options: []
230
246
  require_paths:
231
247
  - lib
@@ -233,15 +249,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
233
249
  requirements:
234
250
  - - ">="
235
251
  - !ruby/object:Gem::Version
236
- version: 2.3.0
252
+ version: 2.7.0
237
253
  required_rubygems_version: !ruby/object:Gem::Requirement
238
254
  requirements:
239
255
  - - ">="
240
256
  - !ruby/object:Gem::Version
241
257
  version: '0'
242
258
  requirements: []
243
- rubygems_version: 3.0.6
244
- signing_key:
259
+ rubygems_version: 3.4.2
260
+ signing_key:
245
261
  specification_version: 4
246
262
  summary: Roo can access the contents of various spreadsheet files.
247
263
  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