robust_excel_ole 1.16 → 1.18.3

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 (50) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog +23 -0
  3. data/README.rdoc +17 -0
  4. data/benchmarking/Gemfile +7 -0
  5. data/benchmarking/README.md +131 -0
  6. data/benchmarking/creek_example.rb +33 -0
  7. data/benchmarking/generating_excel_files.rb +28 -0
  8. data/benchmarking/reo_example.rb +26 -0
  9. data/benchmarking/reo_example1.rb +31 -0
  10. data/benchmarking/reo_example2.rb +26 -0
  11. data/benchmarking/roo_example.rb +33 -0
  12. data/benchmarking/ruby_xl_example.rb +36 -0
  13. data/benchmarking/sample_excel_files/xlsx_500_rows.xlsx +0 -0
  14. data/benchmarking/simple_xlsx_reader_example.rb +33 -0
  15. data/benchmarking/spreadsheet_example.rb +36 -0
  16. data/bin/jreo.bat +3 -0
  17. data/bin/reo.bat +3 -0
  18. data/docs/README_excel.rdoc +6 -0
  19. data/docs/README_open.rdoc +4 -0
  20. data/docs/README_ranges.rdoc +15 -0
  21. data/examples/example_ruby_library.rb +27 -0
  22. data/lib/robust_excel_ole.rb +4 -3
  23. data/lib/robust_excel_ole/{address.rb → address_tool.rb} +23 -22
  24. data/lib/robust_excel_ole/{reo_common.rb → base.rb} +2 -90
  25. data/lib/robust_excel_ole/bookstore.rb +2 -2
  26. data/lib/robust_excel_ole/cell.rb +30 -18
  27. data/lib/robust_excel_ole/excel.rb +65 -30
  28. data/lib/robust_excel_ole/general.rb +7 -5
  29. data/lib/robust_excel_ole/range.rb +38 -15
  30. data/lib/robust_excel_ole/range_owners.rb +26 -11
  31. data/lib/robust_excel_ole/vba_objects.rb +30 -0
  32. data/lib/robust_excel_ole/version.rb +1 -1
  33. data/lib/robust_excel_ole/workbook.rb +136 -147
  34. data/lib/robust_excel_ole/worksheet.rb +47 -15
  35. data/lib/rubygems_plugin.rb +3 -0
  36. data/robust_excel_ole.gemspec +1 -1
  37. data/spec/address_tool_spec.rb +175 -0
  38. data/spec/{reo_common_spec.rb → base_spec.rb} +10 -29
  39. data/spec/cell_spec.rb +67 -25
  40. data/spec/data/more_data/workbook.xls +0 -0
  41. data/spec/excel_spec.rb +41 -273
  42. data/spec/general_spec.rb +15 -19
  43. data/spec/range_spec.rb +57 -3
  44. data/spec/workbook_spec.rb +7 -75
  45. data/spec/workbook_specs/workbook_misc_spec.rb +10 -10
  46. data/spec/workbook_specs/workbook_open_spec.rb +228 -14
  47. data/spec/workbook_specs/workbook_unobtr_spec.rb +31 -31
  48. data/spec/worksheet_spec.rb +42 -0
  49. metadata +27 -8
  50. data/spec/address_spec.rb +0 -174
