jruby-poi 0.5.2 → 0.6.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.
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