robust_excel_ole 1.14 → 1.18.1
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 +34 -1
- data/README.rdoc +20 -6
- data/___dummy_workbook.xls +0 -0
- data/docs/README_excel.rdoc +7 -1
- data/docs/README_open.rdoc +45 -20
- data/docs/README_ranges.rdoc +11 -2
- data/examples/example_ruby_library.rb +27 -0
- data/extconf.rb +13 -0
- data/lib/robust_excel_ole.rb +4 -3
- data/lib/robust_excel_ole/{address.rb → address_tool.rb} +23 -22
- data/lib/robust_excel_ole/{reo_common.rb → base.rb} +2 -90
- 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 +105 -64
- 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 +310 -336
- 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 +570 -30
- data/spec/workbook_specs/workbook_unobtr_spec.rb +440 -136
- data/spec/worksheet_spec.rb +36 -4
- metadata +11 -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
|
@@ -12,33 +12,33 @@ module RobustExcelOle
|
|
12
12
|
class Workbook < RangeOwners
|
13
13
|
|
14
14
|
#include General
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
attr_accessor :color_if_modified
|
20
|
-
attr_accessor :was_open
|
21
|
-
attr_reader :workbook
|
15
|
+
|
16
|
+
attr_reader :ole_workbook
|
17
|
+
attr_reader :excel
|
18
|
+
attr_reader :stored_filename
|
22
19
|
|
23
20
|
alias ole_object ole_workbook
|
24
21
|
|
25
|
-
|
26
|
-
:default => {:excel => :current},
|
22
|
+
CORE_DEFAULT_OPEN_OPTS = {
|
23
|
+
:default => {:excel => :current},
|
27
24
|
:force => {},
|
28
|
-
:update_links => :never
|
25
|
+
:update_links => :never
|
26
|
+
}.freeze
|
27
|
+
|
28
|
+
DEFAULT_OPEN_OPTS = {
|
29
29
|
:if_unsaved => :raise,
|
30
30
|
:if_obstructed => :raise,
|
31
31
|
:if_absent => :raise,
|
32
|
-
:if_exists => :raise
|
33
|
-
|
34
|
-
}.freeze
|
35
|
-
|
36
|
-
CORE_DEFAULT_OPEN_OPTS = {
|
37
|
-
:default => {:excel => :current}, :force => {}, :update_links => :never
|
38
|
-
}.freeze
|
32
|
+
:if_exists => :raise
|
33
|
+
}.merge(CORE_DEFAULT_OPEN_OPTS).freeze
|
39
34
|
|
40
|
-
ABBREVIATIONS = [
|
41
|
-
|
35
|
+
ABBREVIATIONS = [
|
36
|
+
[:default,:d],
|
37
|
+
[:force, :f],
|
38
|
+
[:excel, :e],
|
39
|
+
[:visible, :v],
|
40
|
+
[:if_obstructed, :if_blocked]
|
41
|
+
].freeze
|
42
42
|
|
43
43
|
|
44
44
|
# opens a workbook.
|
@@ -84,50 +84,59 @@ module RobustExcelOle
|
|
84
84
|
# :visible true -> makes the workbook visible
|
85
85
|
# :check_compatibility true -> check compatibility when saving
|
86
86
|
# :update_links true -> user is being asked how to update links, false -> links are never updated
|
87
|
-
# @return [Workbook] a representation of a workbook
|
88
|
-
def self.new(file_or_workbook, opts = { }
|
89
|
-
|
90
|
-
|
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
|
91
94
|
file = file_or_workbook.Fullname.tr('\\','/')
|
92
|
-
|
95
|
+
when Workbook
|
96
|
+
file = file_or_workbook.Fullname.tr('\\','/')
|
97
|
+
when String
|
93
98
|
file = file_or_workbook
|
94
|
-
raise
|
95
|
-
|
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'
|
96
102
|
end
|
97
103
|
# try to fetch the workbook from the bookstore
|
104
|
+
set_was_open opts, file_or_workbook.is_a?(WIN32OLE)
|
98
105
|
book = nil
|
99
|
-
if
|
106
|
+
if opts[:force][:excel] != :new
|
100
107
|
# if readonly is true, then prefer a book that is given in force_excel if this option is set
|
101
|
-
forced_excel =
|
102
|
-
(
|
103
|
-
(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
|
104
114
|
begin
|
105
115
|
book = if File.exists?(file)
|
106
|
-
bookstore.fetch(file, :prefer_writable => !(
|
107
|
-
:prefer_excel => (
|
116
|
+
bookstore.fetch(file, :prefer_writable => !(opts[:read_only]),
|
117
|
+
:prefer_excel => (opts[:read_only] ? forced_excel : nil))
|
108
118
|
end
|
109
119
|
rescue
|
110
|
-
|
120
|
+
raise
|
121
|
+
#trace "#{$!.message}"
|
111
122
|
end
|
112
123
|
if book
|
113
|
-
|
124
|
+
set_was_open opts, book.alive?
|
114
125
|
# drop the fetched workbook if it shall be opened in another Excel instance
|
115
126
|
# or the workbook is an unsaved workbook that should not be accepted
|
116
|
-
if (
|
117
|
-
!(book.alive? && !book.saved && (
|
118
|
-
|
119
|
-
book.ensure_workbook(file,
|
120
|
-
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
|
121
132
|
return book
|
122
133
|
end
|
123
134
|
end
|
124
135
|
end
|
125
|
-
super(file_or_workbook,
|
136
|
+
super(file_or_workbook, opts)
|
126
137
|
end
|
127
138
|
|
128
|
-
|
129
|
-
new(file_or_workbook, opts, &block)
|
130
|
-
end
|
139
|
+
singleton_class.send :alias_method, :open, :new
|
131
140
|
|
132
141
|
# creates a new Workbook object, if a file name is given
|
133
142
|
# Promotes the win32ole workbook to a Workbook object, if a win32ole-workbook is given
|
@@ -135,26 +144,23 @@ module RobustExcelOle
|
|
135
144
|
# @param [Hash] opts
|
136
145
|
# @option opts [Symbol] see above
|
137
146
|
# @return [Workbook] a workbook
|
138
|
-
def initialize(file_or_workbook,
|
147
|
+
def initialize(file_or_workbook, opts)
|
139
148
|
if file_or_workbook.is_a? WIN32OLE
|
140
149
|
@ole_workbook = file_or_workbook
|
141
|
-
ole_excel = begin
|
142
|
-
|
143
|
-
rescue
|
150
|
+
ole_excel = begin
|
151
|
+
@ole_workbook.Application
|
152
|
+
rescue WIN32OLERuntimeError
|
144
153
|
raise ExcelREOError, 'could not determine the Excel instance'
|
145
154
|
end
|
146
155
|
@excel = excel_class.new(ole_excel)
|
147
|
-
filename =
|
156
|
+
filename = @ole_workbook.Fullname.tr('\\','/')
|
148
157
|
else
|
149
158
|
filename = file_or_workbook
|
150
|
-
ensure_workbook(filename,
|
159
|
+
ensure_workbook(filename, opts)
|
151
160
|
end
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
r1c1_letters = @ole_workbook.Worksheets.Item(1).Cells.Item(1,1).Address(true,true,XlR1C1).gsub(/[0-9]/,'') #('ReferenceStyle' => XlR1C1).gsub(/[0-9]/,'')
|
156
|
-
address_class.new(r1c1_letters)
|
157
|
-
if block
|
161
|
+
apply_options(filename, opts)
|
162
|
+
store_myself
|
163
|
+
if block_given?
|
158
164
|
begin
|
159
165
|
yield self
|
160
166
|
ensure
|
@@ -165,52 +171,46 @@ module RobustExcelOle
|
|
165
171
|
|
166
172
|
private
|
167
173
|
|
168
|
-
|
169
|
-
|
170
|
-
translator = proc do |opts|
|
171
|
-
erg = {}
|
172
|
-
opts.each do |key,value|
|
173
|
-
new_key = key
|
174
|
-
ABBREVIATIONS.each { |long,short| new_key = long if key == short }
|
175
|
-
if value.is_a?(Hash)
|
176
|
-
erg[new_key] = {}
|
177
|
-
value.each do |k,v|
|
178
|
-
new_k = k
|
179
|
-
ABBREVIATIONS.each { |l,s| new_k = l if k == s }
|
180
|
-
erg[new_key][new_k] = v
|
181
|
-
end
|
182
|
-
else
|
183
|
-
erg[new_key] = value
|
184
|
-
end
|
185
|
-
end
|
186
|
-
erg[:default] ||= {}
|
187
|
-
erg[:force] ||= {}
|
188
|
-
force_list = [:visible, :excel]
|
189
|
-
erg.each { |key,value| erg[:force][key] = value if force_list.include?(key) }
|
190
|
-
erg[:default][:excel] = erg[:default_excel] unless erg[:default_excel].nil?
|
191
|
-
erg[:force][:excel] = erg[:force_excel] unless erg[:force_excel].nil?
|
192
|
-
erg[:default][:excel] = :current if erg[:default][:excel] == :reuse || erg[:default][:excel] == :active
|
193
|
-
erg[:force][:excel] = :current if erg[:force][:excel] == :reuse || erg[:force][:excel] == :active
|
194
|
-
erg
|
195
|
-
end
|
196
|
-
opts = translator.call(options)
|
197
|
-
default_open_opts = proc_opts[:use_defaults] ? DEFAULT_OPEN_OPTS : CORE_DEFAULT_OPEN_OPTS
|
198
|
-
default_opts = translator.call(default_open_opts)
|
199
|
-
opts = default_opts.merge(opts)
|
200
|
-
opts[:default] = default_opts[:default].merge(opts[:default]) unless opts[:default].nil?
|
201
|
-
opts[:force] = default_opts[:force].merge(opts[:force]) unless opts[:force].nil?
|
202
|
-
opts
|
174
|
+
def self.set_was_open(hash, value)
|
175
|
+
hash[:was_open] = value if hash.has_key?(:was_open)
|
203
176
|
end
|
204
177
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
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
|
213
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
|
214
214
|
end
|
215
215
|
|
216
216
|
public
|
@@ -219,93 +219,91 @@ module RobustExcelOle
|
|
219
219
|
# ensures an excel but not for jruby if current Excel shall be used
|
220
220
|
def ensure_excel(options)
|
221
221
|
return if @excel && @excel.alive?
|
222
|
-
excel_option = options[:force][:excel]
|
222
|
+
excel_option = options[:force][:excel] || options[:default][:excel] || :current
|
223
223
|
@excel = if excel_option == :new
|
224
224
|
excel_class.new(:reuse => false)
|
225
|
-
elsif excel_option
|
225
|
+
elsif excel_option == :current
|
226
226
|
excel_class.new(:reuse => true)
|
227
|
+
elsif excel_option.respond_to?(:to_reo)
|
228
|
+
excel_option.to_reo.excel
|
227
229
|
else
|
228
|
-
|
230
|
+
raise TypeREOError, "provided Excel option value is neither an Excel object nor a valid option"
|
229
231
|
end
|
230
|
-
raise ExcelREOError, "
|
232
|
+
raise ExcelREOError, "Excel is not alive" unless @excel && @excel.alive?
|
231
233
|
end
|
232
234
|
|
235
|
+
|
233
236
|
# @private
|
234
237
|
def ensure_workbook(filename, options)
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
@ole_workbook = workbooks.Item(File.basename(filename)) rescue nil if @ole_workbook.nil?
|
242
|
-
if @ole_workbook
|
243
|
-
@was_open = true
|
244
|
-
manage_blocking_or_unsaved_workbook(filename,options)
|
245
|
-
else
|
246
|
-
if excel_option.nil? || excel_option == :current &&
|
247
|
-
(!JRUBY_BUG_CONNECT || filename[0] != '/')
|
248
|
-
connect(filename,options)
|
249
|
-
else
|
250
|
-
open_or_create_workbook(filename,options)
|
251
|
-
end
|
252
|
-
end
|
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
|
241
|
+
if options[:if_unsaved]==:accept &&
|
242
|
+
((options[:read_only]==true && self.ReadOnly==false) || (options[:read_only]==false && self.ReadOnly==true))
|
243
|
+
raise OptionInvalid, ":if_unsaved:accept and change of read-only mode is not possible"
|
253
244
|
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)
|
261
|
+
end
|
262
|
+
end
|
254
263
|
end
|
255
264
|
|
256
|
-
|
257
|
-
|
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
|
258
271
|
if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
259
|
-
|
260
|
-
@excel.with_displayalerts(false) { @ole_workbook.Close }
|
261
|
-
@ole_workbook = nil
|
262
|
-
open_or_create_workbook(filename, options)
|
272
|
+
ensure_workbook(filename, options)
|
263
273
|
end
|
264
274
|
retain_saved do
|
265
275
|
self.visible = options[:force][:visible].nil? ? @excel.Visible : options[:force][:visible]
|
266
276
|
@excel.calculation = options[:calculation] unless options[:calculation].nil?
|
267
277
|
@ole_workbook.CheckCompatibility = options[:check_compatibility] unless options[:check_compatibility].nil?
|
268
|
-
end
|
278
|
+
end
|
269
279
|
end
|
270
280
|
|
271
|
-
|
272
|
-
private
|
273
|
-
|
274
|
-
# @private
|
275
281
|
# connects to an unknown workbook
|
276
|
-
def connect(filename,options)
|
277
|
-
|
278
|
-
workbooks_number = if excels_number>0
|
279
|
-
excel_class.current.Workbooks.Count
|
280
|
-
else 0
|
281
|
-
end
|
282
|
-
abs_filename = General.absolute_path(filename)
|
282
|
+
def connect(filename, options)
|
283
|
+
workbooks_number = excel_class.excels_number==0 ? 0 : excel_class.current.Workbooks.Count
|
283
284
|
@ole_workbook = begin
|
284
|
-
WIN32OLE.connect(
|
285
|
+
WIN32OLE.connect(General.absolute_path(filename))
|
285
286
|
rescue
|
286
287
|
if $!.message =~ /moniker/
|
287
|
-
raise WorkbookConnectingBlockingError
|
288
|
-
else
|
289
|
-
raise WorkbookConnectingUnknownError
|
288
|
+
raise WorkbookConnectingBlockingError, "some workbook is blocking when connecting"
|
289
|
+
else
|
290
|
+
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook"
|
290
291
|
end
|
291
292
|
end
|
292
293
|
ole_excel = begin
|
293
294
|
@ole_workbook.Application
|
294
295
|
rescue
|
295
296
|
if $!.message =~ /dispid/
|
296
|
-
raise WorkbookConnectingUnsavedError
|
297
|
-
else
|
298
|
-
raise WorkbookConnectingUnknownError
|
297
|
+
raise WorkbookConnectingUnsavedError, "workbook is unsaved when connecting"
|
298
|
+
else
|
299
|
+
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook"
|
299
300
|
end
|
300
301
|
end
|
302
|
+
set_was_open options, (ole_excel.Workbooks.Count == workbooks_number)
|
301
303
|
@excel = excel_class.new(ole_excel)
|
302
|
-
excels_number_after = excel_class.excels_number
|
303
|
-
workbooks_number_after = ole_excel.Workbooks.Count
|
304
|
-
@was_open = (excels_number_after==excels_number) && (workbooks_number_after==workbooks_number)
|
305
304
|
end
|
306
305
|
|
307
|
-
|
308
|
-
def manage_nonexisting_file(filename,options)
|
306
|
+
def manage_nonexisting_file(filename, options)
|
309
307
|
return if File.exist?(filename)
|
310
308
|
abs_filename = General.absolute_path(filename)
|
311
309
|
if options[:if_absent] == :create
|
@@ -323,11 +321,12 @@ module RobustExcelOle
|
|
323
321
|
end
|
324
322
|
end
|
325
323
|
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
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))
|
331
330
|
if obstructed_by_other_book
|
332
331
|
# workbook is being obstructed by a workbook with same name and different path
|
333
332
|
manage_blocking_workbook(filename,options)
|
@@ -339,8 +338,7 @@ module RobustExcelOle
|
|
339
338
|
end
|
340
339
|
end
|
341
340
|
|
342
|
-
|
343
|
-
def manage_blocking_workbook(filename,options)
|
341
|
+
def manage_blocking_workbook(filename, options)
|
344
342
|
case options[:if_obstructed]
|
345
343
|
when :raise
|
346
344
|
raise WorkbookBlocked, "can't open workbook #{filename},
|
@@ -354,7 +352,8 @@ module RobustExcelOle
|
|
354
352
|
manage_saving_workbook(filename, options)
|
355
353
|
when :close_if_saved
|
356
354
|
if !@ole_workbook.Saved
|
357
|
-
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"
|
358
357
|
else
|
359
358
|
manage_forgetting_workbook(filename, options)
|
360
359
|
end
|
@@ -366,15 +365,14 @@ module RobustExcelOle
|
|
366
365
|
end
|
367
366
|
end
|
368
367
|
|
369
|
-
|
370
|
-
def manage_unsaved_workbook(filename,options)
|
368
|
+
def manage_unsaved_workbook(filename, options)
|
371
369
|
case options[:if_unsaved]
|
372
370
|
when :raise
|
373
371
|
raise WorkbookNotSaved, "workbook is already open but not saved: #{File.basename(filename).inspect}" +
|
374
372
|
"\nHint: Save the workbook or open the workbook using option :if_unsaved with values :forget and :accept to
|
375
373
|
close the unsaved workbook and reopen it, or to let the unsaved workbook open, respectively"
|
376
374
|
when :forget
|
377
|
-
manage_forgetting_workbook(filename,options)
|
375
|
+
manage_forgetting_workbook(filename, options)
|
378
376
|
when :accept
|
379
377
|
# do nothing
|
380
378
|
when :save
|
@@ -389,29 +387,26 @@ module RobustExcelOle
|
|
389
387
|
end
|
390
388
|
end
|
391
389
|
|
392
|
-
# @private
|
393
390
|
def manage_forgetting_workbook(filename, options)
|
394
391
|
@excel.with_displayalerts(false) { @ole_workbook.Close }
|
395
392
|
@ole_workbook = nil
|
396
393
|
open_or_create_workbook(filename, options)
|
397
394
|
end
|
398
395
|
|
399
|
-
# @private
|
400
396
|
def manage_saving_workbook(filename, options)
|
401
397
|
save unless @ole_workbook.Saved
|
402
398
|
manage_forgetting_workbook(filename, options)
|
403
399
|
end
|
404
400
|
|
405
|
-
# @private
|
406
401
|
def manage_new_excel(filename, options)
|
407
402
|
@excel = excel_class.new(:reuse => false)
|
408
403
|
@ole_workbook = nil
|
409
404
|
open_or_create_workbook(filename, options)
|
410
405
|
end
|
411
406
|
|
412
|
-
|
413
|
-
|
414
|
-
|
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 )
|
415
410
|
begin
|
416
411
|
abs_filename = General.absolute_path(filename)
|
417
412
|
begin
|
@@ -426,7 +421,7 @@ module RobustExcelOle
|
|
426
421
|
updatelinks_vba(options[:update_links]),
|
427
422
|
options[:read_only] )
|
428
423
|
end
|
429
|
-
rescue WIN32OLERuntimeError => msg
|
424
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
430
425
|
# for Excel2007: for option :if_unsaved => :alert and user cancels: this error appears?
|
431
426
|
# if yes: distinguish these events
|
432
427
|
raise UnexpectedREOError, "cannot open workbook: #{msg.message} #{msg.backtrace}"
|
@@ -435,29 +430,27 @@ module RobustExcelOle
|
|
435
430
|
# workaround for bug in Excel 2010: workbook.Open does not always return the workbook when given file name
|
436
431
|
begin
|
437
432
|
@ole_workbook = workbooks.Item(File.basename(filename))
|
438
|
-
rescue WIN32OLERuntimeError => msg
|
433
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
439
434
|
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message}"
|
440
435
|
end
|
441
|
-
rescue WIN32OLERuntimeError => msg
|
436
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
442
437
|
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message} #{msg.backtrace}"
|
443
438
|
end
|
444
439
|
end
|
445
440
|
end
|
446
441
|
|
447
|
-
# @private
|
448
442
|
# translating the option UpdateLinks from REO to VBA
|
449
443
|
# setting UpdateLinks works only if calculation mode is automatic,
|
450
444
|
# parameter 'UpdateLinks' has no effect
|
451
445
|
def updatelinks_vba(updatelinks_reo)
|
452
446
|
case updatelinks_reo
|
453
|
-
when :alert
|
454
|
-
when :never
|
447
|
+
when :alert then RobustExcelOle::XlUpdateLinksUserSetting
|
448
|
+
when :never then RobustExcelOle::XlUpdateLinksNever
|
455
449
|
when :always then RobustExcelOle::XlUpdateLinksAlways
|
456
|
-
else
|
450
|
+
else RobustExcelOle::XlUpdateLinksNever
|
457
451
|
end
|
458
452
|
end
|
459
453
|
|
460
|
-
# @private
|
461
454
|
# workaround for linked workbooks for Excel 2007:
|
462
455
|
# opening and closing a dummy workbook if Excel has no workbooks.
|
463
456
|
# delay: with visible: 0.2 sec, without visible almost none
|
@@ -467,7 +460,7 @@ module RobustExcelOle
|
|
467
460
|
workaround_condition = @excel.Version.split('.').first.to_i == 12 && workbooks.Count == 0
|
468
461
|
if workaround_condition
|
469
462
|
workbooks.Add
|
470
|
-
@excel.calculation = options[:calculation].nil? ? @excel.calculation : options[:calculation]
|
463
|
+
@excel.calculation = options[:calculation].nil? ? @excel.properties[:calculation] : options[:calculation]
|
471
464
|
end
|
472
465
|
begin
|
473
466
|
# @excel.with_displayalerts(update_links_opt == :alert ? true : @excel.displayalerts) do
|
@@ -521,13 +514,10 @@ module RobustExcelOle
|
|
521
514
|
else
|
522
515
|
close_workbook
|
523
516
|
end
|
524
|
-
# trace "close: canceled by user" if alive? &&
|
525
|
-
# (opts[:if_unsaved] == :alert || opts[:if_unsaved] == :excel) && (not @ole_workbook.Saved)
|
526
517
|
end
|
527
518
|
|
528
519
|
private
|
529
520
|
|
530
|
-
# @private
|
531
521
|
def close_workbook
|
532
522
|
@ole_workbook.Close if alive?
|
533
523
|
@ole_workbook = nil unless alive?
|
@@ -545,20 +535,20 @@ module RobustExcelOle
|
|
545
535
|
end
|
546
536
|
end
|
547
537
|
|
548
|
-
def
|
549
|
-
|
550
|
-
opts = args.last.is_a?(Hash) ? args.pop : {}
|
551
|
-
opts = {:writable => false}.merge(opts)
|
552
|
-
args.push opts
|
553
|
-
unobtrusively(*args, &block)
|
538
|
+
def for_reading(opts = { }, &block)
|
539
|
+
unobtrusively({:writable => false}.merge(opts), &block)
|
554
540
|
end
|
555
541
|
|
556
|
-
def
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
unobtrusively(
|
542
|
+
def for_modifying(opts = { }, &block)
|
543
|
+
unobtrusively({:writable => true}.merge(opts), &block)
|
544
|
+
end
|
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)
|
562
552
|
end
|
563
553
|
|
564
554
|
# allows to read or modify a workbook such that its state remains unchanged
|
@@ -570,97 +560,64 @@ module RobustExcelOle
|
|
570
560
|
# @option opts [Boolean] :writable true (default)/false changes of the workbook shall be saved/not saved
|
571
561
|
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening (default: false)
|
572
562
|
# @return [Workbook] a workbook
|
573
|
-
def self.unobtrusively(file_or_workbook, opts = { })
|
574
|
-
opts = process_options(opts, :use_defaults => false)
|
575
|
-
raise OptionInvalid, 'contradicting options' if opts[:writable] && opts[:read_only]
|
576
|
-
opts = opts.merge({:force => {:excel => opts[:if_closed]}, :if_closed => :current,
|
577
|
-
:if_unsaved => :accept, :keep_open => false})
|
578
|
-
opts = opts.merge({:read_only => opts[:read_only]}) unless opts[:read_only].nil?
|
563
|
+
def self.unobtrusively(file_or_workbook, opts = { }, &block)
|
579
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]}}
|
588
|
+
end
|
589
|
+
open_opts = excel_opts.merge({:if_unsaved => :accept})
|
580
590
|
begin
|
581
|
-
|
591
|
+
open_opts[:was_open] = nil
|
592
|
+
book = open(file, open_opts)
|
582
593
|
was_visible = book.visible
|
583
594
|
was_writable = book.writable
|
584
595
|
was_saved = book.saved
|
585
596
|
was_check_compatibility = book.check_compatibility
|
586
|
-
was_calculation = book.excel.calculation
|
587
|
-
book.
|
588
|
-
if !was_saved && ((opts[:writable] && !was_writable) || (opts[:read_only] && was_writable))
|
589
|
-
raise NotImplementedREOError, 'unsaved read-only workbook shall be written'
|
590
|
-
end
|
597
|
+
was_calculation = book.excel.properties[:calculation]
|
598
|
+
book.send :apply_options, file, opts
|
591
599
|
yield book
|
592
600
|
ensure
|
593
601
|
if book && book.alive?
|
594
|
-
do_not_write =
|
595
|
-
book.save unless
|
596
|
-
# open and close if the read_only mode has changed
|
602
|
+
do_not_write = opts[:read_only] || opts[:writable]==false
|
603
|
+
book.save unless book.saved || do_not_write || !book.writable
|
597
604
|
if (opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable)
|
598
|
-
book
|
605
|
+
book.send :apply_options, file, opts.merge({:read_only => !was_writable,
|
606
|
+
:if_unsaved => (opts[:writable]==false ? :forget : :save)})
|
599
607
|
end
|
600
|
-
|
608
|
+
was_open = open_opts[:was_open]
|
609
|
+
if was_open
|
601
610
|
book.visible = was_visible
|
602
611
|
book.CheckCompatibility = was_check_compatibility
|
603
612
|
book.excel.calculation = was_calculation
|
604
613
|
end
|
605
|
-
book.Saved = (was_saved || !
|
606
|
-
book.close unless
|
607
|
-
end
|
608
|
-
end
|
609
|
-
end
|
610
|
-
|
611
|
-
# allows to read or modify a workbook such that its state remains unchanged
|
612
|
-
# state comprises: open, saved, writable, visible, calculation mode, check compatibility
|
613
|
-
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
614
|
-
# @param [Hash] opts the options
|
615
|
-
# @option opts [Variant] :if_closed :current (default), :new or an Excel instance
|
616
|
-
# @option opts [Boolean] :read_only true/false (default), open the workbook in read-only/read-write modus (save changes)
|
617
|
-
# @option opts [Boolean] :writable true (default)/false changes of the workbook shall be saved/not saved
|
618
|
-
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening (default: false)
|
619
|
-
# @return [Workbook] a workbook
|
620
|
-
=begin
|
621
|
-
def self.unobtrusively(file_or_workbook, opts = { })
|
622
|
-
book = new(file_or_workbook)
|
623
|
-
book.unobtrusively(opts)
|
624
|
-
end
|
625
|
-
=end
|
626
|
-
|
627
|
-
def unobtrusively(opts = { })
|
628
|
-
opts = process_options(opts, :use_defaults => false)
|
629
|
-
raise OptionInvalid, 'contradicting options' if opts[:writable] && opts[:read_only]
|
630
|
-
opts = opts.merge({:force => {:excel => opts[:if_closed]}, :if_closed => :current,
|
631
|
-
:if_unsaved => :accept, :keep_open => false})
|
632
|
-
opts = opts.merge({:read_only => opts[:read_only]}) unless opts[:read_only].nil?
|
633
|
-
file = stored_filename
|
634
|
-
begin
|
635
|
-
book = open(file, opts)
|
636
|
-
was_visible = book.visible
|
637
|
-
was_saved = book.saved
|
638
|
-
was_writable = book.was_writable
|
639
|
-
was_check_compatibility = book.CheckCompatibility
|
640
|
-
was_calculation = book.excel.calculation
|
641
|
-
if !was_saved && ((opts[:writable] && !was_writable) || (opts[:read_only] && was_writable))
|
642
|
-
raise NotImplementedREOError, 'unsaved read-only workbook shall be written'
|
643
|
-
end
|
644
|
-
yield book
|
645
|
-
ensure
|
646
|
-
if book && book.alive?
|
647
|
-
do_not_write = (opts[:read_only] || (opts[:read_only].nil? && opts[:writable] == false))
|
648
|
-
book.save unless book.saved || do_not_write || book.ReadOnly
|
649
|
-
# open and close if the read_only mode has changed
|
650
|
-
if (opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable)
|
651
|
-
book = open(file, :read_only => !was_writable, :if_unsaved => :forget)
|
652
|
-
end
|
653
|
-
if book.was_open
|
654
|
-
book.visible = was_visible
|
655
|
-
book.CheckCompatibility = was_check_compatibility
|
656
|
-
book.excel.calculation = was_calculation
|
657
|
-
end
|
658
|
-
book.Saved = (was_saved || !book.was_open)
|
659
|
-
book.close unless book.was_open || opts[:keep_open]
|
614
|
+
book.Saved = (was_saved || !was_open)
|
615
|
+
book.close unless was_open || opts[:keep_open]
|
660
616
|
end
|
661
617
|
end
|
662
618
|
end
|
663
619
|
|
620
|
+
public
|
664
621
|
|
665
622
|
# reopens a closed workbook
|
666
623
|
# @options options
|
@@ -675,10 +632,6 @@ module RobustExcelOle
|
|
675
632
|
def save(opts = { }) # option opts is deprecated #
|
676
633
|
raise ObjectNotAlive, 'workbook is not alive' unless alive?
|
677
634
|
raise WorkbookReadOnly, 'Not opened for writing (opened with :read_only option)' if @ole_workbook.ReadOnly
|
678
|
-
# if you have open the workbook with :read_only => true,
|
679
|
-
# then you could close the workbook and open it again with option :read_only => false
|
680
|
-
# otherwise the workbook may already be open writable in an another Excel instance
|
681
|
-
# then you could use this workbook or close the workbook there
|
682
635
|
begin
|
683
636
|
@ole_workbook.Save
|
684
637
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
@@ -708,12 +661,12 @@ module RobustExcelOle
|
|
708
661
|
# :close_if_saved -> closes the blocking workbook, if it is saved,
|
709
662
|
# otherwise raises an exception
|
710
663
|
# @return [Workbook], the book itself, if successfully saved, raises an exception otherwise
|
711
|
-
def save_as(file,
|
664
|
+
def save_as(file, options = { })
|
712
665
|
raise FileNameNotGiven, 'filename is nil' if file.nil?
|
713
666
|
raise ObjectNotAlive, 'workbook is not alive' unless alive?
|
714
667
|
raise WorkbookReadOnly, 'Not opened for writing (opened with :read_only option)' if @ole_workbook.ReadOnly
|
715
668
|
raise(FileNotFound, "file #{General.absolute_path(file).inspect} is a directory") if File.directory?(file)
|
716
|
-
|
669
|
+
self.class.process_options(options)
|
717
670
|
if File.exist?(file)
|
718
671
|
case options[:if_exists]
|
719
672
|
when :overwrite
|
@@ -768,7 +721,6 @@ module RobustExcelOle
|
|
768
721
|
|
769
722
|
private
|
770
723
|
|
771
|
-
# @private
|
772
724
|
def save_as_workbook(file, options)
|
773
725
|
dirname, basename = File.split(file)
|
774
726
|
file_format =
|
@@ -778,7 +730,7 @@ module RobustExcelOle
|
|
778
730
|
when '.xlsm' then RobustExcelOle::XlOpenXMLWorkbookMacroEnabled
|
779
731
|
end
|
780
732
|
@ole_workbook.SaveAs(General.absolute_path(file), file_format)
|
781
|
-
|
733
|
+
store_myself
|
782
734
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
783
735
|
if msg.message =~ /SaveAs/ && msg.message =~ /Workbook/
|
784
736
|
# trace "save: canceled by user" if options[:if_exists] == :alert || options[:if_exists] == :excel
|
@@ -788,6 +740,11 @@ module RobustExcelOle
|
|
788
740
|
end
|
789
741
|
end
|
790
742
|
|
743
|
+
def store_myself
|
744
|
+
bookstore.store(self)
|
745
|
+
@stored_filename = filename
|
746
|
+
end
|
747
|
+
|
791
748
|
public
|
792
749
|
|
793
750
|
# closes a given file if it is open
|
@@ -826,12 +783,22 @@ module RobustExcelOle
|
|
826
783
|
raise NameNotFound, "could not return a sheet with name #{name.inspect}"
|
827
784
|
end
|
828
785
|
|
786
|
+
def worksheets_count
|
787
|
+
@ole_workbook.Worksheets.Count
|
788
|
+
end
|
789
|
+
|
829
790
|
def each
|
830
791
|
@ole_workbook.Worksheets.each do |sheet|
|
831
792
|
yield worksheet_class.new(sheet)
|
832
793
|
end
|
833
794
|
end
|
834
795
|
|
796
|
+
def worksheets
|
797
|
+
result = []
|
798
|
+
each { |worksheet| result << worksheet }
|
799
|
+
result
|
800
|
+
end
|
801
|
+
|
835
802
|
def each_with_index(offset = 0)
|
836
803
|
i = offset
|
837
804
|
@ole_workbook.Worksheets.each do |sheet|
|
@@ -856,36 +823,18 @@ module RobustExcelOle
|
|
856
823
|
new_sheet_name = opts.delete(:as)
|
857
824
|
last_sheet_local = last_sheet
|
858
825
|
after_or_before, base_sheet = opts.to_a.first || [:after, last_sheet_local]
|
826
|
+
base_sheet_ole = base_sheet.ole_worksheet
|
859
827
|
begin
|
860
|
-
if
|
861
|
-
|
862
|
-
sheet.Copy({ after_or_before.to_s => base_sheet.ole_worksheet })
|
863
|
-
else
|
864
|
-
@ole_workbook.Worksheets.Add({ after_or_before.to_s => base_sheet.ole_worksheet })
|
865
|
-
#@ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count).Activate
|
866
|
-
end
|
828
|
+
if !::COPYSHEETS_JRUBY_BUG
|
829
|
+
add_or_copy_sheet_simple(sheet, { after_or_before.to_s => base_sheet_ole })
|
867
830
|
else
|
868
831
|
if after_or_before == :before
|
869
|
-
|
870
|
-
sheet.Copy(base_sheet.ole_worksheet)
|
871
|
-
else
|
872
|
-
ole_workbook.Worksheets.Add(base_sheet.ole_worksheet)
|
873
|
-
end
|
832
|
+
add_or_copy_sheet_simple(sheet, base_sheet_ole)
|
874
833
|
else
|
875
|
-
#not_given = WIN32OLE_VARIANT.new(nil, WIN32OLE::VARIANT::VT_NULL)
|
876
|
-
#ole_workbook.Worksheets.Add(not_given,base_sheet.ole_worksheet)
|
877
834
|
if base_sheet.name != last_sheet_local.name
|
878
|
-
|
879
|
-
sheet.Copy(base_sheet.Next)
|
880
|
-
else
|
881
|
-
ole_workbook.Worksheets.Add(base_sheet.Next)
|
882
|
-
end
|
835
|
+
add_or_copy_sheet_simple(sheet, base_sheet.Next)
|
883
836
|
else
|
884
|
-
|
885
|
-
sheet.Copy(base_sheet.ole_worksheet)
|
886
|
-
else
|
887
|
-
ole_workbook.Worksheets.Add(base_sheet.ole_worksheet)
|
888
|
-
end
|
837
|
+
add_or_copy_sheet_simple(sheet, base_sheet_ole)
|
889
838
|
base_sheet.Move(ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count-1))
|
890
839
|
ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count).Activate
|
891
840
|
end
|
@@ -894,14 +843,23 @@ module RobustExcelOle
|
|
894
843
|
rescue WIN32OLERuntimeError, NameNotFound, Java::OrgRacobCom::ComFailException
|
895
844
|
raise WorksheetREOError, "could not add given worksheet #{sheet.inspect}"
|
896
845
|
end
|
897
|
-
|
898
|
-
ole_sheet = ole_workbook.Activesheet
|
899
|
-
#ole_sheet = ole_sheet.nil? ? ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count) : ole_sheet
|
900
|
-
new_sheet = worksheet_class.new(ole_sheet)
|
846
|
+
new_sheet = worksheet_class.new(ole_workbook.Activesheet)
|
901
847
|
new_sheet.name = new_sheet_name if new_sheet_name
|
902
848
|
new_sheet
|
903
849
|
end
|
904
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
|
+
|
905
863
|
# for compatibility to older versions
|
906
864
|
def add_sheet(sheet = nil, opts = { })
|
907
865
|
add_or_copy_sheet(sheet, opts)
|
@@ -931,30 +889,15 @@ module RobustExcelOle
|
|
931
889
|
# @param [String] name the name of the range
|
932
890
|
# @param [Variant] value the contents of the range
|
933
891
|
def []= (name, value)
|
934
|
-
|
935
|
-
workbook.color_if_modified = 42 # 42 - aqua-marin, 4-green
|
936
|
-
set_namevalue_glob(name,value)
|
937
|
-
workbook.color_if_modified = old_color_if_modified
|
892
|
+
set_namevalue_glob(name, value, :color => 42)
|
938
893
|
end
|
939
894
|
|
940
895
|
# sets options
|
941
896
|
# @param [Hash] opts
|
942
897
|
def for_this_workbook(opts)
|
943
898
|
return unless alive?
|
944
|
-
|
945
|
-
|
946
|
-
check_compatibility_before = check_compatibility
|
947
|
-
unless opts[:read_only].nil?
|
948
|
-
# if the ReadOnly status shall be changed, then close and reopen it
|
949
|
-
if (!writable && !(opts[:read_only])) || (writable && opts[:read_only])
|
950
|
-
opts[:check_compatibility] = check_compatibility if opts[:check_compatibility].nil?
|
951
|
-
close(:if_unsaved => true)
|
952
|
-
open_or_create_workbook(@stored_filename, opts)
|
953
|
-
end
|
954
|
-
end
|
955
|
-
self.visible = opts[:force][:visible].nil? ? visible_before : opts[:force][:visible]
|
956
|
-
self.CheckCompatibility = opts[:check_compatibility].nil? ? check_compatibility_before : opts[:check_compatibility]
|
957
|
-
@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
|
958
901
|
end
|
959
902
|
|
960
903
|
# brings workbook to foreground, makes it available for heyboard inputs, makes the Excel instance visible
|
@@ -970,7 +913,6 @@ module RobustExcelOle
|
|
970
913
|
true
|
971
914
|
rescue
|
972
915
|
@ole_workbook = nil # dead object won't be alive again
|
973
|
-
# t $!.message
|
974
916
|
false
|
975
917
|
end
|
976
918
|
|
@@ -990,7 +932,7 @@ module RobustExcelOle
|
|
990
932
|
end
|
991
933
|
|
992
934
|
def calculation
|
993
|
-
@excel.calculation if @ole_workbook
|
935
|
+
@excel.properties[:calculation] if @ole_workbook
|
994
936
|
end
|
995
937
|
|
996
938
|
# @private
|
@@ -1000,7 +942,7 @@ module RobustExcelOle
|
|
1000
942
|
|
1001
943
|
# returns true, if the workbook is visible, false otherwise
|
1002
944
|
def visible
|
1003
|
-
@excel.
|
945
|
+
@excel.Visible && @ole_workbook.Windows(@ole_workbook.Name).Visible
|
1004
946
|
end
|
1005
947
|
|
1006
948
|
# makes both the Excel instance and the window of the workbook visible, or the window invisible
|
@@ -1032,6 +974,7 @@ module RobustExcelOle
|
|
1032
974
|
self.filename == other_book.filename
|
1033
975
|
end
|
1034
976
|
|
977
|
+
# @private
|
1035
978
|
def self.books
|
1036
979
|
bookstore.books
|
1037
980
|
end
|
@@ -1046,6 +989,11 @@ module RobustExcelOle
|
|
1046
989
|
self.class.bookstore
|
1047
990
|
end
|
1048
991
|
|
992
|
+
# @private
|
993
|
+
def workbook
|
994
|
+
self
|
995
|
+
end
|
996
|
+
|
1049
997
|
# @private
|
1050
998
|
def to_s
|
1051
999
|
self.filename.to_s
|
@@ -1077,16 +1025,6 @@ module RobustExcelOle
|
|
1077
1025
|
end
|
1078
1026
|
end
|
1079
1027
|
|
1080
|
-
# @private
|
1081
|
-
def self.address_class
|
1082
|
-
@address_class ||= begin
|
1083
|
-
module_name = self.parent_name
|
1084
|
-
"#{module_name}::Address".constantize
|
1085
|
-
rescue NameError => e
|
1086
|
-
Address
|
1087
|
-
end
|
1088
|
-
end
|
1089
|
-
|
1090
1028
|
# @private
|
1091
1029
|
def excel_class
|
1092
1030
|
self.class.excel_class
|
@@ -1097,11 +1035,6 @@ module RobustExcelOle
|
|
1097
1035
|
self.class.worksheet_class
|
1098
1036
|
end
|
1099
1037
|
|
1100
|
-
# @private
|
1101
|
-
def address_class
|
1102
|
-
self.class.address_class
|
1103
|
-
end
|
1104
|
-
|
1105
1038
|
include MethodHelpers
|
1106
1039
|
|
1107
1040
|
private
|
@@ -1109,7 +1042,7 @@ module RobustExcelOle
|
|
1109
1042
|
def method_missing(name, *args)
|
1110
1043
|
if name.to_s[0,1] =~ /[A-Z]/
|
1111
1044
|
raise ObjectNotAlive, 'method missing: workbook not alive' unless alive?
|
1112
|
-
if
|
1045
|
+
if ::ERRORMESSAGE_JRUBY_BUG
|
1113
1046
|
begin
|
1114
1047
|
@ole_workbook.send(name, *args)
|
1115
1048
|
rescue Java::OrgRacobCom::ComFailException
|
@@ -1131,6 +1064,47 @@ module RobustExcelOle
|
|
1131
1064
|
|
1132
1065
|
public
|
1133
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
|
+
|
1134
1108
|
Book = Workbook
|
1135
1109
|
|
1136
1110
|
end
|