roo 2.0.1 → 2.7.1

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +17 -0
  3. data/.github/ISSUE_TEMPLATE +10 -0
  4. data/.gitignore +4 -0
  5. data/.travis.yml +10 -6
  6. data/CHANGELOG.md +116 -1
  7. data/Gemfile +3 -4
  8. data/Gemfile_ruby2 +30 -0
  9. data/Guardfile +1 -2
  10. data/README.md +56 -22
  11. data/Rakefile +1 -1
  12. data/lib/roo/base.rb +108 -245
  13. data/lib/roo/constants.rb +5 -0
  14. data/lib/roo/csv.rb +94 -87
  15. data/lib/roo/errors.rb +11 -0
  16. data/lib/roo/excelx/cell/base.rb +94 -0
  17. data/lib/roo/excelx/cell/boolean.rb +27 -0
  18. data/lib/roo/excelx/cell/date.rb +28 -0
  19. data/lib/roo/excelx/cell/datetime.rb +111 -0
  20. data/lib/roo/excelx/cell/empty.rb +19 -0
  21. data/lib/roo/excelx/cell/number.rb +87 -0
  22. data/lib/roo/excelx/cell/string.rb +19 -0
  23. data/lib/roo/excelx/cell/time.rb +43 -0
  24. data/lib/roo/excelx/cell.rb +33 -4
  25. data/lib/roo/excelx/comments.rb +33 -0
  26. data/lib/roo/excelx/coordinate.rb +12 -0
  27. data/lib/roo/excelx/extractor.rb +3 -4
  28. data/lib/roo/excelx/format.rb +64 -0
  29. data/lib/roo/excelx/shared.rb +32 -0
  30. data/lib/roo/excelx/shared_strings.rb +124 -4
  31. data/lib/roo/excelx/sheet.rb +12 -7
  32. data/lib/roo/excelx/sheet_doc.rb +108 -97
  33. data/lib/roo/excelx/styles.rb +1 -1
  34. data/lib/roo/excelx.rb +61 -103
  35. data/lib/roo/formatters/base.rb +15 -0
  36. data/lib/roo/formatters/csv.rb +84 -0
  37. data/lib/roo/formatters/matrix.rb +23 -0
  38. data/lib/roo/formatters/xml.rb +31 -0
  39. data/lib/roo/formatters/yaml.rb +40 -0
  40. data/lib/roo/libre_office.rb +1 -2
  41. data/lib/roo/link.rb +21 -2
  42. data/lib/roo/open_office.rb +468 -523
  43. data/lib/roo/spreadsheet.rb +3 -1
  44. data/lib/roo/tempdir.rb +21 -0
  45. data/lib/roo/utils.rb +7 -7
  46. data/lib/roo/version.rb +1 -1
  47. data/lib/roo.rb +8 -3
  48. data/roo.gemspec +2 -1
  49. data/spec/helpers.rb +5 -0
  50. data/spec/lib/roo/base_spec.rb +229 -0
  51. data/spec/lib/roo/csv_spec.rb +19 -0
  52. data/spec/lib/roo/excelx_spec.rb +97 -11
  53. data/spec/lib/roo/openoffice_spec.rb +18 -1
  54. data/spec/lib/roo/spreadsheet_spec.rb +20 -0
  55. data/spec/lib/roo/utils_spec.rb +1 -1
  56. data/spec/spec_helper.rb +5 -5
  57. data/test/all_ss.rb +12 -11
  58. data/test/excelx/cell/test_base.rb +63 -0
  59. data/test/excelx/cell/test_boolean.rb +36 -0
  60. data/test/excelx/cell/test_date.rb +38 -0
  61. data/test/excelx/cell/test_datetime.rb +45 -0
  62. data/test/excelx/cell/test_empty.rb +7 -0
  63. data/test/excelx/cell/test_number.rb +74 -0
  64. data/test/excelx/cell/test_string.rb +28 -0
  65. data/test/excelx/cell/test_time.rb +30 -0
  66. data/test/formatters/test_csv.rb +119 -0
  67. data/test/formatters/test_matrix.rb +76 -0
  68. data/test/formatters/test_xml.rb +78 -0
  69. data/test/formatters/test_yaml.rb +20 -0
  70. data/test/helpers/test_accessing_files.rb +60 -0
  71. data/test/helpers/test_comments.rb +43 -0
  72. data/test/helpers/test_formulas.rb +9 -0
  73. data/test/helpers/test_labels.rb +103 -0
  74. data/test/helpers/test_sheets.rb +55 -0
  75. data/test/helpers/test_styles.rb +62 -0
  76. data/test/roo/test_base.rb +182 -0
  77. data/test/roo/test_csv.rb +60 -0
  78. data/test/roo/test_excelx.rb +325 -0
  79. data/test/roo/test_libre_office.rb +9 -0
  80. data/test/roo/test_open_office.rb +289 -0
  81. data/test/test_helper.rb +116 -18
  82. data/test/test_roo.rb +362 -2088
  83. metadata +70 -4
  84. data/test/test_generic_spreadsheet.rb +0 -237
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module Roo
2
4
  class Spreadsheet