@@ -0,0 +1,36 @@
1
+
2
+ require 'spreadsheet'
3
+
4
+ start_time = Time.now
5
+
6
+ # ============================================
7
+ # =========== Read Example ===============
8
+ # ============================================
9
+
10
+ # Note: spreadsheet only supports .xls files (not .xlsx)
11
+ workbook = Spreadsheet.open './sample_excel_files/xls_500_rows.xls'
12
+
13
+ worksheets = workbook.worksheets
14
+ puts "Found #{worksheets.count} worksheets"
15
+
16
+
17
+ worksheets.each do |worksheet|
18
+ puts "Reading: #{worksheet.name}"
19
+ num_rows = 0
20
+
21
+ worksheet.rows.each do |row|
22
+ row_cells = row.to_a.map{ |v| v.methods.include?(:value) ? v.value : v }
23
+ num_rows += 1
24
+
25
+ # uncomment to print out row values
26
+ # puts row_cells.join " "
27
+ end
28
+ puts "Read #{num_rows} rows"
29
+ end
30
+
31
+ end_time = Time.now
32
+ running_time = end_time - start_time
33
+ puts "time: #{running_time} sec."
34
+
35
+
36
+ puts 'Done'
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ jirb -f -r ../lib/robust_excel_ole -r ../lib/jreo_console.rb
@@ -0,0 +1,3 @@
1
+ @echo off
2
+
3
+ irb -f -r ../lib/robust_excel_ole -r ../lib/reo_console.rb
@@ -124,6 +124,12 @@ or, with a block,
124
124
 
125
125
  excel.each_workbook(:visible => true) {|w| puts w}
126
126
 
127
+ === Accessing the active workbook
128
+
129
+ You can operate on the active workbook with help of the method Workbook#active_workbook, e.g.
130
+
131
+ workbook = excel.active_workbook
132
+
127
133
  === Bringing an Excel instance to the foreground
128
134
 
129
135
  excel1.focus
@@ -153,6 +153,7 @@ The method +General.to_reo+ enables type-lifting WIN32OLE objects to RobustExcel
153
153
  This object can be type-lifted to a RobustExcelOle workbook.
154
154
 
155
155
  workbook = win32ole_workbook.to_reo
156
+
156
157
  workbook.to_class
157
158
  => RobustExcelOle::Workbook
158
159
 
@@ -166,6 +167,9 @@ You can supply options, e.g. +:visible+.
166
167
 
167
168
  workbook = Workbook.new(win32ole_workbook, :visible => true)
168
169
 
170
+ You can also supply a workbook and options, e.g.
171
+
172
+ new_workbook = Workbook.new(workbook, :visible => true)
169
173
 
170
174
  === Identity transperence ===
171
175
 
@@ -394,11 +394,26 @@ The methods Worksheet#each, Worksheet#each_row and Worksheet#each_column enable
394
394
  # do something with column
395
395
  end
396
396
 
397
+ The method Worksheet#values yields all cell values of the used range of the worksheet into a 2-dimensional array. For example:
398
+
399
+ worksheet.values
400
+ => [["foo", "workbook", "sheet1"], ["foo", nil, "foobaaa"], ["matz", "is", "nice"]]
401
+
402
+ The method Worksheet#each_rowvalue provides enable to access the values of each row.
403
+
404
+ worksheet.each_rowvalue do |row_values|
405
+ # do something with the row_values
406
+ end
407
+
397
408
  You access a range of a row by giving the number of the row, and optionally, the range of the cell numbers.
398
409
 
399
410
  worksheet.row_range(1) # => first row
400
411
  worksheet.row_range(1, 1..3 ) # => first three cells of the first row
401
412
 
413
+ Reading the values is enabled with help of #values:
414
+
415
+ worksheet.row_range(1).values
416
+
402
417
  Simarly you can access a range of a column.
403
418
 
404
419
  worksheet.col_range(3) # => third column
@@ -0,0 +1,27 @@
1
+ #require 'robust_excel_ole'
2
+
3
+ #workbook = Workbook.open './sample_excel_files/xlsx_500_rows.xlsx'
4
+
5
+ require_relative '../lib/robust_excel_ole'
6
+
7
+ include RobustExcelOle
8
+
9
+ workbook = Workbook.open './../spec/data/workbook.xls'
10
+
11
+ puts "Found #{workbook.worksheets_count} worksheets"
12
+
13
+ workbook.each do |worksheet|
14
+ puts "Reading: #{worksheet.name}"
15
+ num_rows = 0
16
+
17
+ worksheet.each do |row|
18
+ row_cells = row.map{ |cell| cell.value }
19
+ num_rows += 1
20
+
21
+ # uncomment to print out row values
22
+ # puts row_cells.join " "
23
+ end
24
+ puts "Read #{num_rows} rows"
25
+ end
26
+
27
+ puts 'Done'
@@ -3,10 +3,11 @@ if RUBY_PLATFORM =~ /java/
3
3
  else
