jruby-poi 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.5.2
1
+ 0.6.0
data/jruby-poi.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{jruby-poi}
8
- s.version = "0.5.2"
8
+ s.version = "0.6.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Scott Deming", "Jason Rogers"]
@@ -36,6 +36,7 @@ Gem::Specification.new do |s|
36
36
  "lib/poi.rb",
37
37
  "lib/poi/workbook.rb",
38
38
  "lib/poi/workbook/cell.rb",
39
+ "lib/poi/workbook/named_range.rb",
39
40
  "lib/poi/workbook/row.rb",
40
41
  "lib/poi/workbook/workbook.rb",
41
42
  "lib/poi/workbook/worksheet.rb",
@@ -35,31 +35,53 @@ module POI
35
35
  @cell = cell
36
36
  end
37
37
 
38
+ # This is NOT an inexpensive operation. The purpose of this method is merely to get more information
39
+ # out of cell when one thinks the value returned is incorrect. It may have more value in development
40
+ # than in production.
38
41
  def error_value
39
- @error_value
42
+ if poi_cell.getCellType == CELL_TYPE_ERROR
43
+ Java::org.apache.poi.hssf.record.formula.eval.ErrorEval.getText(poi_cell.getErrorCellValue)
44
+ elsif poi_cell.getCellType == CELL_TYPE_FORMULA && poi_cell.getCachedFormulaResultType == CELL_TYPE_ERROR
45
+ formula_evaluator = Java::org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator.new poi_cell.sheet.workbook
46
+ value_of(formula_evaluator.evaluate(poi_cell))
47
+ else
48
+ nil
49
+ end
50
+ end
51
+
52
+ # returns the formula for this Cell if it has one, otherwise nil
53
+ def formula_value
54
+ poi_cell.getCellType == CELL_TYPE_FORMULA ? poi_cell.getCellFormula : nil
40
55
  end
41
56
 
42
57
  def value
43
- return nil if @cell.nil?
44
- value_of(cell_value_for_type(@cell.getCellType))
58
+ return nil if poi_cell.nil?
59
+ value_of(cell_value_for_type(poi_cell.getCellType))
45
60
  end
46
61
 
47
62
  def comment
48
- @cell.getCellComment
63
+ poi_cell.getCellComment
49
64
  end
50
65
 
51
66
  def index
52
- @cell.getColumnIndex
67
+ poi_cell.getColumnIndex
53
68
  end
54
69
 
70
+ # Get the String representation of this Cell's value.
71
+ #
72
+ # If this Cell is a formula you can pass a false to this method and
73
+ # get the formula instead of the String representation.
55
74
  def to_s(evaluate_formulas=true)
56
- if @cell.getCellType == CELL_TYPE_FORMULA
57
- evaluate_formulas ? value.to_s : @cell.getCellFormula
75
+ return '' if poi_cell.nil?
76
+
77
+ if poi_cell.getCellType == CELL_TYPE_FORMULA && evaluate_formulas == false
78
+ formula_value
58
79
  else
59
80
  value.to_s
60
81
  end
61
82
  end
62
83
 
84
+ # returns the underlying org.apache.poi.ss.usermodel.Cell
63
85
  def poi_cell
64
86
  @cell
65
87
  end
@@ -73,30 +95,30 @@ module POI
73
95
  when CELL_TYPE_BOOLEAN: cell_value.getBooleanValue
74
96
  when CELL_TYPE_ERROR: Java::org.apache.poi.hssf.record.formula.eval.ErrorEval.getText(cell_value.getErrorValue)
75
97
  when CELL_TYPE_NUMERIC
76
- if Java::org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted @cell
98
+ if Java::org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted poi_cell
77
99
  Date.parse(Java::org.apache.poi.ss.usermodel.DateUtil.getJavaDate(cell_value.getNumberValue).to_s)
78
100
  else
79
101
  cell_value.getNumberValue
80
102
  end
