robust_excel_ole 1.35 → 1.36
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/Changelog +20 -2
- data/README.rdoc +31 -95
- data/docs/README_excel.rdoc +5 -6
- data/docs/README_listobjects.rdoc +8 -15
- data/docs/README_open.rdoc +48 -25
- data/docs/README_ranges.rdoc +7 -10
- data/docs/README_save_close.rdoc +4 -5
- data/docs/README_sheet.rdoc +4 -8
- data/examples/introductory_examples/example_introductory.rb +1 -1
- data/examples/introductory_examples/example_open.rb +1 -1
- data/lib/robust_excel_ole/excel.rb +98 -16
- data/lib/robust_excel_ole/general.rb +18 -6
- data/lib/robust_excel_ole/list_object.rb +11 -19
- data/lib/robust_excel_ole/list_row.rb +74 -19
- data/lib/robust_excel_ole/range.rb +6 -1
- data/lib/robust_excel_ole/range_owners.rb +24 -17
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +107 -42
- data/lib/robust_excel_ole/worksheet.rb +1 -1
- data/robust_excel_ole.gemspec +0 -1
- data/spec/bookstore_spec.rb +1 -2
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/data/workbook_linked3.xlsm +0 -0
- data/spec/data/workbook_listobjects.xlsx +0 -0
- data/spec/data/workbook_unsaved.xlsm +0 -0
- data/spec/excel_spec.rb +4 -4
- data/spec/general_spec.rb +1 -2
- data/spec/list_object_spec.rb +26 -9
- data/spec/list_row_spec.rb +34 -20
- data/spec/range_spec.rb +9 -0
- data/spec/workbook_spec.rb +2 -2
- data/spec/workbook_specs/workbook_misc_spec.rb +249 -2
- data/spec/workbook_specs/workbook_open_spec.rb +307 -16
- data/spec/workbook_specs/workbook_unobtr_spec.rb +196 -42
- metadata +4 -16
@@ -1,12 +1,59 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
3
|
require 'weakref'
|
4
|
-
require '
|
4
|
+
require 'fiddle/import'
|
5
5
|
|
6
6
|
def ka
|
7
7
|
Excel.kill_all
|
8
8
|
end
|
9
9
|
|
10
|
+
module User32
|
11
|
+
# Extend this module to an importer
|
12
|
+
extend Fiddle::Importer
|
13
|
+
# Load 'user32' dynamic library into this importer
|
14
|
+
dlload 'user32'
|
15
|
+
# Set C aliases to this importer for further understanding of function signatures
|
16
|
+
typealias 'HWND', 'HANDLE'
|
17
|
+
typealias 'HANDLE', 'void*'
|
18
|
+
typealias 'LPCSTR', 'const char*'
|
19
|
+
typealias 'LPCWSTR', 'const wchar_t*'
|
20
|
+
typealias 'UINT', 'unsigned int'
|
21
|
+
typealias 'HANDLE', 'void*'
|
22
|
+
typealias 'ppvObject', 'void**'
|
23
|
+
typealias 'DWORD', 'unsigned long'
|
24
|
+
typealias 'LPDWORD', 'DWORD*'
|
25
|
+
# Import C functions from loaded libraries and set them as module functions
|
26
|
+
extern 'DWORD GetWindowThreadProcessId(HWND, LPDWORD)'
|
27
|
+
extern 'HWND FindWindowExA(HWND, HWND, LPCSTR, LPCSTR)'
|
28
|
+
extern 'DWORD SetForegroundWindow(HWND)'
|
29
|
+
end
|
30
|
+
|
31
|
+
module Oleacc
|
32
|
+
# Extend this module to an importer
|
33
|
+
extend Fiddle::Importer
|
34
|
+
# Load 'oleacc' dynamic library into this importer
|
35
|
+
dlload 'oleacc'
|
36
|
+
# Set C aliases to this importer for further understanding of function signatures
|
37
|
+
typealias 'HWND', 'HANDLE'
|
38
|
+
typealias 'HANDLE', 'void*'
|
39
|
+
typealias 'ppvObject', 'void**'
|
40
|
+
typealias 'DWORD', 'unsigned long'
|
41
|
+
typealias 'HRESULT', 'long'
|
42
|
+
Guid = struct [
|
43
|
+
'unsigned long data1',
|
44
|
+
'unsigned short data2',
|
45
|
+
'unsigned short data3',
|
46
|
+
'unsigned char data4[8]'
|
47
|
+
]
|
48
|
+
# Import C functions from loaded libraries and set them as module functions
|
49
|
+
extern 'HRESULT AccessibleObjectFromWindow(HWND, DWORD, struct guid*, ppvObject)'
|
50
|
+
#typealias 'REFIID', 'struct guid*'
|
51
|
+
#extern 'HRESULT AccessibleObjectFromWindow(HWND, DWORD, REFIID, ppvObject)'
|
52
|
+
#extern 'HRESULT AccessibleObjectFromWindow(HWND, DWORD, struct GUID*, ppvObject)'
|
53
|
+
#extern 'HRESULT AccessibleObjectFromWindow(HWND, DWORD, void*, ppvObject)'
|
54
|
+
#extern 'HRESULT AccessibleObjectFromWindow(HWND, DWORD, struct GUID*, ppvObject)'
|
55
|
+
end
|
56
|
+
|
10
57
|
module RobustExcelOle
|
11
58
|
|
12
59
|
# This class essentially wraps a Win32Ole Application object.
|
@@ -114,7 +161,7 @@ module RobustExcelOle
|
|
114
161
|
@ole_excel = WIN32OLE.new('Excel.Application')
|
115
162
|
set_options(opts)
|
116
163
|
if opts[:reopen_workbooks]
|
117
|
-
workbook_class.books.each{ |book| book.
|
164
|
+
workbook_class.books.each{ |book| book.open if !book.alive? && book.excel.alive? && book.excel == self }
|
118
165
|
end
|
119
166
|
end
|
120
167
|
self
|
@@ -294,9 +341,8 @@ module RobustExcelOle
|
|
294
341
|
sleep 0.1
|
295
342
|
if finishing_living_excel
|
296
343
|
if hwnd
|
297
|
-
process_id = Win32API.new('user32', 'GetWindowThreadProcessId', %w[I P], 'I')
|
298
344
|
pid_puffer = ' ' * 32
|
299
|
-
|
345
|
+
User32::GetWindowThreadProcessId(hwnd, pid_puffer)
|
300
346
|
pid = pid_puffer.unpack('L')[0]
|
301
347
|
Process.kill('KILL', pid) rescue nil
|
302
348
|
end
|
@@ -354,10 +400,50 @@ module RobustExcelOle
|
|
354
400
|
WIN32OLE.connect('winmgmts:\\\\.').InstancesOf('win32_process').select { |p| p.Name == 'EXCEL.EXE' }.size
|
355
401
|
end
|
356
402
|
|
357
|
-
def self.
|
403
|
+
def self.known_instances_count
|
358
404
|
@@hwnd2excel.size
|
359
405
|
end
|
360
406
|
|
407
|
+
# returns running Excel instances
|
408
|
+
# !!! This is work in progress
|
409
|
+
# the approach is currently restricted to visible Excel instances with at least one workbook
|
410
|
+
def self.running_excel_instances
|
411
|
+
win32ole_excel_instances = []
|
412
|
+
hwnd = 0
|
413
|
+
loop do
|
414
|
+
hwnd = User32::FindWindowExA(0, hwnd, "XLMAIN", nil).to_i
|
415
|
+
break if hwnd == 0
|
416
|
+
hwnd2 = User32::FindWindowExA(hwnd, 0, "XLDESK", nil).to_i
|
417
|
+
hwnd3 = User32::FindWindowExA(hwnd2, 0, "EXCEL7", nil).to_i
|
418
|
+
interface_address_buffer = ' ' * 8
|
419
|
+
guid = Oleacc::Guid.malloc
|
420
|
+
guid.data1 = 0x20400
|
421
|
+
guid.data2 = 0x0
|
422
|
+
guid.data3 = 0x0
|
423
|
+
guid.data4 = [0xc0,0x0,0x0,0x0,0x0,0x0,0x0,0x46]
|
424
|
+
status = Oleacc::AccessibleObjectFromWindow(hwnd3, 0xFFFFFFF0, guid, interface_address_buffer)
|
425
|
+
interface_address = nil
|
426
|
+
if status == 0
|
427
|
+
interface_address = interface_address_buffer.unpack('L')[0]
|
428
|
+
else
|
429
|
+
raise ExcelREOError, "could not determine the addresss of the specified interface of the Excel object"
|
430
|
+
end
|
431
|
+
accessed_object_buffer = ' ' * 8
|
432
|
+
# open issue: is there a dll containing QueryInterface?
|
433
|
+
status = Ole32::QueryInterface(interface_address, guid, accessed_object_buffer)
|
434
|
+
if status == 0
|
435
|
+
accessed_object = accessed_object_buffer.unpack('L')[0]
|
436
|
+
# open issue: a method, similar to create_win32ole in Win32ole creating a win32ole object
|
437
|
+
# we could use pr-win32ole (seems to be an old ruby gem, needing C to be installed)
|
438
|
+
ole_excel = create_win32ole(accessed_object)
|
439
|
+
win32ole_excel_instances << ole_excel.Application
|
440
|
+
else
|
441
|
+
raise ExcelREOError, "could not determine the Excel object from window"
|
442
|
+
end
|
443
|
+
end
|
444
|
+
win32ole_excel_instances.map{|w| w.to_reo}
|
445
|
+
end
|
446
|
+
|
361
447
|
# returns a running Excel instance opened with RobustExcelOle
|
362
448
|
def self.known_running_instance
|
363
449
|
self.known_running_instances.first
|
@@ -369,9 +455,8 @@ module RobustExcelOle
|
|
369
455
|
@@hwnd2excel.each do |hwnd,wr_excel|
|
370
456
|
next unless wr_excel.weakref_alive?
|
371
457
|
excel = wr_excel.__getobj__
|
372
|
-
process_id = Win32API.new('user32', 'GetWindowThreadProcessId', %w[I P], 'I')
|
373
458
|
pid_puffer = ' ' * 32
|
374
|
-
|
459
|
+
User32::GetWindowThreadProcessId(hwnd, pid_puffer)
|
375
460
|
pid = pid_puffer.unpack('L')[0]
|
376
461
|
pid2excel[pid] = excel
|
377
462
|
end
|
@@ -380,10 +465,10 @@ module RobustExcelOle
|
|
380
465
|
end
|
381
466
|
|
382
467
|
class << self
|
383
|
-
alias excels_number instance_count # :deprecated
|
384
|
-
alias known_excels_number
|
385
|
-
alias known_excel_instance known_running_instance # :deprecated
|
386
|
-
alias known_excel_instances known_running_instances # :deprecated
|
468
|
+
alias excels_number instance_count # :deprecated: #
|
469
|
+
alias known_excels_number known_instances_count # :deprecated: #
|
470
|
+
alias known_excel_instance known_running_instance # :deprecated: #
|
471
|
+
alias known_excel_instances known_running_instances # :deprecated: #
|
387
472
|
end
|
388
473
|
|
389
474
|
private
|
@@ -627,11 +712,8 @@ module RobustExcelOle
|
|
627
712
|
|
628
713
|
def focus
|
629
714
|
self.visible = true
|
630
|
-
|
631
|
-
|
632
|
-
# else
|
633
|
-
# Win32API.new("user32","SetForegroundWindow","","I").call
|
634
|
-
# end
|
715
|
+
status = User32::SetForegroundWindow(@ole_excel.Hwnd)
|
716
|
+
raise ExcelREOError, "could not set Excel window as foreground" if status == 0
|
635
717
|
end
|
636
718
|
|
637
719
|
# @private
|
@@ -224,18 +224,30 @@ module General
|
|
224
224
|
network = WIN32OLE.new('WScript.Network')
|
225
225
|
drives = network.enumnetworkdrives
|
226
226
|
count = drives.Count
|
227
|
-
(0..(count - 1)).step(2).map{ |i| NetworkDrive.new( drives.Item(i), drives.Item(i + 1).tr('\\','/')) }
|
227
|
+
# (0..(count - 1)).step(2).map{ |i| NetworkDrive.new( drives.Item(i), drives.Item(i + 1).tr('\\','/')) }
|
228
|
+
result = (0..(count - 1)).step(2).map { |i|
|
229
|
+
NetworkDrive.new( drives.Item(i), drives.Item(i + 1).tr('\\','/')) unless drives.Item(i).empty?
|
230
|
+
}.compact
|
231
|
+
result
|
228
232
|
end
|
229
233
|
end
|
230
234
|
|
231
235
|
# @private
|
232
236
|
def hostnameshare2networkpath(filename)
|
233
237
|
return filename unless filename[0,2] == "//"
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
238
|
+
hostname = filename[0,filename[3,filename.length].index('/')+3]
|
239
|
+
filename_wo_hostname = filename[hostname.length+1,filename.length]
|
240
|
+
abs_filename = absolute_path(filename_wo_hostname).tr('\\','/').tr('C:/','c$/')
|
241
|
+
adapted_filename = hostname + "/" + abs_filename
|
242
|
+
NetworkDrive.get_all_drives.each do |d|
|
243
|
+
new_filename = filename.sub(/#{(Regexp.escape(d.network_name))}/i,d.drive_letter)
|
244
|
+
return new_filename if new_filename != filename
|
245
|
+
new_filename = adapted_filename.sub(/#{(Regexp.escape(d.network_name))}/i,d.drive_letter)
|
246
|
+
return new_filename if new_filename != filename
|
247
|
+
end
|
248
|
+
filename
|
249
|
+
end
|
250
|
+
|
239
251
|
# @private
|
240
252
|
def absolute_path(file)
|
241
253
|
file = file.to_path if file.respond_to?(:to_path)
|
@@ -60,23 +60,6 @@ module RobustExcelOle
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
=begin
|
64
|
-
|
65
|
-
ole_table = @ole_table
|
66
|
-
|
67
|
-
@row_class = Class.new(ListRow) do
|
68
|
-
|
69
|
-
@@ole_table = ole_table
|
70
|
-
|
71
|
-
def ole_table
|
72
|
-
@@ole_table
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
end
|
78
|
-
|
79
|
-
=end
|
80
63
|
|
81
64
|
ole_table = @ole_table
|
82
65
|
|
@@ -141,13 +124,18 @@ module RobustExcelOle
|
|
141
124
|
|
142
125
|
private
|
143
126
|
|
144
|
-
|
127
|
+
def matching_via_traversing(key_hash, opts)
|
145
128
|
encode_utf8 = ->(val) {val.respond_to?(:gsub) ? val.encode('utf-8') : val}
|
146
129
|
cn2i = column_names_to_index
|
147
130
|
max_matching_num = opts[:limit] || 65536
|
148
131
|
matching_rows = @ole_table.ListRows.lazy.select { |listrow|
|
149
132
|
rowvalues = listrow.Range.Value.first
|
150
|
-
key_hash.all?{
|
133
|
+
key_hash.all?{|key,val|
|
134
|
+
rowvalue = encode_utf8.(rowvalues[cn2i[key]])
|
135
|
+
rowvalue == val ||
|
136
|
+
(val == "0" && rowvalue == 0) ||
|
137
|
+
(rowvalue.respond_to?(:abs) && val.to_i != 0 && rowvalue == val.to_i)
|
138
|
+
}
|
151
139
|
}.take(max_matching_num).to_a
|
152
140
|
rescue
|
153
141
|
raise(TableError, "cannot find row with key #{key_hash}")
|
@@ -386,6 +374,10 @@ module RobustExcelOle
|
|
386
374
|
self.Parent.to_reo == other_table.Parent.to_reo
|
387
375
|
end
|
388
376
|
|
377
|
+
# @private
|
378
|
+
def workbook
|
379
|
+
@workbook ||= ole_table.Parent.Parent.to_reo
|
380
|
+
end
|
389
381
|
|
390
382
|
# @private
|
391
383
|
# returns true, if the list object responds to VBA methods, false otherwise
|
@@ -27,6 +27,7 @@ module RobustExcelOle
|
|
27
27
|
# @param [Variant] column number or column name
|
28
28
|
# @return [Variant] value of the cell
|
29
29
|
def [] column_number_or_name
|
30
|
+
column_number_or_name = column_number_or_name.to_s if column_number_or_name.is_a?(Symbol)
|
30
31
|
ole_cell = ole_table.Application.Intersect(
|
31
32
|
@ole_tablerow.Range, ole_table.ListColumns.Item(column_number_or_name).Range)
|
32
33
|
value = ole_cell.Value
|
@@ -40,6 +41,7 @@ module RobustExcelOle
|
|
40
41
|
# @param [Variant] value of the cell
|
41
42
|
def []=(column_number_or_name, value)
|
42
43
|
begin
|
44
|
+
column_number_or_name = column_number_or_name.to_s if column_number_or_name.is_a?(Symbol)
|
43
45
|
ole_cell = ole_table.Application.Intersect(
|
44
46
|
@ole_tablerow.Range, ole_table.ListColumns.Item(column_number_or_name).Range)
|
45
47
|
ole_cell.Value = value
|
@@ -96,27 +98,68 @@ module RobustExcelOle
|
|
96
98
|
other_listrow.is_a?(ListRow) && other_listrow.values == self.values
|
97
99
|
end
|
98
100
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
c.replace_umlauts.underscore.gsub(/\W/,'_') == core_name
|
112
|
-
end
|
113
|
-
if column_name
|
114
|
-
define_and_call_method(column_name, name, *args)
|
115
|
-
else
|
116
|
-
super(name, *args)
|
101
|
+
# @private
|
102
|
+
def workbook
|
103
|
+
@workbook ||= workbook_class.new(ole_table.Parent.Parent)
|
104
|
+
end
|
105
|
+
|
106
|
+
# @private
|
107
|
+
def self.workbook_class
|
108
|
+
@workbook_class ||= begin
|
109
|
+
module_name = parent_name
|
110
|
+
"#{module_name}::Workbook".constantize
|
111
|
+
rescue NameError => e
|
112
|
+
Workbook
|
117
113
|
end
|
118
114
|
end
|
119
115
|
|
116
|
+
# @private
|
117
|
+
def workbook_class
|
118
|
+
self.class.workbook_class
|
119
|
+
end
|
120
|
+
|
121
|
+
# @private
|
122
|
+
def column_names
|
123
|
+
ole_table.HeaderRowRange.Value.first
|
124
|
+
end
|
125
|
+
|
126
|
+
# returns true, if the listrow reacts to methods, false otherwise
|
127
|
+
def alive?
|
128
|
+
@ole_tablerow.Parent
|
129
|
+
true
|
130
|
+
rescue
|
131
|
+
@ole_tablerow = nil # dead object won't be alive again
|
132
|
+
false
|
133
|
+
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def valid_similar_names meth_name
|
138
|
+
[
|
139
|
+
meth_name,
|
140
|
+
meth_name.gsub(/\W/,'_'),
|
141
|
+
meth_name.underscore,
|
142
|
+
meth_name.underscore.gsub(/\W/,'_'),
|
143
|
+
meth_name.replace_umlauts.gsub(/\W/,'_'),
|
144
|
+
meth_name.replace_umlauts.underscore.gsub(/\W/,'_')
|
145
|
+
].uniq
|
146
|
+
end
|
147
|
+
|
148
|
+
public
|
149
|
+
|
150
|
+
# @private
|
151
|
+
def methods
|
152
|
+
@methods ||= begin
|
153
|
+
arr = column_names.map{ |c| valid_similar_names(c) }.flatten
|
154
|
+
(arr + arr.map{|m| m + '='}).map(&:to_sym) + super
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# @private
|
159
|
+
def respond_to?(meth_name)
|
160
|
+
methods.include?(meth_name.to_sym)
|
161
|
+
end
|
162
|
+
|
120
163
|
# @private
|
121
164
|
def to_s
|
122
165
|
inspect
|
@@ -129,7 +172,19 @@ module RobustExcelOle
|
|
129
172
|
|
130
173
|
private
|
131
174
|
|
132
|
-
def
|
175
|
+
def method_missing(meth_name, *args)
|
176
|
+
# this should not happen:
|
177
|
+
raise(TableRowError, "internal error: ole_table not defined") unless self.class.method_defined?(:ole_table)
|
178
|
+
if respond_to?(meth_name)
|
179
|
+
core_name = meth_name.to_s.chomp('=')
|
180
|
+
column_name = column_names.find{ |c| valid_similar_names(c).include?(core_name) }
|
181
|
+
define_and_call_method(column_name, meth_name, *args) if column_name
|
182
|
+
else
|
183
|
+
super(meth_name, *args)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def define_and_call_method(column_name, method_name, *args)
|
133
188
|
#column_name = column_name.force_encoding('cp850')
|
134
189
|
ole_cell = ole_table.Application.Intersect(
|
135
190
|
@ole_tablerow.Range, ole_table.ListColumns.Item(column_name).Range)
|
@@ -223,6 +223,11 @@ module RobustExcelOle
|
|
223
223
|
@worksheet.workbook.excel
|
224
224
|
end
|
225
225
|
|
226
|
+
# @private
|
227
|
+
def workbook
|
228
|
+
@workbook ||= @worksheet.workbook
|
229
|
+
end
|
230
|
+
|
226
231
|
# @private
|
227
232
|
# returns true, if the Range object responds to VBA methods, false otherwise
|
228
233
|
def alive?
|
@@ -231,7 +236,7 @@ module RobustExcelOle
|
|
231
236
|
rescue
|
232
237
|
# trace $!.message
|
233
238
|
false
|
234
|
-
end
|
239
|
+
end
|
235
240
|
|
236
241
|
# @private
|
237
242
|
def to_s
|
@@ -15,22 +15,25 @@ module RobustExcelOle
|
|
15
15
|
# @option opts [Symbol] :default the default value that is provided if no contents could be returned
|
16
16
|
# @return [Variant] the contents of a range with given name
|
17
17
|
def namevalue_global(name, opts = { default: :__not_provided })
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
ole_range = name_obj.RefersToRange
|
24
|
-
worksheet = self if self.is_a?(Worksheet)
|
25
|
-
value = begin
|
26
|
-
if !::RANGES_JRUBY_BUG
|
27
|
-
ole_range.Value
|
28
|
-
else
|
29
|
-
values = RobustExcelOle::Range.new(ole_range, worksheet).v
|
30
|
-
(values.size==1 && values.first.size==1) ? values.first.first : values
|
18
|
+
begin
|
19
|
+
name_obj = begin
|
20
|
+
get_name_object(name)
|
21
|
+
rescue NameNotFound
|
22
|
+
raise
|
31
23
|
end
|
32
|
-
|
24
|
+
ole_range = name_obj.RefersToRange
|
25
|
+
worksheet = self if self.is_a?(Worksheet)
|
26
|
+
value = begin
|
27
|
+
if !::RANGES_JRUBY_BUG
|
28
|
+
ole_range.Value
|
29
|
+
else
|
30
|
+
values = RobustExcelOle::Range.new(ole_range, worksheet).v
|
31
|
+
(values.size==1 && values.first.size==1) ? values.first.first : values
|
32
|
+
end
|
33
|
+
end
|
34
|
+
rescue # WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
33
35
|
sheet = if self.is_a?(Worksheet) then self
|
36
|
+
# chooses simply the 1st worksheet?
|
34
37
|
elsif self.is_a?(Workbook) then self.sheet(1)
|
35
38
|
end
|
36
39
|
begin
|
@@ -42,16 +45,20 @@ module RobustExcelOle
|
|
42
45
|
values = RobustExcelOle::Range.new(ole_range, worksheet).v
|
43
46
|
(values.size==1 && values.first.size==1) ? values.first.first : values
|
44
47
|
end
|
45
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
48
|
+
rescue # WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
46
49
|
return opts[:default] unless opts[:default] == :__not_provided
|
47
|
-
|
50
|
+
if name_obj.nil?
|
51
|
+
raise NameNotFound, "cannot find name #{name.inspect}"
|
52
|
+
else
|
53
|
+
raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect}"
|
54
|
+
end
|
48
55
|
end
|
49
56
|
end
|
50
57
|
if value == -2146828288 + RobustExcelOle::XlErrName
|
51
58
|
return opts[:default] unless opts[:default] == :__not_provided
|
52
59
|
raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{File.basename(workbook.stored_filename).inspect rescue nil}"
|
53
60
|
end
|
54
|
-
return opts[:default]
|
61
|
+
return opts[:default] if opts[:default] != :__not_provided && !value.nil?
|
55
62
|
value
|
56
63
|
end
|
57
64
|
|