4
4
  require 'win32ole'
5
5
  end
6
- require File.join(File.dirname(__FILE__), 'robust_excel_ole/reo_common')
7
- require File.join(File.dirname(__FILE__), 'robust_excel_ole/range_owners')
8
- require File.join(File.dirname(__FILE__), 'robust_excel_ole/address')
6
+ require File.join(File.dirname(__FILE__), 'robust_excel_ole/base')
9
7
  require File.join(File.dirname(__FILE__), 'robust_excel_ole/general')
8
+ require File.join(File.dirname(__FILE__), 'robust_excel_ole/vba_objects')
9
+ require File.join(File.dirname(__FILE__), 'robust_excel_ole/range_owners')
10
+ require File.join(File.dirname(__FILE__), 'robust_excel_ole/address_tool')
10
11
  require File.join(File.dirname(__FILE__), 'robust_excel_ole/excel')
11
12
  require File.join(File.dirname(__FILE__), 'robust_excel_ole/bookstore')
12
13
  require File.join(File.dirname(__FILE__), 'robust_excel_ole/workbook')
@@ -2,37 +2,38 @@
2
2
 
3
3
  module RobustExcelOle
4
4
 
5
- class Address < REOCommon
5
+ class AddressTool < Base
6
6
 
7
- def self.new(r1c1_letters)
8
- @@row_letter = r1c1_letters[0..0]
9
- @@col_letter = r1c1_letters[1..1]
7
+ def initialize(address_string)
8
+ r1c1_letters = address_string.gsub(/[0-9]/,'')
9
+ @row_letter = r1c1_letters[0..0]
10
+ @col_letter = r1c1_letters[1..1]
10
11
  end
11
12
 
12
13
  # address formats that are valid:
13
14
  # r1c1-format: e.g. "Z3S1", "Z3S1:Z5S2", "Z[3]S1", "Z3S[-1]:Z[5]S1", "Z[3]", "S[-2]"
14
15
  # infinite ranges are not possible, e.g. "Z3:Z5", "S2:S5", "Z2", "S3", "Z[2]"
15
- # int_range: e.g. [3,1], [3,"A"], [3..5,1..2], [3..5, "A".."B"],
16
- # [3..4, nil], [nil, 2..4], [2,nil], [nil,4]
16
+ # integer_ranges-fromat: e.g. [3,1], [3,"A"], [3..5,1..2], [3..5, "A".."B"],
17
+ # [3..4, nil], [nil, 2..4], [2,nil], [nil,4]
17
18
  # a1-format: e.g. "A3", "A3:B5", "A:B", "3:5", "A", "3"
18
19
 
19
- def self.r1c1(address)
20
+ def as_r1c1(address)
20
21
  transform_address(address,:r1c1)
21
22
  end
22
23
 
23
- def self.a1(address)
24
+ def as_a1(address)
24
25
  transform_address(address,:a1)
25
26
  end
26
27
 
27
28
  # valid address formats: e.g. [3,1], [3,"A"], [3..5,1..2], [3..5, "A".."B"],
28
29
  # [3..4, nil], [nil, 2..4], [2,nil], [nil,4]
29
- def self.int_range(address)
30
+ def as_integer_ranges(address)
30
31
  transform_address(address,:int_range)
31
32
  end
32
33
 
33
34
  private
34
35
 
35
- def self.transform_address(address, format)
36
+ def transform_address(address, format)
36
37
  address = address.is_a?(Array) ? address : [address]
37
38
  raise AddressInvalid, "address #{address.inspect} has more than two components" if address.size > 2
38
39
  begin
@@ -70,8 +71,8 @@ module RobustExcelOle
70
71
  raise AddressInvalid, "address (#{address.inspect}) format not correct"
71
72
  end
72
73
  if format==:r1c1