81
103
  when CELL_TYPE_STRING: cell_value.getStringValue
82
104
  else
83
- raise "unhandled cell type[#{@cell.getCellType}]"
105
+ raise "unhandled cell type[#{cell_value.getCellType}]"
84
106
  end
85
107
  end
86
108
 
87
109
  def cell_value_for_type(cell_type)
110
+ return nil if cell_type.nil?
88
111
  begin
89
112
  case cell_type
90
113
  when CELL_TYPE_BLANK: nil
91
- when CELL_TYPE_BOOLEAN: CELL_VALUE.valueOf(@cell.getBooleanCellValue)
92
- when CELL_TYPE_FORMULA: cell_value_for_type(@cell.getCachedFormulaResultType)
93
- when CELL_TYPE_STRING: CELL_VALUE.new(@cell.getStringCellValue)
94
- when CELL_TYPE_ERROR, CELL_TYPE_NUMERIC: CELL_VALUE.new(@cell.getNumericCellValue)
114
+ when CELL_TYPE_BOOLEAN: CELL_VALUE.valueOf(poi_cell.getBooleanCellValue)
115
+ when CELL_TYPE_FORMULA: cell_value_for_type(poi_cell.getCachedFormulaResultType)
116
+ when CELL_TYPE_STRING: CELL_VALUE.new(poi_cell.getStringCellValue)
117
+ when CELL_TYPE_ERROR, CELL_TYPE_NUMERIC: CELL_VALUE.new(poi_cell.getNumericCellValue)
95
118
  else
96
- raise "unhandled cell type[#{@cell.getCellType}]"
119
+ raise "unhandled cell type[#{poi_cell.getCellType}]"
97
120
  end
98
121
  rescue
99
- @error_value = $!
100
122
  nil
101
123
  end
102
124
  end
@@ -0,0 +1,45 @@
1
+ class NamedRange
2
+
3
+ # takes an instance of org.apache.poi.ss.usermodel.Name, and a POI::Workbook
4
+ def initialize name, workbook
5
+ @name = name
6
+ @workbook = workbook
7
+ end
8
+
9
+ def name
10
+ @name.getNameName
11
+ end
12
+
13
+ def sheet
14
+ @workbook[@name.getSheetName]
15
+ end
16
+
17
+ def formula
18
+ @name.getRefersToFormula
19
+ end
20
+
21
+ def cells
22
+ area_range? ? all_cells_from_area : @workbook.cell(formula)
23
+ end
24
+
25
+ def values
26
+ cells.collect{|c| c.value}
27
+ end
28
+
29
+ private
30
+ def area_range?
31
+ area.nil? == false
32
+ end
33
+
34
+ def area
35
+ @area ||= begin
36
+ org.apache.poi.ss.util.AreaReference.new formula
37
+ rescue
38
+ nil
39
+ end
40
+ end
41
+
42
+ def all_cells_from_area
43
+ area.getAllReferencedCells.collect{|c| @workbook.cell c.formatAsString}
44
+ end
45
+ end
@@ -27,7 +27,8 @@ module POI
27
27
  end
28
28
 
29
29
  def [](index)
30
- Cell.new(@row.getCell(index))
30
+ return nil if poi_row.nil?
31
+ Cell.new(poi_row.getCell(index))
31
32
  end
32
33
 
33
34
  def cells
@@ -35,7 +36,8 @@ module POI
35
36
  end
36
37
 
37
38
  def index
38
- @row.getRowNum
39
+ return nil if poi_row.nil?
40
+ poi_row.getRowNum
39
41
  end
40
42
 
41
43
  def poi_row
@@ -50,11 +50,46 @@ module POI
50
50
  end
51
51
 
52
52
  def worksheets
53
- Worksheets.new(self)
53
+ @worksheets ||= Worksheets.new(self)
54
+ end
55
+
56
+ def named_ranges
57
+ @named_ranges ||= (0...@workbook.getNumberOfNames).collect do | idx |
58
+ NamedRange.new @workbook.getNameAt(idx), self
59
+ end
54
60
  end
