roo 2.7.1 → 2.8.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.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/.github/issue_template.md +16 -0
  3. data/.github/pull_request_template.md +14 -0
  4. data/.rubocop.yml +186 -0
  5. data/.travis.yml +12 -7
  6. data/CHANGELOG.md +31 -2
  7. data/LICENSE +2 -0
  8. data/README.md +25 -12
  9. data/lib/roo.rb +4 -1
  10. data/lib/roo/base.rb +65 -56
  11. data/lib/roo/constants.rb +5 -3
  12. data/lib/roo/csv.rb +20 -12
  13. data/lib/roo/excelx.rb +42 -16
  14. data/lib/roo/excelx/cell.rb +10 -6
  15. data/lib/roo/excelx/cell/base.rb +26 -12
  16. data/lib/roo/excelx/cell/boolean.rb +9 -6
  17. data/lib/roo/excelx/cell/date.rb +7 -7
  18. data/lib/roo/excelx/cell/datetime.rb +14 -18
  19. data/lib/roo/excelx/cell/empty.rb +3 -2
  20. data/lib/roo/excelx/cell/number.rb +35 -34
  21. data/lib/roo/excelx/cell/string.rb +3 -3
  22. data/lib/roo/excelx/cell/time.rb +4 -3
  23. data/lib/roo/excelx/comments.rb +3 -3
  24. data/lib/roo/excelx/coordinate.rb +11 -4
  25. data/lib/roo/excelx/extractor.rb +21 -3
  26. data/lib/roo/excelx/format.rb +38 -31
  27. data/lib/roo/excelx/images.rb +26 -0
  28. data/lib/roo/excelx/relationships.rb +3 -3
  29. data/lib/roo/excelx/shared.rb +10 -3
  30. data/lib/roo/excelx/shared_strings.rb +9 -15
  31. data/lib/roo/excelx/sheet.rb +49 -10
  32. data/lib/roo/excelx/sheet_doc.rb +86 -48
  33. data/lib/roo/excelx/styles.rb +3 -3
  34. data/lib/roo/excelx/workbook.rb +7 -3
  35. data/lib/roo/helpers/default_attr_reader.rb +20 -0
  36. data/lib/roo/helpers/weak_instance_cache.rb +41 -0
  37. data/lib/roo/open_office.rb +8 -6
  38. data/lib/roo/spreadsheet.rb +1 -1
  39. data/lib/roo/utils.rb +48 -19
  40. data/lib/roo/version.rb +1 -1
  41. data/roo.gemspec +13 -11
  42. data/spec/lib/roo/base_spec.rb +45 -3
  43. data/spec/lib/roo/excelx_spec.rb +125 -31
  44. data/spec/lib/roo/strict_spec.rb +43 -0
  45. data/spec/lib/roo/utils_spec.rb +12 -3
  46. data/spec/lib/roo/weak_instance_cache_spec.rb +92 -0
  47. data/spec/lib/roo_spec.rb +0 -0
  48. data/test/excelx/cell/test_attr_reader_default.rb +72 -0
  49. data/test/excelx/cell/test_base.rb +5 -0
  50. data/test/excelx/cell/test_datetime.rb +6 -6
  51. data/test/excelx/cell/test_empty.rb +11 -0
  52. data/test/excelx/cell/test_number.rb +9 -0
  53. data/test/excelx/cell/test_string.rb +20 -0
  54. data/test/excelx/cell/test_time.rb +4 -4
  55. data/test/excelx/test_coordinate.rb +51 -0
  56. data/test/formatters/test_csv.rb +17 -0
  57. data/test/formatters/test_xml.rb +4 -4
  58. data/test/roo/test_base.rb +2 -2
  59. data/test/roo/test_csv.rb +28 -0
  60. data/test/test_helper.rb +13 -0
  61. data/test/test_roo.rb +7 -7
  62. metadata +21 -11
  63. data/.github/ISSUE_TEMPLATE +0 -10
  64. data/Gemfile_ruby2 +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 711650fb2132509af1a6df5cd4b5a3d83eaac68f
4
- data.tar.gz: ca23282af485cfa63d4b4a761d4081841edd385c
2
+ SHA256:
3
+ metadata.gz: b99744522c3a62e004d42498388c4e99cdb2d45157fc26b87eb54023a957452f
4
+ data.tar.gz: ab4445f118a1144c71142a2c28724686da05d28ce04a04c0746c49628834d132
5
5
  SHA512:
6
- metadata.gz: 7166103bc551a008905e6052369ed5cf714bd949d83021e3596cef8ae083fccead0faac1b28591bf28b09f977202955c4f2e92fda45a5961475eff4ea3caa93e
7
- data.tar.gz: dc030d1d1530114289e8a420283fdf3131759ee107dfaa17bcc35c098e5d0e8b74fe984dc655b72a2701b211e3af3442f3cd79f0ad07e9cf1e7587496cfc7a16
6
+ metadata.gz: 9bc47d73a1556e7b82b652379bcba4940f9982814286feb626097e9ddea0f3a021c7ca7e9d8399293248df5272ac8db0b39c896abd940a759683ce09260e77e2
7
+ data.tar.gz: 69baf682a05fa581756a92a270e6bd44431f36683d9f1104d0466f8452201d32a34cf6a626b8168d6ef022bb2ed6b0d932e2ff5a3b1c2367c02fd4f224ce8eeb
@@ -0,0 +1,16 @@
1
+ Thanks for filing an issue. Following these instructions will help us solve your problem sooner.
2
+
3
+ ### Steps to reproduce
4
+
5
+ 1. Create an executable test case for this issue ([sample test case](https://gist.github.com/tgturner/e4b7f491639b8a6dd883fe2ace408652))
6
+ 2. You can share your executable test case as a [gist](https://gist.github.com), or simply paste the content into the issue description.
7
+ - You can execute the test case by running `ruby the_file.rb` in your terminal. If all goes well, you should see your test case failing.
8
+ 3. Please provide a stripped down version of the offending spreadsheet.
9
+
10
+ ### Issue
11
+ Describe the issue
12
+
13
+ ### System configuration
14
+ **Roo version**:
15
+
16
+ **Ruby version**:
@@ -0,0 +1,14 @@
1
+ ### Summary
2
+
3
+ Provide a general description of the code changes in your pull
4
+ request... were there any bugs you had fixed? If so, mention them. If
5
+ these bugs have open GitHub issues, be sure to tag them here as well,
6
+ to keep the conversation linked together.
7
+
8
+ ### Other Information
9
+
10
+ If there's anything else that's important and relevant to your pull
11
+ request, mention that information here. This could include
12
+ benchmarks, or other information.
13
+
14
+ Thanks for contributing to Roo!
@@ -0,0 +1,186 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+ # RuboCop has a bunch of cops enabled by default. This setting tells RuboCop
4
+ # to ignore them, so only the ones explicitly set in this file are enabled.
5
+ DisabledByDefault: true
6
+
7
+ Performance:
8
+ Exclude:
9
+ - '**/test/**/*'
10
+ - '**/spec/**/*'
11
+
12
+ # Prefer &&/|| over and/or.
13
+ Style/AndOr:
14
+ Enabled: true
15
+
16
+ # Do not use braces for hash literals when they are the last argument of a
17
+ # method call.
18
+ Style/BracesAroundHashParameters:
19
+ Enabled: true
20
+ EnforcedStyle: context_dependent
21
+
22
+ # Align `when` with `case`.
23
+ Layout/CaseIndentation:
24
+ Enabled: true
25
+
26
+ # Align comments with method definitions.
27
+ Layout/CommentIndentation:
28
+ Enabled: true
29
+
30
+ Layout/ElseAlignment:
31
+ Enabled: true
32
+
33
+ # Align `end` with the matching keyword or starting expression except for
34
+ # assignments, where it should be aligned with the LHS.
35
+ Layout/EndAlignment:
36
+ Enabled: true
37
+ EnforcedStyleAlignWith: variable
38
+ AutoCorrect: true
39
+
40
+ Layout/EmptyLineAfterMagicComment:
41
+ Enabled: true
42
+
43
+ Layout/EmptyLinesAroundBlockBody:
44
+ Enabled: true
45
+
46
+ # In a regular class definition, no empty lines around the body.
47
+ Layout/EmptyLinesAroundClassBody:
48
+ Enabled: true
49
+
50
+ # In a regular method definition, no empty lines around the body.
51
+ Layout/EmptyLinesAroundMethodBody:
52
+ Enabled: true
53
+
54
+ # In a regular module definition, no empty lines around the body.
55
+ Layout/EmptyLinesAroundModuleBody:
56
+ Enabled: true
57
+
58
+ Layout/FirstParameterIndentation:
59
+ Enabled: true
60
+
61
+ # Use Ruby >= 1.9 syntax for hashes. Prefer { a: :b } over { :a => :b }.
62
+ Style/HashSyntax:
63
+ Enabled: true
64
+
65
+ # Method definitions after `private` or `protected` isolated calls need one
66
+ # extra level of indentation.
67
+ Layout/IndentationConsistency:
68
+ Enabled: true
69
+
70
+ # Two spaces, no tabs (for indentation).
71
+ Layout/IndentationWidth:
72
+ Enabled: true
73
+
74
+ Layout/LeadingCommentSpace:
75
+ Enabled: true
76
+
77
+ Layout/SpaceAfterColon:
78
+ Enabled: true
79
+
80
+ Layout/SpaceAfterComma:
81
+ Enabled: true
82
+
83
+ Layout/SpaceAroundEqualsInParameterDefault:
84
+ Enabled: true
85
+
86
+ Layout/SpaceAroundKeyword:
87
+ Enabled: true
88
+
89
+ Layout/SpaceAroundOperators:
90
+ Enabled: true
91
+
92
+ Layout/SpaceBeforeComma:
93
+ Enabled: true
94
+
95
+ Layout/SpaceBeforeFirstArg:
96
+ Enabled: true
97
+
98
+ Style/DefWithParentheses:
99
+ Enabled: true
100
+
101
+ # Defining a method with parameters needs parentheses.
102
+ Style/MethodDefParentheses:
103
+ Enabled: true
104
+
105
+ Style/FrozenStringLiteralComment:
106
+ Enabled: true
107
+ EnforcedStyle: always
108
+
109
+ # Use `foo {}` not `foo{}`.
110
+ Layout/SpaceBeforeBlockBraces:
111
+ Enabled: true
112
+
113
+ # Use `foo { bar }` not `foo {bar}`.
114
+ Layout/SpaceInsideBlockBraces:
115
+ Enabled: true
116
+
117
+ # Use `{ a: 1 }` not `{a:1}`.
118
+ Layout/SpaceInsideHashLiteralBraces:
119
+ Enabled: true
120
+
121
+ Layout/SpaceInsideParens:
122
+ Enabled: true
123
+
124
+ # Check quotes usage according to lint rule below.
125
+ Style/StringLiterals:
126
+ Enabled: true
127
+ EnforcedStyle: double_quotes
128
+
129
+ # Detect hard tabs, no hard tabs.
130
+ Layout/Tab:
131
+ Enabled: true
132
+
133
+ # Blank lines should not have any spaces.
134
+ Layout/TrailingBlankLines:
135
+ Enabled: true
136
+
137
+ # No trailing whitespace.
138
+ Layout/TrailingWhitespace:
139
+ Enabled: true
140
+
141
+ # Use quotes for string literals when they are enough.
142
+ Style/UnneededPercentQ:
143
+ Enabled: true
144
+
145
+ # Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
146
+ Lint/RequireParentheses:
147
+ Enabled: true
148
+
149
+ Lint/StringConversionInInterpolation:
150
+ Enabled: true
151
+
152
+ Lint/UriEscapeUnescape:
153
+ Enabled: true
154
+
155
+ Style/ParenthesesAroundCondition:
156
+ Enabled: true
157
+
158
+ Style/RedundantReturn:
159
+ Enabled: true
160
+ AllowMultipleReturnValues: true
161
+
162
+ Style/Semicolon:
163
+ Enabled: true
164
+ AllowAsExpressionSeparator: true
165
+
166
+ # Prefer Foo.method over Foo::method
167
+ Style/ColonMethodCall:
168
+ Enabled: true
169
+
170
+ Style/TrivialAccessors:
171
+ Enabled: true
172
+
173
+ Performance/FlatMap:
174
+ Enabled: true
175
+
176
+ Performance/RedundantMerge:
177
+ Enabled: true
178
+
179
+ Performance/StartWith:
180
+ Enabled: true
181
+
182
+ Performance/EndWith:
183
+ Enabled: true
184
+
185
+ Performance/RegexpMatch:
186
+ Enabled: true
@@ -1,17 +1,22 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 2.2.4
4
- - 2.3.1
5
- - 2.4.0
3
+ - 2.3
4
+ - 2.4
5
+ - 2.5
6
+ - 2.6
6
7
  - ruby-head
7
8
  - jruby-9.1.6.0
9
+ env:
10
+ - LONG_RUN=true
8
11
  matrix:
9
12
  include:
10
- - rvm: 2.0.0
11
- gemfile: Gemfile_ruby2
12
- - rvm: 2.1.8
13
- gemfile: Gemfile_ruby2
13
+ - rvm: 2.6
14
+ env: RUBYOPT=--jit LONG_RUN=true
15
+ - rvm: ruby-head
16
+ env: RUBYOPT=--jit LONG_RUN=true
14
17
  allow_failures:
15
18
  - rvm: ruby-head
19
+ - rvm: ruby-head
20
+ env: RUBYOPT=--jit LONG_RUN=true
16
21
  - rvm: jruby-9.1.6.0
17
22
  bundler_args: --without local_development
@@ -1,4 +1,33 @@
1
- ## Unreleased
1
+ ## [2.8.0] 2019-01-18
2
+ ### Fixed
3
+ - Fixed inconsistent column length for CSV [375](https://github.com/roo-rb/roo/pull/375)
4
+ - Fixed formatted_value with `%` for Excelx [416](https://github.com/roo-rb/roo/pull/416)
5
+ - Improved Memory consumption and performance [434](https://github.com/roo-rb/roo/pull/434) [449](https://github.com/roo-rb/roo/pull/449) [454](https://github.com/roo-rb/roo/pull/454) [456](https://github.com/roo-rb/roo/pull/456) [458](https://github.com/roo-rb/roo/pull/458) [462](https://github.com/roo-rb/roo/pull/462) [466](https://github.com/roo-rb/roo/pull/466)
6
+ - Accept both Transitional and Strict Type for Excelx's worksheets [441](https://github.com/roo-rb/roo/pull/441)
7
+ - Fixed ruby warnings [442](https://github.com/roo-rb/roo/pull/442) [476](https://github.com/roo-rb/roo/pull/476)
8
+ - Restore support for URL as file identifier for CSV [462](https://github.com/roo-rb/roo/pull/462)
9
+ - Fixed missing location for Excelx's links [482](https://github.com/roo-rb/roo/pull/482)
10
+
11
+ ### Changed / Added
12
+ - Drop support for ruby 2.2.x and lower
13
+ - Updated rubyzip version for fixing security issue. Now minimal version is 1.2.1
14
+ - Roo::Excelx::Coordinate now inherits Array [458](https://github.com/roo-rb/roo/pull/458)
15
+ - Improved Roo::HeaderRowNotFoundError exception's message [461](https://github.com/roo-rb/roo/pull/461)
16
+ - Added `empty_cell` option which by default disable allocation for Roo::Excelx::Cell::Empty [464](https://github.com/roo-rb/roo/pull/464)
17
+ - Added support for variable number of decimals for Excelx's formatted_value [387](https://github.com/roo-rb/roo/pull/387)
18
+ - Added `disable_html_injection` option to disable html injection for shared string in `Roo::Excelx` [392](https://github.com/roo-rb/roo/pull/392)
19
+ - Added image extraction for Excelx [414](https://github.com/roo-rb/roo/pull/414) [397](https://github.com/roo-rb/roo/pull/397)
20
+ - Added support for `1e6` as scientific notation for Excelx [433](https://github.com/roo-rb/roo/pull/433)
21
+ - Added support for Integer as 0 based index for Excelx's `sheet_for` [455](https://github.com/roo-rb/roo/pull/455)
22
+ - Extended `no_hyperlinks` option for non streaming Excelx methods [459](https://github.com/roo-rb/roo/pull/459)
23
+ - Added `empty_cell` option to disable Roo::Excelx::Cell::Empty allocation for Excelx [464](https://github.com/roo-rb/roo/pull/464)
24
+ - Added support for Integer with leading zero for Roo:Excelx [479](https://github.com/roo-rb/roo/pull/479)
25
+ - Refactored Excelx code [453](https://github.com/roo-rb/roo/pull/453) [477](https://github.com/roo-rb/roo/pull/477) [483](https://github.com/roo-rb/roo/pull/483) [484](https://github.com/roo-rb/roo/pull/484)
26
+
27
+ ### Deprecations
28
+ - Roo::Excelx::Sheet#present_cells is deprecated [454](https://github.com/roo-rb/roo/pull/454)
29
+ - Roo::Utils.split_coordinate is deprecated [458](https://github.com/roo-rb/roo/pull/458)
30
+ - Roo::Excelx::Cell::Base#link is deprecated [457](https://github.com/roo-rb/roo/pull/457)
2
31
 
3
32
  ## [2.7.1] 2017-01-03
4
33
  ### Fixed
@@ -48,7 +77,7 @@
48
77
  - Discard hyperlinks lookups to allow streaming parsing without loading whole files
49
78
 
50
79
  ## [2.4.0] 2016-05-14
51
- ### Fixed
80
+ ### Fixed
52
81
  - Fixed opening spreadsheets with charts [315](https://github.com/roo-rb/roo/pull/315)
53
82
  - Fixed memory issues for Roo::Utils.number_to_letter [308](https://github.com/roo-rb/roo/pull/308)
54
83
  - Fixed Roo::Excelx::Cell::Number to recognize floating point numbers [306](https://github.com/roo-rb/roo/pull/306)
data/LICENSE CHANGED
@@ -1,4 +1,6 @@
1
1
  Copyright (c) 2008-2014 Thomas Preymesser, Ben Woosley
2
+ Copyright (c) 2014-2017 Ben Woosley
3
+ Copyright (c) 2015-2017 Oleksandr Simonov, Steven Daniels
2
4
 
3
5
  MIT License
4
6
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Roo
2
2
 
3
- [![Build Status](https://img.shields.io/travis/roo-rb/roo.svg?style=flat-square)](https://travis-ci.org/roo-rb/roo) [![Code Climate](https://img.shields.io/codeclimate/github/roo-rb/roo.svg?style=flat-square)](https://codeclimate.com/github/roo-rb/roo) [![Coverage Status](https://img.shields.io/coveralls/roo-rb/roo.svg?style=flat-square)](https://coveralls.io/r/roo-rb/roo) [![Gem Version](https://img.shields.io/gem/v/roo.svg?style=flat-square)](https://rubygems.org/gems/roo)
3
+ [![Build Status](https://img.shields.io/travis/roo-rb/roo.svg?style=flat-square)](https://travis-ci.org/roo-rb/roo) [![Maintainability](https://api.codeclimate.com/v1/badges/be8d7bf34e2aeaf67c62/maintainability)](https://codeclimate.com/github/roo-rb/roo/maintainability) [![Coverage Status](https://img.shields.io/coveralls/roo-rb/roo.svg?style=flat-square)](https://coveralls.io/r/roo-rb/roo) [![Gem Version](https://img.shields.io/gem/v/roo.svg?style=flat-square)](https://rubygems.org/gems/roo)
4
4
 
5
5
  Roo implements read access for all common spreadsheet types. It can handle:
6
6
  * Excel 2007 - 2013 formats (xlsx, xlsm)
@@ -89,13 +89,13 @@ sheet.last_column
89
89
  You can access the top-left cell in the following ways
90
90
 
91
91
  ```ruby
92
- s.cell(1,1)
93
- s.cell('A',1)
94
- s.cell(1,'A')
95
- s.a1
92
+ sheet.cell(1,1)
93
+ sheet.cell('A',1)
94
+ sheet.cell(1,'A')
95
+ sheet.a1
96
96
 
97
97
  # Access the second sheet's top-left cell.
98
- s.cell(1,'A',s.sheets[1])
98
+ sheet.cell(1,'A',sheet.sheets[1])
99
99
  ```
100
100
 
101
101
  #### Querying a spreadsheet
@@ -117,6 +117,12 @@ sheet.parse(id: /UPC|SKU/, qty: /ATS*\sATP\s*QTY\z/)
117
117
  # => [{:id => 727880013358, :qty => 12}, ...]
118
118
  ```
119
119
 
120
+ Use the ``:headers`` option to include the header row in the parsed content.
121
+
122
+ ```ruby
123
+ sheet.parse(headers: true)
124
+ ```
125
+
120
126
  Use the ``:header_search`` option to locate the header row and assign the header names.
121
127
 
122
128
  ```ruby
@@ -129,6 +135,16 @@ Use the ``:clean`` option to strip out control characters and surrounding white
129
135
  sheet.parse(clean: true)
130
136
  ```
131
137
 
138
+ #### Options
139
+
140
+ When opening the file you can add a hash of options.
141
+
142
+ ##### expand_merged_ranges
143
+ If you open a document with merged cells and do not want to end up with nil values for the rows after the first one.
144
+ ```ruby
145
+ xlsx = Roo::Excelx.new('./roo_error.xlsx', {:expand_merged_ranges => true})
146
+ ```
147
+
132
148
  ### Exporting spreadsheets
133
149
  Roo has the ability to export sheets using the following formats. It
134
150
  will only export the ``default_sheet``.
@@ -230,7 +246,7 @@ ods.formula('A', 2)
230
246
 
231
247
  ```ruby
232
248
  # Load a CSV file
233
- s = Roo::CSV.new("mycsv.csv")
249
+ csv = Roo::CSV.new("mycsv.csv")
234
250
  ```
235
251
 
236
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.
@@ -240,10 +256,10 @@ For instance, you can load tab-delimited files (``.tsv``), and you can use a par
240
256
 
241
257
  ```ruby
242
258
  # Load a tab-delimited csv
243
- s = Roo::CSV.new("mytsv.tsv", csv_options: {col_sep: "\t"})
259
+ csv = Roo::CSV.new("mytsv.tsv", csv_options: {col_sep: "\t"})
244
260
 
245
261
  # Load a csv with an explicit encoding
246
- s = Roo::CSV.new("mycsv.csv", csv_options: {encoding: Encoding::ISO_8859_1})
262
+ csv = Roo::CSV.new("mycsv.csv", csv_options: {encoding: Encoding::ISO_8859_1})
247
263
  ```
248
264
 
249
265
  ## Upgrading from Roo 1.13.x
@@ -272,9 +288,6 @@ You can run the tests/examples with Rspec like reporters by running
272
288
  Roo also has a few tests that take a long time (5+ seconds). To run these, use
273
289
  `LONG_RUN=true bundle exec rake`
274
290
 
275
- When testing using Ruby 2.0 or 2.1, use this command:
276
- `BUNDLE_GEMFILE=Gemfile_ruby2 bundle exec rake`
277
-
278
291
  ### Issues
279
292
 
280
293
  If you find an issue, please create a gist and refer to it in an issue ([sample gist](https://gist.github.com/stevendaniels/98a05849036e99bb8b3c)). Here are some instructions for creating such a gist.
data/lib/roo.rb CHANGED
@@ -1,3 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'roo/version'
1
4
  require 'roo/constants'
2
5
  require 'roo/errors'
3
6
  require 'roo/spreadsheet'
@@ -9,7 +12,7 @@ module Roo
9
12
  autoload :Excelx, 'roo/excelx'
10
13
  autoload :CSV, 'roo/csv'
11
14
 
12
- TEMP_PREFIX = 'roo_'.freeze
15
+ TEMP_PREFIX = 'roo_'
13
16
 
14
17
  CLASS_FOR_EXTENSION = {
15
18
  ods: Roo::OpenOffice,
@@ -1,9 +1,7 @@
1
- # encoding: utf-8
2
-
3
- require 'tmpdir'
4
- require 'stringio'
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.freeze
23
- MIN_ROW_COL = 0.freeze
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 '[DEPRECATION] please access TEMP_PREFIX via Roo::TEMP_PREFIX'
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 (1 = first sheet) or the name of a sheet.
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
- %w(first_row last_row first_column last_column).each do |key|
114
- class_eval <<-EOS, __FILE__, __LINE__ + 1
115
- def #{key}(sheet = default_sheet) # def first_row(sheet = default_sheet)
116
- read_cells(sheet) # read_cells(sheet)
117
- @#{key}[sheet] ||= first_last_row_col_for_sheet(sheet)[:#{key}] # @first_row[sheet] ||= first_last_row_col_for_sheet(sheet)[:first_row]
118
- end # end
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 << 'Sheet ' + n.to_s + ":\n"
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 << ' - empty -'
217
+ result << " - empty -"
216
218
  end
217
219
  result << "\n" if sheet != sheets.last
218
220
  n += 1
@@ -286,12 +288,12 @@ class Roo::Base
286
288
  clean_sheet_if_need(options)
287
289
  search_or_set_header(options)
288
290
  headers = @headers ||
289
- Hash[(first_column..last_column).map do |col|
290
- [cell(@header_line, col), 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(Hash[headers.map { |k, v| [k, cell(line, v)] }])
296
+ yield(headers.each_with_object({}) { |(k, v), hash| hash[k] = cell(line, v) })
295
297
  end
296
298
  end
297
299
  end
@@ -306,18 +308,22 @@ class Roo::Base
306
308
 
307
309
  def row_with(query, return_headers = false)
308
310
  line_no = 0
311
+ closest_mismatched_headers = []
309
312
  each do |row|
310
313
  line_no += 1
311
314
  headers = query.map { |q| row.grep(q)[0] }.compact
312
-
313
315
  if headers.length == query.length
314
316
  @header_line = line_no
315
317
  return return_headers ? headers : line_no
316
- elsif line_no > 100
317
- raise Roo::HeaderRowNotFoundError
318
+ else
319
+ closest_mismatched_headers = headers if headers.length > closest_mismatched_headers.length
320
+ if line_no > 100
321
+ break
322
+ end
318
323
  end
319
324
  end
320
- raise Roo::HeaderRowNotFoundError
325
+ missing_headers = query.select { |q| closest_mismatched_headers.grep(q).empty? }
326
+ raise Roo::HeaderRowNotFoundError, missing_headers
321
327
  end
322
328
 
323
329
  protected
@@ -330,7 +336,7 @@ class Roo::Base
330
336
  filename = File.basename(filename, File.extname(filename))
331
337
  end
332
338
 
333
- if uri?(filename) && (qs_begin = filename.rindex('?'))
339
+ if uri?(filename) && (qs_begin = filename.rindex("?"))
334
340
  filename = filename[0..qs_begin - 1]
335
341
  end
336
342
  exts = Array(exts)
@@ -356,7 +362,7 @@ class Roo::Base
356
362
  # Diese Methode ist eine temp. Loesung, um zu erforschen, ob der
357
363
  # Zugriff mit numerischen Keys schneller ist.
358
364
  def key_to_num(str)
359
- r, c = str.split(',')
365
+ r, c = str.split(",")
360
366
  [r.to_i, c.to_i]
361
367
  end
362
368
 
@@ -418,9 +424,9 @@ class Roo::Base
418
424
 
419
425
  def find_by_conditions(options)
420
426
  rows = first_row.upto(last_row)
421
- header_for = Hash[1.upto(last_column).map do |col|
422
- [col, cell(@header_line, col)]
423
- end]
427
+ header_for = 1.upto(last_column).each_with_object({}) do |col, hash|
428
+ hash[col] = cell(@header_line, col)
429
+ end
424
430
 
425
431
  # are all conditions met?
426
432
  conditions = options[:conditions]
@@ -435,9 +441,9 @@ class Roo::Base
435
441
  rows.map { |i| row(i) }
436
442
  else
437
443
  rows.map do |i|
438
- Hash[1.upto(row(i).size).map do |j|
439
- [header_for.fetch(j), cell(i, j)]
440
- end]
444
+ 1.upto(row(i).size).each_with_object({}) do |j, hash|
445
+ hash[header_for.fetch(j)] = cell(i, j)
446
+ end
441
447
  end
442
448
  end
443
449
  end
@@ -455,7 +461,7 @@ class Roo::Base
455
461
 
456
462
  def find_basename(filename)
457
463
  if uri?(filename)
458
- require 'uri'
464
+ require "uri"
459
465
  uri = URI.parse filename
460
466
  File.basename(uri.path)
461
467
  elsif !is_stream?(filename)
@@ -464,9 +470,9 @@ class Roo::Base
464
470
  end
465
471
 
466
472
  def make_tmpdir(prefix = nil, root = nil, &block)
467
- warn '[DEPRECATION] extend Roo::Tempdir and use its .make_tempdir instead'
473
+ warn "[DEPRECATION] extend Roo::Tempdir and use its .make_tempdir instead"
468
474
  prefix = "#{Roo::TEMP_PREFIX}#{prefix}"
469
- root ||= ENV['ROO_TMP']
475
+ root ||= ENV["ROO_TMP"]
470
476
 
471
477
  if block_given?
472
478
  # folder is deleted at end of block
@@ -485,14 +491,17 @@ class Roo::Base
485
491
  end
486
492
 
487
493
  def sanitize_value(v)
488
- v.gsub(/[[:cntrl:]]|^[\p{Space}]+|[\p{Space}]+$/, '')
494
+ v.gsub(/[[:cntrl:]]|^[\p{Space}]+|[\p{Space}]+$/, "")
489
495
  end
490
496
 
491
497
  def set_headers(hash = {})
492
498
  # try to find header row with all values or give an error
493
499
  # then create new hash by indexing strings and keeping integers for header array
494
- @headers = row_with(hash.values, true)
495
- @headers = Hash[hash.keys.zip(@headers.map { |x| header_index(x) })]
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
496
505
  end
497
506
 
498
507
  def header_index(query)
@@ -525,17 +534,17 @@ class Roo::Base
525
534
  end
526
535
 
527
536
  def uri?(filename)
528
- filename.start_with?('http://', 'https://', 'ftp://')
537
+ filename.start_with?("http://", "https://", "ftp://")
529
538
  rescue
530
539
  false
531
540
  end
532
541
 
533
542
  def download_uri(uri, tmpdir)
534
- require 'open-uri'
543
+ require "open-uri"
535
544
  tempfilename = File.join(tmpdir, find_basename(uri))
536
545
  begin
537
- File.open(tempfilename, 'wb') do |file|
538
- open(uri, 'User-Agent' => "Ruby/#{RUBY_VERSION}") do |net|
546
+ File.open(tempfilename, "wb") do |file|
547
+ open(uri, "User-Agent" => "Ruby/#{RUBY_VERSION}") do |net|
539
548
  file.write(net.read)
540
549
  end
541
550
  end
@@ -546,15 +555,15 @@ class Roo::Base
546
555
  end
547
556
 
548
557
  def open_from_stream(stream, tmpdir)
549
- tempfilename = File.join(tmpdir, 'spreadsheet')
550
- File.open(tempfilename, 'wb') do |file|
558
+ tempfilename = File.join(tmpdir, "spreadsheet")
559
+ File.open(tempfilename, "wb") do |file|
551
560
  file.write(stream[7..-1])
552
561
  end
553
- File.join(tmpdir, 'spreadsheet')
562
+ File.join(tmpdir, "spreadsheet")
554
563
  end
555
564
 
556
565
  def unzip(filename, tmpdir)
557
- require 'zip/filesystem'
566
+ require "zip/filesystem"
558
567
 
559
568
  Zip::File.open(filename) do |zip|
560
569
  process_zipfile_packed(zip, tmpdir)
@@ -567,7 +576,7 @@ class Roo::Base
567
576
  when nil
568
577
  fail ArgumentError, "Error: sheet 'nil' not valid"
569
578
  when Integer
570
- sheets.fetch(sheet - 1) do
579
+ sheets.fetch(sheet) do
571
580
  fail RangeError, "sheet index #{sheet} not found"
572
581
  end
573
582
  when String
@@ -579,16 +588,16 @@ class Roo::Base
579
588
  end
580
589
  end
581
590
 
582
- def process_zipfile_packed(zip, tmpdir, path = '')
591
+ def process_zipfile_packed(zip, tmpdir, path = "")
583
592
  if zip.file.file? path
584
593
  # extract and return filename
585
- File.open(File.join(tmpdir, path), 'wb') do |file|
594
+ File.open(File.join(tmpdir, path), "wb") do |file|
586
595
  file.write(zip.read(path))
587
596
  end
588
597
  File.join(tmpdir, path)
589
598
  else
590
599
  ret = nil
591
- path += '/' unless path.empty?
600
+ path += "/" unless path.empty?
592
601
  zip.dir.foreach(path) do |filename|
593
602
  ret = process_zipfile_packed(zip, tmpdir, path + filename)
594
603
  end