robust_excel_ole 1.31 → 1.32
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.
- 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
|