55
61
 
62
+ # sheet_index can be a Fixnum, referring to the 0-based sheet or
63
+ # a String which is the sheet name or a cell reference.
64
+ #
65
+ # If a cell reference is passed the value of that cell is returned.
56
66
  def [](sheet_index)
57
- worksheets[sheet_index]
67
+ begin
68
+ cell = cell(sheet_index)
69
+ Array === cell ? cell.collect{|e| e.value} : cell.value
70
+ rescue
71
+ answer = worksheets[sheet_index]
72
+ answer.poi_worksheet.nil? ? nil : answer
73
+ end
74
+ end
75
+
76
+ # takes a String in the form of a 3D cell reference and returns the Cell (eg. "Sheet 1!A1")
77
+ def cell reference
78
+ if named_range = named_ranges.detect{|e| e.name == reference}
79
+ cells = named_range.cells.compact
80
+ if cells.empty?
81
+ return nil
82
+ else
83
+ return cells.length == 1 ? cells.first : cells
84
+ end
85
+ end
86
+
87
+ ref = org.apache.poi.ss.util.CellReference.new(reference)
88
+ if ref.getSheetName.nil?
89
+ raise 'cell references at the workbook level must include a sheet reference (eg. Sheet1!A1)'
90
+ else
91
+ worksheets[ref.getSheetName][ref.getRow][ref.getCol]
92
+ end
58
93
  end
59
94
 
60
95
  def poi_workbook
@@ -39,8 +39,17 @@ module POI
39
39
  Rows.new(self)
40
40
  end
41
41
 
42
+ # Accepts a Fixnum or a String as the row_index
43
+ #
44
+ # row_index as Fixnum - returns the 0-based row
45
+ # row_index as String - assumes a cell reference within this sheet and returns the cell value for that reference
42
46
  def [](row_index)
43
- rows[row_index]
47
+ if Fixnum === row_index
48
+ rows[row_index]
49
+ else
50
+ ref = org.apache.poi.ss.util.CellReference.new(row_index)
51
+ rows[ref.getRow][ref.getCol].value
52
+ end
44
53
  end
45
54
 
46
55
  def poi_worksheet
data/lib/poi/workbook.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require File.join(JRUBY_POI_LIB_PATH, 'poi', 'workbook', 'named_range')
1
2
  require File.join(JRUBY_POI_LIB_PATH, 'poi', 'workbook', 'workbook')
2
3
  require File.join(JRUBY_POI_LIB_PATH, 'poi', 'workbook', 'worksheet')
3
4
  require File.join(JRUBY_POI_LIB_PATH, 'poi', 'workbook', 'row')
Binary file
@@ -6,23 +6,81 @@ describe POI::Workbook do
6
6
  it "should open a workbook and allow access to its worksheets" do
7
7
  name = TestDataFile.expand_path("various_samples.xlsx")
8
8
  book = POI::Workbook.open(name)
9
- book.worksheets.size.should == 4
9
+ book.worksheets.size.should == 5
10
10
  book.filename.should == name
11
11
  end
12
12
 
13
13
  it "should be able to create a Workbook from an IO object" do
14
14
  content = StringIO.new(open(TestDataFile.expand_path("various_samples.xlsx"), 'rb'){|f| f.read})
15
15
  book = POI::Workbook.open(content)
16
- book.worksheets.size.should == 4
16
+ book.worksheets.size.should == 5
17
17
  book.filename.should =~ /spreadsheet.xlsx$/
18
18
  end
19
19
 
20
20
  it "should be able to create a Workbook from a Java input stream" do
21
21
  content = java.io.FileInputStream.new(TestDataFile.expand_path("various_samples.xlsx"))
22
22
  book = POI::Workbook.open(content)
23
- book.worksheets.size.should == 4
23
+ book.worksheets.size.should == 5
24
24
  book.filename.should =~ /spreadsheet.xlsx$/
