jruby-poi 0.9.0 → 1.0.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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.travis.yml +18 -4
  4. data/Gemfile +3 -6
  5. data/Gemfile.lock +20 -27
  6. data/README.markdown +49 -47
  7. data/Rakefile +20 -27
  8. data/jruby-poi.gemspec +7 -70
  9. data/lib/poi-jars/lib/commons-codec-1.10.jar +0 -0
  10. data/lib/poi-jars/lib/commons-collections4-4.1.jar +0 -0
  11. data/lib/poi-jars/lib/commons-logging-1.2.jar +0 -0
  12. data/lib/poi-jars/lib/junit-4.12.jar +0 -0
  13. data/lib/poi-jars/lib/log4j-1.2.17.jar +0 -0
  14. data/lib/poi-jars/ooxml-lib/curvesapi-1.04.jar +0 -0
  15. data/lib/{ooxml-lib/xmlbeans-2.3.0.jar → poi-jars/ooxml-lib/xmlbeans-2.6.0.jar} +0 -0
  16. data/lib/poi-jars/poi-3.15.jar +0 -0
  17. data/lib/poi-jars/poi-examples-3.15.jar +0 -0
  18. data/lib/poi-jars/poi-excelant-3.15.jar +0 -0
  19. data/lib/poi-jars/poi-ooxml-3.15.jar +0 -0
  20. data/lib/poi-jars/poi-ooxml-schemas-3.15.jar +0 -0
  21. data/lib/poi-jars/poi-scratchpad-3.15.jar +0 -0
  22. data/lib/poi.rb +13 -7
  23. data/lib/poi/version.rb +11 -0
  24. data/lib/poi/workbook/area.rb +20 -17
  25. data/lib/poi/workbook/cell.rb +28 -42
  26. data/lib/poi/workbook/row.rb +1 -1
  27. data/lib/poi/workbook/workbook.rb +3 -7
  28. data/lib/poi/workbook/worksheet.rb +2 -2
  29. data/spec/data/1904_window_dates.xls +0 -0
  30. data/spec/data/various_samples.xlsx +0 -0
  31. data/spec/facade_spec.rb +35 -35
  32. data/spec/spec_helper.rb +10 -0
  33. data/spec/support/matchers/cell_matcher.rb +3 -3
  34. data/spec/workbook_spec.rb +368 -385
  35. data/spec/writing_spec.rb +144 -144
  36. metadata +111 -121
  37. data/VERSION +0 -1
  38. data/lib/ooxml-lib/dom4j-1.6.1.jar +0 -0
  39. data/lib/ooxml-lib/stax-api-1.0.1.jar +0 -0
  40. data/lib/poi-3.8-20120326.jar +0 -0
  41. data/lib/poi-examples-3.8-20120326.jar +0 -0
  42. data/lib/poi-excelant-3.8-20120326.jar +0 -0
  43. data/lib/poi-ooxml-3.8-20120326.jar +0 -0
  44. data/lib/poi-ooxml-schemas-3.8-20120326.jar +0 -0
  45. data/lib/poi-scratchpad-3.8-20120326.jar +0 -0
@@ -1,3 +1,5 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'date'
1
3
  module POI
2
4
  class Cells
3
5
  include Enumerable
@@ -9,7 +11,7 @@ module POI
9
11
  end
10
12
 
11
13
  def [](index)
12
- @cells[index] ||= Cell.new(@poi_row.cell(index) || @poi_row.create_cell(index), @row)
14
+ @cells[index] ||= Cell.new(@poi_row.get_cell(index) || @poi_row.create_cell(index), @row)
13
15
  end
14
16
 
15
17
  def size
@@ -52,8 +54,8 @@ module POI
52
54
  elsif poi_cell.cell_type == CELL_TYPE_FORMULA &&
53
55
  poi_cell.cached_formula_result_type == CELL_TYPE_ERROR
54
56
 
55
- # breaks Law of Demeter by reaching into the Row's Worksheet, but it makes sense to do in this case
56
- value_of(@row.worksheet.workbook.formula_evaluator.evaluate(poi_cell))
57
+ cell_value = formula_evaluator.evaluate(poi_cell)
58
+ cell_value && error_value_from(cell_value.error_value)
57
59
  else
58
60
  nil
59
61
  end
@@ -66,7 +68,7 @@ module POI
66
68
 
67
69
  def value
68
70
  return nil if poi_cell.nil?
69
- value_of(cell_value_for_type(poi_cell.cell_type))
71
+ cast_value
70
72
  end
71
73
 
72
74
  def formula= new_value
@@ -124,51 +126,35 @@ module POI
124
126
  end
125
127
 
126
128
  private
127
- def value_of(cell_value)
128
- return nil if cell_value.nil?
129
-
130
- case cell_value.cell_type
129
+ def cast_value(type = cell_type)
130
+ case type
131
131
  when CELL_TYPE_BLANK then nil
132
- when CELL_TYPE_BOOLEAN then cell_value.boolean_value
133
- when CELL_TYPE_ERROR then error_value_from(cell_value.error_value)
134
- when CELL_TYPE_NUMERIC then numeric_value_from(cell_value)
135
- when CELL_TYPE_STRING then cell_value.string_value
136
- else
137
- raise "unhandled cell type[#{cell_value.cell_type}]"
138
- end
139
- end
140
-
141
- def cell_value_for_type(cell_type)
142
- return nil if cell_type.nil?
143
- begin
144
- case cell_type
145
- when CELL_TYPE_BLANK then nil
146
- when CELL_TYPE_BOOLEAN then CELL_VALUE.value_of(poi_cell.boolean_cell_value)
147
- when CELL_TYPE_FORMULA then cell_value_for_type(poi_cell.cached_formula_result_type)
148
- when CELL_TYPE_STRING then CELL_VALUE.new(poi_cell.string_cell_value)
149
- when CELL_TYPE_ERROR, CELL_TYPE_NUMERIC then CELL_VALUE.new(poi_cell.numeric_cell_value)
132
+ when CELL_TYPE_BOOLEAN then get_boolean_cell_value
133
+ when CELL_TYPE_ERROR then nil
134
+ when CELL_TYPE_FORMULA then cast_value(poi_cell.cached_formula_result_type)
135
+ when CELL_TYPE_STRING then get_string_cell_value
136
+ when CELL_TYPE_NUMERIC
137
+ if DATE_UTIL.cell_date_formatted(poi_cell)
138
+ DateTime.parse(get_date_cell_value.to_s)
150
139
  else