73
- r1c1_string(@@row_letter,rows,:min) + r1c1_string(@@col_letter,columns,:min) + ":" +
74
- r1c1_string(@@row_letter,rows,:max) + r1c1_string(@@col_letter,columns,:max)
74
+ r1c1_string(@row_letter,rows,:min) + r1c1_string(@col_letter,columns,:min) + ":" +
75
+ r1c1_string(@row_letter,rows,:max) + r1c1_string(@col_letter,columns,:max)
75
76
  elsif format==:int_range
76
77
  [rows,columns]
77
78
  else
@@ -79,8 +80,7 @@ module RobustExcelOle
79
80
  end
80
81
  end
81
82
 
82
- # @private
83
- def self.r1c1_string(letter,int_range,type)
83
+ def r1c1_string(letter,int_range,type)
84
84
  return "" if int_range.nil? || int_range.begin.nil?
85
85
  parameter = type == :min ? int_range.begin : int_range.end
86
86
  is_relative = parameter.is_a?(Array)
@@ -88,27 +88,28 @@ module RobustExcelOle
88
88
  letter + (is_relative ? "(" : "") + parameter.to_s + (is_relative ? ")" : "")
89
89
  end
90
90
 
91
- # @private
92
- def self.analyze(comp,format)
91
+ def analyze(comp,format)
93
92
  row_comp, col_comp = if format==:a1
94
93
  [comp.gsub(/[A-Z]/,''), comp.gsub(/[0-9]/,'')]
95
94
  else
96
- a,b = comp.split(@@row_letter)
97
- c,d = b.split(@@col_letter)
95
+ a,b = comp.split(@row_letter)
96
+ c,d = b.split(@col_letter)
98
97
  b.nil? ? ["",b] : (d.nil? ? [c,""] : [c,d])
99
98
  end
100
- def self.s2n(s)
99
+ def s2n(s)
101
100
  s!="" ? (s[0] == "[" ? [s.gsub(/\[|\]/,'').to_i] : (s.to_i!=0 ? s.to_i : s)) : nil
102
101
  end
103
102
  [s2n(row_comp), s2n(col_comp)]
104
103
  end
105
104
 
106
-
107
- # @private
108
- def self.str2num(str)
105
+ def str2num(str)
109
106
  str.tr("A-Z","0-9A-P").to_i(26) + (26**str.size-1)/25
110
107
  end
111
108
 
112
109
  end
113
110
 
111
+ # @private
112
+ class AddressInvalid < REOError
113
+ end
114
+
114
115
  end
@@ -50,94 +50,10 @@ module RobustExcelOle
50
50
  class MiscREOError < REOError
51
51
  end
52
52
 
53
- # @private
54
- class ExcelDamaged < ExcelREOError
55
- end
56
-
57
- # @private
58
- class UnsavedWorkbooks < ExcelREOError
59
- end
60
-
61
- # @private
62
- class WorkbookBlocked < WorkbookREOError
63
- end
64
-
65
- # @private
66
- class WorkbookNotSaved < WorkbookREOError
67
- end
68
-
69
- # @private
70
- class WorkbookReadOnly < WorkbookREOError
71
- end
72
-
73
- # @private
74
- class WorkbookBeingUsed < WorkbookREOError
75
- end
76
-
77
- # @private
78
- class WorkbookConnectingUnsavedError < WorkbookREOError
79
- end
80
-
81
- # @private
82
- class WorkbookConnectingBlockingError < WorkbookREOError
83
- end
84
-
85
- # @private
86
- class WorkbookConnectingUnknownError < WorkbookREOError
87
- end
88
-
89
- # @private
90
- class FileNotFound < FileREOError
91
- end
92
-
93
- # @private
94
- class FileNameNotGiven < FileREOError
95
- end
96
-
97
- # @private
98
- class FileAlreadyExists < FileREOError
99
- end
100
-
101
- # @private
102
- class NameNotFound < NamesREOError
103
- end
104
-
105
- # @private
106
- class NameAlreadyExists < NamesREOError
107
- end
108
-
109
- # @private
110
- class RangeNotEvaluatable < MiscREOError
111
- end
112
-
113
- # @private
114
- class RangeNotCreated < MiscREOError
115
- end
116
-
117
- # @private
118
- class RangeNotCopied < MiscREOError
119
- end
120
-
121
- # @private
122
- class OptionInvalid < MiscREOError
123
- end
124
-
125
- # @private
126
- class ObjectNotAlive < MiscREOError
127
- end
128
-
129
53
  # @private