25
25
  end
26
+
27
+ it "should return cells by reference" do
28
+ name = TestDataFile.expand_path("various_samples.xlsx")
29
+ book = POI::Workbook.open(name)
30
+
31
+ book.cell("numbers!A1").value.should == 'NUM'
32
+ book.cell("numbers!A2").to_s.should == '1.0'
33
+ book.cell("numbers!A3").to_s.should == '2.0'
34
+ book.cell("numbers!A4").to_s.should == '3.0'
35
+
36
+ book.cell("numbers!A10").to_s.should == '9.0'
37
+ book.cell("numbers!B10").to_s.should == '81.0'
38
+ book.cell("numbers!C10").to_s.should == '729.0'
39
+ book.cell("numbers!D10").to_s.should == '3.0'
40
+
41
+ book.cell("text & pic!A10").value.should == 'This is an Excel XLSX workbook.'
42
+ book.cell("bools & errors!B3").value.should == true
43
+ book.cell("high refs!AM619").value.should == 'This is some text'
44
+ book.cell("high refs!AO624").value.should == 24.0
45
+ book.cell("high refs!AP631").value.should == 13.0
46
+
47
+ book.cell(%Q{'text & pic'!A10}).value.should == 'This is an Excel XLSX workbook.'
48
+ book.cell(%Q{'bools & errors'!B3}).value.should == true
49
+ book.cell(%Q{'high refs'!AM619}).value.should == 'This is some text'
50
+ book.cell(%Q{'high refs'!AO624}).value.should == 24.0
51
+ book.cell(%Q{'high refs'!AP631}).value.should == 13.0
52
+ end
53
+
54
+ it "should handle named cell ranges" do
55
+ name = TestDataFile.expand_path("various_samples.xlsx")
56
+ book = POI::Workbook.open(name)
57
+
58
+ book.named_ranges.length.should == 3
59
+ book.named_ranges.collect{|e| e.name}.should == %w{four_times_six NAMES nums}
60
+ book.named_ranges.collect{|e| e.sheet.name}.should == ['high refs', 'bools & errors', 'high refs']
61
+ book.named_ranges.collect{|e| e.formula}.should == ["'high refs'!$AO$624", "'bools & errors'!$D$2:$D$11", "'high refs'!$AP$619:$AP$631"]
62
+ book['four_times_six'].should == 24.0
63
+ book['nums'].should == (1..13).collect{|e| e * 1.0}
64
+
65
+ # NAMES is a range of empty cells
66
+ book['NAMES'].should == [nil, nil, nil, nil, nil, nil, nil]
67
+ book.cell('NAMES').each do | cell |
68
+ cell.value.should be_nil
69
+ cell.poi_cell.should be_nil
70
+ cell.to_s.should be_empty
71
+ end
72
+ end
73
+
74
+ it "should return cell values by reference" do
75
+ name = TestDataFile.expand_path("various_samples.xlsx")
76
+ book = POI::Workbook.open(name)
77
+
78
+ book['text & pic!A10'].should == 'This is an Excel XLSX workbook.'
79
+ book['bools & errors!B3'].should == true
80
+ book['high refs!AM619'].should == 'This is some text'
81
+ book['high refs!AO624'].should == 24.0
82
+ book['high refs!AP631'].should == 13.0
83
+ end
26
84
  end
27
85
 
28
86
  describe POI::Worksheets do
@@ -54,8 +112,19 @@ describe POI::Worksheets do
54
112
  sheet.should be_kind_of POI::Worksheet
55
113
  end
56
114
 