151
- raise "unhandled cell type[#{poi_cell.cell_type}]"
140
+ get_numeric_cell_value
152
141
  end
153
- rescue
154
- nil
142
+ else
143
+ raise "unhandled cell type[#{type}]"
155
144
  end
156
145
  end
157
-
158
- def error_value_from(cell_value)
159
- org.apache.poi.ss.usermodel.ErrorConstants.text(cell_value)
146
+
147
+ def workbook
148
+ @row.worksheet.workbook
160
149
  end
161
-
162
- def formula_evaluator_for(workbook)
163
- workbook.creation_helper.create_formula_evaluator
150
+
151
+ def formula_evaluator
152
+ workbook.formula_evaluator
164
153
  end
165
-
166
- def numeric_value_from(cell_value)
167
- if DATE_UTIL.cell_date_formatted(poi_cell)
168
- Date.parse(DATE_UTIL.get_java_date(cell_value.number_value).to_s)
169
- else
170
- cell_value.number_value
171
- end
154
+
155
+ def error_value_from(cell_value)
156
+ #org.apache.poi.ss.usermodel.ErrorConstants.get_text(cell_value)
157
+ org.apache.poi.ss.usermodel.FormulaError.forInt(cell_value).getString
172
158
  end
173
159
  end
174
160
  end
@@ -9,7 +9,7 @@ module POI
9
9
  end
10
10
 
11
11
  def [](index)
12
- @rows[index] ||= Row.new(@poi_worksheet.row(index) || @poi_worksheet.create_row(index), @worksheet)
12
+ @rows[index] ||= Row.new(@poi_worksheet.get_row(index) || @poi_worksheet.create_row(index), @worksheet)
13
13
  end
14
14
 
15
15
  def size
@@ -132,7 +132,7 @@ module POI
132
132
 
133
133
  def named_ranges
134
134
  @named_ranges ||= (0...@workbook.number_of_names).collect do | idx |
135
- NamedRange.new @workbook.name_at(idx), self
135
+ NamedRange.new @workbook.get_name_at(idx), self
136
136
  end
137
137
  end
138
138
 
@@ -208,7 +208,7 @@ module POI
208
208
  end
209
209
 
210
210
  def cells_in_area reference
211
- area = Area.new(reference)
211
+ area = Area.new(reference, self.get_spreadsheet_version)
212
212
  area.in(self)
213
213
  end
214
214
 
@@ -242,13 +242,9 @@ module POI
242
242
  area_start = "#{sheet_parts.first}!#{area_parts.first}"
243
243
  area_end = area_parts.last
244
244
 
245
- area = org.apache.poi.ss.util.AreaReference.getWholeColumn(area_start, area_end)
245
+ area = AREA_REF.getWholeColumn(get_worksheet_version, area_start, area_end)
246
246
  full_ref = "#{area.first_cell.format_as_string}:#{area.last_cell.format_as_string}"
247
247
  Area.new(full_ref).in(self)
248
- # cell_reference = org.apache.poi.ss.util.CellReference.new( reference + "1" )
249
- # column = cell_reference.get_col
250
- # sheet = cell_reference.get_sheet_name
251
- # worksheets[sheet].rows.collect{|row| row[column]}
252
248
  end
253
249
 
254
250
  private
@@ -10,7 +10,7 @@ module POI
10
10
  def [](index_or_name)
11
11
  worksheet = case
12
12
  when index_or_name.kind_of?(Numeric)
13
- @poi_workbook.sheet_at(index_or_name) || @poi_workbook.create_sheet
13
+ @poi_workbook.get_sheet_at(index_or_name) || @poi_workbook.create_sheet
14
14
  else
15
15
  @poi_workbook.get_sheet(index_or_name) || @poi_workbook.create_sheet(index_or_name)
16
16
  end
@@ -22,7 +22,7 @@ module POI
22
22
  end
23
23
 
24
24
  def each
25
- (0...size).each { |i| yield Worksheet.new(@poi_workbook.sheet_at(i), @workbook) }
25
+ (0...size).each { |i| yield Worksheet.new(@poi_workbook.get_sheet_at(i), @workbook) }
26
26
  end
27
27
  end
28
28
 
@@ -4,45 +4,45 @@ describe "POI.Facade" do
4
4
  it "should create specialized methods for boolean methods, getters, and setters" do
5
5
  book = POI::Workbook.create('foo.xlsx')
6
6
  sheet = book.create_sheet
7
- sheet.respond_to?(:column_broken?).should be_true
8
- sheet.respond_to?(:column_hidden?).should be_true
9
- sheet.respond_to?(:display_formulas?).should be_true
10
- sheet.respond_to?(:display_gridlines?).should be_true
11
- sheet.respond_to?(:selected?).should be_true
12
- sheet.respond_to?(:column_breaks).should be_true
13
- sheet.respond_to?(:column_break=).should be_true
14
- sheet.respond_to?(:autobreaks?).should be_true
15
- sheet.respond_to?(:autobreaks=).should be_true
16
- sheet.respond_to?(:autobreaks!).should be_true
17
- sheet.respond_to?(:column_broken?).should be_true
18
- sheet.respond_to?(:fit_to_page).should be_true
19
- sheet.respond_to?(:fit_to_page?).should be_true
20
- sheet.respond_to?(:fit_to_page=).should be_true
21
- sheet.respond_to?(:fit_to_page!).should be_true
7
+ sheet.respond_to?(:column_broken?).should be true
8
+ sheet.respond_to?(:column_hidden?).should be true
9
+ sheet.respond_to?(:display_formulas?).should be true
10
+ sheet.respond_to?(:display_gridlines?).should be true
11
+ sheet.respond_to?(:selected?).should be true
12
+ sheet.respond_to?(:column_breaks).should be true
13
+ sheet.respond_to?(:column_break=).should be true
14
+ sheet.respond_to?(:autobreaks?).should be true
15
+ sheet.respond_to?(:autobreaks=).should be true
16
+ sheet.respond_to?(:autobreaks!).should be true
17
+ sheet.respond_to?(:column_broken?).should be true
18
+ sheet.respond_to?(:fit_to_page).should be true
19
+ sheet.respond_to?(:fit_to_page?).should be true
20
+ sheet.respond_to?(:fit_to_page=).should be true
21
+ sheet.respond_to?(:fit_to_page!).should be true
22
22
 
