robust_excel_ole 1.31 → 1.32
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +20 -1
- data/README.rdoc +118 -18
- data/___dummy_workbook.xls +0 -0
- data/benchmarking/creek_example.rb +1 -1
- data/benchmarking/roo_example.rb +1 -1
- data/benchmarking/simple_xlsx_reader_example.rb +1 -1
- data/benchmarking/spreadsheet_example.rb +1 -1
- data/docs/README_excel.rdoc +16 -24
- data/docs/README_listobjects.rdoc +176 -0
- data/docs/README_open.rdoc +12 -12
- data/docs/README_ranges.rdoc +72 -55
- data/docs/README_save_close.rdoc +3 -3
- data/docs/README_sheet.rdoc +18 -13
- data/examples/example_ruby_library.rb +2 -2
- data/examples/introductory_examples/example_range.rb +2 -2
- data/examples/modifying_sheets/example_access_sheets_and_cells.rb +6 -6
- data/examples/modifying_sheets/example_add_names.rb +1 -1
- data/examples/modifying_sheets/example_concating.rb +1 -1
- data/examples/modifying_sheets/example_copying.rb +2 -2
- data/examples/modifying_sheets/example_listobjects.rb +86 -0
- data/examples/modifying_sheets/example_naming.rb +1 -1
- data/examples/modifying_sheets/example_ranges.rb +1 -1
- data/examples/open_save_close/example_control_to_excel.rb +1 -1
- data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +1 -1
- data/examples/open_save_close/example_if_obstructed_save.rb +3 -3
- data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
- data/examples/open_save_close/example_if_unsaved_forget.rb +3 -3
- data/examples/open_save_close/example_if_unsaved_forget_more.rb +4 -4
- data/examples/open_save_close/example_read_only.rb +1 -1
- data/examples/open_save_close/example_simple.rb +1 -1
- data/examples/open_save_close/example_unobtrusively.rb +3 -3
- data/lib/robust_excel_ole/address_tool.rb +54 -44
- data/lib/robust_excel_ole/base.rb +4 -6
- data/lib/robust_excel_ole/bookstore.rb +2 -16
- data/lib/robust_excel_ole/cell.rb +16 -21
- data/lib/robust_excel_ole/excel.rb +131 -186
- data/lib/robust_excel_ole/general.rb +82 -55
- data/lib/robust_excel_ole/list_object.rb +182 -109
- data/lib/robust_excel_ole/list_row.rb +65 -38
- data/lib/robust_excel_ole/range.rb +125 -93
- data/lib/robust_excel_ole/range_owners.rb +52 -66
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +168 -176
- data/lib/robust_excel_ole/worksheet.rb +177 -141
- data/robust_excel_ole.gemspec +4 -3
- data/spec/bookstore_spec.rb +2 -3
- data/spec/cell_spec.rb +9 -9
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/excel_spec.rb +132 -85
- data/spec/general_spec.rb +47 -15
- data/spec/list_object_spec.rb +258 -145
- data/spec/list_row_spec.rb +218 -0
- data/spec/range_spec.rb +76 -29
- data/spec/spec_helper.rb +15 -1
- data/spec/workbook_spec.rb +75 -34
- data/spec/workbook_specs/workbook_all_spec.rb +2 -1
- data/spec/workbook_specs/workbook_misc_spec.rb +20 -13
- data/spec/workbook_specs/workbook_open_spec.rb +47 -45
- data/spec/workbook_specs/workbook_save_spec.rb +21 -22
- data/spec/workbook_specs/workbook_sheet_spec.rb +3 -3
- data/spec/workbook_specs/workbook_unobtr_spec.rb +303 -303
- data/spec/worksheet_spec.rb +522 -318
- metadata +37 -2
@@ -1,33 +1,54 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
require 'pathname'
|
3
3
|
|
4
|
-
# @private
|
5
|
-
#class WIN32OLE
|
6
4
|
module ToReoRefinement
|
7
5
|
|
8
6
|
refine WIN32OLE do
|
9
7
|
|
10
8
|
# type-lifting WIN32OLE objects to RobustExcelOle objects
|
11
9
|
def to_reo
|
12
|
-
General.
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
10
|
+
General.main_classes_ole_types_and_recognising_methods.each do |classname, ole_type, methods|
|
11
|
+
if !::OLETYPE_JRUBY_BUG
|
12
|
+
if self.ole_type.name == ole_type
|
13
|
+
if classname != RobustExcelOle::Range
|
14
|
+
return classname.new(self)
|
15
|
+
elsif self.Rows.Count == 1 && self.Columns.Count == 1
|
16
|
+
return RobustExcelOle::Cell.new(self, self.Parent)
|
17
|
+
else
|
18
|
+
return RobustExcelOle::Range.new(self, self.Parent)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
else
|
22
|
+
begin
|
23
|
+
recognising_method, no_method = methods
|
24
|
+
self.send(recognising_method)
|
25
|
+
unless no_method.nil?
|
26
|
+
begin
|
27
|
+
self.send(no_method[:no_method])
|
28
|
+
next
|
29
|
+
rescue NoMethodError
|
30
|
+
return classname.new(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
if classname != RobustExcelOle::Range
|
34
|
+
return classname.new(self)
|
35
|
+
elsif self.Rows.Count == 1 && self.Columns.Count == 1
|
36
|
+
return RobustExcelOle::Cell.new(self, self.Parent)
|
37
|
+
else
|
38
|
+
return RobustExcelOle::Range.new(self, self.Parent)
|
39
|
+
end
|
40
|
+
rescue Java::OrgRacobCom::ComFailException => msg # NoMethodError
|
41
|
+
#if $!.message =~ /undefined method/ &&
|
42
|
+
# main_classes_ole_types_and_recognising_methods.any?{ |_c, _o, recognising_method| $!.message.include?(recognising_method.to_s) }
|
43
|
+
next
|
44
|
+
#end
|
21
45
|
end
|
22
|
-
rescue
|
23
|
-
next
|
24
46
|
end
|
25
47
|
end
|
26
|
-
raise TypeREOError, "given object cannot be type-lifted to a RobustExcelOle object"
|
48
|
+
raise RobustExcelOle::TypeREOError, "given object cannot be type-lifted to a RobustExcelOle object"
|
27
49
|
end
|
28
50
|
|
29
51
|
end
|
30
|
-
|
31
52
|
end
|
32
53
|
|
33
54
|
# @private
|
@@ -43,6 +64,7 @@ module FindAllIndicesRefinement
|
|
43
64
|
refine Array do
|
44
65
|
|
45
66
|
def find_all_indices elem
|
67
|
+
elem = elem.encode('utf-8') if elem.respond_to?(:gsub)
|
46
68
|
found, index, result = -1, -1, []
|
47
69
|
while found
|
48
70
|
found = self[index+1..-1].index(elem)
|
@@ -58,39 +80,32 @@ module FindAllIndicesRefinement
|
|
58
80
|
|
59
81
|
end
|
60
82
|
|
83
|
+
TRANSLATION_TABLE = {
|
84
|
+
'ä' => 'ae', 'ö' => 'oe', 'ü' => 'ue', 'Ä' => 'Ae', 'Ö' => 'Oe', 'Ü' => 'Ue',
|
85
|
+
'ß' => 'ss', '²' => '2', '³' => '3'
|
86
|
+
}
|
87
|
+
|
61
88
|
# @private
|
62
89
|
module StringRefinement
|
63
90
|
|
64
91
|
refine String do
|
65
92
|
|
66
93
|
def / path_part
|
67
|
-
if empty?
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
path_part = path_part.strip
|
75
|
-
(path_part =~ /^(\/|([A-Z]:\/))/i) ? path_part : (self.chomp('/') + '/' + path_part)
|
76
|
-
rescue TypeError
|
77
|
-
raise TypeError, "Only strings can be parts of paths (given: #{path_part.inspect} of class #{path_part.class})"
|
78
|
-
end
|
79
|
-
end
|
94
|
+
return path_part if empty?
|
95
|
+
return self if path_part.nil? || path_part.empty?
|
96
|
+
begin
|
97
|
+
path_part = path_part.strip
|
98
|
+
(path_part =~ /^(\/|([A-Z]:\/))/i) ? path_part : (chomp('/') + '/' + path_part)
|
99
|
+
rescue TypeError
|
100
|
+
raise TypeError, "Only strings can be parts of paths (given: #{path_part.inspect} of class #{path_part.class})"
|
80
101
|
end
|
81
|
-
end
|
102
|
+
end
|
82
103
|
|
83
104
|
def replace_umlauts
|
84
|
-
|
85
|
-
#word = self.encode("UTF-8")
|
86
|
-
#word = self.encode("UTF-8", "Windows-1252")
|
87
|
-
word.gsub('ä','ae').gsub('Ä','Ae').gsub('ö','oe').gsub('Ö','Oe').gsub('ü','ue').gsub('Ü','Ue')
|
88
|
-
word.gsub('ß','ss').gsub('²','2').gsub('³','3')
|
89
|
-
#word.gsub("\x84",'ae').gsub("\x8E",'Ae').gsub("\x94",'oe').gsub("\x99",'Oe').gsub("\x81",'ue').gsub("\x9A",'Ue')
|
90
|
-
#word.gsub("\xE1",'ss').gsub("\xFD",'2').gsub("\xFC",'3')
|
91
|
-
word
|
105
|
+
TRANSLATION_TABLE.inject(encode('utf-8')) { |word,(umlaut, replacement)| word.gsub(umlaut, replacement) }
|
92
106
|
end
|
93
107
|
|
108
|
+
|
94
109
|
# taken from http://apidock.com/rails/ActiveSupport/Inflector/underscore
|
95
110
|
def underscore
|
96
111
|
word = gsub('::', '/')
|
@@ -163,7 +178,6 @@ class Integer
|
|
163
178
|
alias old_spaceship <=>
|
164
179
|
|
165
180
|
def <=> other
|
166
|
-
# p other
|
167
181
|
if other.is_a? Array
|
168
182
|
self <=> other.first
|
169
183
|
else
|
@@ -201,6 +215,7 @@ module General
|
|
201
215
|
::ERRORMESSAGE_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
202
216
|
::CONNECT_EXCEL_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
203
217
|
::RANGES_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
218
|
+
::OLETYPE_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
204
219
|
|
205
220
|
# @private
|
206
221
|
NetworkDrive = Struct.new(:drive_letter, :network_name) do
|
@@ -208,12 +223,8 @@ module General
|
|
208
223
|
def self.get_all_drives
|
209
224
|
network = WIN32OLE.new('WScript.Network')
|
210
225
|
drives = network.enumnetworkdrives
|
211
|
-
ndrives = []
|
212
226
|
count = drives.Count
|
213
|
-
(0..(count - 1)).step(2)
|
214
|
-
ndrives << NetworkDrive.new( drives.Item(i), drives.Item(i + 1).tr('\\','/'))
|
215
|
-
end
|
216
|
-
ndrives
|
227
|
+
(0..(count - 1)).step(2).map{ |i| NetworkDrive.new( drives.Item(i), drives.Item(i + 1).tr('\\','/')) }
|
217
228
|
end
|
218
229
|
end
|
219
230
|
|
@@ -258,30 +269,46 @@ module General
|
|
258
269
|
end
|
259
270
|
|
260
271
|
# @private
|
261
|
-
def
|
262
|
-
[
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
272
|
+
def main_classes_ole_types_and_recognising_methods
|
273
|
+
[[RobustExcelOle::Range , 'Range' , :Row],
|
274
|
+
[RobustExcelOle::Worksheet , '_Worksheet' , :UsedRange],
|
275
|
+
[RobustExcelOle::Workbook , '_Workbook' , :FullName],
|
276
|
+
[RobustExcelOle::Excel , '_Application', :Hwnd],
|
277
|
+
[RobustExcelOle::ListObject, 'ListObject' , :ListRows],
|
278
|
+
[RobustExcelOle::ListRow , 'ListRow' , [:Creator, :no_method => :Row]]]
|
267
279
|
end
|
268
280
|
|
269
281
|
# @private
|
270
282
|
# enable RobustExcelOle methods to Win32Ole objects
|
271
283
|
def init_reo_for_win32ole
|
272
|
-
|
273
|
-
classname = element.first.first
|
284
|
+
main_classes_ole_types_and_recognising_methods.each do |classname, _ole_type, _recognising_method|
|
274
285
|
meths = (classname.instance_methods(false) - WIN32OLE.instance_methods(false) - Object.methods - Enumerable.instance_methods(false) - [:Calculation=])
|
275
286
|
meths.each do |inst_method|
|
276
|
-
|
277
|
-
|
287
|
+
if classname.method_defined?(inst_method)
|
288
|
+
WIN32OLE.send(:define_method, inst_method) do |*args, &blk|
|
289
|
+
begin
|
290
|
+
obj = to_reo
|
291
|
+
rescue
|
292
|
+
return self.send(inst_method.capitalize, *args, &blk)
|
293
|
+
end
|
294
|
+
obj.send(inst_method, *args, &blk)
|
295
|
+
end
|
296
|
+
else
|
297
|
+
WIN32OLE.send(:define_method, inst_method) do |*args, &blk|
|
298
|
+
begin
|
299
|
+
obj = classname.constantize.new(self)
|
300
|
+
rescue
|
301
|
+
return self.send(inst_method.capitalize, *args, &blk)
|
302
|
+
end
|
303
|
+
obj.send(inst_method, *args, &blk)
|
304
|
+
end
|
278
305
|
end
|
279
306
|
end
|
280
307
|
end
|
281
|
-
nil
|
282
308
|
end
|
283
309
|
|
284
|
-
module_function :absolute_path, :canonize, :normalize, :change_current_binding,
|
310
|
+
module_function :absolute_path, :canonize, :normalize, :change_current_binding,
|
311
|
+
:main_classes_ole_types_and_recognising_methods,
|
285
312
|
:init_reo_for_win32ole, :hostnameshare2networkpath, :test
|
286
313
|
|
287
314
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
-
|
3
2
|
module RobustExcelOle
|
4
3
|
|
5
4
|
using ToReoRefinement
|
@@ -12,6 +11,8 @@ module RobustExcelOle
|
|
12
11
|
|
13
12
|
class ListObject < VbaObjects
|
14
13
|
|
14
|
+
include Enumerable
|
15
|
+
|
15
16
|
attr_reader :ole_table
|
16
17
|
|
17
18
|
alias ole_object ole_table
|
@@ -55,7 +56,7 @@ module RobustExcelOle
|
|
55
56
|
@ole_table.Name = table_name_or_number
|
56
57
|
@ole_table.HeaderRowRange.Value = [column_names] unless column_names.empty?
|
57
58
|
rescue WIN32OLERuntimeError => msg # , Java::OrgRacobCom::ComFailException => msg
|
58
|
-
raise TableError, "
|
59
|
+
raise TableError, "#{$!.message}"
|
59
60
|
end
|
60
61
|
end
|
61
62
|
|
@@ -73,32 +74,119 @@ module RobustExcelOle
|
|
73
74
|
|
74
75
|
end
|
75
76
|
|
77
|
+
# @return [Enumerator] traversing all list row objects
|
78
|
+
def each
|
79
|
+
if block_given?
|
80
|
+
@ole_table.ListRows.lazy.each do |ole_listrow|
|
81
|
+
yield @row_class.new(ole_listrow)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
to_enum(:each).lazy
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
76
88
|
# accesses a table row object
|
77
|
-
# @param [
|
78
|
-
# @
|
79
|
-
|
80
|
-
|
89
|
+
# @param [Variant] a hash of key (key column: value) or a row number (>= 1)
|
90
|
+
# @option opts [Variant] limit: maximal number of matching table rows to return, or return the first matching table row (default :first)
|
91
|
+
# @return [Variant] a listrow, if limit == :first
|
92
|
+
# an array of listrows, with maximal number=limit, if list rows were found and limit is not :first
|
93
|
+
# nil, if no list object was found
|
94
|
+
def [] (key_hash_or_number, options = { })
|
95
|
+
return @row_class.new(key_hash_or_number) if key_hash_or_number.respond_to?(:succ)
|
96
|
+
options = {limit: :first}.merge(options)
|
97
|
+
opts = options.dup
|
98
|
+
opts[:limit] = 1 if options[:limit] == :first
|
99
|
+
key_hash = key_hash_or_number.transform_keys{|k| k.downcase.to_sym}
|
100
|
+
matching = if @ole_table.ListRows.Count < 150
|
101
|
+
matching_via_traversing(key_hash, opts)
|
102
|
+
else
|
103
|
+
matching_via_filter(key_hash, opts)
|
104
|
+
end
|
105
|
+
matching_listrows = matching.map{ |r| @row_class.new(r) }
|
106
|
+
options[:limit] == :first ? matching_listrows.first : matching_listrows
|
107
|
+
end
|
108
|
+
|
109
|
+
private
|
110
|
+
|
111
|
+
def matching_via_traversing(key_hash, opts)
|
112
|
+
encode_utf8 = ->(val) {val.respond_to?(:gsub) ? val.encode('utf-8') : val}
|
113
|
+
cn2i = column_names_to_index
|
114
|
+
max_matching_num = opts[:limit] || 65536
|
115
|
+
matching_rows = @ole_table.ListRows.lazy.select { |listrow|
|
116
|
+
rowvalues = listrow.Range.Value.first
|
117
|
+
key_hash.all?{ |key,val| encode_utf8.(rowvalues[cn2i[key]])==val}
|
118
|
+
}.take(max_matching_num).to_a
|
119
|
+
rescue
|
120
|
+
raise(TableError, "cannot find row with key #{key_hash}")
|
81
121
|
end
|
82
122
|
|
123
|
+
def matching_via_filter(key_hash, opts)
|
124
|
+
ole_worksheet = self.Parent
|
125
|
+
ole_workbook = ole_worksheet.Parent
|
126
|
+
row_numbers = []
|
127
|
+
ole_workbook.retain_saved do
|
128
|
+
added_ole_worksheet = ole_workbook.Worksheets.Add
|
129
|
+
criteria = Table.new(added_ole_worksheet, "criteria", [2,1], 2, key_hash.keys.map{|s| s.to_s})
|
130
|
+
criteria[1].values = key_hash.values
|
131
|
+
self.Range.AdvancedFilter({
|
132
|
+
Action: XlFilterInPlace,
|
133
|
+
CriteriaRange: added_ole_worksheet.range([2..3,1..key_hash.length]).ole_range, Unique: false})
|
134
|
+
filtered_ole_range = self.DataBodyRange.SpecialCells(XlCellTypeVisible) rescue nil
|
135
|
+
ole_worksheet.ShowAllData
|
136
|
+
self.Range.AdvancedFilter({Action: XlFilterInPlace,
|
137
|
+
CriteriaRange: added_ole_worksheet.range([1,1]).ole_range, Unique: false})
|
138
|
+
ole_workbook.Parent.with_displayalerts(false){added_ole_worksheet.Delete}
|
139
|
+
if filtered_ole_range
|
140
|
+
filtered_ole_range.Areas.each do |area|
|
141
|
+
break if area.Rows.each do |row|
|
142
|
+
row_numbers << row.Row-position.first
|
143
|
+
break true if row_numbers.count == opts[:limit]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
@ole_table = ole_worksheet.table(self.Name)
|
148
|
+
end
|
149
|
+
row_numbers
|
150
|
+
rescue
|
151
|
+
raise(TableError, "cannot find row with key #{key_hash}")
|
152
|
+
end
|
153
|
+
|
154
|
+
public
|
155
|
+
|
156
|
+
# @return [Integer] number of rows
|
157
|
+
def rows_number
|
158
|
+
@ole_table.ListRows.Count
|
159
|
+
end
|
160
|
+
|
161
|
+
# @return [Array] values of the table
|
162
|
+
def value
|
163
|
+
[column_names] + self.DataBodyRange.Value
|
164
|
+
end
|
165
|
+
|
83
166
|
# @return [Array] a list of column names
|
84
167
|
def column_names
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
168
|
+
@ole_table.HeaderRowRange.Value.first.map{|v| v.encode('utf-8')}
|
169
|
+
rescue WIN32OLERuntimeError
|
170
|
+
raise TableError, "could not determine column names\n#{$!.message}"
|
171
|
+
end
|
172
|
+
|
173
|
+
# @return [Hash] pairs of column names and index
|
174
|
+
def column_names_to_index
|
175
|
+
header_row_values = @ole_table.HeaderRowRange.Value.first
|
176
|
+
header_row_values.map{|v| v.encode('utf-8').downcase.to_sym}.zip(0..header_row_values.size-1).to_h
|
177
|
+
rescue WIN32OLERuntimeError
|
178
|
+
raise TableError, "could not determine column names\n#{$!.message}"
|
90
179
|
end
|
91
180
|
|
181
|
+
|
92
182
|
# adds a row
|
93
183
|
# @param [Integer] position of the new row
|
94
184
|
# @param [Array] values of the column
|
95
185
|
def add_row(position = nil, contents = nil)
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
raise TableError, ("could not add row" + (" at position #{position.inspect}" if position))
|
101
|
-
end
|
186
|
+
@ole_table.ListRows.Add(position)
|
187
|
+
set_row_values(position, contents) if contents
|
188
|
+
rescue WIN32OLERuntimeError
|
189
|
+
raise TableError, ("could not add row" + (" at position #{position.inspect}" if position) + "\n#{$!.message}")
|
102
190
|
end
|
103
191
|
|
104
192
|
# adds a column
|
@@ -106,116 +194,96 @@ module RobustExcelOle
|
|
106
194
|
# @param [Integer] position of the new column
|
107
195
|
# @param [Array] values of the column
|
108
196
|
def add_column(column_name = nil, position = nil, contents = nil)
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
raise TableError, ("could not add column"+ ("at position #{position.inspect} with name #{column_name.inspect}" if position))
|
115
|
-
end
|
197
|
+
new_column = @ole_table.ListColumns.Add(position)
|
198
|
+
new_column.Name = column_name if column_name
|
199
|
+
set_column_values(column_name, contents) if contents
|
200
|
+
rescue WIN32OLERuntimeError, TableError
|
201
|
+
raise TableError, ("could not add column"+ ("at position #{position.inspect} with name #{column_name.inspect}" if position) + "\n#{$!.message}")
|
116
202
|
end
|
117
203
|
|
118
204
|
# deletes a row
|
119
205
|
# @param [Integer] position of the old row
|
120
206
|
def delete_row(row_number) # :nodoc: #
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
raise TableError, "could not delete row #{row_number.inspect}"
|
125
|
-
end
|
207
|
+
@ole_table.ListRows.Item(row_number).Delete
|
208
|
+
rescue WIN32OLERuntimeError
|
209
|
+
raise TableError, "could not delete row #{row_number.inspect}\n#{$!.message}"
|
126
210
|
end
|
127
211
|
|
128
212
|
# deletes a column
|
129
213
|
# @param [Variant] column number or column name
|
130
214
|
def delete_column(column_number_or_name) # :nodoc: #
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
raise TableError, "could not delete column #{column_number_or_name.inspect}"
|
135
|
-
end
|
215
|
+
@ole_table.ListColumns.Item(column_number_or_name).Delete
|
216
|
+
rescue WIN32OLERuntimeError
|
217
|
+
raise TableError, "could not delete column #{column_number_or_name.inspect}\n#{$!.message}"
|
136
218
|
end
|
137
219
|
|
138
220
|
# deletes the contents of a row
|
139
221
|
# @param [Integer] row number
|
140
222
|
def delete_row_values(row_number)
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
raise TableError, "could not delete contents of row #{row_number.inspect}"
|
146
|
-
end
|
223
|
+
@ole_table.ListRows.Item(row_number).Range.Value = [[].fill(nil,0..(@ole_table.ListColumns.Count-1))]
|
224
|
+
nil
|
225
|
+
rescue WIN32OLERuntimeError
|
226
|
+
raise TableError, "could not delete contents of row #{row_number.inspect}\n#{$!.message}"
|
147
227
|
end
|
148
228
|
|
149
229
|
# deletes the contents of a column
|
150
230
|
# @param [Variant] column number or column name
|
151
231
|
def delete_column_values(column_number_or_name)
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
raise TableError, "could not delete contents of column #{column_number_or_name.inspect}"
|
158
|
-
end
|
232
|
+
column_name = @ole_table.ListColumns.Item(column_number_or_name).Range.Value.first
|
233
|
+
@ole_table.ListColumns.Item(column_number_or_name).Range.Value = [column_name] + [].fill([nil],0..(@ole_table.ListRows.Count-1))
|
234
|
+
nil
|
235
|
+
rescue WIN32OLERuntimeError
|
236
|
+
raise TableError, "could not delete contents of column #{column_number_or_name.inspect}\n#{$!.message}"
|
159
237
|
end
|
160
238
|
|
161
239
|
# renames a row
|
162
240
|
# @param [String] previous name or number of the column
|
163
241
|
# @param [String] new name of the column
|
164
242
|
def rename_column(name_or_number, new_name) # :nodoc: #
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
raise TableError, "could not rename column #{name_or_number.inspect} to #{new_name.inspect}"
|
169
|
-
end
|
243
|
+
@ole_table.ListColumns.Item(name_or_number).Name = new_name
|
244
|
+
rescue
|
245
|
+
raise TableError, "could not rename column #{name_or_number.inspect} to #{new_name.inspect}\n#{$!.message}"
|
170
246
|
end
|
171
247
|
|
172
248
|
# contents of a row
|
173
249
|
# @param [Integer] row number
|
174
250
|
# @return [Array] contents of a row
|
175
251
|
def row_values(row_number)
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
raise TableError, "could not read the values of row #{row_number.inspect}"
|
180
|
-
end
|
252
|
+
@ole_table.ListRows.Item(row_number).Range.Value.first.map{|v| v.respond_to?(:gsub) ? v.encode('utf-8') : v}
|
253
|
+
rescue WIN32OLERuntimeError
|
254
|
+
raise TableError, "could not read the values of row #{row_number.inspect}\n#{$!.message}"
|
181
255
|
end
|
182
256
|
|
183
257
|
# sets the contents of a row
|
184
258
|
# @param [Integer] row number
|
185
259
|
# @param [Array] values of the row
|
186
260
|
def set_row_values(row_number, values)
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
raise TableError, "could not set the values of row #{row_number.inspect}"
|
194
|
-
end
|
261
|
+
updated_values = row_values(row_number)
|
262
|
+
updated_values[0,values.length] = values
|
263
|
+
@ole_table.ListRows.Item(row_number).Range.Value = [updated_values]
|
264
|
+
values
|
265
|
+
rescue WIN32OLERuntimeError
|
266
|
+
raise TableError, "could not set the values of row #{row_number.inspect}\n#{$!.message}"
|
195
267
|
end
|
196
268
|
|
197
269
|
# @return [Array] contents of a column
|
198
270
|
def column_values(column_number_or_name)
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
raise TableError, "could not read the values of column #{column_number_or_name.inspect}"
|
203
|
-
end
|
271
|
+
@ole_table.ListColumns.Item(column_number_or_name).Range.Value[1,@ole_table.ListRows.Count].flatten.map{|v| v.respond_to?(:gsub) ? v.encode('utf-8') : v}
|
272
|
+
rescue WIN32OLERuntimeError
|
273
|
+
raise TableError, "could not read the values of column #{column_number_or_name.inspect}\n#{$!.message}"
|
204
274
|
end
|
205
275
|
|
206
276
|
# sets the contents of a column
|
207
277
|
# @param [Integer] column name or column number
|
208
278
|
# @param [Array] contents of the column
|
209
279
|
def set_column_values(column_number_or_name, values)
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
raise TableError, "could not read the values of column #{column_number_or_name.inspect}"
|
218
|
-
end
|
280
|
+
updated_values = column_values(column_number_or_name)
|
281
|
+
updated_values[0,values.length] = values
|
282
|
+
column_name = @ole_table.ListColumns.Item(column_number_or_name).Range.Value.first
|
283
|
+
@ole_table.ListColumns.Item(column_number_or_name).Range.Value = column_name + updated_values.map{|v| [v]}
|
284
|
+
values
|
285
|
+
rescue WIN32OLERuntimeError
|
286
|
+
raise TableError, "could not read the values of column #{column_number_or_name.inspect}\n#{$!.message}"
|
219
287
|
end
|
220
288
|
|
221
289
|
# deletes rows that have an empty contents
|
@@ -228,7 +296,7 @@ module RobustExcelOle
|
|
228
296
|
if row.Range.Value == nil_array
|
229
297
|
row.Delete
|
230
298
|
else
|
231
|
-
i
|
299
|
+
i += 1
|
232
300
|
end
|
233
301
|
end
|
234
302
|
end
|
@@ -243,7 +311,7 @@ module RobustExcelOle
|
|
243
311
|
if column.Range.Value[1..-1] == nil_array
|
244
312
|
column.Delete
|
245
313
|
else
|
246
|
-
i
|
314
|
+
i += 1
|
247
315
|
end
|
248
316
|
end
|
249
317
|
end
|
@@ -252,15 +320,14 @@ module RobustExcelOle
|
|
252
320
|
# @param[Variant] value to find
|
253
321
|
# @return [Array] win32ole cells containing the given value
|
254
322
|
def find_cells(value)
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
323
|
+
encode_utf8 = ->(val) {val.respond_to?(:gsub) ? val.encode('utf-8') : val}
|
324
|
+
listrows = @ole_table.ListRows
|
325
|
+
listrows.map { |listrow|
|
326
|
+
listrow_range = listrow.Range
|
327
|
+
listrow_range.Value.first.map{ |v| encode_utf8.(v) }.find_all_indices(value).map do |col_number|
|
328
|
+
listrow_range.Cells(1,col_number+1).to_reo
|
261
329
|
end
|
262
|
-
|
263
|
-
result
|
330
|
+
}.flatten
|
264
331
|
end
|
265
332
|
|
266
333
|
# sorts the rows of the list object according to the given column
|
@@ -274,6 +341,19 @@ module RobustExcelOle
|
|
274
341
|
@ole_table.Sort.Apply
|
275
342
|
end
|
276
343
|
|
344
|
+
# @return [Array] position of the first cell of the table
|
345
|
+
def position
|
346
|
+
first_cell = self.Range.Cells(1,1)
|
347
|
+
@position = [first_cell.Row, first_cell.Column]
|
348
|
+
end
|
349
|
+
|
350
|
+
def == other_table
|
351
|
+
other_table.is_a?(ListObject) &&
|
352
|
+
self.HeaderRowRange.Value == other_table.HeaderRowRange.Value &&
|
353
|
+
self.DataBodyRange.Value == other_table.DataBodyRange.Value
|
354
|
+
end
|
355
|
+
|
356
|
+
|
277
357
|
# @private
|
278
358
|
# returns true, if the list object responds to VBA methods, false otherwise
|
279
359
|
def alive?
|
@@ -291,9 +371,9 @@ module RobustExcelOle
|
|
291
371
|
|
292
372
|
# @private
|
293
373
|
def inspect
|
294
|
-
"#<ListObject
|
374
|
+
"#<ListObject:#{@ole_table.Name}" +
|
295
375
|
" #{@ole_table.ListRows.Count}x#{@ole_table.ListColumns.Count}" +
|
296
|
-
" #{@ole_table.Parent.Name}
|
376
|
+
" #{@ole_table.Parent.Name} #{@ole_table.Parent.Parent.Name}>"
|
297
377
|
end
|
298
378
|
|
299
379
|
include MethodHelpers
|
@@ -301,22 +381,19 @@ module RobustExcelOle
|
|
301
381
|
private
|
302
382
|
|
303
383
|
def method_missing(name, *args)
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
end
|
311
|
-
else
|
312
|
-
begin
|
313
|
-
@ole_table.send(name, *args)
|
314
|
-
rescue NoMethodError
|
315
|
-
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
316
|
-
end
|
384
|
+
super unless name.to_s[0,1] =~ /[A-Z]/
|
385
|
+
if ::ERRORMESSAGE_JRUBY_BUG
|
386
|
+
begin
|
387
|
+
@ole_table.send(name, *args)
|
388
|
+
rescue Java::OrgRacobCom::ComFailException
|
389
|
+
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
317
390
|
end
|
318
391
|
else
|
319
|
-
|
392
|
+
begin
|
393
|
+
@ole_table.send(name, *args)
|
394
|
+
rescue NoMethodError
|
395
|
+
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
396
|
+
end
|
320
397
|
end
|
321
398
|
end
|
322
399
|
end
|
@@ -325,10 +402,6 @@ module RobustExcelOle
|
|
325
402
|
class TableError < WorksheetREOError
|
326
403
|
end
|
327
404
|
|
328
|
-
# @private
|
329
|
-
class TableRowError < WorksheetREOError
|
330
|
-
end
|
331
|
-
|
332
405
|
Table = ListObject
|
333
406
|
|
334
407
|
end
|