robust_excel_ole 1.16 → 1.17
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/docs/README_open.rdoc +4 -0
- data/lib/robust_excel_ole.rb +5 -4
- 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 +2 -2
- data/lib/robust_excel_ole/cell.rb +21 -17
- data/lib/robust_excel_ole/excel.rb +64 -26
- data/lib/robust_excel_ole/general.rb +7 -5
- data/lib/robust_excel_ole/range.rb +15 -7
- data/lib/robust_excel_ole/range_owners.rb +18 -6
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +140 -147
- data/lib/robust_excel_ole/worksheet.rb +7 -7
- data/spec/address_tool_spec.rb +175 -0
- data/spec/{reo_common_spec.rb → base_spec.rb} +10 -29
- data/spec/cell_spec.rb +67 -25
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/data/workbook.xls +0 -0
- data/spec/excel_spec.rb +25 -273
- data/spec/general_spec.rb +16 -19
- data/spec/range_spec.rb +1 -1
- data/spec/workbook_spec.rb +7 -75
- data/spec/workbook_specs/workbook_misc_spec.rb +10 -10
- data/spec/workbook_specs/workbook_open_spec.rb +228 -14
- data/spec/workbook_specs/workbook_unobtr_spec.rb +31 -31
- metadata +6 -6
- data/spec/address_spec.rb +0 -174
@@ -95,26 +95,28 @@ end
|
|
95
95
|
|
96
96
|
# @private
|
97
97
|
class WIN32OLE
|
98
|
-
|
99
|
-
include RobustExcelOle
|
100
98
|
|
101
99
|
# type-lifting WIN32OLE objects to RobustExcelOle objects
|
102
100
|
def to_reo
|
103
|
-
class2method = [{Excel => :Hwnd}, {Workbook => :FullName}, {Worksheet => :Copy}, {Range => :
|
101
|
+
class2method = [{Excel => :Hwnd}, {Workbook => :FullName}, {Worksheet => :Copy}, {RobustExcelOle::Range => :Row}]
|
104
102
|
class2method.each do |element|
|
105
103
|
classname = element.first.first
|
106
104
|
method = element.first.last
|
107
105
|
begin
|
108
106
|
self.send(method)
|
109
|
-
|
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
|
110
112
|
rescue
|
111
113
|
next
|
112
114
|
end
|
113
115
|
end
|
116
|
+
raise TypeREOError, "given object cannot be type-lifted to a RobustExcelOle object"
|
114
117
|
end
|
115
118
|
end
|
116
119
|
|
117
|
-
|
118
120
|
# @private
|
119
121
|
class ::String
|
120
122
|
def / path_part
|
@@ -6,7 +6,7 @@ module RobustExcelOle
|
|
6
6
|
# that you would apply for a Range object.
|
7
7
|
# See https://docs.microsoft.com/en-us/office/vba/api/excel.worksheet#methods
|
8
8
|
|
9
|
-
class Range <
|
9
|
+
class Range < VbaObjects
|
10
10
|
include Enumerable
|
11
11
|
attr_reader :ole_range
|
12
12
|
attr_reader :worksheet
|
@@ -48,7 +48,7 @@ module RobustExcelOle
|
|
48
48
|
self.Value
|
49
49
|
else
|
50
50
|
address_r1c1 = self.AddressLocal(true,true,XlR1C1)
|
51
|
-
row, col =
|
51
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
52
52
|
values = []
|
53
53
|
row.each do |r|
|
54
54
|
values_col = []
|
@@ -69,7 +69,7 @@ module RobustExcelOle
|
|
69
69
|
ole_range.Value = value
|
70
70
|
else
|
71
71
|
address_r1c1 = ole_range.AddressLocal(true,true,XlR1C1)
|
72
|
-
row, col =
|
72
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
73
73
|
row.each_with_index do |r,i|
|
74
74
|
col.each_with_index do |c,j|
|
75
75
|
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value)
|
@@ -115,8 +115,7 @@ module RobustExcelOle
|
|
115
115
|
{ }
|
116
116
|
end
|
117
117
|
end
|
118
|
-
rows, columns =
|
119
|
-
#dest_sheet = @worksheet if dest_sheet == :__not_provided
|
118
|
+
rows, columns = address_tool.as_integer_ranges(dest_address)
|
120
119
|
dest_address_is_position = (rows.min == rows.max && columns.min == columns.max)
|
121
120
|
dest_range_address = if (not dest_address_is_position)
|
122
121
|
[rows.min..rows.max,columns.min..columns.max]
|
@@ -168,7 +167,7 @@ module RobustExcelOle
|
|
168
167
|
# @options [Worksheet] the destination worksheet
|
169
168
|
# @options [Hash] options: :transpose, :values_only
|
170
169
|
def copy_special(dest_address, dest_sheet = :__not_provided, options = { })
|
171
|
-
rows, columns =
|
170
|
+
rows, columns = address_tool.as_integer_ranges(dest_address)
|
172
171
|
dest_sheet = @worksheet if dest_sheet == :__not_provided
|
173
172
|
dest_address_is_position = (rows.min == rows.max && columns.min == columns.max)
|
174
173
|
dest_range_address = if (not dest_address_is_position)
|
@@ -220,6 +219,11 @@ module RobustExcelOle
|
|
220
219
|
self.Address == other_range.Address
|
221
220
|
end
|
222
221
|
|
222
|
+
# @private
|
223
|
+
def excel
|
224
|
+
@worksheet.workbook.excel
|
225
|
+
end
|
226
|
+
|
223
227
|
# @private
|
224
228
|
def self.worksheet_class
|
225
229
|
@worksheet_class ||= begin
|
@@ -237,7 +241,6 @@ module RobustExcelOle
|
|
237
241
|
|
238
242
|
private
|
239
243
|
|
240
|
-
# @private
|
241
244
|
def method_missing(name, *args)
|
242
245
|
if name.to_s[0,1] =~ /[A-Z]/
|
243
246
|
if ::ERRORMESSAGE_JRUBY_BUG
|
@@ -258,4 +261,9 @@ module RobustExcelOle
|
|
258
261
|
end
|
259
262
|
end
|
260
263
|
end
|
264
|
+
|
265
|
+
# @private
|
266
|
+
class RangeNotCopied < MiscREOError
|
267
|
+
end
|
268
|
+
|
261
269
|
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,
|
@@ -75,7 +75,7 @@ module RobustExcelOle
|
|
75
75
|
ole_range.Value = value
|
76
76
|
else
|
77
77
|
address_r1c1 = ole_range.AddressLocal(true,true,XlR1C1)
|
78
|
-
row, col =
|
78
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
79
79
|
row.each_with_index do |r,i|
|
80
80
|
col.each_with_index do |c,j|
|
81
81
|
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value )
|
@@ -141,7 +141,7 @@ module RobustExcelOle
|
|
141
141
|
ole_range.Value = value
|
142
142
|
else
|
143
143
|
address_r1c1 = ole_range.AddressLocal(true,true,XlR1C1)
|
144
|
-
row, col =
|
144
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
145
145
|
row.each_with_index do |r,i|
|
146
146
|
col.each_with_index do |c,j|
|
147
147
|
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value)
|
@@ -192,7 +192,7 @@ module RobustExcelOle
|
|
192
192
|
if self.is_a?(Worksheet) && (range.nil? || (address2 != :__not_provided))
|
193
193
|
address = name_or_address
|
194
194
|
address = [name_or_address,address2] unless address2 == :__not_provided
|
195
|
-
self.Names.Add('__dummy001',nil,true,nil,nil,nil,nil,nil,nil,'=' +
|
195
|
+
self.Names.Add('__dummy001',nil,true,nil,nil,nil,nil,nil,nil,'=' + address_tool.as_r1c1(address))
|
196
196
|
range = RobustExcelOle::Range.new(name_object('__dummy001').RefersToRange)
|
197
197
|
self.Names.Item('__dummy001').Delete
|
198
198
|
workbook = self.is_a?(Workbook) ? self : self.workbook
|
@@ -216,7 +216,7 @@ module RobustExcelOle
|
|
216
216
|
def add_name(name, addr, addr_deprecated = :__not_provided)
|
217
217
|
addr = [addr,addr_deprecated] unless addr_deprecated == :__not_provided
|
218
218
|
begin
|
219
|
-
self.Names.Add(name, nil, true, nil, nil, nil, nil, nil, nil, '=' +
|
219
|
+
self.Names.Add(name, nil, true, nil, nil, nil, nil, nil, nil, '=' + address_tool.as_r1c1(addr))
|
220
220
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
221
221
|
raise RangeNotEvaluatable, "cannot add name #{name.inspect} to range #{addr.inspect}"
|
222
222
|
end
|
@@ -257,7 +257,7 @@ module RobustExcelOle
|
|
257
257
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
258
258
|
raise UnexpectedREOError, "name error in #{File.basename(self.stored_filename).inspect}"
|
259
259
|
end
|
260
|
-
end
|
260
|
+
end
|
261
261
|
|
262
262
|
private
|
263
263
|
|
@@ -273,4 +273,16 @@ module RobustExcelOle
|
|
273
273
|
|
274
274
|
end
|
275
275
|
|
276
|
+
# @private
|
277
|
+
class NameNotFound < NamesREOError
|
278
|
+
end
|
279
|
+
|
280
|
+
# @private
|
281
|
+
class NameAlreadyExists < NamesREOError
|
282
|
+
end
|
283
|
+
|
284
|
+
# @private
|
285
|
+
class RangeNotCreated < MiscREOError
|
286
|
+
end
|
287
|
+
|
276
288
|
end
|
@@ -22,7 +22,7 @@ module RobustExcelOle
|
|
22
22
|
CORE_DEFAULT_OPEN_OPTS = {
|
23
23
|
:default => {:excel => :current},
|
24
24
|
:force => {},
|
25
|
-
:update_links => :never
|
25
|
+
:update_links => :never
|
26
26
|
}.freeze
|
27
27
|
|
28
28
|
DEFAULT_OPEN_OPTS = {
|
@@ -85,7 +85,7 @@ module RobustExcelOle
|
|
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
87
|
# @return [Workbook] a representation of a workbook
|
88
|
-
def self.new(file_or_workbook, opts = { }
|
88
|
+
def self.new(file_or_workbook, opts = { })
|
89
89
|
process_options(opts)
|
90
90
|
case file_or_workbook
|
91
91
|
when NilClass
|
@@ -93,7 +93,7 @@ module RobustExcelOle
|
|
93
93
|
when WIN32OLE
|
94
94
|
file = file_or_workbook.Fullname.tr('\\','/')
|
95
95
|
when Workbook
|
96
|
-
|
96
|
+
file = file_or_workbook.Fullname.tr('\\','/')
|
97
97
|
when String
|
98
98
|
file = file_or_workbook
|
99
99
|
raise FileNotFound, "file #{General.absolute_path(file).inspect} is a directory" if File.directory?(file)
|
@@ -105,9 +105,12 @@ module RobustExcelOle
|
|
105
105
|
book = nil
|
106
106
|
if opts[:force][:excel] != :new
|
107
107
|
# if readonly is true, then prefer a book that is given in force_excel if this option is set
|
108
|
-
forced_excel =
|
108
|
+
forced_excel = begin
|
109
109
|
(opts[:force][:excel].nil? || opts[:force][:excel] == :current) ?
|
110
|
-
(excel_class.new(:reuse => true) if !::CONNECT_JRUBY_BUG) :
|
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
|
111
114
|
begin
|
112
115
|
book = if File.exists?(file)
|
113
116
|
bookstore.fetch(file, :prefer_writable => !(opts[:read_only]),
|
@@ -115,7 +118,7 @@ module RobustExcelOle
|
|
115
118
|
end
|
116
119
|
rescue
|
117
120
|
raise
|
118
|
-
trace "#{$!.message}"
|
121
|
+
#trace "#{$!.message}"
|
119
122
|
end
|
120
123
|
if book
|
121
124
|
set_was_open opts, book.alive?
|
@@ -125,12 +128,12 @@ module RobustExcelOle
|
|
125
128
|
!(book.alive? && !book.saved && (opts[:if_unsaved] != :accept))
|
126
129
|
opts[:force][:excel] = book.excel if book.excel && book.excel.alive?
|
127
130
|
book.ensure_workbook(file,opts)
|
128
|
-
book.
|
131
|
+
book.send :apply_options, file, opts
|
129
132
|
return book
|
130
133
|
end
|
131
134
|
end
|
132
135
|
end
|
133
|
-
super(file_or_workbook, opts
|
136
|
+
super(file_or_workbook, opts)
|
134
137
|
end
|
135
138
|
|
136
139
|
singleton_class.send :alias_method, :open, :new
|
@@ -141,25 +144,23 @@ module RobustExcelOle
|
|
141
144
|
# @param [Hash] opts
|
142
145
|
# @option opts [Symbol] see above
|
143
146
|
# @return [Workbook] a workbook
|
144
|
-
def initialize(file_or_workbook,
|
147
|
+
def initialize(file_or_workbook, opts)
|
145
148
|
if file_or_workbook.is_a? WIN32OLE
|
146
149
|
@ole_workbook = file_or_workbook
|
147
|
-
ole_excel = begin
|
148
|
-
|
149
|
-
rescue
|
150
|
+
ole_excel = begin
|
151
|
+
@ole_workbook.Application
|
152
|
+
rescue WIN32OLERuntimeError
|
150
153
|
raise ExcelREOError, 'could not determine the Excel instance'
|
151
154
|
end
|
152
155
|
@excel = excel_class.new(ole_excel)
|
153
|
-
filename =
|
156
|
+
filename = @ole_workbook.Fullname.tr('\\','/')
|
154
157
|
else
|
155
158
|
filename = file_or_workbook
|
156
|
-
ensure_workbook(filename,
|
159
|
+
ensure_workbook(filename, opts)
|
157
160
|
end
|
158
|
-
|
161
|
+
apply_options(filename, opts)
|
159
162
|
store_myself
|
160
|
-
|
161
|
-
address_class.new(r1c1_letters)
|
162
|
-
if block
|
163
|
+
if block_given?
|
163
164
|
begin
|
164
165
|
yield self
|
165
166
|
ensure
|
@@ -170,28 +171,21 @@ module RobustExcelOle
|
|
170
171
|
|
171
172
|
private
|
172
173
|
|
173
|
-
# @private
|
174
174
|
def self.set_was_open(hash, value)
|
175
175
|
hash[:was_open] = value if hash.has_key?(:was_open)
|
176
176
|
end
|
177
177
|
|
178
|
-
# @private
|
179
178
|
def set_was_open(hash, value)
|
180
179
|
self.class.set_was_open(hash, value)
|
181
180
|
end
|
182
181
|
|
183
|
-
# @private
|
184
|
-
# translates abbreviations and synonyms and merges with default options
|
185
182
|
def self.process_options(opts, proc_opts = {:use_defaults => true})
|
186
183
|
translate(opts)
|
187
184
|
default_opts = (proc_opts[:use_defaults] ? DEFAULT_OPEN_OPTS : CORE_DEFAULT_OPEN_OPTS).dup
|
188
185
|
translate(default_opts)
|
189
|
-
opts.merge!(default_opts) {|key, v1, v2| v1 }
|
190
|
-
opts[:default] = default_opts[:default].merge(opts[:default]) unless opts[:default].nil?
|
191
|
-
opts[:force] = default_opts[:force].merge(opts[:force]) unless opts[:force].nil?
|
186
|
+
opts.merge!(default_opts) { |key, v1, v2| !v2.is_a?(Hash) ? v1 : v2.merge(v1 || {}) }
|
192
187
|
end
|
193
188
|
|
194
|
-
# @private
|
195
189
|
def self.translate(opts)
|
196
190
|
erg = {}
|
197
191
|
opts.each do |key,value|
|
@@ -219,34 +213,26 @@ module RobustExcelOle
|
|
219
213
|
opts[:force][:excel] = :current if opts[:force][:excel] == :reuse || opts[:force][:excel] == :active
|
220
214
|
end
|
221
215
|
|
222
|
-
# returns an Excel object when given Excel, Workbook or Win32ole object representing a Workbook or an Excel
|
223
|
-
# @private
|
224
|
-
def self.excel_of(object)
|
225
|
-
begin
|
226
|
-
object = object.to_reo if object.is_a? WIN32OLE
|
227
|
-
object.excel
|
228
|
-
rescue
|
229
|
-
raise TypeREOError, 'given object is neither an Excel, a Workbook, nor a Win32ole'
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
216
|
public
|
234
217
|
|
235
218
|
# @private
|
236
219
|
# ensures an excel but not for jruby if current Excel shall be used
|
237
220
|
def ensure_excel(options)
|
238
221
|
return if @excel && @excel.alive?
|
239
|
-
excel_option = options[:force][:excel]
|
222
|
+
excel_option = options[:force][:excel] || options[:default][:excel] || :current
|
240
223
|
@excel = if excel_option == :new
|
241
224
|
excel_class.new(:reuse => false)
|
242
|
-
elsif excel_option
|
225
|
+
elsif excel_option == :current
|
243
226
|
excel_class.new(:reuse => true)
|
227
|
+
elsif excel_option.respond_to?(:to_reo)
|
228
|
+
excel_option.to_reo.excel
|
244
229
|
else
|
245
|
-
|
230
|
+
raise TypeREOError, "provided Excel option value is neither an Excel object nor a valid option"
|
246
231
|
end
|
247
|
-
raise ExcelREOError, "
|
232
|
+
raise ExcelREOError, "Excel is not alive" unless @excel && @excel.alive?
|
248
233
|
end
|
249
234
|
|
235
|
+
|
250
236
|
# @private
|
251
237
|
def ensure_workbook(filename, options)
|
252
238
|
set_was_open options, true
|
@@ -263,12 +249,12 @@ module RobustExcelOle
|
|
263
249
|
workbooks = @excel.Workbooks
|
264
250
|
@ole_workbook = workbooks.Item(File.basename(filename)) rescue nil if @ole_workbook.nil?
|
265
251
|
if @ole_workbook && alive?
|
266
|
-
set_was_open options, true
|
252
|
+
set_was_open options, true
|
267
253
|
manage_blocking_or_unsaved_workbook(filename,options)
|
268
254
|
open_or_create_workbook(filename,options) if @ole_workbook.ReadOnly != options[:read_only]
|
269
255
|
else
|
270
|
-
if excel_option.nil? || excel_option == :current &&
|
271
|
-
(
|
256
|
+
if (excel_option.nil? || excel_option == :current) &&
|
257
|
+
!(::CONNECT_JRUBY_BUG && filename[0] == '/')
|
272
258
|
connect(filename,options)
|
273
259
|
else
|
274
260
|
open_or_create_workbook(filename,options)
|
@@ -276,11 +262,14 @@ module RobustExcelOle
|
|
276
262
|
end
|
277
263
|
end
|
278
264
|
|
279
|
-
|
280
|
-
|
281
|
-
|
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
|
282
271
|
if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
283
|
-
ensure_workbook(filename, options)
|
272
|
+
ensure_workbook(filename, options)
|
284
273
|
end
|
285
274
|
retain_saved do
|
286
275
|
self.visible = options[:force][:visible].nil? ? @excel.Visible : options[:force][:visible]
|
@@ -289,36 +278,32 @@ module RobustExcelOle
|
|
289
278
|
end
|
290
279
|
end
|
291
280
|
|
292
|
-
private
|
293
|
-
|
294
|
-
# @private
|
295
281
|
# connects to an unknown workbook
|
296
|
-
def connect(filename,options)
|
282
|
+
def connect(filename, options)
|
297
283
|
workbooks_number = excel_class.excels_number==0 ? 0 : excel_class.current.Workbooks.Count
|
298
284
|
@ole_workbook = begin
|
299
285
|
WIN32OLE.connect(General.absolute_path(filename))
|
300
286
|
rescue
|
301
287
|
if $!.message =~ /moniker/
|
302
|
-
raise WorkbookConnectingBlockingError
|
303
|
-
else
|
304
|
-
raise WorkbookConnectingUnknownError
|
288
|
+
raise WorkbookConnectingBlockingError, "some workbook is blocking when connecting"
|
289
|
+
else
|
290
|
+
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook"
|
305
291
|
end
|
306
292
|
end
|
307
293
|
ole_excel = begin
|
308
294
|
@ole_workbook.Application
|
309
295
|
rescue
|
310
296
|
if $!.message =~ /dispid/
|
311
|
-
raise WorkbookConnectingUnsavedError
|
312
|
-
else
|
313
|
-
raise WorkbookConnectingUnknownError
|
297
|
+
raise WorkbookConnectingUnsavedError, "workbook is unsaved when connecting"
|
298
|
+
else
|
299
|
+
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook"
|
314
300
|
end
|
315
301
|
end
|
316
302
|
set_was_open options, (ole_excel.Workbooks.Count == workbooks_number)
|
317
303
|
@excel = excel_class.new(ole_excel)
|
318
304
|
end
|
319
305
|
|
320
|
-
|
321
|
-
def manage_nonexisting_file(filename,options)
|
306
|
+
def manage_nonexisting_file(filename, options)
|
322
307
|
return if File.exist?(filename)
|
323
308
|
abs_filename = General.absolute_path(filename)
|
324
309
|
if options[:if_absent] == :create
|
@@ -336,8 +321,7 @@ module RobustExcelOle
|
|
336
321
|
end
|
337
322
|
end
|
338
323
|
|
339
|
-
|
340
|
-
def manage_blocking_or_unsaved_workbook(filename,options)
|
324
|
+
def manage_blocking_or_unsaved_workbook(filename, options)
|
341
325
|
filename = General.absolute_path(filename)
|
342
326
|
filename = General.canonize(filename)
|
343
327
|
previous_file = General.canonize(@ole_workbook.Fullname)
|
@@ -354,8 +338,7 @@ module RobustExcelOle
|
|
354
338
|
end
|
355
339
|
end
|
356
340
|
|
357
|
-
|
358
|
-
def manage_blocking_workbook(filename,options)
|
341
|
+
def manage_blocking_workbook(filename, options)
|
359
342
|
case options[:if_obstructed]
|
360
343
|
when :raise
|
361
344
|
raise WorkbookBlocked, "can't open workbook #{filename},
|
@@ -369,7 +352,8 @@ module RobustExcelOle
|
|
369
352
|
manage_saving_workbook(filename, options)
|
370
353
|
when :close_if_saved
|
371
354
|
if !@ole_workbook.Saved
|
372
|
-
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"
|
373
357
|
else
|
374
358
|
manage_forgetting_workbook(filename, options)
|
375
359
|
end
|
@@ -381,15 +365,14 @@ module RobustExcelOle
|
|
381
365
|
end
|
382
366
|
end
|
383
367
|
|
384
|
-
|
385
|
-
def manage_unsaved_workbook(filename,options)
|
368
|
+
def manage_unsaved_workbook(filename, options)
|
386
369
|
case options[:if_unsaved]
|
387
370
|
when :raise
|
388
371
|
raise WorkbookNotSaved, "workbook is already open but not saved: #{File.basename(filename).inspect}" +
|
389
372
|
"\nHint: Save the workbook or open the workbook using option :if_unsaved with values :forget and :accept to
|
390
373
|
close the unsaved workbook and reopen it, or to let the unsaved workbook open, respectively"
|
391
374
|
when :forget
|
392
|
-
manage_forgetting_workbook(filename,options)
|
375
|
+
manage_forgetting_workbook(filename, options)
|
393
376
|
when :accept
|
394
377
|
# do nothing
|
395
378
|
when :save
|
@@ -404,27 +387,23 @@ module RobustExcelOle
|
|
404
387
|
end
|
405
388
|
end
|
406
389
|
|
407
|
-
# @private
|
408
390
|
def manage_forgetting_workbook(filename, options)
|
409
391
|
@excel.with_displayalerts(false) { @ole_workbook.Close }
|
410
392
|
@ole_workbook = nil
|
411
393
|
open_or_create_workbook(filename, options)
|
412
394
|
end
|
413
395
|
|
414
|
-
# @private
|
415
396
|
def manage_saving_workbook(filename, options)
|
416
397
|
save unless @ole_workbook.Saved
|
417
398
|
manage_forgetting_workbook(filename, options)
|
418
399
|
end
|
419
400
|
|
420
|
-
# @private
|
421
401
|
def manage_new_excel(filename, options)
|
422
402
|
@excel = excel_class.new(:reuse => false)
|
423
403
|
@ole_workbook = nil
|
424
404
|
open_or_create_workbook(filename, options)
|
425
405
|
end
|
426
406
|
|
427
|
-
# @private
|
428
407
|
def open_or_create_workbook(filename, options)
|
429
408
|
return if @ole_workbook && options[:if_unsaved] != :alert && options[:if_unsaved] != :excel &&
|
430
409
|
(options[:read_only].nil? || options[:read_only]==@ole_workbook.ReadOnly )
|
@@ -460,7 +439,6 @@ module RobustExcelOle
|
|
460
439
|
end
|
461
440
|
end
|
462
441
|
|
463
|
-
# @private
|
464
442
|
# translating the option UpdateLinks from REO to VBA
|
465
443
|
# setting UpdateLinks works only if calculation mode is automatic,
|
466
444
|
# parameter 'UpdateLinks' has no effect
|
@@ -473,7 +451,6 @@ module RobustExcelOle
|
|
473
451
|
end
|
474
452
|
end
|
475
453
|
|
476
|
-
# @private
|
477
454
|
# workaround for linked workbooks for Excel 2007:
|
478
455
|
# opening and closing a dummy workbook if Excel has no workbooks.
|
479
456
|
# delay: with visible: 0.2 sec, without visible almost none
|
@@ -537,13 +514,10 @@ module RobustExcelOle
|
|
537
514
|
else
|
538
515
|
close_workbook
|
539
516
|
end
|
540
|
-
# trace "close: canceled by user" if alive? &&
|
541
|
-
# (opts[:if_unsaved] == :alert || opts[:if_unsaved] == :excel) && (not @ole_workbook.Saved)
|
542
517
|
end
|
543
518
|
|
544
519
|
private
|
545
520
|
|
546
|
-
# @private
|
547
521
|
def close_workbook
|
548
522
|
@ole_workbook.Close if alive?
|
549
523
|
@ole_workbook = nil unless alive?
|
@@ -596,7 +570,8 @@ module RobustExcelOle
|
|
596
570
|
self.class.unobtrusively_opening(file, opts, alive?, &block)
|
597
571
|
end
|
598
572
|
|
599
|
-
|
573
|
+
private
|
574
|
+
|
600
575
|
def self.unobtrusively_opening(file, opts, book_is_alive, &block)
|
601
576
|
process_options(opts)
|
602
577
|
opts = {:if_closed => :current, :keep_open => false}.merge(opts)
|
@@ -620,15 +595,15 @@ module RobustExcelOle
|
|
620
595
|
was_saved = book.saved
|
621
596
|
was_check_compatibility = book.check_compatibility
|
622
597
|
was_calculation = book.excel.properties[:calculation]
|
623
|
-
book.
|
598
|
+
book.send :apply_options, file, opts
|
624
599
|
yield book
|
625
600
|
ensure
|
626
601
|
if book && book.alive?
|
627
602
|
do_not_write = opts[:read_only] || opts[:writable]==false
|
628
603
|
book.save unless book.saved || do_not_write || !book.writable
|
629
604
|
if (opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable)
|
630
|
-
book.
|
631
|
-
|
605
|
+
book.send :apply_options, file, opts.merge({:read_only => !was_writable,
|
606
|
+
:if_unsaved => (opts[:writable]==false ? :forget : :save)})
|
632
607
|
end
|
633
608
|
was_open = open_opts[:was_open]
|
634
609
|
if was_open
|
@@ -642,6 +617,8 @@ module RobustExcelOle
|
|
642
617
|
end
|
643
618
|
end
|
644
619
|
|
620
|
+
public
|
621
|
+
|
645
622
|
# reopens a closed workbook
|
646
623
|
# @options options
|
647
624
|
def reopen(options = { })
|
@@ -655,10 +632,6 @@ module RobustExcelOle
|
|
655
632
|
def save(opts = { }) # option opts is deprecated #
|
656
633
|
raise ObjectNotAlive, 'workbook is not alive' unless alive?
|
657
634
|
raise WorkbookReadOnly, 'Not opened for writing (opened with :read_only option)' if @ole_workbook.ReadOnly
|
658
|
-
# if you have open the workbook with :read_only => true,
|
659
|
-
# then you could close the workbook and open it again with option :read_only => false
|
660
|
-
# otherwise the workbook may already be open writable in an another Excel instance
|
661
|
-
# then you could use this workbook or close the workbook there
|
662
635
|
begin
|
663
636
|
@ole_workbook.Save
|
664
637
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
@@ -748,12 +721,6 @@ module RobustExcelOle
|
|
748
721
|
|
749
722
|
private
|
750
723
|
|
751
|
-
def store_myself
|
752
|
-
bookstore.store(self)
|
753
|
-
@stored_filename = filename
|
754
|
-
end
|
755
|
-
|
756
|
-
# @private
|
757
724
|
def save_as_workbook(file, options)
|
758
725
|
dirname, basename = File.split(file)
|
759
726
|
file_format =
|
@@ -773,6 +740,11 @@ module RobustExcelOle
|
|
773
740
|
end
|
774
741
|
end
|
775
742
|
|
743
|
+
def store_myself
|
744
|
+
bookstore.store(self)
|
745
|
+
@stored_filename = filename
|
746
|
+
end
|
747
|
+
|
776
748
|
public
|
777
749
|
|
778
750
|
# closes a given file if it is open
|
@@ -842,35 +814,23 @@ module RobustExcelOle
|
|
842
814
|
last_sheet_local = last_sheet
|
843
815
|
after_or_before, base_sheet = opts.to_a.first || [:after, last_sheet_local]
|
844
816
|
begin
|
845
|
-
if !::COPYSHEETS_JRUBY_BUG
|
846
|
-
if sheet
|
847
|
-
|
848
|
-
else
|
849
|
-
|
850
|
-
|
851
|
-
|
817
|
+
if !::COPYSHEETS_JRUBY_BUG
|
818
|
+
#if sheet
|
819
|
+
# sheet.Copy({ after_or_before.to_s => base_sheet.ole_worksheet })
|
820
|
+
#else
|
821
|
+
# ole_workbook.Worksheets.Add({ after_or_before.to_s => base_sheet.ole_worksheet })
|
822
|
+
#end
|
823
|
+
add_or_copy_sheet_simple(sheet, { after_or_before.to_s => base_sheet.ole_worksheet })
|
852
824
|
else
|
853
825
|
if after_or_before == :before
|
854
|
-
|
855
|
-
|
856
|
-
else
|
857
|
-
ole_workbook.Worksheets.Add(base_sheet.ole_worksheet)
|
858
|
-
end
|
826
|
+
#add_or_copy_sheet_simple(sheet,base_sheet)
|
827
|
+
add_or_copy_sheet_simple(sheet, base_sheet.ole_worksheet)
|
859
828
|
else
|
860
|
-
#not_given = WIN32OLE_VARIANT.new(nil, WIN32OLE::VARIANT::VT_NULL)
|
861
|
-
#ole_workbook.Worksheets.Add(not_given,base_sheet.ole_worksheet)
|
862
829
|
if base_sheet.name != last_sheet_local.name
|
863
|
-
|
864
|
-
sheet.Copy(base_sheet.Next)
|
865
|
-
else
|
866
|
-
ole_workbook.Worksheets.Add(base_sheet.Next)
|
867
|
-
end
|
830
|
+
add_or_copy_sheet_simple(sheet, base_sheet.Next)
|
868
831
|
else
|
869
|
-
|
870
|
-
|
871
|
-
else
|
872
|
-
ole_workbook.Worksheets.Add(base_sheet.ole_worksheet)
|
873
|
-
end
|
832
|
+
#add_or_copy_sheet_simple(sheet,base_sheet)
|
833
|
+
add_or_copy_sheet_simple(sheet, base_sheet.ole_worksheet)
|
874
834
|
base_sheet.Move(ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count-1))
|
875
835
|
ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count).Activate
|
876
836
|
end
|
@@ -879,12 +839,31 @@ module RobustExcelOle
|
|
879
839
|
rescue WIN32OLERuntimeError, NameNotFound, Java::OrgRacobCom::ComFailException
|
880
840
|
raise WorksheetREOError, "could not add given worksheet #{sheet.inspect}"
|
881
841
|
end
|
882
|
-
|
883
|
-
new_sheet = worksheet_class.new(ole_sheet)
|
842
|
+
new_sheet = worksheet_class.new(ole_workbook.Activesheet)
|
884
843
|
new_sheet.name = new_sheet_name if new_sheet_name
|
885
844
|
new_sheet
|
886
845
|
end
|
887
846
|
|
847
|
+
private
|
848
|
+
|
849
|
+
#def add_or_copy_sheet_simple(sheet, base_sheet)
|
850
|
+
# if sheet
|
851
|
+
# sheet.Copy(base_sheet.ole_worksheet)
|
852
|
+
# else
|
853
|
+
# ole_workbook.Worksheets.Add(base_sheet.ole_worksheet)
|
854
|
+
# end
|
855
|
+
#end
|
856
|
+
|
857
|
+
def add_or_copy_sheet_simple(sheet, base_ole_worksheet)
|
858
|
+
if sheet
|
859
|
+
sheet.Copy(base_ole_worksheet)
|
860
|
+
else
|
861
|
+
ole_workbook.Worksheets.Add(base_ole_worksheet)
|
862
|
+
end
|
863
|
+
end
|
864
|
+
|
865
|
+
public
|
866
|
+
|
888
867
|
# for compatibility to older versions
|
889
868
|
def add_sheet(sheet = nil, opts = { })
|
890
869
|
add_or_copy_sheet(sheet, opts)
|
@@ -914,7 +893,7 @@ module RobustExcelOle
|
|
914
893
|
# @param [String] name the name of the range
|
915
894
|
# @param [Variant] value the contents of the range
|
916
895
|
def []= (name, value)
|
917
|
-
set_namevalue_glob(name,value
|
896
|
+
set_namevalue_glob(name, value, :color => 42)
|
918
897
|
end
|
919
898
|
|
920
899
|
# sets options
|
@@ -922,19 +901,7 @@ module RobustExcelOle
|
|
922
901
|
def for_this_workbook(opts)
|
923
902
|
return unless alive?
|
924
903
|
self.class.process_options(opts, :use_defaults => false)
|
925
|
-
|
926
|
-
check_compatibility_before = check_compatibility
|
927
|
-
unless opts[:read_only].nil?
|
928
|
-
# if the ReadOnly status shall be changed, then close and reopen it
|
929
|
-
if (!writable && !(opts[:read_only])) || (writable && opts[:read_only])
|
930
|
-
opts[:check_compatibility] = check_compatibility if opts[:check_compatibility].nil?
|
931
|
-
close(:if_unsaved => true)
|
932
|
-
open_or_create_workbook(@stored_filename, opts)
|
933
|
-
end
|
934
|
-
end
|
935
|
-
self.visible = opts[:force][:visible].nil? ? visible_before : opts[:force][:visible]
|
936
|
-
self.CheckCompatibility = opts[:check_compatibility].nil? ? check_compatibility_before : opts[:check_compatibility]
|
937
|
-
@excel.calculation = opts[:calculation] unless opts[:calculation].nil?
|
904
|
+
self.send :apply_options, @stored_filename, opts
|
938
905
|
end
|
939
906
|
|
940
907
|
# brings workbook to foreground, makes it available for heyboard inputs, makes the Excel instance visible
|
@@ -950,7 +917,6 @@ module RobustExcelOle
|
|
950
917
|
true
|
951
918
|
rescue
|
952
919
|
@ole_workbook = nil # dead object won't be alive again
|
953
|
-
# t $!.message
|
954
920
|
false
|
955
921
|
end
|
956
922
|
|
@@ -1012,6 +978,7 @@ module RobustExcelOle
|
|
1012
978
|
self.filename == other_book.filename
|
1013
979
|
end
|
1014
980
|
|
981
|
+
# @private
|
1015
982
|
def self.books
|
1016
983
|
bookstore.books
|
1017
984
|
end
|
@@ -1062,16 +1029,6 @@ module RobustExcelOle
|
|
1062
1029
|
end
|
1063
1030
|
end
|
1064
1031
|
|
1065
|
-
# @private
|
1066
|
-
def self.address_class
|
1067
|
-
@address_class ||= begin
|
1068
|
-
module_name = self.parent_name
|
1069
|
-
"#{module_name}::Address".constantize
|
1070
|
-
rescue NameError => e
|
1071
|
-
Address
|
1072
|
-
end
|
1073
|
-
end
|
1074
|
-
|
1075
1032
|
# @private
|
1076
1033
|
def excel_class
|
1077
1034
|
self.class.excel_class
|
@@ -1082,11 +1039,6 @@ module RobustExcelOle
|
|
1082
1039
|
self.class.worksheet_class
|
1083
1040
|
end
|
1084
1041
|
|
1085
|
-
# @private
|
1086
|
-
def address_class
|
1087
|
-
self.class.address_class
|
1088
|
-
end
|
1089
|
-
|
1090
1042
|
include MethodHelpers
|
1091
1043
|
|
1092
1044
|
private
|
@@ -1116,6 +1068,47 @@ module RobustExcelOle
|
|
1116
1068
|
|
1117
1069
|
public
|
1118
1070
|
|
1071
|
+
# @private
|
1072
|
+
class WorkbookBlocked < WorkbookREOError
|
1073
|
+
end
|
1074
|
+
|
1075
|
+
# @private
|
1076
|
+
class WorkbookNotSaved < WorkbookREOError
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
# @private
|
1080
|
+
class WorkbookReadOnly < WorkbookREOError
|
1081
|
+
end
|
1082
|
+
|
1083
|
+
# @private
|
1084
|
+
class WorkbookBeingUsed < WorkbookREOError
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
# @private
|
1088
|
+
class WorkbookConnectingUnsavedError < WorkbookREOError
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
# @private
|
1092
|
+
class WorkbookConnectingBlockingError < WorkbookREOError
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
# @private
|
1096
|
+
class WorkbookConnectingUnknownError < WorkbookREOError
|
1097
|
+
end
|
1098
|
+
|
1099
|
+
# @private
|
1100
|
+
class FileAlreadyExists < FileREOError
|
1101
|
+
end
|
1102
|
+
|
1103
|
+
# @private
|
1104
|
+
class FileNameNotGiven < FileREOError
|
1105
|
+
end
|
1106
|
+
|
1107
|
+
# @private
|
1108
|
+
class FileNotFound < FileREOError
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
|
1119
1112
|
Book = Workbook
|
1120
1113
|
|
1121
1114
|
end
|