23
- sheet.respond_to?(:array_formula).should_not be_true
24
- sheet.respond_to?(:array_formula=).should_not be_true
23
+ sheet.respond_to?(:array_formula).should_not be true
24
+ sheet.respond_to?(:array_formula=).should_not be true
25
25
 
26
26
  row = sheet[0]
27
- row.respond_to?(:first_cell_num).should be_true
28
- row.respond_to?(:height).should be_true
29
- row.respond_to?(:height=).should be_true
30
- row.respond_to?(:height_in_points).should be_true
31
- row.respond_to?(:height_in_points=).should be_true
32
- row.respond_to?(:zero_height?).should be_true
33
- row.respond_to?(:zero_height!).should be_true
34
- row.respond_to?(:zero_height=).should be_true
27
+ row.respond_to?(:first_cell_num).should be true
28
+ row.respond_to?(:height).should be true
29
+ row.respond_to?(:height=).should be true
30
+ row.respond_to?(:height_in_points).should be true
31
+ row.respond_to?(:height_in_points=).should be true
32
+ row.respond_to?(:zero_height?).should be true
33
+ row.respond_to?(:zero_height!).should be true
34
+ row.respond_to?(:zero_height=).should be true
35
35
 
36
36
  cell = row[0]
37
- cell.respond_to?(:boolean_cell_value).should be_true
38
- cell.respond_to?(:boolean_cell_value?).should be_true
39
- cell.respond_to?(:cached_formula_result_type).should be_true
40
- cell.respond_to?(:cell_error_value=).should be_true
41
- cell.respond_to?(:cell_value=).should be_true
42
- cell.respond_to?(:hyperlink=).should be_true
43
- cell.respond_to?(:cell_value!).should be_true
44
- cell.respond_to?(:remove_cell_comment!).should be_true
45
- cell.respond_to?(:cell_style).should be_true
46
- cell.respond_to?(:cell_style=).should be_true
37
+ cell.respond_to?(:boolean_cell_value).should be true
38
+ cell.respond_to?(:boolean_cell_value?).should be true
39
+ cell.respond_to?(:cached_formula_result_type).should be true
40
+ cell.respond_to?(:cell_error_value=).should be true
41
+ cell.respond_to?(:cell_value=).should be true
42
+ cell.respond_to?(:hyperlink=).should be true
43
+ cell.respond_to?(:cell_value!).should be true
44
+ cell.respond_to?(:remove_cell_comment!).should be true
45
+ cell.respond_to?(:cell_style).should be true
46
+ cell.respond_to?(:cell_style=).should be true
47
47
  end
48
48
  end
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.configure do |c|
4
4
  c.filter_run_excluding :unimplemented => true
5
+ c.expect_with(:rspec) { |expect_config| expect_config.syntax = :should }
5
6
  end
6
7
 
7
8
  require File.expand_path('../lib/poi', File.dirname(__FILE__))
@@ -14,3 +15,12 @@ class TestDataFile
14
15
  File.expand_path(File.join(File.dirname(__FILE__), 'data', name))
15
16
  end
16
17
  end
18
+
19
+ if RUBY_VERSION < '1.9'
20
+ class DateTime
21
+ def to_date
22
+ Date.parse(self.strftime('%Y-%m-%d'))
23
+ end
24
+ end
25
+ end
26
+
@@ -3,15 +3,15 @@ RSpec::Matchers.define :equal_at_cell do |expected, row, col|
3
3
  actual == expected
4
4
  end
5
5
 
6
- failure_message_for_should do |actual|
6
+ failure_message do |actual|
7
7
  "expected #{actual} to equal #{expected} (row:#{row}, cell:#{col})"
8
8
  end
9
9
 
10
- failure_message_for_should_not do |actual|
10
+ failure_message_when_negated do |actual|
11
11
  "expected #{actual} not to equal #{expected} (row:#{row}, cell:#{col})"
12
12
  end
13
13
 
14
14
  description do
15
15
  "to equal #{expected}"
16
16
  end