130
54
  class TypeREOError < REOError
131
55
  end
132
56
 
133
- # @private
134
- class TimeOut < REOError
135
- end
136
-
137
- # @private
138
- class AddressInvalid < REOError
139
- end
140
-
141
57
  # @private
142
58
  class UnexpectedREOError < REOError
143
59
  end
@@ -145,13 +61,9 @@ module RobustExcelOle
145
61
  # @private
146
62
  class NotImplementedREOError < REOError
147
63
  end
64
+
148
65
 
149
- class REOCommon
150
-
151
- # @private
152
- def excel
153
- raise TypeREOError, 'receiver instance is neither an Excel nor a Workbook'
154
- end
66
+ class Base
155
67
 
156
68
  # @private
157
69
  def own_methods
@@ -2,7 +2,8 @@
2
2
 
3
3
  module RobustExcelOle
4
4
 
5
- class Bookstore < REOCommon
5
+ class Bookstore < Base
6
+
6
7
  def initialize
7
8
  @filename2books ||= Hash.new { |hash, key| hash[key] = [] }
8
9
  @hidden_excel_instance = nil
@@ -103,7 +104,6 @@ module RobustExcelOle
103
104
 
104
105
  private
105
106
 
106
- # @private
107
107
  def try_hidden_excel
108
108
  @hidden_excel_instance.__getobj__ if @hidden_excel_instance && @hidden_excel_instance.weakref_alive? && @hidden_excel_instance.__getobj__.alive?
109
109
  end
@@ -1,11 +1,15 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ require File.join(File.dirname(__FILE__), './range')
4
+
3
5
  module RobustExcelOle
4
- class Cell < REOCommon
5
- attr_reader :cell
6
6
 
7
- def initialize(win32_cell)
8
- @cell = win32_cell.MergeCells ? win32_cell.MergeArea.Item(1,1) : win32_cell
7
+ class Cell < Range
8
+ #attr_reader :ole_cell
9
+
10
+ def initialize(win32_cell, worksheet)
11
+ super
12
+ ole_cell
9
13
  end
10
14
 
11
15
  def v
@@ -16,25 +20,33 @@ module RobustExcelOle
16
20
  self.Value = value
17
21
  end
18
22
 
23
+ def ole_cell
24
+ @ole_range = @ole_range.MergeArea.Item(1,1) if @ole_range.MergeCells
25
+ end
26
+
27
+ private
28
+
19
29
  # @private
20
30
  def method_missing(name, *args)
21
- #if name.to_s[0,1] =~ /[A-Z]/
22
- if ::ERRORMESSAGE_JRUBY_BUG
23
- begin
24
- @cell.send(name, *args)
25
- rescue Java::OrgRacobCom::ComFailException
26
- raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
31
+ if name.to_s[0,1] =~ /[A-Z]/
32
+ if ::ERRORMESSAGE_JRUBY_BUG
33
+ begin
34
+ #@ole_cell.send(name, *args)
35
+ @ole_range.send(name, *args)
36
+ rescue Java::OrgRacobCom::ComFailException
37
+ raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
38
+ end
39
+ else
40
+ begin
41
+ #@ole_cell.send(name, *args)
42
+ @ole_range.send(name, *args)
43
+ rescue NoMethodError
44
+ raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
45
+ end
27
46
  end
28
47
  else
29
- begin
30
- @cell.send(name, *args)
31
- rescue NoMethodError
32
- raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
33
- end
48
+ super
34
49
  end
35
- # else
36
- # super
37
- # end
38
50
  end
39
51
  end
40
52
  end