roo 2.0.1 → 2.7.1

Sign up to get free protection for your applications and to get access to all the features.
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