17
- end
17
+ end
@@ -1,385 +1,368 @@
1
- require 'spec_helper'
2
-
3
- require 'date'
4
- require 'stringio'
5
-
6
- describe POI::Workbook do
7
- it "should open a workbook and allow access to its worksheets" do
8
- name = TestDataFile.expand_path("various_samples.xlsx")
9
- book = POI::Workbook.open(name)
10
- book.worksheets.size.should == 5
11
- book.filename.should == name
12
- end
13
-
14
- it "should be able to create a Workbook from an IO object" do
15
- content = StringIO.new(open(TestDataFile.expand_path("various_samples.xlsx"), 'rb'){|f| f.read})
16
- book = POI::Workbook.open(content)
17
- book.worksheets.size.should == 5
18
- book.filename.should =~ /spreadsheet.xlsx$/
19
- end
20
-
21
- it "should be able to create a Workbook from a Java input stream" do
22
- content = java.io.FileInputStream.new(TestDataFile.expand_path("various_samples.xlsx"))
23
- book = POI::Workbook.open(content)
24
- book.worksheets.size.should == 5
25
- book.filename.should =~ /spreadsheet.xlsx$/
26
- end
27
-
28
- it "should create an HSSFWorkbook when passed a :format => :hssf option" do
29
- book = POI::Workbook.create('test.xls', :format => :hssf)
30
- book.poi_workbook.should be_kind_of(org.apache.poi.hssf.usermodel.HSSFWorkbook)
31
- end
32
-
33
- it "should create an XSSFWorkbook when passed a :format => :xssf option" do
34
- book = POI::Workbook.create('test.xlsx', :format => :xssf)
35
- book.poi_workbook.should be_kind_of(org.apache.poi.xssf.usermodel.XSSFWorkbook)
36
- end
37
-
38
- it "should create an XSSFWorkbook by default" do
39
- book = POI::Workbook.create('test.xlsx')
40
- book.poi_workbook.should be_kind_of(org.apache.poi.xssf.usermodel.XSSFWorkbook)
41
- end
42
-
43
- it "should return a column of cells by reference" do
44
- name = TestDataFile.expand_path("various_samples.xlsx")
45
- book = POI::Workbook.open(name)
46
- book["numbers!$A"].should == book['numbers'].rows.collect{|e| e[0].value}
47
- book["numbers!A"].should == book['numbers'].rows.collect{|e| e[0].value}
48
- book["numbers!C"].should == book['numbers'].rows.collect{|e| e[2].value}
49
- book["numbers!$D:$D"].should == book['numbers'].rows.collect{|e| e[3].value}
50
- book["numbers!$c:$D"].should == {"C" => book['numbers'].rows.collect{|e| e[2].value}, "D" => book['numbers'].rows.collect{|e| e[3].value}}
51
- end
52
-
53
- it "should return cells by reference" do
54
- name = TestDataFile.expand_path("various_samples.xlsx")
55
- book = POI::Workbook.open(name)
56
- book.cell("numbers!A1").value.should == 'NUM'
57
- book.cell("numbers!A2").to_s.should == '1.0'
58
- book.cell("numbers!A3").to_s.should == '2.0'
59
- book.cell("numbers!A4").to_s.should == '3.0'
60
-
61
- book.cell("numbers!A10").to_s.should == '9.0'
62
- book.cell("numbers!B10").to_s.should == '81.0'
63
- book.cell("numbers!C10").to_s.should == '729.0'
64
- book.cell("numbers!D10").to_s.should == '3.0'
65
-
66
- book.cell("text & pic!A10").value.should == 'This is an Excel XLSX workbook.'
67
- book.cell("bools & errors!B3").value.should == true
68
- book.cell("high refs!AM619").value.should == 'This is some text'
69
- book.cell("high refs!AO624").value.should == 24.0
70
- book.cell("high refs!AP631").value.should == 13.0
71
-
72
- book.cell(%Q{'text & pic'!A10}).value.should == 'This is an Excel XLSX workbook.'
73
- book.cell(%Q{'bools & errors'!B3}).value.should == true
74
- book.cell(%Q{'high refs'!AM619}).value.should == 'This is some text'
75
- book.cell(%Q{'high refs'!AO624}).value.should == 24.0
76
- book.cell(%Q{'high refs'!AP631}).value.should == 13.0
77
- end
78
-
79
- it "should handle named cell ranges" do
80
- name = TestDataFile.expand_path("various_samples.xlsx")
81
- book = POI::Workbook.open(name)
82
-
83
- book.named_ranges.length.should == 3
84
- book.named_ranges.collect{|e| e.name}.should == %w{four_times_six NAMES nums}
85
- book.named_ranges.collect{|e| e.sheet.name}.should == ['high refs', 'bools & errors', 'high refs']
86
- book.named_ranges.collect{|e| e.formula}.should == ["'high refs'!$AO$624", "'bools & errors'!$D$2:$D$11", "'high refs'!$AP$619:$AP$631"]
87
- book['four_times_six'].should == 24.0
88
- book['nums'].should == (1..13).collect{|e| e * 1.0}
89
-
90
- # NAMES is a range of empty cells
91
- book['NAMES'].should == [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
92
- book.cell('NAMES').each do | cell |
93
- cell.value.should be_nil
94
- cell.poi_cell.should_not be_nil
95
- cell.to_s.should be_empty
96
- end
97
- end
98
-
99
- it "should return an array of cell values by reference" do
100
- name = TestDataFile.expand_path("various_samples.xlsx")
101
- book = POI::Workbook.open(name)
102
- book['dates!A2:A16'].should == (Date.parse('2010-02-28')..Date.parse('2010-03-14')).to_a
103
- end
104
-
105
- it "should return cell values by reference" do
106
- name = TestDataFile.expand_path("various_samples.xlsx")
107
- book = POI::Workbook.open(name)
108
-
109
- book['text & pic!A10'].should == 'This is an Excel XLSX workbook.'
110
- book['bools & errors!B3'].should == true
111
- book['high refs!AM619'].should == 'This is some text'
112
- book['high refs!AO624'].should == 24.0
113
- book['high refs!AP631'].should == 13.0
114
- end
115
- end
116
-
117
- describe POI::Worksheets do
118
- it "should allow indexing worksheets by ordinal" do
119
- name = TestDataFile.expand_path("various_samples.xlsx")
120
- book = POI::Workbook.open(name)
121
-
122
- book.worksheets[0].name.should == "text & pic"
123
- book.worksheets[1].name.should == "numbers"
124
- book.worksheets[2].name.should == "dates"
125
- book.worksheets[3].name.should == "bools & errors"
126
- end
127
-
128
- it "should allow indexing worksheets by name" do
129
- name = TestDataFile.expand_path("various_samples.xlsx")
130
- book = POI::Workbook.open(name)
131
-
132
- book.worksheets["text & pic"].name.should == "text & pic"
133
- book.worksheets["numbers"].name.should == "numbers"
134
- book.worksheets["dates"].name.should == "dates"
135
- end
136
-
137
- it "should be enumerable" do
138
- name = TestDataFile.expand_path("various_samples.xlsx")
139
- book = POI::Workbook.open(name)
140
- book.worksheets.should be_kind_of Enumerable
141
-
142
- book.worksheets.each do |sheet|
143
- sheet.should be_kind_of POI::Worksheet
144
- end
145
-
146
- book.worksheets.count.should == 5
147
- book.worksheets.collect.count.should == 5
148
- end
149
-
150
- it "returns cells when passing a cell reference" do
151
- name = TestDataFile.expand_path("various_samples.xlsx")
152
- book = POI::Workbook.open(name)
153
- book['dates']['A2'].to_s.should == '2010-02-28'
154
- book['dates']['a2'].to_s.should == '2010-02-28'
155
- book['dates']['B2'].to_s.should == '2010-03-14'
156
- book['dates']['b2'].to_s.should == '2010-03-14'
157
- book['dates']['C2'].to_s.should == '2010-03-28'
158
- book['dates']['c2'].to_s.should == '2010-03-28'
159
- end
160
- end
161
-
162
- describe POI::Rows do
163
- it "should be enumerable" do
164
- name = TestDataFile.expand_path("various_samples.xlsx")
165
- book = POI::Workbook.open(name)
166
- sheet = book.worksheets["text & pic"]
167
- sheet.rows.should be_kind_of Enumerable
168
-
169
- sheet.rows.each do |row|
170
- row.should be_kind_of POI::Row
171
- end
172
-
173
- sheet.rows.count.should == 7
174
- sheet.rows.collect.count.should == 7
175
- end
176
- end
177
-
178
- describe POI::Cells do
179
- before :each do
180
- @name = TestDataFile.expand_path("various_samples.xlsx")
181
- @book = POI::Workbook.open(@name)
182
- end
183
-
184
- def book
185
- @book
186
- end
187
-
188
- def name
189
- @name
190
- end
191
-
192
- it "should be enumerable" do
193
- sheet = book.worksheets["text & pic"]
194
- rows = sheet.rows
195
- cells = rows[0].cells
196
-
197
- cells.should be_kind_of Enumerable
198
- cells.count.should == 1
199
- cells.collect.count.should == 1
200
- end
201
- end
202
-
203
- describe POI::Cell do
204
- before :each do
205
- @name = TestDataFile.expand_path("various_samples.xlsx")
206
- @book = POI::Workbook.open(@name)
207
- end
208
-
209
- def book
210
- @book
211
- end
212
-
213
- def name
214
- @name
215
- end
216
-
217
- it "should provide dates for date cells" do
218
- sheet = book.worksheets["dates"]
219
- rows = sheet.rows
220
-
221
- dates_by_column = [
222
- (Date.parse('2010-02-28')..Date.parse('2010-03-14')),
223
- (Date.parse('2010-03-14')..Date.parse('2010-03-28')),
224
- (Date.parse('2010-03-28')..Date.parse('2010-04-11'))]
225
- (0..2).each do |col|
226
- dates_by_column[col].each_with_index do |date, index|
227
- row = index + 1
228
- rows[row][col].value.should equal_at_cell(date, row, col)
229
- end
230
- end
231
- end
232
-
233
- it "should provide numbers for numeric cells" do
234
- sheet = book.worksheets["numbers"]
235
- rows = sheet.rows
236
-
237
- (1..15).each do |number|
238
- row = number
239
- rows[row][0].value.should equal_at_cell(number, row, 0)
240
- rows[row][1].value.should equal_at_cell(number ** 2, row, 1)
241
- rows[row][2].value.should equal_at_cell(number ** 3, row, 2)
242
- rows[row][3].value.should equal_at_cell(Math.sqrt(number), row, 3)
243
- end
244
-
245
- rows[9][0].to_s.should == '9.0'
246
- rows[9][1].to_s.should == '81.0'
247
- rows[9][2].to_s.should == '729.0'
248
- rows[9][3].to_s.should == '3.0'
249
- end
250
-
251
- it "should handle array access from the workbook down to cells" do
252
- book[1][9][0].to_s.should == '9.0'
253
- book[1][9][1].to_s.should == '81.0'
254
- book[1][9][2].to_s.should == '729.0'
255
- book[1][9][3].to_s.should == '3.0'
256
-
257
- book["numbers"][9][0].to_s.should == '9.0'
258
- book["numbers"][9][1].to_s.should == '81.0'
259
- book["numbers"][9][2].to_s.should == '729.0'
260
- book["numbers"][9][3].to_s.should == '3.0'
261
- end
262
-
263
- it "should provide error text for error cells" do
264
- sheet = book.worksheets["bools & errors"]
265
- rows = sheet.rows
266
-
267
- rows[6][0].value.should == 0.0 #'~CIRCULAR~REF~'
268
- rows[6][0].error_value.should be_nil
269
-
270
- rows[7][0].value.should be_nil
271
- rows[7][0].error_value.should == '#DIV/0!'
272
-
273
- rows[8][0].value.should be_nil
274
- rows[8][0].error_value.should == '#N/A'
275
-
276
- rows[9][0].value.should be_nil
277
- rows[9][0].error_value.should == '#NAME?'
278
-
279
- rows[10][0].value.should be_nil
280
- rows[10][0].error_value.should == '#NULL!'
281
-
282
- rows[11][0].value.should be_nil
283
- rows[11][0].error_value.should == '#NUM!'
284
-
285
- rows[12][0].value.should be_nil
286
- rows[12][0].error_value.should == '#REF!'
287
-
288
- rows[13][0].value.should be_nil
289
- rows[13][0].error_value.should == '#VALUE!'
290
-
291
- lambda{ rows[14][0].value }.should_not raise_error(Java::java.lang.RuntimeException)
292
-
293
- rows[6][0].to_s.should == '0.0' #'~CIRCULAR~REF~'
294
- rows[7][0].to_s.should == '' #'#DIV/0!'
295
- rows[8][0].to_s.should == '' #'#N/A'
296
- rows[9][0].to_s.should == '' #'#NAME?'
297
- rows[10][0].to_s.should == '' #'#NULL!'
298
- rows[11][0].to_s.should == '' #'#NUM!'
299
- rows[12][0].to_s.should == '' #'#REF!'
300
- rows[13][0].to_s.should == '' #'#VALUE!'
301
- rows[14][0].to_s.should == ''
302
- end
303
-
304
- it "should provide booleans for boolean cells" do
305
- sheet = book.worksheets["bools & errors"]
306
- rows = sheet.rows
307
- rows[1][0].value.should == false
308
- rows[1][0].to_s.should == 'false'
309
-
310
- rows[1][1].value.should == false
311
- rows[1][1].to_s.should == 'false'
312
-
313
- rows[2][0].value.should == true
314
- rows[2][0].to_s.should == 'true'
315
-
316
- rows[2][1].value.should == true
317
- rows[2][1].to_s.should == 'true'
318
- end
319
-
320
- it "should provide the cell value as a string" do
321
- sheet = book.worksheets["text & pic"]
322
- rows = sheet.rows
323
-
324
- rows[0][0].value.should == "This"
325
- rows[1][0].value.should == "is"
326
- rows[2][0].value.should == "an"
327
- rows[3][0].value.should == "Excel"
328
- rows[4][0].value.should == "XLSX"
329
- rows[5][0].value.should == "workbook"
330
- rows[9][0].value.should == 'This is an Excel XLSX workbook.'
331
-
332
-
333
- rows[0][0].to_s.should == "This"
334
- rows[1][0].to_s.should == "is"
335
- rows[2][0].to_s.should == "an"
336
- rows[3][0].to_s.should == "Excel"
337
- rows[4][0].to_s.should == "XLSX"
338
- rows[5][0].to_s.should == "workbook"
339
- rows[9][0].to_s.should == 'This is an Excel XLSX workbook.'
340
- end
341
-
342
- it "should provide formulas instead of string-ified values" do
343
- sheet = book.worksheets["numbers"]
344
- rows = sheet.rows
345
-
346
- (1..15).each do |number|
347
- row = number
348
- rows[row][0].to_s(false).should == "#{number}.0"
349
- rows[row][1].to_s(false).should == "A#{row + 1}*A#{row + 1}"
350
- rows[row][2].to_s(false).should == "B#{row + 1}*A#{row + 1}"
351
- rows[row][3].to_s(false).should == "SQRT(A#{row + 1})"
352
- end
353
-
354
- sheet = book.worksheets["bools & errors"]
355
- rows = sheet.rows
356
- rows[1][0].to_s(false).should == '1=2'
357
- rows[1][1].to_s(false).should == 'FALSE'
358
- rows[2][0].to_s(false).should == '1=1'
359
- rows[2][1].to_s(false).should == 'TRUE'
360
- rows[14][0].to_s(false).should == 'foobar(1)'
361
-
362
- sheet = book.worksheets["text & pic"]
363
- sheet.rows[9][0].to_s(false).should == 'CONCATENATE(A1," ", A2," ", A3," ", A4," ", A5," ", A6,".")'
364
- end
365
-
366
- it "should handle getting values out of 'non-existent' cells" do
367
- sheet = book.worksheets["bools & errors"]
368
- sheet.rows[14][2].value.should be_nil
369
- end
370
-
371
- it "should notify the workbook that I have been updated" do
372
- book['dates!A10'].to_s.should == '2010-03-08'
373
- book['dates!A16'].to_s.should == '2010-03-14'
374
- book['dates!B2'].to_s.should == '2010-03-14'
375
-
376
- cell = book.cell('dates!B2')
377
- cell.formula.should == 'A16'
378
-
379
- cell.formula = 'A10 + 1'
380
- book.cell('dates!B2').poi_cell.should === cell.poi_cell
381
- book.cell('dates!B2').formula.should == 'A10 + 1'
382
-
383
- book['dates!B2'].to_s.should == '2010-03-09'
384
- end
385
- end
1
+ require 'spec_helper'
2
+
3
+ require 'date'
4
+ require 'stringio'
5
+
6
+ VARIOUS_SAMPLES_PATH = TestDataFile.expand_path("various_samples.xlsx")
7
+ DATES_1904_WINDOW_XLS_PATH = TestDataFile.expand_path("1904_window_dates.xls")
8
+
9
+ describe POI::Workbook do
10
+ it "should open a workbook and allow access to its worksheets" do
11
+ book = POI::Workbook.open(VARIOUS_SAMPLES_PATH)
12
+ book.worksheets.size.should == 6
13
+ book.filename.should == VARIOUS_SAMPLES_PATH
14
+ end
15
+
16
+ it "should be able to create a Workbook from an IO object" do
17
+ content = StringIO.new(open(VARIOUS_SAMPLES_PATH, 'rb'){|f| f.read})
18
+ book = POI::Workbook.open(content)
19
+ book.worksheets.size.should == 6
20
+ book.filename.should =~ /spreadsheet.xlsx$/
21
+ end
22
+
23
+ it "should be able to create a Workbook from a Java input stream" do
24
+ content = java.io.FileInputStream.new(VARIOUS_SAMPLES_PATH)
25
+ book = POI::Workbook.open(content)
26
+ book.worksheets.size.should == 6
27
+ book.filename.should =~ /spreadsheet.xlsx$/
28
+ end
29
+
30
+ it "should create an HSSFWorkbook when passed a :format => :hssf option" do
31
+ book = POI::Workbook.create('test.xls', :format => :hssf)
32
+ book.poi_workbook.should be_kind_of(org.apache.poi.hssf.usermodel.HSSFWorkbook)
33
+ end
34
+
35
+ it "should create an XSSFWorkbook when passed a :format => :xssf option" do
36
+ book = POI::Workbook.create('test.xlsx', :format => :xssf)
37
+ book.poi_workbook.should be_kind_of(org.apache.poi.xssf.usermodel.XSSFWorkbook)
38
+ end
39
+
40
+ it "should create an XSSFWorkbook by default" do
41
+ book = POI::Workbook.create('test.xlsx')
42
+ book.poi_workbook.should be_kind_of(org.apache.poi.xssf.usermodel.XSSFWorkbook)
43
+ end
44
+
45
+ it "should return a column of cells by reference" do
46
+ book = POI::Workbook.open(VARIOUS_SAMPLES_PATH)
47
+
48
+ book["numbers!$A"].should == book['numbers'].rows.collect{|e| e[0].value}
49
+ book["numbers!A"].should == book['numbers'].rows.collect{|e| e[0].value}
50
+ book["numbers!C"].should == book['numbers'].rows.collect{|e| e[2].value}
51
+ book["numbers!$D:$D"].should == book['numbers'].rows.collect{|e| e[3].value}
52
+ book["numbers!$c:$D"].should == {"C" => book['numbers'].rows.collect{|e| e[2].value}, "D" => book['numbers'].rows.collect{|e| e[3].value}}
53
+ end
54
+
55
+ it "should return cells by reference" do
56
+ book = POI::Workbook.open(VARIOUS_SAMPLES_PATH)
57
+ book.cell("numbers!A1").value.should == 'NUM'
58
+ book.cell("numbers!A2").to_s.should == '1.0'
59
+ book.cell("numbers!A3").to_s.should == '2.0'
60
+ book.cell("numbers!A4").to_s.should == '3.0'
61
+
62
+ book.cell("numbers!A10").to_s.should == '9.0'
63
+ book.cell("numbers!B10").to_s.should == '81.0'
64
+ book.cell("numbers!C10").to_s.should == '729.0'
65
+ book.cell("numbers!D10").to_s.should == '3.0'
66
+
67
+ book.cell(%Q{'text & pic'!A10}).value.should == 'This is an Excel XLSX workbook.'
68
+ book.cell(%Q{'bools & errors'!B3}).value.should == true
69
+ book.cell(%Q{'high refs'!AM619}).value.should == 'This is some text'
70
+ book.cell(%Q{'high refs'!AO624}).value.should == 24.0
71
+ book.cell(%Q{'high refs'!AP631}).value.should == 13.0
72
+ end
73
+
74
+ it "should handle named cell ranges" do
75
+ book = POI::Workbook.open(VARIOUS_SAMPLES_PATH)
76
+
77
+ book.named_ranges.length.should == 3
78
+ book.named_ranges.collect{|e| e.name}.should == %w{four_times_six NAMES nums}
79
+ book.named_ranges.collect{|e| e.sheet.name}.should == ['high refs', 'bools & errors', 'high refs']
80
+ book.named_ranges.collect{|e| e.formula}.should == ["'high refs'!$AO$624", "'bools & errors'!$D$2:$D$11", "'high refs'!$AP$619:$AP$631"]
81
+ book['four_times_six'].should == 24.0
82
+ book['nums'].should == (1..13).collect{|e| e * 1.0}
83
+
84
+ # NAMES is a range of empty cells
85
+ book['NAMES'].should == [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil]
86
+ book.cell('NAMES').each do | cell |
87
+ cell.value.should be_nil
88
+ cell.poi_cell.should_not be_nil
89
+ cell.to_s.should be_empty
90
+ end
91
+ end
92
+
93
+ it "should return an array of cell values by reference" do
94
+ book = POI::Workbook.open(VARIOUS_SAMPLES_PATH)
95
+ book['dates!A2:A16'].map(&:to_date).should == (Date.parse('2010-02-28')..Date.parse('2010-03-14')).to_a
96
+ end
97
+
98
+ it "should return cell values by reference" do
99
+ book = POI::Workbook.open(VARIOUS_SAMPLES_PATH)
100
+
101
+ book[%Q{'text & pic'!A10}].should == 'This is an Excel XLSX workbook.'
102
+ book[%Q{'bools & errors'!B3}].should == true
103
+ book[%Q{'high refs'!AM619}].should == 'This is some text'
104
+ book[%Q{'high refs'!AO624}].should == 24.0
105
+ book[%Q{'high refs'!AP631}].should == 13.0
106
+ end
107
+ end
108
+
109
+ describe POI::Worksheets do
110
+ let(:book) { POI::Workbook.open(VARIOUS_SAMPLES_PATH) }
111
+
112
+ it "should allow indexing worksheets by ordinal" do
113
+ book.worksheets[0].name.should == "text & pic"
114
+ book.worksheets[1].name.should == "numbers"
115
+ book.worksheets[2].name.should == "dates"
116
+ book.worksheets[3].name.should == "bools & errors"
117
+ end
118
+
119
+ it "should allow indexing worksheets by name" do
120
+ book.worksheets["text & pic"].name.should == "text & pic"
121
+ book.worksheets["numbers"].name.should == "numbers"
122
+ book.worksheets["dates"].name.should == "dates"
123
+ end
124
+
125
+ it "should be enumerable" do
126
+ book.worksheets.should be_kind_of Enumerable
127
+
128
+ book.worksheets.each do |sheet|
129
+ sheet.should be_kind_of POI::Worksheet
130
+ end
131
+
132
+ book.worksheets.count.should == 6
133
+ book.worksheets.collect.count.should == 6
134
+ end
135
+
136
+ it "returns cells when passing a cell reference" do
137
+ book['dates']['A2'].class.should == DateTime
138
+ book['dates']['A2'].to_date.should == Date.parse('2010-02-28')
139
+ book['dates']['a2'].to_date.should == Date.parse('2010-02-28')
140
+ book['dates']['B2'].to_date.should == Date.parse('2010-03-14')
141
+ book['dates']['b2'].to_date.should == Date.parse('2010-03-14')
142
+ book['dates']['C2'].to_date.should == Date.parse('2010-03-28')
143
+ book['dates']['c2'].to_date.should == Date.parse('2010-03-28')
144
+ end
145
+ end
146
+
147
+ describe POI::Rows do
148
+ it "should be enumerable" do
149
+ book = POI::Workbook.open(VARIOUS_SAMPLES_PATH)
150
+ sheet = book.worksheets["text & pic"]
151
+ sheet.rows.should be_kind_of Enumerable
152
+
153
+ sheet.rows.each do |row|
154
+ row.should be_kind_of POI::Row
155
+ end
156
+
157
+ sheet.rows.count.should == 7
158
+ sheet.rows.collect.count.should == 7
159
+ end
160
+ end
161
+
162
+ describe POI::Cells do
163
+ let(:book) { POI::Workbook.open(VARIOUS_SAMPLES_PATH) }
164
+
165
+ it "should be enumerable" do
166
+ sheet = book.worksheets["text & pic"]
167
+ rows = sheet.rows
168
+ cells = rows[0].cells
169
+
170
+ cells.should be_kind_of Enumerable
171
+ cells.count.should == 1
172
+ cells.collect.count.should == 1
173
+ end
174
+ end
175
+
176
+ describe POI::Cell do
177
+ let(:book) { POI::Workbook.open(VARIOUS_SAMPLES_PATH) }
178
+
179
+ context "1900 windowed dates" do
180
+ it "should provide dates for date cells" do
181
+ sheet = book.worksheets["dates"]
182
+ rows = sheet.rows
183
+
184
+ dates_by_column = [
185
+ (DateTime.parse('2010-02-28')..DateTime.parse('2010-03-14')),
186
+ (DateTime.parse('2010-03-14')..DateTime.parse('2010-03-28')),
187
+ (DateTime.parse('2010-03-28')..DateTime.parse('2010-04-11'))
188
+ ]
189
+ (0..2).each do |col|
190
+ dates_by_column[col].each_with_index do |date, index|
191
+ row = index + 1
192
+ c = sheet.rows[row].cells[col]
193
+ c.value.to_date.should == date.to_date
194
+ end
195
+ end
196
+ end
197
+ end
198
+
199
+ context "1904 windowed dates" do
200
+ let(:book) { POI::Workbook.open(DATES_1904_WINDOW_XLS_PATH) }
201
+ it "returns entered dates correctly" do
202
+ c = book.worksheets[0].rows[1].cells[0]
203
+ c.value.to_date.should == Date.parse("2012-01-01")
204
+ end
205
+
206
+ it "returns dates computed by a formula correctly" do
207
+ c = book.worksheets[0].rows[1].cells[3]
208
+ c.value.to_date.should == Date.parse("2012-01-02")
209
+ end
210
+ end
211
+
212
+ it "should provide numbers for numeric cells" do
213
+ sheet = book.worksheets["numbers"]
214
+ rows = sheet.rows
215
+
216
+ (1..15).each do |number|
217
+ row = number
218
+ rows[row][0].value.should equal_at_cell(number, row, 0)
219
+ rows[row][1].value.should equal_at_cell(number ** 2, row, 1)
220
+ rows[row][2].value.should equal_at_cell(number ** 3, row, 2)
221
+ rows[row][3].value.should equal_at_cell(Math.sqrt(number), row, 3)
222
+ end
223
+
224
+ rows[9][0].to_s.should == '9.0'
225
+ rows[9][1].to_s.should == '81.0'
226
+ rows[9][2].to_s.should == '729.0'
227
+ rows[9][3].to_s.should == '3.0'
228
+ end
229
+
230
+ it "should handle array access from the workbook down to cells" do
231
+ book[1][9][0].to_s.should == '9.0'
232
+ book[1][9][1].to_s.should == '81.0'
233
+ book[1][9][2].to_s.should == '729.0'
234
+ book[1][9][3].to_s.should == '3.0'
235
+
236
+ book["numbers"][9][0].to_s.should == '9.0'
237
+ book["numbers"][9][1].to_s.should == '81.0'
238
+ book["numbers"][9][2].to_s.should == '729.0'
239
+ book["numbers"][9][3].to_s.should == '3.0'
240
+ end
241
+
242
+ it "should provide error text for error cells" do
243
+ sheet = book.worksheets["bools & errors"]
244
+ rows = sheet.rows
245
+
246
+ rows[6][0].value.should == 0.0 #'~CIRCULAR~REF~'
247
+ rows[6][0].error_value.should be_nil
248
+
249
+ rows[7][0].value.should be_nil
250
+ rows[7][0].error_value.should == '#DIV/0!'
251
+
252
+ rows[8][0].value.should be_nil
253
+ rows[8][0].error_value.should == '#N/A'
254
+
255
+ rows[9][0].value.should be_nil
256
+ rows[9][0].error_value.should == '#NAME?'
257
+
258
+ rows[10][0].value.should be_nil
259
+ rows[10][0].error_value.should == '#NULL!'
260
+
261
+ rows[11][0].value.should be_nil
262
+ rows[11][0].error_value.should == '#NUM!'
263
+
264
+ rows[12][0].value.should be_nil
265
+ rows[12][0].error_value.should == '#REF!'
266
+
267
+ rows[13][0].value.should be_nil
268
+ rows[13][0].error_value.should == '#VALUE!'
269
+
270
+ lambda{ rows[14][0].value }.should_not raise_error
271
+
272
+ rows[6][0].to_s.should == '0.0' #'~CIRCULAR~REF~'
273
+ rows[7][0].to_s.should == '' #'#DIV/0!'
274
+ rows[8][0].to_s.should == '' #'#N/A'
275
+ rows[9][0].to_s.should == '' #'#NAME?'
276
+ rows[10][0].to_s.should == '' #'#NULL!'
277
+ rows[11][0].to_s.should == '' #'#NUM!'
278
+ rows[12][0].to_s.should == '' #'#REF!'
279
+ rows[13][0].to_s.should == '' #'#VALUE!'
280
+ rows[14][0].to_s.should == ''
281
+ end
282
+
283
+ it "should provide booleans for boolean cells" do
284
+ sheet = book.worksheets["bools & errors"]
285
+ rows = sheet.rows
286
+ rows[1][0].value.should == false
287
+ rows[1][0].to_s.should == 'false'
288
+
289
+ rows[1][1].value.should == false
290
+ rows[1][1].to_s.should == 'false'
291
+
292
+ rows[2][0].value.should == true
293
+ rows[2][0].to_s.should == 'true'
294
+
295
+ rows[2][1].value.should == true
296
+ rows[2][1].to_s.should == 'true'
297
+ end
298
+
299
+ it "should provide the cell value as a string" do
300
+ sheet = book.worksheets["text & pic"]
301
+ rows = sheet.rows
302
+
303
+ rows[0][0].value.should == "This"
304
+ rows[1][0].value.should == "is"
305
+ rows[2][0].value.should == "an"
306
+ rows[3][0].value.should == "Excel"
307
+ rows[4][0].value.should == "XLSX"
308
+ rows[5][0].value.should == "workbook"
309
+ rows[9][0].value.should == 'This is an Excel XLSX workbook.'
310
+
311
+
312
+ rows[0][0].to_s.should == "This"
313
+ rows[1][0].to_s.should == "is"
314
+ rows[2][0].to_s.should == "an"
315
+ rows[3][0].to_s.should == "Excel"
316
+ rows[4][0].to_s.should == "XLSX"
317
+ rows[5][0].to_s.should == "workbook"
318
+ rows[9][0].to_s.should == 'This is an Excel XLSX workbook.'
319
+ end
320
+
321
+ it "should provide formulas instead of string-ified values" do
322
+ sheet = book.worksheets["numbers"]
323
+ rows = sheet.rows
324
+
325
+ (1..15).each do |number|
326
+ row = number
327
+ rows[row][0].to_s(false).should == "#{number}.0"
328
+ rows[row][1].to_s(false).should == "A#{row + 1}*A#{row + 1}"
329
+ rows[row][2].to_s(false).should == "B#{row + 1}*A#{row + 1}"
330
+ rows[row][3].to_s(false).should == "SQRT(A#{row + 1})"
331
+ end
332
+
333
+ sheet = book.worksheets["bools & errors"]
334
+ rows = sheet.rows
335
+ rows[1][0].to_s(false).should == '1=2'
336
+ rows[1][1].to_s(false).should == 'FALSE'
337
+ rows[2][0].to_s(false).should == '1=1'
338
+ rows[2][1].to_s(false).should == 'TRUE'
339
+ rows[14][0].to_s(false).should == 'foobar(1)'
340
+
341
+ sheet = book.worksheets["text & pic"]
342
+ sheet.rows[9][0].to_s(false).should == 'CONCATENATE(A1," ", A2," ", A3," ", A4," ", A5," ", A6,".")'
343
+ end
344
+
345
+ it "should handle getting values out of 'non-existent' cells" do
346
+ sheet = book.worksheets["bools & errors"]
347
+ sheet.rows[14][2].value.should be_nil
348
+ end
349
+
350
+ it "should notify the workbook that I have been updated" do
351
+ book['dates!A10'].to_date.should == Date.parse('2010-03-08')
352
+ book['dates!A16'].to_date.should == Date.parse('2010-03-14')
353
+ book['dates!B2'].to_date.should == Date.parse('2010-03-14')
354
+
355
+ cell = book.cell('dates!B2')
356
+ cell.formula.should == 'A16'
357
+
358
+ cell.formula = 'A10 + 1'
359
+ book.cell('dates!B2').poi_cell.should === cell.poi_cell
360
+ book.cell('dates!B2').formula.should == 'A10 + 1'
361
+
362
+ book['dates!B2'].to_date.should == Date.parse('2010-03-09')
363
+ end
364
+
365
+ it "should work with IFERROR" do
366
+ book['newfeatures!F6'].should == 'NOT FOUND'
367
+ end
368
+ end