3
5
  class << self
@@ -22,7 +24,7 @@ module Roo
22
24
  options[:file_warning] = :ignore
23
25
  extension.tr('.', '').downcase.to_sym
24
26
  else
25
- res = ::File.extname((path =~ ::URI.regexp) ? ::URI.parse(::URI.encode(path)).path : path)
27
+ res = ::File.extname((path =~ /\A#{::URI.regexp}\z/) ? ::URI.parse(::URI.encode(path)).path : path)
26
28
  res.tr('.', '').downcase.to_sym
27
29
  end
28
30
  end
@@ -0,0 +1,21 @@
1
+ module Roo
2
+ module Tempdir
3
+ def finalize_tempdirs(object_id)
4
+ if @tempdirs && (dirs_to_remove = @tempdirs[object_id])
5
+ @tempdirs.delete(object_id)
6
+ dirs_to_remove.each do |dir|
7
+ ::FileUtils.remove_entry(dir)
8
+ end
9
+ end
10
+ end
11
+
12
+ def make_tempdir(object, prefix, root)
13
+ root ||= ENV["ROO_TMP"]
14
+ # NOTE: This folder is cleaned up by finalize_tempdirs.
15
+ ::Dir.mktmpdir("#{Roo::TEMP_PREFIX}#{prefix}", root).tap do |tmpdir|
16
+ @tempdirs ||= Hash.new { |h, k| h[k] = [] }
17
+ @tempdirs[object.object_id] << tmpdir
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/roo/utils.rb CHANGED
@@ -2,6 +2,8 @@ module Roo
2
2
  module Utils
3
3
  extend self
4
4
 
5
+ LETTERS = ('A'..'Z').to_a
6
+
5
7
  def split_coordinate(str)
6
8
  @split_coordinate ||= {}
7
9
 
@@ -27,16 +29,14 @@ module Roo
27
29
 
28
30
  # convert a number to something like 'AB' (1 => 'A', 2 => 'B', ...)
29
31
  def number_to_letter(num)
30
- results = []
31
- num = num.to_i
32
+ result = ""
32
33
 
33
- while (num > 0)
34
- mod = (num - 1) % 26
35
- results = [(65 + mod).chr] + results
36
- num = ((num - mod) / 26)
34
+ until num.zero?
35
+ num, index = (num - 1).divmod(26)
36
+ result.prepend(LETTERS[index])
37
37
  end
38
38
 
39
- results.join
39
+ result
40
40
  end
41
41
 
42
42
  def letter_to_number(letters)
data/lib/roo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Roo
2
- VERSION = "2.0.1"
2
+ VERSION = "2.7.1"
3
3
  end
data/lib/roo.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'roo/constants'
2
+ require 'roo/errors'
1
3
  require 'roo/spreadsheet'
2
4
  require 'roo/base'
3
5
 
@@ -7,20 +9,23 @@ module Roo
7
9
  autoload :Excelx, 'roo/excelx'
8
10
  autoload :CSV, 'roo/csv'
9
11
 
12
+ TEMP_PREFIX = 'roo_'.freeze
13
+
10
14
  CLASS_FOR_EXTENSION = {
11
15
  ods: Roo::OpenOffice,
12
16
  xlsx: Roo::Excelx,
17
+ xlsm: Roo::Excelx,
13
18
  csv: Roo::CSV
14
19
  }
15
20
 
16
21
  def self.const_missing(const_name)
17
22
  case const_name
18
23
  when :Excel
19
- raise "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."
24
+ raise ROO_EXCEL_NOTICE
20
25
  when :Excel2003XML
21
- raise "Excel SpreadsheetML support has been extracted to roo-xls. Install roo-xls to use Roo::Excel2003XML."
26
+ raise ROO_EXCELML_NOTICE
22
27
  when :Google
23
- raise "Google support has been extracted to roo-google. Install roo-google to use Roo::Google."
28
+ raise ROO_GOOGLE_NOTICE
24
29
  else
25
30
  super
26
31
  end
data/roo.gemspec CHANGED
@@ -6,7 +6,7 @@ require 'roo/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'roo'
8
8
  spec.version = Roo::VERSION
9
- spec.authors = ['Thomas Preymesser', 'Hugh McGowan', 'Ben Woosley', 'Oleksandr Simonov']
9
+ spec.authors = ['Thomas Preymesser', 'Hugh McGowan', 'Ben Woosley', 'Oleksandr Simonov', 'Steven Daniels']
10
10
  spec.email = ['ruby.ruby.ruby.roo@gmail.com', 'oleksandr@simonov.me']
11
11
  spec.summary = 'Roo can access the contents of various spreadsheet files.'
12
12
  spec.description = "Roo can access the contents of various spreadsheet files. It can handle\n* OpenOffice\n* Excelx\n* LibreOffice\n* CSV"
@@ -22,4 +22,5 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_development_dependency 'rake', '~> 10.1'
24
24
  spec.add_development_dependency 'minitest', '~> 5.4', '>= 5.4.3'
25
+ spec.add_development_dependency 'rack', '~> 1.6', '< 2.0.0'
25
26
  end
data/spec/helpers.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Helpers
2
+ def yaml_entry(row,col,type,value)
3
+ "cell_#{row}_#{col}: \n row: #{row} \n col: #{col} \n celltype: #{type} \n value: #{value} \n"
4
+ end
5
+ end
@@ -1,4 +1,233 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Roo::Base do
4
+ let(:klass) do
5
+ Class.new(Roo::Base) do
6
+ def initialize(filename, data = {})
7
+ super(filename)
8
+ @data ||= data
9
+ end
10
+
11
+ def read_cells(sheet = default_sheet)
12
+ return if @cells_read[sheet]
13
+ type_map = { String => :string, Date => :date, Numeric => :float }
14
+
15
+ @cell[sheet] = @data
16
+ @cell_type[sheet] = Hash[@data.map { |k, v| [k, type_map.find {|type,_| v.is_a?(type) }.last ] }]
17
+ @first_row[sheet] = @data.map { |k, _| k[0] }.min
18
+ @last_row[sheet] = @data.map { |k, _| k[0] }.max
19
+ @first_column[sheet] = @data.map { |k, _| k[1] }.min
20
+ @last_column[sheet] = @data.map { |k, _| k[1] }.max
21
+ @cells_read[sheet] = true
22
+ end
23
+
24
+ def cell(row, col, sheet = nil)
25
+ sheet ||= default_sheet
26
+ read_cells(sheet)
27
+ @cell[sheet][[row, col]]
28
+ end
29
+
30
+ def celltype(row, col, sheet = nil)
31
+ sheet ||= default_sheet
32
+ read_cells(sheet)
33
+ @cell_type[sheet][[row, col]]
34
+ end
35
+
36
+ def sheets
37
+ ['my_sheet', 'blank sheet']
38
+ end
39
+ end
40
+ end
41
+
42
+ let(:spreadsheet_data) do
43
+ {
44
+ [3, 1] => 'Header',
45
+
46
+ [5, 1] => Date.civil(1961, 11, 21),
47
+
48
+ [8, 3] => 'thisisc8',
49
+ [8, 7] => 'thisisg8',
50
+
51
+ [12, 1] => 41.0,
52
+ [12, 2] => 42.0,
53
+ [12, 3] => 43.0,
54
+ [12, 4] => 44.0,
55
+ [12, 5] => 45.0,
56
+
57
+ [15, 3] => 43.0,
58
+ [15, 4] => 44.0,
59
+ [15, 5] => 45.0,
60
+
61
+ [16, 2] => '"Hello world!"',
62
+ [16, 3] => 'forty-three',
63
+ [16, 4] => 'forty-four',
64
+ [16, 5] => 'forty-five'
65
+ }
66
+ end
67
+
68
+ let(:spreadsheet) { klass.new('some_file', spreadsheet_data) }
69
+
70
+ describe '#uri?' do
71
+ it 'should return true when passed a filename starting with http(s)://' do
72
+ expect(spreadsheet.send(:uri?, 'http://example.com/')).to be_truthy
73
+ expect(spreadsheet.send(:uri?, 'https://example.com/')).to be_truthy
74
+ end
75
+
76
+ it 'should return false when passed a filename which does not start with http(s)://' do
77
+ expect(spreadsheet.send(:uri?, 'example.com')).to be_falsy
78
+ end
79
+
80
+ it 'should return false when passed non-String object such as Tempfile' do
81
+ expect(spreadsheet.send(:uri?, Tempfile.new('test'))).to be_falsy
82
+ end
83
+ end
84
+
85
+ describe '#set' do
86
+ it 'should not update cell when setting an invalid type' do
87
+ spreadsheet.set(1, 1, 1)
88
+ expect { spreadsheet.set(1, 1, :invalid_type) }.to raise_error(ArgumentError)
89
+ expect(spreadsheet.cell(1, 1)).to eq(1)
90
+ expect(spreadsheet.celltype(1, 1)).to eq(:float)
91
+ end
92
+ end
93
+
94
+ describe '#first_row' do
95
+ it 'should return the first row' do
96
+ expect(spreadsheet.first_row).to eq(3)
97
+ end
98
+ end
99
+
100
+ describe '#last_row' do
101
+ it 'should return the last row' do
102
+ expect(spreadsheet.last_row).to eq(16)
103
+ end
104
+ end
105
+
106
+ describe '#first_column' do
107
+ it 'should return the first column' do
108
+ expect(spreadsheet.first_column).to eq(1)
109
+ end
110
+ end
111
+
112
+ describe '#first_column_as_letter' do
113
+ it 'should return the first column as a letter' do
114
+ expect(spreadsheet.first_column_as_letter).to eq('A')
115
+ end
116
+ end
117
+
118
+ describe '#last_column' do
119
+ it 'should return the last column' do
120
+ expect(spreadsheet.last_column).to eq(7)
121
+ end
122
+ end
123
+
124
+ describe '#last_column_as_letter' do
125
+ it 'should return the last column as a letter' do
126
+ expect(spreadsheet.last_column_as_letter).to eq('G')
127
+ end
128
+ end
129
+
130
+ describe '#row' do
131
+ it 'should return the specified row' do
132
+ expect(spreadsheet.row(12)).to eq([41.0, 42.0, 43.0, 44.0, 45.0, nil, nil])
133
+ expect(spreadsheet.row(16)).to eq([nil, '"Hello world!"', 'forty-three', 'forty-four', 'forty-five', nil, nil])
134
+ end
135
+ end
136
+
137
+ describe '#row_with' do
138
+ context 'with a matching header row' do
139
+ it 'returns the row number' do
140
+ expect(spreadsheet.row_with([/Header/])). to eq 3
141
+ end
142
+ end
143
+
144
+ context 'without a matching header row' do
145
+ it 'raises an error' do
146
+ expect { spreadsheet.row_with([/Missing Header/]) }.to \
147
+ raise_error(Roo::HeaderRowNotFoundError)
148
+ end
149
+ end
150
+ end
151
+
152
+ describe '#empty?' do
153
+ it 'should return true when empty' do
154
+ expect(spreadsheet.empty?(1, 1)).to be_truthy
155
+ expect(spreadsheet.empty?(8, 3)).to be_falsy
156
+ expect(spreadsheet.empty?('A', 11)).to be_truthy
157
+ expect(spreadsheet.empty?('A', 12)).to be_falsy
158
+ end
159
+ end
160
+
161
+ describe '#reload' do
162
+ it 'should return reinitialize the spreadsheet' do
163
+ spreadsheet.reload
164
+ expect(spreadsheet.instance_variable_get(:@cell).empty?).to be_truthy
165
+ end
166
+ end
167
+
168
+ describe '#each' do
169
+ it 'should return an enumerator with all the rows' do
170
+ each = spreadsheet.each
171
+ expect(each).to be_a(Enumerator)
172
+ expect(each.to_a.last).to eq([nil, '"Hello world!"', 'forty-three', 'forty-four', 'forty-five', nil, nil])
173
+ end
174
+ end
175
+
176
+ describe '#to_yaml' do
177
+ it 'should convert the spreadsheet to yaml' do
178
+ expect(spreadsheet.to_yaml({}, 5, 1, 5, 1)).to eq("--- \n" + yaml_entry(5, 1, 'date', '1961-11-21'))
179
+ expect(spreadsheet.to_yaml({}, 8, 3, 8, 3)).to eq("--- \n" + yaml_entry(8, 3, 'string', 'thisisc8'))
180
+
181
+ expect(spreadsheet.to_yaml({}, 12, 3, 12, 3)).to eq("--- \n" + yaml_entry(12, 3, 'float', 43.0))
182
+
183
+ expect(spreadsheet.to_yaml({}, 12, 3, 12)).to eq(
184
+ "--- \n" + yaml_entry(12, 3, 'float', 43.0) +
185
+ yaml_entry(12, 4, 'float', 44.0) +
186
+ yaml_entry(12, 5, 'float', 45.0))
187
+
188
+ expect(spreadsheet.to_yaml({}, 12, 3)).to eq(
189
+ "--- \n" + yaml_entry(12, 3, 'float', 43.0) +
190
+ yaml_entry(12, 4, 'float', 44.0) +
191
+ yaml_entry(12, 5, 'float', 45.0) +
192
+ yaml_entry(15, 3, 'float', 43.0) +
193
+ yaml_entry(15, 4, 'float', 44.0) +
194
+ yaml_entry(15, 5, 'float', 45.0) +
195
+ yaml_entry(16, 3, 'string', 'forty-three') +
196
+ yaml_entry(16, 4, 'string', 'forty-four') +
197
+ yaml_entry(16, 5, 'string', 'forty-five'))
198
+ end
199
+ end
200
+
201
+ let(:expected_csv) do
202
+ <<EOS
203
+ ,,,,,,
204
+ ,,,,,,
205
+ "Header",,,,,,
206
+ ,,,,,,
207
+ 1961-11-21,,,,,,
208
+ ,,,,,,
209
+ ,,,,,,
210
+ ,,"thisisc8",,,,"thisisg8"
211
+ ,,,,,,
212
+ ,,,,,,
213
+ ,,,,,,
214
+ 41,42,43,44,45,,
215
+ ,,,,,,
216
+ ,,,,,,
217
+ ,,43,44,45,,
218
+ ,"""Hello world!""","forty-three","forty-four","forty-five",,
219
+ EOS
220
+ end
221
+
222
+ let(:expected_csv_with_semicolons) { expected_csv.gsub(/\,/, ';') }
223
+
224
+ describe '#to_csv' do
225
+ it 'should convert the spreadsheet to csv' do
226
+ expect(spreadsheet.to_csv).to eq(expected_csv)
227
+ end
228
+
229
+ it 'should convert the spreadsheet to csv using the separator when is passed on the parameter' do
230
+ expect(spreadsheet.to_csv(nil, ';')).to eq(expected_csv_with_semicolons)
231
+ end
232
+ end
4
233
  end
@@ -10,6 +10,13 @@ describe Roo::CSV do
10
10
  end
11
11
  end
12
12
 
13
+ describe '.new with stream' do
14
+ let(:csv) { Roo::CSV.new(File.read(path)) }
15
+ it 'creates an instance' do
16
+ expect(csv).to be_a(Roo::CSV)
17
+ end
18
+ end
19
+
13
20
  describe '#parse' do
14
21
  subject do
15
22
  csv.parse(options)
@@ -59,4 +66,16 @@ describe Roo::CSV do
59
66
  end
60
67
  end
61
68
  end
69
+
70
+ describe '#set_value' do
71
+ it 'returns the cell value' do
72
+ expect(csv.set_value('A', 1, 'some-value', nil)).to eq('some-value')
73
+ end
74
+ end
75
+
76
+ describe '#set_type' do
77
+ it 'returns the cell type' do
78
+ expect(csv.set_type('A', 1, 'some-type', nil)).to eq('some-type')
79
+ end
80
+ end
62
81
  end
@@ -6,6 +6,18 @@ describe Roo::Excelx do
6
6
  Roo::Excelx.new(path)
7
7
  end
8
8
 
9
+ describe 'Constants' do
10
+ describe 'ERROR_VALUES' do
11
+ it 'returns all possible errorr values' do
12
+ expect(described_class::ERROR_VALUES).to eq(%w(#N/A #REF! #NAME? #DIV/0! #NULL! #VALUE! #NUM!).to_set)
13
+ end
14
+
15
+ it 'is a set' do
16
+ expect(described_class::ERROR_VALUES).to be_an_instance_of(Set)
17
+ end
18
+ end
19
+ end
20
+
9
21
  describe '.new' do
10
22
  let(:path) { 'test/files/numeric-link.xlsx' }
11
23
 
@@ -44,7 +56,6 @@ describe Roo::Excelx do
44
56
  expect(subject).to be_a(Roo::Excelx)
45
57
  end
46
58
  end
47
-
48
59
  end
49
60
 
50
61
  describe '#cell' do
@@ -58,7 +69,11 @@ describe Roo::Excelx do
58
69
 
59
70
  it 'returns a link with the number as a string value' do
60
71
  expect(subject).to be_a(Roo::Link)
61
- expect(subject).to eq('8675309.0')
72
+ # FIXME: Because Link inherits from String, it is a String,
73
+ # But in theory, it shouldn't have to be a String.
74
+ # NOTE: This test is broken becase Cell::Numeric formats numbers
75
+ # more intelligently.
76
+ # expect(subject).to eq('8675309.0')
62
77
  end
63
78
  end
64
79
  end
@@ -82,7 +97,7 @@ describe Roo::Excelx do
82
97
  this: 'This',
83
98
  that: 'That'
84
99
  )
85
- end.to raise_error("Couldn't find header row.")
100
+ end.to raise_error(Roo::HeaderRowNotFoundError)
86
101
  end
87
102
  end
88
103
  end
@@ -107,16 +122,12 @@ describe Roo::Excelx do
107
122
  let(:options) { {clean: true, name: 'Name'} }
108
123
 
109
124
  context 'with clean: true' do
110
-
111
125
  it 'returns a non empty string' do
112
126
  expect(xlsx.parse(options).last[:name]).to eql('凯')
113
127
  end
114
128
  end
115
129
  end
116
130
 
117
-
118
-
119
-
120
131
  describe '#sheets' do
121
132
  let(:path) { 'test/files/numbers1.xlsx' }
122
133
 
@@ -191,7 +202,6 @@ describe Roo::Excelx do
191
202
  end
192
203
 
193
204
  describe '#set' do
194
-
195
205
  before do
196
206
  subject.set(1, 2, "Foo", "Sheet5")
197
207
  end
@@ -268,15 +278,29 @@ describe Roo::Excelx do
268
278
  end
269
279
  end
270
280
 
281
+ # FIXME: IMO, these tests don't provide much value. Under what circumstances
282
+ # will a user require the "index" value for the shared strings table?
283
+ # Excel value should be the raw unformatted value for the cell.
271
284
  describe '#excelx_value' do
272
285
  let(:path) { 'test/files/numbers1.xlsx' }
273
286
 
274
287
  it 'returns the expected result' do
275
288
  # These values are the index in the shared strings table, might be a better
276
289
  # way to get these rather than hardcoding.
277
- expect(subject.excelx_value(1, 1, "Sheet5")).to eq "1"
278
- expect(subject.excelx_value(6, 2, "Sheet5")).to eq "16"
279
- expect(subject.excelx_value(6000, 2000, "Sheet5")).to eq nil
290
+
291
+ # expect(subject.excelx_value(1, 1, "Sheet5")).to eq "1" # passes by accident
292
+ # expect(subject.excelx_value(6, 2, "Sheet5")).to eq "16"
293
+ # expect(subject.excelx_value(6000, 2000, "Sheet5")).to eq nil
294
+ end
295
+ end
296
+
297
+ describe '#formatted_value' do
298
+ context 'contains zero-padded numbers' do
299
+ let(:path) { 'test/files/zero-padded-number.xlsx' }
300
+
301
+ it 'returns a zero-padded number' do
302
+ expect(subject.formatted_value(4, 1)).to eq '05010'
303
+ end
280
304
  end
281
305
  end
282
306
 
@@ -447,5 +471,67 @@ describe Roo::Excelx do
447
471
  expect(index).to eq 4
448
472
  end
449
473
  end
474
+
475
+ context 'without block passed' do
476
+ it 'returns an enumerator' do
477
+ expect(subject.each_row_streaming).to be_a(Enumerator)
478
+ end
479
+ end
480
+ end
481
+
482
+ describe '#html_strings' do
483
+ let(:path) { 'test/files/html_strings_formatting.xlsx' }
484
+
485
+ it 'returns the expected result' do
486
+ expect(subject.excelx_value(1, 1, "Sheet1")).to eq "This has no formatting."
487
+ expect(subject.excelx_value(2, 1, "Sheet1")).to eq "<html>This has<b> bold </b>formatting.</html>"
488
+ expect(subject.excelx_value(2, 2, "Sheet1")).to eq "<html>This has <i>italics</i> formatting.</html>"
489
+ expect(subject.excelx_value(2, 3, "Sheet1")).to eq "<html>This has <u>underline</u> format.</html>"
490
+ expect(subject.excelx_value(2, 4, "Sheet1")).to eq "<html>Superscript. x<sup>123</sup></html>"
491
+ expect(subject.excelx_value(2, 5, "Sheet1")).to eq "<html>SubScript. T<sub>j</sub></html>"
492
+
493
+ expect(subject.excelx_value(3, 1, "Sheet1")).to eq "<html>Bold, italics <b><i>together</i></b>.</html>"
494
+ expect(subject.excelx_value(3, 2, "Sheet1")).to eq "<html>Bold, Underline <b><u>together</u></b>.</html>"
495
+ expect(subject.excelx_value(3, 3, "Sheet1")).to eq "<html>Bold, Superscript. <b>x</b><sup><b>N</b></sup></html>"
496
+ expect(subject.excelx_value(3, 4, "Sheet1")).to eq "<html>Bold, Subscript. <b>T</b><sub><b>abc</b></sub></html>"
497
+ expect(subject.excelx_value(3, 5, "Sheet1")).to eq "<html>Italics, Underline <i><u>together</u></i>.</html>"
498
+ expect(subject.excelx_value(3, 6, "Sheet1")).to eq "<html>Italics, Superscript. <i>X</i><sup><i>abc</i></sup></html>"
499
+ expect(subject.excelx_value(3, 7, "Sheet1")).to eq "<html>Italics, Subscript. <i>B</i><sub><i>efg</i></sub></html>"
500
+ expect(subject.excelx_value(4, 1, "Sheet1")).to eq "<html>Bold, italics underline,<b><i><u> together</u></i></b>.</html>"
501
+ expect(subject.excelx_value(4, 2, "Sheet1")).to eq "<html>Bold, italics, superscript. <b>X</b><sup><b><i>abc</i></b></sup><b><i>123</i></b></html>"
502
+ expect(subject.excelx_value(4, 3, "Sheet1")).to eq "<html>Bold, Italics, subscript. <b><i>Mg</i></b><sub><b><i>ha</i></b></sub><b><i>2</i></b></html>"
503
+ expect(subject.excelx_value(4, 4, "Sheet1")).to eq "<html>Bold, Underline, superscript. <b><u>AB</u></b><sup><b><u>C12</u></b></sup><b><u>3</u></b></html>"
504
+ expect(subject.excelx_value(4, 5, "Sheet1")).to eq "<html>Bold, Underline, subscript. <b><u>Good</u></b><sub><b><u>XYZ</u></b></sub></html>"
505
+ expect(subject.excelx_value(4, 6, "Sheet1")).to eq "<html>Italics, Underline, superscript. <i><u>Up</u></i><sup><i><u>swing</u></i></sup></html>"
506
+ expect(subject.excelx_value(4, 7, "Sheet1")).to eq "<html>Italics, Underline, subscript. <i><u>T</u></i><sub><i><u>swing</u></i></sub></html>"
507
+ expect(subject.excelx_value(5, 1, "Sheet1")).to eq "<html>Bold, italics, underline, superscript. <b><i><u>GHJK</u></i></b><sup><b><i><u>190</u></i></b></sup><b><i><u>4</u></i></b></html>"
508
+ expect(subject.excelx_value(5, 2, "Sheet1")).to eq "<html>Bold, italics, underline, subscript. <b><i><u>Mike</u></i></b><sub><b><i><u>drop</u></i></b></sub></html>"
509
+ expect(subject.excelx_value(6, 1, "Sheet1")).to eq "See that regular html tags do not create html tags.\n<ol>\n <li> Denver Broncos </li>\n <li> Carolina Panthers </li>\n <li> New England Patriots</li>\n <li>Arizona Panthers</li>\n</ol>"
510
+ expect(subject.excelx_value(7, 1, "Sheet1")).to eq "<html>Does create html tags when formatting is used..\n<ol>\n <li> <b>Denver Broncos</b> </li>\n <li> <i>Carolina Panthers </i></li>\n <li> <u>New England Patriots</u></li>\n <li>Arizona Panthers</li>\n</ol></html>"
511
+ end
512
+ end
513
+
514
+ describe '_x000D_' do
515
+ let(:path) { 'test/files/x000D.xlsx' }
516
+ it 'does not contain _x000D_' do
517
+ expect(subject.cell(2, 9)).not_to include('_x000D_')
518
+ end
519
+ end
520
+
521
+ describe 'opening a file with a chart sheet' do
522
+ let(:path) { 'test/files/chart_sheet.xlsx' }
523
+ it 'should not raise' do
524
+ expect{ subject }.to_not raise_error
525
+ end
526
+ end
527
+
528
+ describe 'opening a file with white space in the styles.xml' do
529
+ let(:path) { 'test/files/style_nodes_with_white_spaces.xlsx' }
530
+ subject(:xlsx) do
531
+ Roo::Spreadsheet.open(path, expand_merged_ranges: true, extension: :xlsx)
532
+ end
533
+ it 'should properly recognize formats' do
534
+ expect(subject.sheet(0).excelx_format(2,1)).to eq 'm/d/yyyy" "h:mm:ss" "AM/PM'
535
+ end
450
536
  end
451
537
  end
@@ -10,6 +10,23 @@ describe Roo::OpenOffice do
10
10
  expect(subject).to be_a(Roo::OpenOffice)
11
11
  end
12
12
 
13
+ context 'for float/integer values' do
14
+ context 'integer without point' do
15
+ it { expect(subject.cell(3,"A","Sheet4")).to eq(1234) }
16
+ it { expect(subject.cell(3,"A","Sheet4")).to be_a(Integer) }
17
+ end
18
+
19
+ context 'float with point' do
20
+ it { expect(subject.cell(3,"B","Sheet4")).to eq(1234.00) }
21
+ it { expect(subject.cell(3,"B","Sheet4")).to be_a(Float) }
22
+ end
23
+
24
+ context 'float with point' do
25
+ it { expect(subject.cell(3,"C","Sheet4")).to eq(1234.12) }
26
+ it { expect(subject.cell(3,"C","Sheet4")).to be_a(Float) }
27
+ end
28
+ end
29
+
13
30
  context 'file path is a Pathname' do
14
31
  subject do
15
32
  Roo::OpenOffice.new(Pathname.new('test/files/numbers1.ods'))
@@ -19,7 +36,7 @@ describe Roo::OpenOffice do
19
36
  expect(subject).to be_a(Roo::OpenOffice)
20
37
  end
21
38
  end
22
-
39
+
23
40
  end
24
41
 
25
42
  # OpenOffice is an alias of LibreOffice. See libreoffice_spec.
@@ -41,6 +41,26 @@ describe Roo::Spreadsheet do
41
41
  end
42
42
  end
43
43
 
44
+ context 'for a windows path' do
45
+ context 'that is xlsx' do
46
+ let(:filename) { 'c:\Users\Joe\Desktop\myfile.xlsx' }
47
+
48
+ it 'loads the proper type' do
49
+ expect(Roo::Excelx).to receive(:new).with(filename, {})
50
+ Roo::Spreadsheet.open(filename)
51
+ end
52
+ end
53
+ end
54
+
55
+ context 'for a xlsm file' do
56
+ let(:filename) { 'macros spreadsheet.xlsm' }
57
+
58
+ it 'loads the proper type' do
59
+ expect(Roo::Excelx).to receive(:new).with(filename, {})
60
+ Roo::Spreadsheet.open(filename)
61
+ end
62
+ end
63
+
44
64
  context 'for a csv file' do
45
65
  let(:filename) { 'file.csv' }
46
66
  let(:options) { { csv_options: { col_sep: '"' } } }
@@ -4,7 +4,7 @@ RSpec.describe ::Roo::Utils do
4
4
  subject { described_class }
5
5
 
6
6
  context '#number_to_letter' do
7
- ('A'..'Z').to_a.each_with_index do |letter, index|
7
+ described_class::LETTERS.each_with_index do |letter, index|
8
8
  it "should return '#{ letter }' when passed #{ index + 1 }" do
9
9
  expect(described_class.number_to_letter(index + 1)).to eq(letter)
10
10
  end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  require 'simplecov'
2
2
  require 'roo'
3
+ require 'helpers'
3
4
 
4
- require 'vcr'
5
-
6
- VCR.configure do |c|
7
- c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
8
- c.hook_into :webmock # or :fakeweb
5
+ RSpec.configure do |c|
6
+ c.include Helpers
7
+ c.color = true
8
+ c.formatter = :documentation if ENV["USE_REPORTERS"]
9
9
  end
data/test/all_ss.rb CHANGED
@@ -1,11 +1,12 @@
1
- require 'roo'
2
- Dir.glob("test/files/*.ods").each do |fn|
3
- begin
4
- oo = Roo::OpenOffice.new fn
5
- print File.basename(fn) + " "
6
- puts oo.officeversion
7
- rescue Zip::ZipError, Errno::ENOENT => e
8
- # file is not a real .ods spreadsheet file
9
- puts e.message
10
- end
11
- end
1
+ require 'roo'
2
+
3
+ Dir.glob('test/files/*.ods').each do |fn|
4
+ begin
5
+ oo = Roo::OpenOffice.new fn
6
+ print "#{File.basename(fn)} "
7
+ puts oo.officeversion
8
+ rescue Zip::ZipError, Errno::ENOENT => e
9
+ # file is not a real .ods spreadsheet file
10
+ puts e.message
11
+ end
12
+ end