57
- book.worksheets.size.should == 4
58
- book.worksheets.collect.size.should == 4
115
+ book.worksheets.size.should == 5
116
+ book.worksheets.collect.size.should == 5
117
+ end
118
+
119
+ it "returns cells when passing a cell reference" do
120
+ name = TestDataFile.expand_path("various_samples.xlsx")
121
+ book = POI::Workbook.open(name)
122
+ book['dates']['A2'].should == Date.parse('2010-02-28')
123
+ book['dates']['a2'].should == Date.parse('2010-02-28')
124
+ book['dates']['B2'].should == Date.parse('2010-03-14')
125
+ book['dates']['b2'].should == Date.parse('2010-03-14')
126
+ book['dates']['C2'].should == Date.parse('2010-03-28')
127
+ book['dates']['c2'].should == Date.parse('2010-03-28')
59
128
  end
60
129
  end
61
130
 
@@ -133,7 +202,6 @@ describe POI::Cells do
133
202
  rows[9][3].to_s.should == '3.0'
134
203
  end
135
204
 
136
-
137
205
  it "should handle array access from the workbook down to cells" do
138
206
  book[1][9][0].to_s.should == '9.0'
139
207
  book[1][9][1].to_s.should == '81.0'
@@ -153,26 +221,26 @@ describe POI::Cells do
153
221
  rows[6][0].value.should == 0.0 #'~CIRCULAR~REF~'
154
222
  rows[6][0].error_value.should be_nil
155
223
 
156
- rows[7][0].value.should be_nil #'#DIV/0!'
157
- rows[7][0].error_value.should == 'java.lang.NumberFormatException: For input string: "#N/A"'
224
+ rows[7][0].value.should be_nil
225
+ rows[7][0].error_value.should == '#DIV/0!'
158
226
 
159
- rows[8][0].value.should be_nil #'#N/A'
160
- rows[8][0].error_value.should == 'java.lang.NumberFormatException: For input string: "#N/A"'
227
+ rows[8][0].value.should be_nil
228
+ rows[8][0].error_value.should == '#N/A'
161
229
 
162
- rows[9][0].value.should be_nil #'#NAME?'
163
- rows[9][0].error_value.should == 'java.lang.NumberFormatException: For input string: "#N/A"'
230
+ rows[9][0].value.should be_nil
231
+ rows[9][0].error_value.should == '#NAME?'
164
232
 
165
- rows[10][0].value.should be_nil #'#NULL!'
166
- rows[10][0].error_value.should == 'java.lang.NumberFormatException: For input string: "#N/A"'
233
+ rows[10][0].value.should be_nil
234
+ rows[10][0].error_value.should == '#NULL!'
167
235
 
168
- rows[11][0].value.should be_nil #'#NUM!'
169
- rows[11][0].error_value.should == 'java.lang.NumberFormatException: For input string: "#N/A"'
236
+ rows[11][0].value.should be_nil
237
+ rows[11][0].error_value.should == '#NUM!'
170
238
 
171
- rows[12][0].value.should be_nil #'#REF!'
172
- rows[12][0].error_value.should == 'java.lang.NumberFormatException: For input string: "#N/A"'
239
+ rows[12][0].value.should be_nil
240
+ rows[12][0].error_value.should == '#REF!'
173
241
 
174
- rows[13][0].value.should be_nil #'#VALUE!'
175
- rows[13][0].error_value.should == 'java.lang.NumberFormatException: For input string: "#N/A"'
242
+ rows[13][0].value.should be_nil
243
+ rows[13][0].error_value.should == '#VALUE!'
176
244
 
177
245
  lambda{ rows[14][0].value }.should_not raise_error(Java::java.lang.RuntimeException)
178
246
 
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 5
8
- - 2
9
- version: 0.5.2
7
+ - 6
8
+ - 0
9
+ version: 0.6.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Scott Deming
@@ -50,6 +50,7 @@ files:
50
50
  - lib/poi.rb
51
51
  - lib/poi/workbook.rb
52
52
  - lib/poi/workbook/cell.rb
53
+ - lib/poi/workbook/named_range.rb
53
54
  - lib/poi/workbook/row.rb
54
55
  - lib/poi/workbook/workbook.rb
55
56
  - lib/poi/workbook/worksheet.rb