robust_excel_ole 1.13 → 1.18
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 +47 -4
- data/README.rdoc +52 -47
- data/___dummy_workbook.xls +0 -0
- data/docs/README_excel.rdoc +9 -3
- data/docs/README_open.rdoc +86 -44
- data/docs/README_ranges.rdoc +90 -81
- data/docs/README_save_close.rdoc +9 -9
- data/docs/README_sheet.rdoc +17 -17
- data/examples/example_ruby_library.rb +27 -0
- data/extconf.rb +7 -0
- data/lib/robust_excel_ole.rb +7 -4
- data/lib/robust_excel_ole/{address.rb → address_tool.rb} +23 -22
- data/lib/robust_excel_ole/{reo_common.rb → base.rb} +3 -92
- data/lib/robust_excel_ole/bookstore.rb +14 -77
- data/lib/robust_excel_ole/cell.rb +30 -18
- data/lib/robust_excel_ole/excel.rb +138 -92
- data/lib/robust_excel_ole/general.rb +40 -15
- data/lib/robust_excel_ole/range.rb +42 -19
- data/lib/robust_excel_ole/range_owners.rb +40 -25
- data/lib/robust_excel_ole/vba_objects.rb +30 -0
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +320 -319
- data/lib/robust_excel_ole/worksheet.rb +51 -25
- data/robust_excel_ole.gemspec +1 -0
- data/spec/address_tool_spec.rb +175 -0
- data/spec/{reo_common_spec.rb → base_spec.rb} +19 -34
- data/spec/bookstore_spec.rb +3 -3
- data/spec/cell_spec.rb +67 -25
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/excel_spec.rb +137 -369
- data/spec/general_spec.rb +21 -27
- data/spec/range_spec.rb +57 -3
- data/spec/workbook_spec.rb +11 -79
- data/spec/workbook_specs/workbook_misc_spec.rb +29 -40
- data/spec/workbook_specs/workbook_open_spec.rb +599 -31
- data/spec/workbook_specs/workbook_unobtr_spec.rb +760 -93
- data/spec/worksheet_spec.rb +36 -4
- metadata +12 -7
- data/spec/address_spec.rb +0 -174
@@ -3,24 +3,47 @@
|
|
3
3
|
module General
|
4
4
|
|
5
5
|
IS_JRUBY_PLATFORM = (RUBY_PLATFORM =~ /java/)
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
::EXPANDPATH_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
7
|
+
::CONNECT_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
8
|
+
::COPYSHEETS_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
9
|
+
::ERRORMESSAGE_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
10
|
+
::CONNECT_EXCEL_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
11
|
+
::RANGES_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
12
|
+
|
13
|
+
@private
|
14
|
+
def network2hostnamesharepath(filename)
|
15
|
+
network = WIN32OLE.new('WScript.Network')
|
16
|
+
drives = network.enumnetworkdrives
|
17
|
+
drive_letter, filename_after_drive_letter = filename.split(':')
|
18
|
+
# if filename starts with a drive letter not c and this drive exists,
|
19
|
+
# then determine the corresponding host_share_path
|
20
|
+
default_drive = File.absolute_path(".")[0]
|
21
|
+
if drive_letter != default_drive && drive_letter != filename
|
22
|
+
for i in 0 .. drives.Count-1
|
23
|
+
next if i % 2 == 1
|
24
|
+
if drives.Item(i).gsub(':','') == drive_letter
|
25
|
+
hostname_share = drives.Item(i+1) #.gsub('\\','/').gsub('//','')
|
26
|
+
break
|
27
|
+
end
|
28
|
+
end
|
29
|
+
hostname_share + filename_after_drive_letter if hostname_share
|
30
|
+
else
|
31
|
+
return filename
|
32
|
+
end
|
33
|
+
end
|
12
34
|
|
13
35
|
# @private
|
14
|
-
def absolute_path(file)
|
36
|
+
def absolute_path(file)
|
37
|
+
file[0,2] = './' if ::EXPANDPATH_JRUBY_BUG && file =~ /[A-Z]:[^\/]/
|
15
38
|
file = File.expand_path(file)
|
16
39
|
file = RobustExcelOle::Cygwin.cygpath('-w', file) if RUBY_PLATFORM =~ /cygwin/
|
17
40
|
WIN32OLE.new('Scripting.FileSystemObject').GetAbsolutePathName(file).tr('/','\\')
|
18
41
|
end
|
19
42
|
|
20
43
|
# @private
|
21
|
-
def canonize(filename)
|
44
|
+
def canonize(filename)
|
22
45
|
raise TypeREOError, "No string given to canonize, but #{filename.inspect}" unless filename.is_a?(String)
|
23
|
-
|
46
|
+
filename = network2hostnamesharepath(filename)
|
24
47
|
normalize(filename).downcase
|
25
48
|
end
|
26
49
|
|
@@ -72,26 +95,28 @@ end
|
|
72
95
|
|
73
96
|
# @private
|
74
97
|
class WIN32OLE
|
75
|
-
|
76
|
-
include RobustExcelOle
|
77
98
|
|
78
|
-
#
|
99
|
+
# type-lifting WIN32OLE objects to RobustExcelOle objects
|
79
100
|
def to_reo
|
80
|
-
class2method = [{Excel => :Hwnd}, {Workbook => :FullName}, {Worksheet => :Copy}, {Range => :
|
101
|
+
class2method = [{Excel => :Hwnd}, {Workbook => :FullName}, {Worksheet => :Copy}, {RobustExcelOle::Range => :Row}]
|
81
102
|
class2method.each do |element|
|
82
103
|
classname = element.first.first
|
83
104
|
method = element.first.last
|
84
105
|
begin
|
85
106
|
self.send(method)
|
86
|
-
|
107
|
+
if classname == RobustExcelOle::Range && self.Rows.Count == 1 && self.Columns.Count == 1
|
108
|
+
return Cell.new(self)
|
109
|
+
else
|
110
|
+
return classname.new(self)
|
111
|
+
end
|
87
112
|
rescue
|
88
113
|
next
|
89
114
|
end
|
90
115
|
end
|
116
|
+
raise TypeREOError, "given object cannot be type-lifted to a RobustExcelOle object"
|
91
117
|
end
|
92
118
|
end
|
93
119
|
|
94
|
-
|
95
120
|
# @private
|
96
121
|
class ::String
|
97
122
|
def / path_part
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
|
+
|
2
3
|
module RobustExcelOle
|
3
4
|
|
4
5
|
# This class essentially wraps a Win32Ole Range object.
|
@@ -6,28 +7,44 @@ module RobustExcelOle
|
|
6
7
|
# that you would apply for a Range object.
|
7
8
|
# See https://docs.microsoft.com/en-us/office/vba/api/excel.worksheet#methods
|
8
9
|
|
9
|
-
class Range <
|
10
|
+
class Range < VbaObjects
|
10
11
|
include Enumerable
|
11
12
|
attr_reader :ole_range
|
12
13
|
attr_reader :worksheet
|
13
14
|
|
14
|
-
def initialize(win32_range)
|
15
|
+
def initialize(win32_range, worksheet = nil)
|
15
16
|
@ole_range = win32_range
|
16
|
-
@worksheet = worksheet_class.new(self.Parent)
|
17
|
+
@worksheet = worksheet ? worksheet : worksheet_class.new(self.Parent)
|
18
|
+
#@worksheet = worksheet_class.new(self.Parent)
|
17
19
|
end
|
18
20
|
|
19
21
|
def each
|
20
|
-
@ole_range.
|
21
|
-
yield
|
22
|
+
@ole_range.each_with_index do |ole_cell, index|
|
23
|
+
yield cell(index){ole_cell}
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
27
|
+
def [] index
|
28
|
+
cell(index) {
|
29
|
+
@ole_range.Cells.Item(index + 1)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def cell(index)
|
36
|
+
@cells ||= []
|
37
|
+
@cells[index + 1] ||= RobustExcelOle::Cell.new(yield,@worksheet)
|
38
|
+
end
|
39
|
+
|
40
|
+
public
|
41
|
+
|
25
42
|
# returns flat array of the values of a given range
|
26
43
|
# @params [Range] a range
|
27
44
|
# @returns [Array] the values
|
28
45
|
def values(range = nil)
|
29
46
|
#result = map { |x| x.Value }.flatten
|
30
|
-
result_unflatten = if
|
47
|
+
result_unflatten = if !::RANGES_JRUBY_BUG
|
31
48
|
map { |x| x.v }
|
32
49
|
else
|
33
50
|
self.v
|
@@ -44,11 +61,11 @@ module RobustExcelOle
|
|
44
61
|
|
45
62
|
def v
|
46
63
|
begin
|
47
|
-
if
|
64
|
+
if !::RANGES_JRUBY_BUG
|
48
65
|
self.Value
|
49
66
|
else
|
50
67
|
address_r1c1 = self.AddressLocal(true,true,XlR1C1)
|
51
|
-
row, col =
|
68
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
52
69
|
values = []
|
53
70
|
row.each do |r|
|
54
71
|
values_col = []
|
@@ -65,11 +82,11 @@ module RobustExcelOle
|
|
65
82
|
|
66
83
|
def v=(value)
|
67
84
|
begin
|
68
|
-
if
|
85
|
+
if !::RANGES_JRUBY_BUG
|
69
86
|
ole_range.Value = value
|
70
87
|
else
|
71
88
|
address_r1c1 = ole_range.AddressLocal(true,true,XlR1C1)
|
72
|
-
row, col =
|
89
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
73
90
|
row.each_with_index do |r,i|
|
74
91
|
col.each_with_index do |c,j|
|
75
92
|
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value)
|
@@ -82,10 +99,8 @@ module RobustExcelOle
|
|
82
99
|
end
|
83
100
|
end
|
84
101
|
|
85
|
-
|
86
|
-
|
87
|
-
@cells[index + 1] = RobustExcelOle::Cell.new(@ole_range.Cells.Item(index + 1))
|
88
|
-
end
|
102
|
+
alias_method :value, :v
|
103
|
+
alias_method :value=, :v=
|
89
104
|
|
90
105
|
# copies a range
|
91
106
|
# @params [Address or Address-Array] address or upper left position of the destination range
|
@@ -115,8 +130,7 @@ module RobustExcelOle
|
|
115
130
|
{ }
|
116
131
|
end
|
117
132
|
end
|
118
|
-
rows, columns =
|
119
|
-
#dest_sheet = @worksheet if dest_sheet == :__not_provided
|
133
|
+
rows, columns = address_tool.as_integer_ranges(dest_address)
|
120
134
|
dest_address_is_position = (rows.min == rows.max && columns.min == columns.max)
|
121
135
|
dest_range_address = if (not dest_address_is_position)
|
122
136
|
[rows.min..rows.max,columns.min..columns.max]
|
@@ -168,7 +182,7 @@ module RobustExcelOle
|
|
168
182
|
# @options [Worksheet] the destination worksheet
|
169
183
|
# @options [Hash] options: :transpose, :values_only
|
170
184
|
def copy_special(dest_address, dest_sheet = :__not_provided, options = { })
|
171
|
-
rows, columns =
|
185
|
+
rows, columns = address_tool.as_integer_ranges(dest_address)
|
172
186
|
dest_sheet = @worksheet if dest_sheet == :__not_provided
|
173
187
|
dest_address_is_position = (rows.min == rows.max && columns.min == columns.max)
|
174
188
|
dest_range_address = if (not dest_address_is_position)
|
@@ -220,6 +234,11 @@ module RobustExcelOle
|
|
220
234
|
self.Address == other_range.Address
|
221
235
|
end
|
222
236
|
|
237
|
+
# @private
|
238
|
+
def excel
|
239
|
+
@worksheet.workbook.excel
|
240
|
+
end
|
241
|
+
|
223
242
|
# @private
|
224
243
|
def self.worksheet_class
|
225
244
|
@worksheet_class ||= begin
|
@@ -237,10 +256,9 @@ module RobustExcelOle
|
|
237
256
|
|
238
257
|
private
|
239
258
|
|
240
|
-
# @private
|
241
259
|
def method_missing(name, *args)
|
242
260
|
if name.to_s[0,1] =~ /[A-Z]/
|
243
|
-
if
|
261
|
+
if ::ERRORMESSAGE_JRUBY_BUG
|
244
262
|
begin
|
245
263
|
@ole_range.send(name, *args)
|
246
264
|
rescue Java::OrgRacobCom::ComFailException
|
@@ -258,4 +276,9 @@ module RobustExcelOle
|
|
258
276
|
end
|
259
277
|
end
|
260
278
|
end
|
279
|
+
|
280
|
+
# @private
|
281
|
+
class RangeNotCopied < MiscREOError
|
282
|
+
end
|
283
|
+
|
261
284
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module RobustExcelOle
|
4
4
|
|
5
|
-
class RangeOwners <
|
5
|
+
class RangeOwners < VbaObjects
|
6
6
|
|
7
7
|
# returns the contents of a range with given name
|
8
8
|
# if the name could not be found or the value could not be determined,
|
@@ -22,12 +22,13 @@ module RobustExcelOle
|
|
22
22
|
raise
|
23
23
|
end
|
24
24
|
ole_range = name_obj.RefersToRange
|
25
|
+
worksheet = self if self.is_a?(Worksheet)
|
25
26
|
value = begin
|
26
27
|
#name_obj.RefersToRange.Value
|
27
|
-
if
|
28
|
+
if !::RANGES_JRUBY_BUG
|
28
29
|
ole_range.Value
|
29
30
|
else
|
30
|
-
values = RobustExcelOle::Range.new(ole_range).v
|
31
|
+
values = RobustExcelOle::Range.new(ole_range, worksheet).v
|
31
32
|
(values.size==1 && values.first.size==1) ? values.first.first : values
|
32
33
|
end
|
33
34
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
@@ -39,10 +40,10 @@ module RobustExcelOle
|
|
39
40
|
#sheet.Evaluate(name_obj.Name).Value
|
40
41
|
# does it result in a range?
|
41
42
|
ole_range = sheet.Evaluate(name_obj.Name)
|
42
|
-
if
|
43
|
+
if !::RANGES_JRUBY_BUG
|
43
44
|
ole_range.Value
|
44
45
|
else
|
45
|
-
values = RobustExcelOle::Range.new(ole_range).v
|
46
|
+
values = RobustExcelOle::Range.new(ole_range, worksheet).v
|
46
47
|
(values.size==1 && values.first.size==1) ? values.first.first : values
|
47
48
|
end
|
48
49
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
@@ -61,7 +62,8 @@ module RobustExcelOle
|
|
61
62
|
# sets the contents of a range
|
62
63
|
# @param [String] name the name of a range
|
63
64
|
# @param [Variant] value the contents of the range
|
64
|
-
|
65
|
+
# @option opts [Symbol] :color the color of the cell when set
|
66
|
+
def set_namevalue_glob(name, value, opts = { })
|
65
67
|
begin
|
66
68
|
name_obj = begin
|
67
69
|
name_object(name)
|
@@ -69,13 +71,12 @@ module RobustExcelOle
|
|
69
71
|
raise
|
70
72
|
end
|
71
73
|
ole_range = name_object(name).RefersToRange
|
72
|
-
|
73
|
-
|
74
|
-
if !JRUBY_BUG_RANGES
|
74
|
+
ole_range.Interior.ColorIndex = opts[:color] unless opts[:color].nil?
|
75
|
+
if !::RANGES_JRUBY_BUG
|
75
76
|
ole_range.Value = value
|
76
77
|
else
|
77
78
|
address_r1c1 = ole_range.AddressLocal(true,true,XlR1C1)
|
78
|
-
row, col =
|
79
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
79
80
|
row.each_with_index do |r,i|
|
80
81
|
col.each_with_index do |c,j|
|
81
82
|
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value )
|
@@ -105,11 +106,12 @@ module RobustExcelOle
|
|
105
106
|
raise NameNotFound, "name #{name.inspect} not in #{self.inspect}"
|
106
107
|
end
|
107
108
|
begin
|
109
|
+
worksheet = self if self.is_a?(Worksheet)
|
108
110
|
#value = ole_range.Value
|
109
|
-
value = if
|
111
|
+
value = if !::RANGES_JRUBY_BUG
|
110
112
|
ole_range.Value
|
111
113
|
else
|
112
|
-
values = RobustExcelOle::Range.new(ole_range).v
|
114
|
+
values = RobustExcelOle::Range.new(ole_range, worksheet).v
|
113
115
|
(values.size==1 && values.first.size==1) ? values.first.first : values
|
114
116
|
end
|
115
117
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
@@ -127,21 +129,21 @@ module RobustExcelOle
|
|
127
129
|
# assigns a value to a range given a locally defined name
|
128
130
|
# @param [String] name the name of a range
|
129
131
|
# @param [Variant] value the assigned value
|
130
|
-
|
132
|
+
# @option opts [Symbol] :color the color of the cell when set
|
133
|
+
def set_namevalue(name, value, opts = { })
|
131
134
|
begin
|
132
|
-
return set_namevalue_glob(name, value, opts) if self.is_a?(Workbook)
|
135
|
+
return set_namevalue_glob(name, value, opts) if self.is_a?(Workbook)
|
133
136
|
ole_range = self.Range(name)
|
134
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
137
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException, VBAMethodMissingError
|
135
138
|
raise NameNotFound, "name #{name.inspect} not in #{self.inspect}"
|
136
139
|
end
|
137
140
|
begin
|
138
|
-
|
139
|
-
|
140
|
-
if !JRUBY_BUG_RANGES
|
141
|
+
ole_range.Interior.ColorIndex = opts[:color] unless opts[:color].nil?
|
142
|
+
if !::RANGES_JRUBY_BUG
|
141
143
|
ole_range.Value = value
|
142
144
|
else
|
143
145
|
address_r1c1 = ole_range.AddressLocal(true,true,XlR1C1)
|
144
|
-
row, col =
|
146
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
145
147
|
row.each_with_index do |r,i|
|
146
148
|
col.each_with_index do |c,j|
|
147
149
|
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value)
|
@@ -180,10 +182,11 @@ module RobustExcelOle
|
|
180
182
|
# @return [Range] a range
|
181
183
|
def range(name_or_address, address2 = :__not_provided)
|
182
184
|
begin
|
185
|
+
worksheet = self if self.is_a?(Worksheet)
|
183
186
|
if address2 == :__not_provided
|
184
187
|
range = if name_or_address.is_a?(String)
|
185
188
|
begin
|
186
|
-
RobustExcelOle::Range.new(name_object(name_or_address).RefersToRange)
|
189
|
+
RobustExcelOle::Range.new(name_object(name_or_address).RefersToRange, worksheet)
|
187
190
|
rescue NameNotFound
|
188
191
|
nil
|
189
192
|
end
|
@@ -192,8 +195,8 @@ module RobustExcelOle
|
|
192
195
|
if self.is_a?(Worksheet) && (range.nil? || (address2 != :__not_provided))
|
193
196
|
address = name_or_address
|
194
197
|
address = [name_or_address,address2] unless address2 == :__not_provided
|
195
|
-
self.Names.Add('__dummy001',nil,true,nil,nil,nil,nil,nil,nil,'=' +
|
196
|
-
range = RobustExcelOle::Range.new(name_object('__dummy001').RefersToRange)
|
198
|
+
self.Names.Add('__dummy001',nil,true,nil,nil,nil,nil,nil,nil,'=' + address_tool.as_r1c1(address))
|
199
|
+
range = RobustExcelOle::Range.new(name_object('__dummy001').RefersToRange, worksheet)
|
197
200
|
self.Names.Item('__dummy001').Delete
|
198
201
|
workbook = self.is_a?(Workbook) ? self : self.workbook
|
199
202
|
workbook.save
|
@@ -216,7 +219,7 @@ module RobustExcelOle
|
|
216
219
|
def add_name(name, addr, addr_deprecated = :__not_provided)
|
217
220
|
addr = [addr,addr_deprecated] unless addr_deprecated == :__not_provided
|
218
221
|
begin
|
219
|
-
self.Names.Add(name, nil, true, nil, nil, nil, nil, nil, nil, '=' +
|
222
|
+
self.Names.Add(name, nil, true, nil, nil, nil, nil, nil, nil, '=' + address_tool.as_r1c1(addr))
|
220
223
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
221
224
|
raise RangeNotEvaluatable, "cannot add name #{name.inspect} to range #{addr.inspect}"
|
222
225
|
end
|
@@ -257,13 +260,13 @@ module RobustExcelOle
|
|
257
260
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
258
261
|
raise UnexpectedREOError, "name error in #{File.basename(self.stored_filename).inspect}"
|
259
262
|
end
|
260
|
-
end
|
263
|
+
end
|
261
264
|
|
262
265
|
private
|
263
266
|
|
264
267
|
def name_object(name)
|
265
268
|
self.Names.Item(name)
|
266
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
269
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException, VBAMethodMissingError
|
267
270
|
begin
|
268
271
|
self.Parent.Names.Item(name)
|
269
272
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
@@ -273,4 +276,16 @@ module RobustExcelOle
|
|
273
276
|
|
274
277
|
end
|
275
278
|
|
279
|
+
# @private
|
280
|
+
class NameNotFound < NamesREOError
|
281
|
+
end
|
282
|
+
|
283
|
+
# @private
|
284
|
+
class NameAlreadyExists < NamesREOError
|
285
|
+
end
|
286
|
+
|
287
|
+
# @private
|
288
|
+
class RangeNotCreated < MiscREOError
|
289
|
+
end
|
290
|
+
|
276
291
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module RobustExcelOle
|
4
|
+
|
5
|
+
class VbaObjects < Base
|
6
|
+
|
7
|
+
def to_reo
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
# @private
|
12
|
+
def address_tool
|
13
|
+
excel.address_tool
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# @private
|
19
|
+
class RangeNotEvaluatable < MiscREOError
|
20
|
+
end
|
21
|
+
|
22
|
+
# @private
|
23
|
+
class OptionInvalid < MiscREOError
|
24
|
+
end
|
25
|
+
|
26
|
+
# @private
|
27
|
+
class ObjectNotAlive < MiscREOError
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -11,35 +11,38 @@ module RobustExcelOle
|
|
11
11
|
|
12
12
|
class Workbook < RangeOwners
|
13
13
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
attr_reader :
|
14
|
+
#include General
|
15
|
+
|
16
|
+
attr_reader :ole_workbook
|
17
|
+
attr_reader :excel
|
18
|
+
attr_reader :stored_filename
|
19
19
|
|
20
20
|
alias ole_object ole_workbook
|
21
21
|
|
22
|
-
|
23
|
-
:default => {:excel => :current},
|
22
|
+
CORE_DEFAULT_OPEN_OPTS = {
|
23
|
+
:default => {:excel => :current},
|
24
24
|
:force => {},
|
25
|
-
:update_links => :never
|
25
|
+
:update_links => :never
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
DEFAULT_OPEN_OPTS = {
|
26
29
|
:if_unsaved => :raise,
|
27
30
|
:if_obstructed => :raise,
|
28
31
|
:if_absent => :raise,
|
29
|
-
:if_exists => :raise
|
30
|
-
|
31
|
-
}.freeze
|
32
|
-
|
33
|
-
CORE_DEFAULT_OPEN_OPTS = {
|
34
|
-
:default => {:excel => :current}, :force => {}, :update_links => :never
|
35
|
-
}.freeze
|
32
|
+
:if_exists => :raise
|
33
|
+
}.merge(CORE_DEFAULT_OPEN_OPTS).freeze
|
36
34
|
|
37
|
-
ABBREVIATIONS = [
|
38
|
-
|
35
|
+
ABBREVIATIONS = [
|
36
|
+
[:default,:d],
|
37
|
+
[:force, :f],
|
38
|
+
[:excel, :e],
|
39
|
+
[:visible, :v],
|
40
|
+
[:if_obstructed, :if_blocked]
|
41
|
+
].freeze
|
39
42
|
|
40
43
|
|
41
44
|
# opens a workbook.
|
42
|
-
# @param [String]
|
45
|
+
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
43
46
|
# @param [Hash] opts the options
|
44
47
|
# @option opts [Hash] :default or :d
|
45
48
|
# @option opts [Hash] :force or :f
|
@@ -81,49 +84,59 @@ module RobustExcelOle
|
|
81
84
|
# :visible true -> makes the workbook visible
|
82
85
|
# :check_compatibility true -> check compatibility when saving
|
83
86
|
# :update_links true -> user is being asked how to update links, false -> links are never updated
|
84
|
-
# @return [Workbook] a representation of a workbook
|
85
|
-
def self.new(file_or_workbook, opts = { }
|
86
|
-
|
87
|
-
|
87
|
+
# @return [Workbook] a representation of a workbook
|
88
|
+
def self.new(file_or_workbook, opts = { })
|
89
|
+
process_options(opts)
|
90
|
+
case file_or_workbook
|
91
|
+
when NilClass
|
92
|
+
raise FileNameNotGiven, 'filename is nil'
|
93
|
+
when WIN32OLE
|
88
94
|
file = file_or_workbook.Fullname.tr('\\','/')
|
89
|
-
|
95
|
+
when Workbook
|
96
|
+
file = file_or_workbook.Fullname.tr('\\','/')
|
97
|
+
when String
|
90
98
|
file = file_or_workbook
|
91
|
-
raise
|
92
|
-
|
99
|
+
raise FileNotFound, "file #{General.absolute_path(file).inspect} is a directory" if File.directory?(file)
|
100
|
+
else
|
101
|
+
raise TypeREOError, 'given object is neither a filename, a Win32ole, nor a Workbook object'
|
93
102
|
end
|
94
103
|
# try to fetch the workbook from the bookstore
|
104
|
+
set_was_open opts, file_or_workbook.is_a?(WIN32OLE)
|
95
105
|
book = nil
|
96
|
-
if
|
106
|
+
if opts[:force][:excel] != :new
|
97
107
|
# if readonly is true, then prefer a book that is given in force_excel if this option is set
|
98
|
-
forced_excel =
|
99
|
-
(
|
100
|
-
(excel_class.new(:reuse => true) if
|
108
|
+
forced_excel = begin
|
109
|
+
(opts[:force][:excel].nil? || opts[:force][:excel] == :current) ?
|
110
|
+
(excel_class.new(:reuse => true) if !::CONNECT_JRUBY_BUG) : opts[:force][:excel].to_reo.excel
|
111
|
+
rescue NoMethodError
|
112
|
+
raise TypeREOError, "provided Excel option value is neither an Excel object nor a valid option"
|
113
|
+
end
|
101
114
|
begin
|
102
115
|
book = if File.exists?(file)
|
103
|
-
bookstore.fetch(file, :prefer_writable => !(
|
104
|
-
:prefer_excel => (
|
116
|
+
bookstore.fetch(file, :prefer_writable => !(opts[:read_only]),
|
117
|
+
:prefer_excel => (opts[:read_only] ? forced_excel : nil))
|
105
118
|
end
|
106
119
|
rescue
|
107
|
-
|
120
|
+
raise
|
121
|
+
#trace "#{$!.message}"
|
108
122
|
end
|
109
|
-
if book
|
123
|
+
if book
|
124
|
+
set_was_open opts, book.alive?
|
110
125
|
# drop the fetched workbook if it shall be opened in another Excel instance
|
111
126
|
# or the workbook is an unsaved workbook that should not be accepted
|
112
|
-
if (
|
113
|
-
!(book.alive? && !book.saved && (
|
114
|
-
|
115
|
-
book.ensure_workbook(file,
|
116
|
-
book.
|
127
|
+
if (opts[:force][:excel].nil? || opts[:force][:excel] == :current || forced_excel == book.excel) &&
|
128
|
+
!(book.alive? && !book.saved && (opts[:if_unsaved] != :accept))
|
129
|
+
opts[:force][:excel] = book.excel if book.excel && book.excel.alive?
|
130
|
+
book.ensure_workbook(file,opts)
|
131
|
+
book.send :apply_options, file, opts
|
117
132
|
return book
|
118
133
|
end
|
119
134
|
end
|
120
135
|
end
|
121
|
-
super(file_or_workbook,
|
136
|
+
super(file_or_workbook, opts)
|
122
137
|
end
|
123
138
|
|
124
|
-
|
125
|
-
new(file_or_workbook, opts, &block)
|
126
|
-
end
|
139
|
+
singleton_class.send :alias_method, :open, :new
|
127
140
|
|
128
141
|
# creates a new Workbook object, if a file name is given
|
129
142
|
# Promotes the win32ole workbook to a Workbook object, if a win32ole-workbook is given
|
@@ -131,26 +144,23 @@ module RobustExcelOle
|
|
131
144
|
# @param [Hash] opts
|
132
145
|
# @option opts [Symbol] see above
|
133
146
|
# @return [Workbook] a workbook
|
134
|
-
def initialize(file_or_workbook,
|
147
|
+
def initialize(file_or_workbook, opts)
|
135
148
|
if file_or_workbook.is_a? WIN32OLE
|
136
149
|
@ole_workbook = file_or_workbook
|
137
|
-
ole_excel = begin
|
138
|
-
|
139
|
-
rescue
|
150
|
+
ole_excel = begin
|
151
|
+
@ole_workbook.Application
|
152
|
+
rescue WIN32OLERuntimeError
|
140
153
|
raise ExcelREOError, 'could not determine the Excel instance'
|
141
154
|
end
|
142
155
|
@excel = excel_class.new(ole_excel)
|
143
|
-
filename =
|
156
|
+
filename = @ole_workbook.Fullname.tr('\\','/')
|
144
157
|
else
|
145
158
|
filename = file_or_workbook
|
146
|
-
ensure_workbook(filename,
|
159
|
+
ensure_workbook(filename, opts)
|
147
160
|
end
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
r1c1_letters = @ole_workbook.Worksheets.Item(1).Cells.Item(1,1).Address(true,true,XlR1C1).gsub(/[0-9]/,'') #('ReferenceStyle' => XlR1C1).gsub(/[0-9]/,'')
|
152
|
-
address_class.new(r1c1_letters)
|
153
|
-
if block
|
161
|
+
apply_options(filename, opts)
|
162
|
+
store_myself
|
163
|
+
if block_given?
|
154
164
|
begin
|
155
165
|
yield self
|
156
166
|
ensure
|
@@ -161,52 +171,46 @@ module RobustExcelOle
|
|
161
171
|
|
162
172
|
private
|
163
173
|
|
164
|
-
|
165
|
-
|
166
|
-
translator = proc do |opts|
|
167
|
-
erg = {}
|
168
|
-
opts.each do |key,value|
|
169
|
-
new_key = key
|
170
|
-
ABBREVIATIONS.each { |long,short| new_key = long if key == short }
|
171
|
-
if value.is_a?(Hash)
|
172
|
-
erg[new_key] = {}
|
173
|
-
value.each do |k,v|
|
174
|
-
new_k = k
|
175
|
-
ABBREVIATIONS.each { |l,s| new_k = l if k == s }
|
176
|
-
erg[new_key][new_k] = v
|
177
|
-
end
|
178
|
-
else
|
179
|
-
erg[new_key] = value
|
180
|
-
end
|
181
|
-
end
|
182
|
-
erg[:default] ||= {}
|
183
|
-
erg[:force] ||= {}
|
184
|
-
force_list = [:visible, :excel]
|
185
|
-
erg.each { |key,value| erg[:force][key] = value if force_list.include?(key) }
|
186
|
-
erg[:default][:excel] = erg[:default_excel] unless erg[:default_excel].nil?
|
187
|
-
erg[:force][:excel] = erg[:force_excel] unless erg[:force_excel].nil?
|
188
|
-
erg[:default][:excel] = :current if erg[:default][:excel] == :reuse || erg[:default][:excel] == :active
|
189
|
-
erg[:force][:excel] = :current if erg[:force][:excel] == :reuse || erg[:force][:excel] == :active
|
190
|
-
erg
|
191
|
-
end
|
192
|
-
opts = translator.call(options)
|
193
|
-
default_open_opts = proc_opts[:use_defaults] ? DEFAULT_OPEN_OPTS : CORE_DEFAULT_OPEN_OPTS
|
194
|
-
default_opts = translator.call(default_open_opts)
|
195
|
-
opts = default_opts.merge(opts)
|
196
|
-
opts[:default] = default_opts[:default].merge(opts[:default]) unless opts[:default].nil?
|
197
|
-
opts[:force] = default_opts[:force].merge(opts[:force]) unless opts[:force].nil?
|
198
|
-
opts
|
174
|
+
def self.set_was_open(hash, value)
|
175
|
+
hash[:was_open] = value if hash.has_key?(:was_open)
|
199
176
|
end
|
200
177
|
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
178
|
+
def set_was_open(hash, value)
|
179
|
+
self.class.set_was_open(hash, value)
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.process_options(opts, proc_opts = {:use_defaults => true})
|
183
|
+
translate(opts)
|
184
|
+
default_opts = (proc_opts[:use_defaults] ? DEFAULT_OPEN_OPTS : CORE_DEFAULT_OPEN_OPTS).dup
|
185
|
+
translate(default_opts)
|
186
|
+
opts.merge!(default_opts) { |key, v1, v2| !v2.is_a?(Hash) ? v1 : v2.merge(v1 || {}) }
|
187
|
+
end
|
188
|
+
|
189
|
+
def self.translate(opts)
|
190
|
+
erg = {}
|
191
|
+
opts.each do |key,value|
|
192
|
+
new_key = key
|
193
|
+
ABBREVIATIONS.each { |long,short| new_key = long if key == short }
|
194
|
+
if value.is_a?(Hash)
|
195
|
+
erg[new_key] = {}
|
196
|
+
value.each do |k,v|
|
197
|
+
new_k = k
|
198
|
+
ABBREVIATIONS.each { |l,s| new_k = l if k == s }
|
199
|
+
erg[new_key][new_k] = v
|
200
|
+
end
|
201
|
+
else
|
202
|
+
erg[new_key] = value
|
203
|
+
end
|
209
204
|
end
|
205
|
+
opts.merge!(erg)
|
206
|
+
opts[:default] ||= {}
|
207
|
+
opts[:force] ||= {}
|
208
|
+
force_list = [:visible, :excel]
|
209
|
+
opts.each { |key,value| opts[:force][key] = value if force_list.include?(key) }
|
210
|
+
opts[:default][:excel] = opts[:default_excel] unless opts[:default_excel].nil?
|
211
|
+
opts[:force][:excel] = opts[:force_excel] unless opts[:force_excel].nil?
|
212
|
+
opts[:default][:excel] = :current if opts[:default][:excel] == :reuse || opts[:default][:excel] == :active
|
213
|
+
opts[:force][:excel] = :current if opts[:force][:excel] == :reuse || opts[:force][:excel] == :active
|
210
214
|
end
|
211
215
|
|
212
216
|
public
|
@@ -215,102 +219,91 @@ module RobustExcelOle
|
|
215
219
|
# ensures an excel but not for jruby if current Excel shall be used
|
216
220
|
def ensure_excel(options)
|
217
221
|
return if @excel && @excel.alive?
|
218
|
-
excel_option = options[:force][:excel]
|
222
|
+
excel_option = options[:force][:excel] || options[:default][:excel] || :current
|
219
223
|
@excel = if excel_option == :new
|
220
224
|
excel_class.new(:reuse => false)
|
221
|
-
elsif excel_option
|
225
|
+
elsif excel_option == :current
|
222
226
|
excel_class.new(:reuse => true)
|
227
|
+
elsif excel_option.respond_to?(:to_reo)
|
228
|
+
excel_option.to_reo.excel
|
223
229
|
else
|
224
|
-
|
230
|
+
raise TypeREOError, "provided Excel option value is neither an Excel object nor a valid option"
|
225
231
|
end
|
226
|
-
raise ExcelREOError, "
|
232
|
+
raise ExcelREOError, "Excel is not alive" unless @excel && @excel.alive?
|
227
233
|
end
|
228
234
|
|
229
|
-
|
230
|
-
#
|
235
|
+
|
236
|
+
# @private
|
231
237
|
def ensure_workbook(filename, options)
|
238
|
+
set_was_open options, true
|
239
|
+
return if (@ole_workbook && alive? && (options[:read_only].nil? || @ole_workbook.ReadOnly == options[:read_only]))
|
240
|
+
set_was_open options, false
|
232
241
|
if options[:if_unsaved]==:accept &&
|
233
242
|
((options[:read_only]==true && self.ReadOnly==false) || (options[:read_only]==false && self.ReadOnly==true))
|
234
243
|
raise OptionInvalid, ":if_unsaved:accept and change of read-only mode is not possible"
|
235
244
|
end
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
manage_unsaved_workbook(filename,options) unless @ole_workbook.Saved
|
253
|
-
else
|
254
|
-
ensure_excel(options)
|
255
|
-
workbooks = @excel.Workbooks
|
256
|
-
@ole_workbook = workbooks.Item(File.basename(filename)) rescue nil if @ole_workbook.nil?
|
257
|
-
if @ole_workbook
|
258
|
-
manage_blocking_or_unsaved_workbook(filename,options)
|
259
|
-
else
|
260
|
-
if excel_option.nil? || excel_option == :current &&
|
261
|
-
(!JRUBY_BUG_CONNECT || filename[0] != '/')
|
262
|
-
connect(filename,options)
|
263
|
-
else
|
264
|
-
open_or_create_workbook(filename,options)
|
265
|
-
end
|
266
|
-
end
|
245
|
+
filename = @stored_filename ? @stored_filename : filename
|
246
|
+
manage_nonexisting_file(filename,options)
|
247
|
+
excel_option = options[:force][:excel].nil? ? options[:default][:excel] : options[:force][:excel]
|
248
|
+
ensure_excel(options)
|
249
|
+
workbooks = @excel.Workbooks
|
250
|
+
@ole_workbook = workbooks.Item(File.basename(filename)) rescue nil if @ole_workbook.nil?
|
251
|
+
if @ole_workbook && alive?
|
252
|
+
set_was_open options, true
|
253
|
+
manage_blocking_or_unsaved_workbook(filename,options)
|
254
|
+
open_or_create_workbook(filename,options) if @ole_workbook.ReadOnly != options[:read_only]
|
255
|
+
else
|
256
|
+
if (excel_option.nil? || excel_option == :current) &&
|
257
|
+
!(::CONNECT_JRUBY_BUG && filename[0] == '/')
|
258
|
+
connect(filename,options)
|
259
|
+
else
|
260
|
+
open_or_create_workbook(filename,options)
|
267
261
|
end
|
268
|
-
end
|
262
|
+
end
|
269
263
|
end
|
270
264
|
|
271
|
-
|
272
|
-
|
265
|
+
private
|
266
|
+
|
267
|
+
# applies options to workbook named with filename
|
268
|
+
def apply_options(filename, options)
|
269
|
+
# changing read-only mode
|
270
|
+
#ensure_workbook(filename, options) if options[:read_only] && options[:read_only] != @ole_workbook.ReadOnly
|
273
271
|
if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
274
|
-
|
275
|
-
@ole_workbook = nil
|
276
|
-
open_or_create_workbook(filename, options)
|
272
|
+
ensure_workbook(filename, options)
|
277
273
|
end
|
278
274
|
retain_saved do
|
279
275
|
self.visible = options[:force][:visible].nil? ? @excel.Visible : options[:force][:visible]
|
280
276
|
@excel.calculation = options[:calculation] unless options[:calculation].nil?
|
281
277
|
@ole_workbook.CheckCompatibility = options[:check_compatibility] unless options[:check_compatibility].nil?
|
282
|
-
end
|
278
|
+
end
|
283
279
|
end
|
284
280
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
# connects to an unknown workbook and returns true, if it exists
|
289
|
-
def connect(filename,options)
|
290
|
-
abs_filename = General.absolute_path(filename)
|
281
|
+
# connects to an unknown workbook
|
282
|
+
def connect(filename, options)
|
283
|
+
workbooks_number = excel_class.excels_number==0 ? 0 : excel_class.current.Workbooks.Count
|
291
284
|
@ole_workbook = begin
|
292
|
-
WIN32OLE.connect(
|
285
|
+
WIN32OLE.connect(General.absolute_path(filename))
|
293
286
|
rescue
|
294
287
|
if $!.message =~ /moniker/
|
295
|
-
raise WorkbookConnectingBlockingError
|
296
|
-
else
|
297
|
-
raise WorkbookConnectingUnknownError
|
288
|
+
raise WorkbookConnectingBlockingError, "some workbook is blocking when connecting"
|
289
|
+
else
|
290
|
+
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook"
|
298
291
|
end
|
299
292
|
end
|
300
293
|
ole_excel = begin
|
301
294
|
@ole_workbook.Application
|
302
295
|
rescue
|
303
296
|
if $!.message =~ /dispid/
|
304
|
-
raise WorkbookConnectingUnsavedError
|
305
|
-
else
|
306
|
-
raise WorkbookConnectingUnknownError
|
297
|
+
raise WorkbookConnectingUnsavedError, "workbook is unsaved when connecting"
|
298
|
+
else
|
299
|
+
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook"
|
307
300
|
end
|
308
301
|
end
|
302
|
+
set_was_open options, (ole_excel.Workbooks.Count == workbooks_number)
|
309
303
|
@excel = excel_class.new(ole_excel)
|
310
304
|
end
|
311
305
|
|
312
|
-
|
313
|
-
def manage_nonexisting_file(filename,options)
|
306
|
+
def manage_nonexisting_file(filename, options)
|
314
307
|
return if File.exist?(filename)
|
315
308
|
abs_filename = General.absolute_path(filename)
|
316
309
|
if options[:if_absent] == :create
|
@@ -328,11 +321,12 @@ module RobustExcelOle
|
|
328
321
|
end
|
329
322
|
end
|
330
323
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
324
|
+
def manage_blocking_or_unsaved_workbook(filename, options)
|
325
|
+
filename = General.absolute_path(filename)
|
326
|
+
filename = General.canonize(filename)
|
327
|
+
previous_file = General.canonize(@ole_workbook.Fullname)
|
328
|
+
obstructed_by_other_book = (File.basename(filename) == File.basename(previous_file)) &&
|
329
|
+
(File.dirname(filename) != File.dirname(previous_file))
|
336
330
|
if obstructed_by_other_book
|
337
331
|
# workbook is being obstructed by a workbook with same name and different path
|
338
332
|
manage_blocking_workbook(filename,options)
|
@@ -344,8 +338,7 @@ module RobustExcelOle
|
|
344
338
|
end
|
345
339
|
end
|
346
340
|
|
347
|
-
|
348
|
-
def manage_blocking_workbook(filename,options)
|
341
|
+
def manage_blocking_workbook(filename, options)
|
349
342
|
case options[:if_obstructed]
|
350
343
|
when :raise
|
351
344
|
raise WorkbookBlocked, "can't open workbook #{filename},
|
@@ -359,7 +352,8 @@ module RobustExcelOle
|
|
359
352
|
manage_saving_workbook(filename, options)
|
360
353
|
when :close_if_saved
|
361
354
|
if !@ole_workbook.Saved
|
362
|
-
raise WorkbookBlocked, "workbook with the same name in a different path is unsaved: #{@ole_workbook.Fullname.tr('\\','/')}"
|
355
|
+
raise WorkbookBlocked, "workbook with the same name in a different path is unsaved: #{@ole_workbook.Fullname.tr('\\','/')}" +
|
356
|
+
"\nHint: Use the option :if_blocked => :save to save the workbook"
|
363
357
|
else
|
364
358
|
manage_forgetting_workbook(filename, options)
|
365
359
|
end
|
@@ -371,15 +365,14 @@ module RobustExcelOle
|
|
371
365
|
end
|
372
366
|
end
|
373
367
|
|
374
|
-
|
375
|
-
def manage_unsaved_workbook(filename,options)
|
368
|
+
def manage_unsaved_workbook(filename, options)
|
376
369
|
case options[:if_unsaved]
|
377
370
|
when :raise
|
378
371
|
raise WorkbookNotSaved, "workbook is already open but not saved: #{File.basename(filename).inspect}" +
|
379
372
|
"\nHint: Save the workbook or open the workbook using option :if_unsaved with values :forget and :accept to
|
380
373
|
close the unsaved workbook and reopen it, or to let the unsaved workbook open, respectively"
|
381
374
|
when :forget
|
382
|
-
manage_forgetting_workbook(filename,options)
|
375
|
+
manage_forgetting_workbook(filename, options)
|
383
376
|
when :accept
|
384
377
|
# do nothing
|
385
378
|
when :save
|
@@ -394,29 +387,26 @@ module RobustExcelOle
|
|
394
387
|
end
|
395
388
|
end
|
396
389
|
|
397
|
-
# @private
|
398
390
|
def manage_forgetting_workbook(filename, options)
|
399
391
|
@excel.with_displayalerts(false) { @ole_workbook.Close }
|
400
392
|
@ole_workbook = nil
|
401
393
|
open_or_create_workbook(filename, options)
|
402
394
|
end
|
403
395
|
|
404
|
-
# @private
|
405
396
|
def manage_saving_workbook(filename, options)
|
406
397
|
save unless @ole_workbook.Saved
|
407
398
|
manage_forgetting_workbook(filename, options)
|
408
399
|
end
|
409
400
|
|
410
|
-
# @private
|
411
401
|
def manage_new_excel(filename, options)
|
412
402
|
@excel = excel_class.new(:reuse => false)
|
413
403
|
@ole_workbook = nil
|
414
404
|
open_or_create_workbook(filename, options)
|
415
405
|
end
|
416
406
|
|
417
|
-
|
418
|
-
|
419
|
-
|
407
|
+
def open_or_create_workbook(filename, options)
|
408
|
+
return if @ole_workbook && options[:if_unsaved] != :alert && options[:if_unsaved] != :excel &&
|
409
|
+
(options[:read_only].nil? || options[:read_only]==@ole_workbook.ReadOnly )
|
420
410
|
begin
|
421
411
|
abs_filename = General.absolute_path(filename)
|
422
412
|
begin
|
@@ -431,7 +421,7 @@ module RobustExcelOle
|
|
431
421
|
updatelinks_vba(options[:update_links]),
|
432
422
|
options[:read_only] )
|
433
423
|
end
|
434
|
-
rescue WIN32OLERuntimeError => msg
|
424
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
435
425
|
# for Excel2007: for option :if_unsaved => :alert and user cancels: this error appears?
|
436
426
|
# if yes: distinguish these events
|
437
427
|
raise UnexpectedREOError, "cannot open workbook: #{msg.message} #{msg.backtrace}"
|
@@ -440,29 +430,27 @@ module RobustExcelOle
|
|
440
430
|
# workaround for bug in Excel 2010: workbook.Open does not always return the workbook when given file name
|
441
431
|
begin
|
442
432
|
@ole_workbook = workbooks.Item(File.basename(filename))
|
443
|
-
rescue WIN32OLERuntimeError => msg
|
433
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
444
434
|
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message}"
|
445
435
|
end
|
446
|
-
rescue WIN32OLERuntimeError => msg
|
436
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
447
437
|
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message} #{msg.backtrace}"
|
448
438
|
end
|
449
439
|
end
|
450
440
|
end
|
451
441
|
|
452
|
-
# @private
|
453
442
|
# translating the option UpdateLinks from REO to VBA
|
454
443
|
# setting UpdateLinks works only if calculation mode is automatic,
|
455
444
|
# parameter 'UpdateLinks' has no effect
|
456
445
|
def updatelinks_vba(updatelinks_reo)
|
457
446
|
case updatelinks_reo
|
458
|
-
when :alert
|
459
|
-
when :never
|
447
|
+
when :alert then RobustExcelOle::XlUpdateLinksUserSetting
|
448
|
+
when :never then RobustExcelOle::XlUpdateLinksNever
|
460
449
|
when :always then RobustExcelOle::XlUpdateLinksAlways
|
461
|
-
else
|
450
|
+
else RobustExcelOle::XlUpdateLinksNever
|
462
451
|
end
|
463
452
|
end
|
464
453
|
|
465
|
-
# @private
|
466
454
|
# workaround for linked workbooks for Excel 2007:
|
467
455
|
# opening and closing a dummy workbook if Excel has no workbooks.
|
468
456
|
# delay: with visible: 0.2 sec, without visible almost none
|
@@ -472,7 +460,7 @@ module RobustExcelOle
|
|
472
460
|
workaround_condition = @excel.Version.split('.').first.to_i == 12 && workbooks.Count == 0
|
473
461
|
if workaround_condition
|
474
462
|
workbooks.Add
|
475
|
-
@excel.calculation = options[:calculation].nil? ? @excel.calculation : options[:calculation]
|
463
|
+
@excel.calculation = options[:calculation].nil? ? @excel.properties[:calculation] : options[:calculation]
|
476
464
|
end
|
477
465
|
begin
|
478
466
|
# @excel.with_displayalerts(update_links_opt == :alert ? true : @excel.displayalerts) do
|
@@ -526,13 +514,10 @@ module RobustExcelOle
|
|
526
514
|
else
|
527
515
|
close_workbook
|
528
516
|
end
|
529
|
-
# trace "close: canceled by user" if alive? &&
|
530
|
-
# (opts[:if_unsaved] == :alert || opts[:if_unsaved] == :excel) && (not @ole_workbook.Saved)
|
531
517
|
end
|
532
518
|
|
533
519
|
private
|
534
520
|
|
535
|
-
# @private
|
536
521
|
def close_workbook
|
537
522
|
@ole_workbook.Close if alive?
|
538
523
|
@ole_workbook = nil unless alive?
|
@@ -550,84 +535,81 @@ module RobustExcelOle
|
|
550
535
|
end
|
551
536
|
end
|
552
537
|
|
553
|
-
def
|
554
|
-
|
555
|
-
opts = args.last.is_a?(Hash) ? args.pop : {}
|
556
|
-
opts = {:writable => false}.merge(opts)
|
557
|
-
args.push opts
|
558
|
-
unobtrusively(*args, &block)
|
538
|
+
def for_reading(opts = { }, &block)
|
539
|
+
unobtrusively({:writable => false}.merge(opts), &block)
|
559
540
|
end
|
560
541
|
|
561
|
-
def
|
562
|
-
|
563
|
-
opts = args.last.is_a?(Hash) ? args.pop : {}
|
564
|
-
opts = {:writable => true}.merge(opts)
|
565
|
-
args.push opts
|
566
|
-
unobtrusively(*args, &block)
|
542
|
+
def for_modifying(opts = { }, &block)
|
543
|
+
unobtrusively({:writable => true}.merge(opts), &block)
|
567
544
|
end
|
568
545
|
|
546
|
+
def self.for_reading(arg, opts = { }, &block)
|
547
|
+
unobtrusively(arg, {:writable => false}.merge(opts), &block)
|
548
|
+
end
|
549
|
+
|
550
|
+
def self.for_modifying(arg, opts = { }, &block)
|
551
|
+
unobtrusively(arg, {:writable => true}.merge(opts), &block)
|
552
|
+
end
|
569
553
|
|
570
554
|
# allows to read or modify a workbook such that its state remains unchanged
|
571
555
|
# state comprises: open, saved, writable, visible, calculation mode, check compatibility
|
572
|
-
# @param [String]
|
556
|
+
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
573
557
|
# @param [Hash] opts the options
|
574
558
|
# @option opts [Variant] :if_closed :current (default), :new or an Excel instance
|
575
|
-
# @option opts [Boolean] :read_only true/false, open the workbook in read-only/read-write modus (save changes)
|
576
|
-
# @option opts [Boolean] :writable true/false changes of the workbook shall be saved/not saved
|
577
|
-
# @option opts [Boolean] :
|
578
|
-
# write permissions shall be opened :current (default), :new or an Excel instance
|
579
|
-
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening
|
559
|
+
# @option opts [Boolean] :read_only true/false (default), open the workbook in read-only/read-write modus (save changes)
|
560
|
+
# @option opts [Boolean] :writable true (default)/false changes of the workbook shall be saved/not saved
|
561
|
+
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening (default: false)
|
580
562
|
# @return [Workbook] a workbook
|
581
|
-
def self.unobtrusively(
|
582
|
-
|
583
|
-
opts
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
563
|
+
def self.unobtrusively(file_or_workbook, opts = { }, &block)
|
564
|
+
file = (file_or_workbook.is_a? WIN32OLE) ? file_or_workbook.Fullname.tr('\\','/') : file_or_workbook
|
565
|
+
unobtrusively_opening(file, opts, nil, &block)
|
566
|
+
end
|
567
|
+
|
568
|
+
def unobtrusively(opts = { }, &block)
|
569
|
+
file = @stored_filename
|
570
|
+
self.class.unobtrusively_opening(file, opts, alive?, &block)
|
571
|
+
end
|
572
|
+
|
573
|
+
private
|
574
|
+
|
575
|
+
def self.unobtrusively_opening(file, opts, book_is_alive, &block)
|
576
|
+
process_options(opts)
|
577
|
+
opts = {:if_closed => :current, :keep_open => false}.merge(opts)
|
578
|
+
raise OptionInvalid, 'contradicting options' if opts[:writable] && opts[:read_only]
|
579
|
+
if book_is_alive.nil?
|
580
|
+
prefer_writable = ((!(opts[:read_only]) || opts[:writable] == true) &&
|
581
|
+
!(opts[:read_only].nil? && opts[:writable] == false))
|
582
|
+
known_book = bookstore.fetch(file, :prefer_writable => prefer_writable)
|
583
|
+
end
|
584
|
+
excel_opts = if (book_is_alive==false || (book_is_alive.nil? && (known_book.nil? || !known_book.alive?)))
|
585
|
+
{:force => {:excel => opts[:if_closed]}}
|
586
|
+
else
|
587
|
+
{:force => {:excel => opts[:force][:excel]}, :default => {:excel => opts[:default][:excel]}}
|
603
588
|
end
|
604
|
-
|
589
|
+
open_opts = excel_opts.merge({:if_unsaved => :accept})
|
605
590
|
begin
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
else
|
615
|
-
opts = opts.merge({:force => {:excel => opts[:if_closed]}, :read_only => do_not_write})
|
616
|
-
open(file, opts)
|
617
|
-
end
|
591
|
+
open_opts[:was_open] = nil
|
592
|
+
book = open(file, open_opts)
|
593
|
+
was_visible = book.visible
|
594
|
+
was_writable = book.writable
|
595
|
+
was_saved = book.saved
|
596
|
+
was_check_compatibility = book.check_compatibility
|
597
|
+
was_calculation = book.excel.properties[:calculation]
|
598
|
+
book.send :apply_options, file, opts
|
618
599
|
yield book
|
619
600
|
ensure
|
620
601
|
if book && book.alive?
|
621
|
-
|
602
|
+
do_not_write = opts[:read_only] || opts[:writable]==false
|
603
|
+
book.save unless book.saved || do_not_write || !book.writable
|
604
|
+
if (opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable)
|
605
|
+
book.send :apply_options, file, opts.merge({:read_only => !was_writable,
|
606
|
+
:if_unsaved => (opts[:writable]==false ? :forget : :save)})
|
607
|
+
end
|
608
|
+
was_open = open_opts[:was_open]
|
622
609
|
if was_open
|
623
|
-
|
624
|
-
book.close
|
625
|
-
opts = opts.merge({:force => {:excel => opts[:rw_change_excel]}, :read_only => !was_writable})
|
626
|
-
book = open(file, opts)
|
627
|
-
end
|
628
|
-
book.excel.calculation = was_calculation
|
610
|
+
book.visible = was_visible
|
629
611
|
book.CheckCompatibility = was_check_compatibility
|
630
|
-
|
612
|
+
book.excel.calculation = was_calculation
|
631
613
|
end
|
632
614
|
book.Saved = (was_saved || !was_open)
|
633
615
|
book.close unless was_open || opts[:keep_open]
|
@@ -635,6 +617,8 @@ module RobustExcelOle
|
|
635
617
|
end
|
636
618
|
end
|
637
619
|
|
620
|
+
public
|
621
|
+
|
638
622
|
# reopens a closed workbook
|
639
623
|
# @options options
|
640
624
|
def reopen(options = { })
|
@@ -648,10 +632,6 @@ module RobustExcelOle
|
|
648
632
|
def save(opts = { }) # option opts is deprecated #
|
649
633
|
raise ObjectNotAlive, 'workbook is not alive' unless alive?
|
650
634
|
raise WorkbookReadOnly, 'Not opened for writing (opened with :read_only option)' if @ole_workbook.ReadOnly
|
651
|
-
# if you have open the workbook with :read_only => true,
|
652
|
-
# then you could close the workbook and open it again with option :read_only => false
|
653
|
-
# otherwise the workbook may already be open writable in an another Excel instance
|
654
|
-
# then you could use this workbook or close the workbook there
|
655
635
|
begin
|
656
636
|
@ole_workbook.Save
|
657
637
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
@@ -681,12 +661,12 @@ module RobustExcelOle
|
|
681
661
|
# :close_if_saved -> closes the blocking workbook, if it is saved,
|
682
662
|
# otherwise raises an exception
|
683
663
|
# @return [Workbook], the book itself, if successfully saved, raises an exception otherwise
|
684
|
-
def save_as(file,
|
664
|
+
def save_as(file, options = { })
|
685
665
|
raise FileNameNotGiven, 'filename is nil' if file.nil?
|
686
666
|
raise ObjectNotAlive, 'workbook is not alive' unless alive?
|
687
667
|
raise WorkbookReadOnly, 'Not opened for writing (opened with :read_only option)' if @ole_workbook.ReadOnly
|
688
668
|
raise(FileNotFound, "file #{General.absolute_path(file).inspect} is a directory") if File.directory?(file)
|
689
|
-
|
669
|
+
self.class.process_options(options)
|
690
670
|
if File.exist?(file)
|
691
671
|
case options[:if_exists]
|
692
672
|
when :overwrite
|
@@ -741,7 +721,6 @@ module RobustExcelOle
|
|
741
721
|
|
742
722
|
private
|
743
723
|
|
744
|
-
# @private
|
745
724
|
def save_as_workbook(file, options)
|
746
725
|
dirname, basename = File.split(file)
|
747
726
|
file_format =
|
@@ -751,7 +730,7 @@ module RobustExcelOle
|
|
751
730
|
when '.xlsm' then RobustExcelOle::XlOpenXMLWorkbookMacroEnabled
|
752
731
|
end
|
753
732
|
@ole_workbook.SaveAs(General.absolute_path(file), file_format)
|
754
|
-
|
733
|
+
store_myself
|
755
734
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
756
735
|
if msg.message =~ /SaveAs/ && msg.message =~ /Workbook/
|
757
736
|
# trace "save: canceled by user" if options[:if_exists] == :alert || options[:if_exists] == :excel
|
@@ -761,6 +740,11 @@ module RobustExcelOle
|
|
761
740
|
end
|
762
741
|
end
|
763
742
|
|
743
|
+
def store_myself
|
744
|
+
bookstore.store(self)
|
745
|
+
@stored_filename = filename
|
746
|
+
end
|
747
|
+
|
764
748
|
public
|
765
749
|
|
766
750
|
# closes a given file if it is open
|
@@ -799,12 +783,22 @@ module RobustExcelOle
|
|
799
783
|
raise NameNotFound, "could not return a sheet with name #{name.inspect}"
|
800
784
|
end
|
801
785
|
|
786
|
+
def worksheets_count
|
787
|
+
@ole_workbook.Worksheets.Count
|
788
|
+
end
|
789
|
+
|
802
790
|
def each
|
803
791
|
@ole_workbook.Worksheets.each do |sheet|
|
804
792
|
yield worksheet_class.new(sheet)
|
805
793
|
end
|
806
794
|
end
|
807
795
|
|
796
|
+
def worksheets
|
797
|
+
result = []
|
798
|
+
each { |worksheet| result << worksheet }
|
799
|
+
result
|
800
|
+
end
|
801
|
+
|
808
802
|
def each_with_index(offset = 0)
|
809
803
|
i = offset
|
810
804
|
@ole_workbook.Worksheets.each do |sheet|
|
@@ -829,36 +823,18 @@ module RobustExcelOle
|
|
829
823
|
new_sheet_name = opts.delete(:as)
|
830
824
|
last_sheet_local = last_sheet
|
831
825
|
after_or_before, base_sheet = opts.to_a.first || [:after, last_sheet_local]
|
826
|
+
base_sheet_ole = base_sheet.ole_worksheet
|
832
827
|
begin
|
833
|
-
if
|
834
|
-
|
835
|
-
sheet.Copy({ after_or_before.to_s => base_sheet.ole_worksheet })
|
836
|
-
else
|
837
|
-
@ole_workbook.Worksheets.Add({ after_or_before.to_s => base_sheet.ole_worksheet })
|
838
|
-
#@ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count).Activate
|
839
|
-
end
|
828
|
+
if !::COPYSHEETS_JRUBY_BUG
|
829
|
+
add_or_copy_sheet_simple(sheet, { after_or_before.to_s => base_sheet_ole })
|
840
830
|
else
|
841
831
|
if after_or_before == :before
|
842
|
-
|
843
|
-
sheet.Copy(base_sheet.ole_worksheet)
|
844
|
-
else
|
845
|
-
ole_workbook.Worksheets.Add(base_sheet.ole_worksheet)
|
846
|
-
end
|
832
|
+
add_or_copy_sheet_simple(sheet, base_sheet_ole)
|
847
833
|
else
|
848
|
-
#not_given = WIN32OLE_VARIANT.new(nil, WIN32OLE::VARIANT::VT_NULL)
|
849
|
-
#ole_workbook.Worksheets.Add(not_given,base_sheet.ole_worksheet)
|
850
834
|
if base_sheet.name != last_sheet_local.name
|
851
|
-
|
852
|
-
sheet.Copy(base_sheet.Next)
|
853
|
-
else
|
854
|
-
ole_workbook.Worksheets.Add(base_sheet.Next)
|
855
|
-
end
|
835
|
+
add_or_copy_sheet_simple(sheet, base_sheet.Next)
|
856
836
|
else
|
857
|
-
|
858
|
-
sheet.Copy(base_sheet.ole_worksheet)
|
859
|
-
else
|
860
|
-
ole_workbook.Worksheets.Add(base_sheet.ole_worksheet)
|
861
|
-
end
|
837
|
+
add_or_copy_sheet_simple(sheet, base_sheet_ole)
|
862
838
|
base_sheet.Move(ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count-1))
|
863
839
|
ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count).Activate
|
864
840
|
end
|
@@ -867,14 +843,23 @@ module RobustExcelOle
|
|
867
843
|
rescue WIN32OLERuntimeError, NameNotFound, Java::OrgRacobCom::ComFailException
|
868
844
|
raise WorksheetREOError, "could not add given worksheet #{sheet.inspect}"
|
869
845
|
end
|
870
|
-
|
871
|
-
ole_sheet = ole_workbook.Activesheet
|
872
|
-
#ole_sheet = ole_sheet.nil? ? ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count) : ole_sheet
|
873
|
-
new_sheet = worksheet_class.new(ole_sheet)
|
846
|
+
new_sheet = worksheet_class.new(ole_workbook.Activesheet)
|
874
847
|
new_sheet.name = new_sheet_name if new_sheet_name
|
875
848
|
new_sheet
|
876
849
|
end
|
877
850
|
|
851
|
+
private
|
852
|
+
|
853
|
+
def add_or_copy_sheet_simple(sheet, base_sheet_ole_or_hash)
|
854
|
+
if sheet
|
855
|
+
sheet.Copy(base_sheet_ole_or_hash)
|
856
|
+
else
|
857
|
+
ole_workbook.Worksheets.Add(base_sheet_ole_or_hash)
|
858
|
+
end
|
859
|
+
end
|
860
|
+
|
861
|
+
public
|
862
|
+
|
878
863
|
# for compatibility to older versions
|
879
864
|
def add_sheet(sheet = nil, opts = { })
|
880
865
|
add_or_copy_sheet(sheet, opts)
|
@@ -904,30 +889,15 @@ module RobustExcelOle
|
|
904
889
|
# @param [String] name the name of the range
|
905
890
|
# @param [Variant] value the contents of the range
|
906
891
|
def []= (name, value)
|
907
|
-
|
908
|
-
workbook.color_if_modified = 42 # 42 - aqua-marin, 4-green
|
909
|
-
set_namevalue_glob(name,value)
|
910
|
-
workbook.color_if_modified = old_color_if_modified
|
892
|
+
set_namevalue_glob(name, value, :color => 42)
|
911
893
|
end
|
912
894
|
|
913
895
|
# sets options
|
914
896
|
# @param [Hash] opts
|
915
897
|
def for_this_workbook(opts)
|
916
898
|
return unless alive?
|
917
|
-
|
918
|
-
|
919
|
-
check_compatibility_before = check_compatibility
|
920
|
-
unless opts[:read_only].nil?
|
921
|
-
# if the ReadOnly status shall be changed, then close and reopen it
|
922
|
-
if (!writable && !(opts[:read_only])) || (writable && opts[:read_only])
|
923
|
-
opts[:check_compatibility] = check_compatibility if opts[:check_compatibility].nil?
|
924
|
-
close(:if_unsaved => true)
|
925
|
-
open_or_create_workbook(@stored_filename, opts)
|
926
|
-
end
|
927
|
-
end
|
928
|
-
self.visible = opts[:force][:visible].nil? ? visible_before : opts[:force][:visible]
|
929
|
-
self.CheckCompatibility = opts[:check_compatibility].nil? ? check_compatibility_before : opts[:check_compatibility]
|
930
|
-
@excel.calculation = opts[:calculation] unless opts[:calculation].nil?
|
899
|
+
self.class.process_options(opts, :use_defaults => false)
|
900
|
+
self.send :apply_options, @stored_filename, opts
|
931
901
|
end
|
932
902
|
|
933
903
|
# brings workbook to foreground, makes it available for heyboard inputs, makes the Excel instance visible
|
@@ -943,7 +913,6 @@ module RobustExcelOle
|
|
943
913
|
true
|
944
914
|
rescue
|
945
915
|
@ole_workbook = nil # dead object won't be alive again
|
946
|
-
# t $!.message
|
947
916
|
false
|
948
917
|
end
|
949
918
|
|
@@ -963,7 +932,7 @@ module RobustExcelOle
|
|
963
932
|
end
|
964
933
|
|
965
934
|
def calculation
|
966
|
-
@excel.calculation if @ole_workbook
|
935
|
+
@excel.properties[:calculation] if @ole_workbook
|
967
936
|
end
|
968
937
|
|
969
938
|
# @private
|
@@ -973,7 +942,7 @@ module RobustExcelOle
|
|
973
942
|
|
974
943
|
# returns true, if the workbook is visible, false otherwise
|
975
944
|
def visible
|
976
|
-
@excel.
|
945
|
+
@excel.Visible && @ole_workbook.Windows(@ole_workbook.Name).Visible
|
977
946
|
end
|
978
947
|
|
979
948
|
# makes both the Excel instance and the window of the workbook visible, or the window invisible
|
@@ -1005,6 +974,7 @@ module RobustExcelOle
|
|
1005
974
|
self.filename == other_book.filename
|
1006
975
|
end
|
1007
976
|
|
977
|
+
# @private
|
1008
978
|
def self.books
|
1009
979
|
bookstore.books
|
1010
980
|
end
|
@@ -1019,6 +989,11 @@ module RobustExcelOle
|
|
1019
989
|
self.class.bookstore
|
1020
990
|
end
|
1021
991
|
|
992
|
+
# @private
|
993
|
+
def workbook
|
994
|
+
self
|
995
|
+
end
|
996
|
+
|
1022
997
|
# @private
|
1023
998
|
def to_s
|
1024
999
|
self.filename.to_s
|
@@ -1050,16 +1025,6 @@ module RobustExcelOle
|
|
1050
1025
|
end
|
1051
1026
|
end
|
1052
1027
|
|
1053
|
-
# @private
|
1054
|
-
def self.address_class
|
1055
|
-
@address_class ||= begin
|
1056
|
-
module_name = self.parent_name
|
1057
|
-
"#{module_name}::Address".constantize
|
1058
|
-
rescue NameError => e
|
1059
|
-
Address
|
1060
|
-
end
|
1061
|
-
end
|
1062
|
-
|
1063
1028
|
# @private
|
1064
1029
|
def excel_class
|
1065
1030
|
self.class.excel_class
|
@@ -1070,11 +1035,6 @@ module RobustExcelOle
|
|
1070
1035
|
self.class.worksheet_class
|
1071
1036
|
end
|
1072
1037
|
|
1073
|
-
# @private
|
1074
|
-
def address_class
|
1075
|
-
self.class.address_class
|
1076
|
-
end
|
1077
|
-
|
1078
1038
|
include MethodHelpers
|
1079
1039
|
|
1080
1040
|
private
|
@@ -1082,7 +1042,7 @@ module RobustExcelOle
|
|
1082
1042
|
def method_missing(name, *args)
|
1083
1043
|
if name.to_s[0,1] =~ /[A-Z]/
|
1084
1044
|
raise ObjectNotAlive, 'method missing: workbook not alive' unless alive?
|
1085
|
-
if
|
1045
|
+
if ::ERRORMESSAGE_JRUBY_BUG
|
1086
1046
|
begin
|
1087
1047
|
@ole_workbook.send(name, *args)
|
1088
1048
|
rescue Java::OrgRacobCom::ComFailException
|
@@ -1104,6 +1064,47 @@ module RobustExcelOle
|
|
1104
1064
|
|
1105
1065
|
public
|
1106
1066
|
|
1067
|
+
# @private
|
1068
|
+
class WorkbookBlocked < WorkbookREOError
|
1069
|
+
end
|
1070
|
+
|
1071
|
+
# @private
|
1072
|
+
class WorkbookNotSaved < WorkbookREOError
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
# @private
|
1076
|
+
class WorkbookReadOnly < WorkbookREOError
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
# @private
|
1080
|
+
class WorkbookBeingUsed < WorkbookREOError
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
# @private
|
1084
|
+
class WorkbookConnectingUnsavedError < WorkbookREOError
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
# @private
|
1088
|
+
class WorkbookConnectingBlockingError < WorkbookREOError
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
# @private
|
1092
|
+
class WorkbookConnectingUnknownError < WorkbookREOError
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
# @private
|
1096
|
+
class FileAlreadyExists < FileREOError
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
# @private
|
1100
|
+
class FileNameNotGiven < FileREOError
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
# @private
|
1104
|
+
class FileNotFound < FileREOError
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
|
1107
1108
|
Book = Workbook
|
1108
1109
|
|
1109
1110
|
end
|