robust_excel_ole 1.0 → 1.0.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.
- data/Changelog +14 -0
- data/README.rdoc +94 -351
- data/README_detail.rdoc +791 -0
- data/examples/edit_sheets/example_saving.rb +1 -1
- data/examples/open_save_close/example_default_excel.rb +5 -5
- data/examples/open_save_close/example_force_excel.rb +2 -2
- data/lib/robust_excel_ole/book.rb +237 -161
- data/lib/robust_excel_ole/excel.rb +96 -68
- data/lib/robust_excel_ole/reo_common.rb +19 -1
- data/lib/robust_excel_ole/sheet.rb +2 -3
- data/lib/robust_excel_ole/version.rb +1 -1
- data/robust_excel_ole.gemspec +2 -2
- data/spec/book_spec.rb +71 -16
- data/spec/book_specs/book_misc_spec.rb +244 -7
- data/spec/book_specs/book_open_spec.rb +472 -33
- data/spec/book_specs/book_save_spec.rb +19 -0
- data/spec/book_specs/book_unobtr_spec.rb +46 -4
- data/spec/data/another_workbook.xls +0 -0
- data/spec/data/book_with_blank.xls +0 -0
- data/spec/data/different_workbook.xls +0 -0
- data/spec/data/workbook.xls +0 -0
- data/spec/excel_spec.rb +134 -31
- metadata +7 -6
- data/spec/data/refed_wb.xls +0 -0
@@ -28,7 +28,7 @@ begin
|
|
28
28
|
end
|
29
29
|
book.close(:if_unsaved => :save)
|
30
30
|
# alternative: delete all other sheets
|
31
|
-
#book = Book.open(file_sheet_name, :
|
31
|
+
#book = Book.open(file_sheet_name, :force => {:excel => :new}, :visible => true)
|
32
32
|
#book.each do |sheet|
|
33
33
|
# book.sheet(sheet.Name).Delete() unless sheet.Name == sheet_orig.Name
|
34
34
|
#end
|
@@ -23,18 +23,18 @@ begin
|
|
23
23
|
p "book1 == book2" if book2 == book1 # the books are identical
|
24
24
|
sleep 2
|
25
25
|
new_excel = Excel.new(:reuse => false) # create a new Excel
|
26
|
-
book3 = Book.open(file_name2, :
|
27
|
-
if book3.excel == book2.excel then # since this book cannot be reopened, the option :
|
28
|
-
p "book3 opened in the first Excel" # according to :
|
26
|
+
book3 = Book.open(file_name2, :default => {:excel => :current}, :visible => true) # open another book
|
27
|
+
if book3.excel == book2.excel then # since this book cannot be reopened, the option :default => {:excel} applies:
|
28
|
+
p "book3 opened in the first Excel" # according to :default => {:excel => :current} the book is opened
|
29
29
|
end # in the Excel instance the was created first
|
30
30
|
sleep 2
|
31
31
|
new_excel = Excel.new(:reuse => false)
|
32
|
-
book4 = Book.open(file_name3, :
|
32
|
+
book4 = Book.open(file_name3, :default => {:excel => new_excel}, :visible => true) # open another book
|
33
33
|
if book4.excel == new_excel then # since this book cannot be reopened, the option :default_excel applies:
|
34
34
|
p "book4 opened in the second Excel" # according to :default_excel => new_excel the book is opened
|
35
35
|
end # in the given Excel, namely the second Excel instance new_excel
|
36
36
|
sleep 2
|
37
|
-
book5 = Book.open(file_name4, :
|
37
|
+
book5 = Book.open(file_name4, :default => {:excel => :new}, :visible => true) # open another book
|
38
38
|
if ((not book5.excel == book1.excel) && (not book5.excel == new_excel)) then # since this book cannot be reopened,
|
39
39
|
p "book5 opened in a third Excel" # the option :default_excel applies. according to :default_excel => :new
|
40
40
|
end # the book is opened in a new Excel
|
@@ -17,11 +17,11 @@ begin
|
|
17
17
|
book2 = Book.open(simple_file) # open a new book in the same Excel instance
|
18
18
|
p "book1 == book2" if book2 == book1 # the books are identical
|
19
19
|
sleep 2
|
20
|
-
book3 = Book.open(simple_file, :
|
20
|
+
book3 = Book.open(simple_file, :force => {:excel => :new, :visible => true}) # open another book in a new Excel instance,
|
21
21
|
p "book3 != book1" if (not (book3 == book1)) # the books are not identical
|
22
22
|
sleep 2
|
23
23
|
new_excel = Excel.new(:reuse => false) # create a third Excel instance
|
24
|
-
book4 = Book.open(simple_file, :
|
24
|
+
book4 = Book.open(simple_file, :force => {:excel => new_excel, :visible => true}) # open another book in the new Excel instance
|
25
25
|
p "book4 != book3 && book4 != book1" if (not (book4 == book3) && (not (book4 == book1)))
|
26
26
|
sleep 2 # (Excel chooses the first Excel application)
|
27
27
|
book4.close # close the books
|
@@ -9,47 +9,54 @@ module RobustExcelOle
|
|
9
9
|
attr_accessor :excel
|
10
10
|
attr_accessor :ole_workbook
|
11
11
|
attr_accessor :stored_filename
|
12
|
-
attr_accessor :options
|
13
|
-
attr_accessor :can_be_closed
|
12
|
+
attr_accessor :options
|
14
13
|
|
15
14
|
alias ole_object ole_workbook
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
DEFAULT_OPEN_OPTS = {
|
17
|
+
:default => {:excel => :current},
|
18
|
+
:force => {},
|
19
|
+
:if_unsaved => :raise,
|
20
|
+
:if_obstructed => :raise,
|
21
|
+
:if_absent => :raise,
|
22
|
+
:read_only => false,
|
23
|
+
:check_compatibility => false,
|
24
|
+
:update_links => :never
|
25
|
+
}
|
26
|
+
|
27
|
+
SYNONYMS_OPTS = [[[:default],[:d]], [[:force], [:f]],
|
28
|
+
[[:default,:excel],[:default_excel]],[[:force,:excel],[:force_excel]],
|
29
|
+
[[:default,:excel],[:default,:e]], [[:force,:excel],[:force,:e]],
|
30
|
+
[[:default,:visible],[:default,:v]], [[:force,:visible],[:force,:v]],
|
31
|
+
[[:force,:visible],[:visible]], [[:force,:visible],[:v]]
|
32
|
+
]
|
26
33
|
|
27
34
|
class << self
|
28
35
|
|
29
36
|
# opens a workbook.
|
30
37
|
# @param [String] file the file name
|
31
38
|
# @param [Hash] opts the options
|
32
|
-
# @option opts [
|
33
|
-
# @option opts [
|
39
|
+
# @option opts [Hash] :default or :d
|
40
|
+
# @option opts [Hash] :force or :f
|
34
41
|
# @option opts [Symbol] :if_unsaved :raise (default), :forget, :accept, :alert, :excel, or :new_excel
|
35
42
|
# @option opts [Symbol] :if_obstructed :raise (default), :forget, :save, :close_if_saved, or _new_excel
|
36
43
|
# @option opts [Symbol] :if_absent :raise (default) or :create
|
37
44
|
# @option opts [Boolean] :read_only true (default) or false
|
38
45
|
# @option opts [Boolean] :update_links :never (default), :always, :alert
|
39
|
-
# @option opts [Boolean] :
|
46
|
+
# @option opts [Boolean] :calculation :manual, :automatic, or nil (default)
|
40
47
|
# options:
|
41
|
-
# :
|
42
|
-
#
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
48
|
+
# :default : if the workbook was already open before, then use (unchange) its properties,
|
49
|
+
# otherwise, i.e. if the workbook cannot be reopened, use the properties stated in :default
|
50
|
+
# :force : no matter whether the workbook was already open before, use the properties stated in :force
|
51
|
+
# :default and :force contain: :excel, :visible
|
52
|
+
# :excel :current (or :active or :reuse)
|
53
|
+
# -> connects to a running (the first opened) Excel instance,
|
54
|
+
# excluding the hidden Excel instance, if it exists,
|
55
|
+
# otherwise opens in a new Excel instance.
|
56
|
+
# :new -> opens in a new Excel instance
|
57
|
+
# <excel-instance> -> opens in the given Excel instance
|
58
|
+
# :visible true, false, or nil (default)
|
59
|
+
# alternatives: :default_excel, :force_excel, :visible, :d, :f, :e, :v
|
53
60
|
# :if_unsaved if an unsaved workbook with the same name is open, then
|
54
61
|
# :raise -> raises an exception
|
55
62
|
# :forget -> close the unsaved workbook, open the new workbook
|
@@ -65,35 +72,33 @@ module RobustExcelOle
|
|
65
72
|
# :new_excel -> opens the new workbook in a new Excel instance
|
66
73
|
# :if_absent :raise -> raises an exception , if the file does not exists
|
67
74
|
# :create -> creates a new Excel file, if it does not exists
|
68
|
-
# :read_only true -> opens in read-only mode
|
69
|
-
# :
|
70
|
-
# :visible true -> makes the window of the workbook visible
|
75
|
+
# :read_only true -> opens in read-only mode
|
76
|
+
# :visible true -> makes the workbook visible
|
71
77
|
# :check_compatibility true -> check compatibility when saving
|
78
|
+
# :update_links true -> user is being asked how to update links, false -> links are never updated
|
72
79
|
# @return [Book] a workbook
|
73
80
|
def open(file, opts={ }, &block)
|
74
|
-
options =
|
75
|
-
options[:default_excel] = :current if (options[:default_excel] == :reuse || options[:default_excel] == :active)
|
76
|
-
options[:force_excel] = :current if (options[:force_excel] == :reuse || options[:force_excel] == :active)
|
81
|
+
options = process_options(opts)
|
77
82
|
book = nil
|
78
|
-
if (not (options[:
|
83
|
+
if (not (options[:force][:excel] == :new))
|
79
84
|
# if readonly is true, then prefer a book that is given in force_excel if this option is set
|
80
|
-
forced_excel = if options[:
|
81
|
-
options[:
|
85
|
+
forced_excel = if options[:force][:excel]
|
86
|
+
options[:force][:excel] == :current ? excel_class.new(:reuse => true) : excel_of(options[:force][:excel])
|
82
87
|
end
|
83
88
|
book = bookstore.fetch(file,
|
84
89
|
:prefer_writable => (not options[:read_only]),
|
85
90
|
:prefer_excel => (options[:read_only] ? forced_excel : nil)) rescue nil
|
86
91
|
if book
|
87
|
-
if (((not options[:
|
92
|
+
if (((not options[:force][:excel]) || (forced_excel == book.excel)) &&
|
88
93
|
(not (book.alive? && (not book.saved) && (not options[:if_unsaved] == :accept))))
|
89
|
-
book.options =
|
90
|
-
book.ensure_excel(options) unless book.excel.alive?
|
94
|
+
book.options = options
|
95
|
+
book.ensure_excel(options) # unless book.excel.alive?
|
91
96
|
# if the book is opened as readonly and should be opened as writable, then close it and open the book with the new readonly mode
|
92
97
|
book.close if (book.alive? && (not book.writable) && (not options[:read_only]))
|
93
98
|
# reopens the book
|
94
99
|
book.ensure_workbook(file,options) unless book.alive?
|
95
|
-
book.visible = options[:visible]
|
96
|
-
|
100
|
+
book.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
101
|
+
book.excel.calculation = options[:calculation] unless options[:calculation].nil?
|
97
102
|
return book
|
98
103
|
end
|
99
104
|
end
|
@@ -108,14 +113,16 @@ module RobustExcelOle
|
|
108
113
|
# @param [Hash] opts the options
|
109
114
|
# @option opts [Symbol] see above
|
110
115
|
# @return [Book] a workbook
|
111
|
-
def self.new(workbook, opts={ }, &block)
|
116
|
+
def self.new(workbook, opts={ }, &block)
|
112
117
|
if workbook && (workbook.is_a? WIN32OLE)
|
118
|
+
opts = process_options(opts)
|
113
119
|
filename = workbook.Fullname.tr('\\','/') rescue nil
|
114
120
|
if filename
|
115
121
|
book = bookstore.fetch(filename)
|
116
122
|
if book && book.alive?
|
117
|
-
|
118
|
-
book.
|
123
|
+
book.visible = opts[:force][:visible] unless opts[:force][:visible].nil?
|
124
|
+
#book.excel.calculation = opts[:calculation].nil? ? book.excel.calculation : opts[:calculation]
|
125
|
+
book.excel.calculation = opts[:calculation] unless opts[:calculation].nil?
|
119
126
|
return book
|
120
127
|
end
|
121
128
|
end
|
@@ -130,21 +137,20 @@ module RobustExcelOle
|
|
130
137
|
# @option opts [Symbol] see above
|
131
138
|
# @return [Book] a workbook
|
132
139
|
def initialize(file_or_workbook, opts={ }, &block)
|
133
|
-
options =
|
134
|
-
if file_or_workbook.is_a? WIN32OLE
|
140
|
+
options = self.class.process_options(opts)
|
141
|
+
if file_or_workbook.is_a? WIN32OLE
|
135
142
|
workbook = file_or_workbook
|
136
143
|
@ole_workbook = workbook
|
137
144
|
# use the Excel instance where the workbook is opened
|
138
145
|
win32ole_excel = WIN32OLE.connect(workbook.Fullname).Application rescue nil
|
139
146
|
@excel = excel_class.new(win32ole_excel)
|
140
|
-
@excel.visible = options[:visible] unless options[:visible].nil?
|
141
|
-
|
147
|
+
@excel.visible = options[force][:visible] unless options[:force][:visible].nil?
|
148
|
+
@excel.calculation = options[:calculation] unless options[:calculation].nil?
|
142
149
|
ensure_excel(options)
|
143
150
|
else
|
144
151
|
file = file_or_workbook
|
145
152
|
ensure_excel(options)
|
146
153
|
ensure_workbook(file, options)
|
147
|
-
@can_be_closed = false if @can_be_closed.nil?
|
148
154
|
end
|
149
155
|
bookstore.store(self)
|
150
156
|
if block
|
@@ -158,6 +164,32 @@ module RobustExcelOle
|
|
158
164
|
|
159
165
|
private
|
160
166
|
|
167
|
+
# merges options with defaults and translates abbreviations and synonyms
|
168
|
+
def self.process_options(options) # :nodoc: #
|
169
|
+
translator = proc do |opts|
|
170
|
+
SYNONYMS_OPTS.each do |a|
|
171
|
+
synonym = a[1][1].nil? ? opts[a[1][0]] : opts[a[1][0]][a[1][1]] unless opts[a[1][0]].nil?
|
172
|
+
unless synonym.nil?
|
173
|
+
if a[0][1].nil?
|
174
|
+
opts[a[0][0]] = synonym if opts[a[0][0]].nil?
|
175
|
+
else
|
176
|
+
opts[a[0][0]] = {} if opts[a[0][0]].nil?
|
177
|
+
opts[a[0][0]][a[0][1]] = synonym if opts[a[0][0]][a[0][1]].nil?
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
opts[:default][:excel] = :current if (not opts[:default].nil?) && (opts[:default][:excel] == :reuse || opts[:default][:excel] == :active)
|
182
|
+
opts[:force][:excel] = :current if (not opts[:force].nil?) && (opts[:force][:excel] == :reuse || opts[:force][:excel] == :active)
|
183
|
+
opts
|
184
|
+
end
|
185
|
+
default_opts = translator.call(DEFAULT_OPEN_OPTS)
|
186
|
+
given_opts = translator.call(options)
|
187
|
+
opts = default_opts.merge(given_opts)
|
188
|
+
opts[:default] = default_opts[:default].merge(opts[:default]) unless opts[:default].nil?
|
189
|
+
opts[:force] = default_opts[:force].merge(opts[:force]) unless opts[:force].nil?
|
190
|
+
opts
|
191
|
+
end
|
192
|
+
|
161
193
|
# returns an Excel object when given Excel, Book or Win32ole object representing a Workbook or an Excel
|
162
194
|
def self.excel_of(object) # :nodoc: #
|
163
195
|
if object.is_a? WIN32OLE
|
@@ -186,8 +218,7 @@ module RobustExcelOle
|
|
186
218
|
filename = General::absolute_path(file)
|
187
219
|
ole_workbook = WIN32OLE.connect(filename)
|
188
220
|
workbook = Book.new(ole_workbook)
|
189
|
-
|
190
|
-
workbook.visible = options[:visible].nil? ? workbook.excel.visible : options[:visible]
|
221
|
+
workbook.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
191
222
|
update_links_opt =
|
192
223
|
case options[:update_links]
|
193
224
|
when :alert; RobustExcelOle::XlUpdateLinksUserSetting
|
@@ -200,13 +231,19 @@ module RobustExcelOle
|
|
200
231
|
workbook
|
201
232
|
end
|
202
233
|
|
203
|
-
|
204
234
|
def ensure_excel(options) # :nodoc: #
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
235
|
+
if @excel && @excel.alive?
|
236
|
+
@excel.created = false
|
237
|
+
return
|
238
|
+
end
|
239
|
+
excel_option = (options[:force].nil? or options[:force][:excel].nil?) ? options[:default][:excel] : options[:force][:excel]
|
240
|
+
@excel = self.class.excel_of(excel_option) unless (excel_option == :current || excel_option == :new)
|
241
|
+
@excel = excel_class.new(:reuse => (excel_option == :current)) unless (@excel && @excel.alive?)
|
242
|
+
|
243
|
+
#options[:excel] = options[:force_excel] ? options[:force_excel] : options[:default_excel]
|
244
|
+
#options[:excel] = :current if (options[:excel] == :reuse || options[:excel] == :active)
|
245
|
+
#@excel = self.class.excel_of(options[:excel]) unless (options[:excel] == :current || options[:excel] == :new)
|
246
|
+
#@excel = excel_class.new(:reuse => (options[:excel] == :current)) unless (@excel && @excel.alive?)
|
210
247
|
end
|
211
248
|
|
212
249
|
def ensure_workbook(file, options) # :nodoc: #
|
@@ -246,9 +283,7 @@ module RobustExcelOle
|
|
246
283
|
open_or_create_workbook(file, options)
|
247
284
|
end
|
248
285
|
when :new_excel
|
249
|
-
|
250
|
-
excel_options[:reuse] = false
|
251
|
-
@excel = excel_class.new(excel_options)
|
286
|
+
@excel = excel_class.new(:reuse => false)
|
252
287
|
open_or_create_workbook(file, options)
|
253
288
|
else
|
254
289
|
raise OptionInvalid, ":if_obstructed: invalid option: #{options[:if_obstructed].inspect}"
|
@@ -268,7 +303,6 @@ module RobustExcelOle
|
|
268
303
|
when :alert, :excel
|
269
304
|
@excel.with_displayalerts(true) { open_or_create_workbook(file,options) }
|
270
305
|
when :new_excel
|
271
|
-
excel_options = {:visible => false}.merge(options)
|
272
306
|
excel_options[:reuse] = false
|
273
307
|
@excel = excel_class.new(excel_options)
|
274
308
|
open_or_create_workbook(file, options)
|
@@ -278,7 +312,7 @@ module RobustExcelOle
|
|
278
312
|
end
|
279
313
|
end
|
280
314
|
else
|
281
|
-
#
|
315
|
+
# open a new workbook
|
282
316
|
open_or_create_workbook(file, options)
|
283
317
|
end
|
284
318
|
end
|
@@ -292,58 +326,80 @@ module RobustExcelOle
|
|
292
326
|
begin
|
293
327
|
workbooks = @excel.Workbooks
|
294
328
|
rescue RuntimeError => msg
|
295
|
-
trace "RuntimeError: #{msg.message}"
|
296
329
|
if msg.message =~ /method missing: Excel not alive/
|
297
330
|
raise ExcelDamaged, "Excel instance not alive or damaged"
|
298
331
|
else
|
299
|
-
raise UnexpectedError, "unknown RuntimeError"
|
332
|
+
raise UnexpectedError, "unknown RuntimeError: #{msg.message}"
|
300
333
|
end
|
301
|
-
rescue WeakRef::RefError => msg
|
302
|
-
raise WeakRef::RefError, "#{msg.message}"
|
303
|
-
end
|
304
|
-
# workaround for linked workbooks for Excel 2007:
|
305
|
-
# opening and closing a dummy workbook if Excel has no workbooks.
|
306
|
-
# delay: with visible: 0.2 sec, without visible almost none
|
307
|
-
count = workbooks.Count
|
308
|
-
if @excel.Version.split(".").first.to_i >= 12 && count == 0
|
309
|
-
workbooks.Add
|
310
|
-
#@excel.set_calculation(:automatic)
|
311
|
-
end
|
312
|
-
update_links_opt =
|
313
|
-
case options[:update_links]
|
314
|
-
when :alert; RobustExcelOle::XlUpdateLinksUserSetting
|
315
|
-
when :never; RobustExcelOle::XlUpdateLinksNever
|
316
|
-
when :always; RobustExcelOle::XlUpdateLinksAlways
|
317
|
-
else RobustExcelOle::XlUpdateLinksNever
|
318
|
-
end
|
319
|
-
# probably bug in Excel: setting UpadateLinks seems to be dependent on calculation mode:
|
320
|
-
# update happens, if calcultion mode is automatic, does not, if calculation mode is manual
|
321
|
-
# parameter 'UpdateLinks' has no effect
|
322
|
-
@excel.with_displayalerts(update_links_opt == :alert ? true : @excel.displayalerts) do
|
323
|
-
workbooks.Open(filename, { 'ReadOnly' => options[:read_only] , 'UpdateLinks' => update_links_opt } )
|
324
334
|
end
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
335
|
+
begin
|
336
|
+
with_workaround_linked_workbooks_excel2007(options) do
|
337
|
+
workbooks.Open(filename, { 'ReadOnly' => options[:read_only] ,
|
338
|
+
'UpdateLinks' => updatelinks_vba(options[:update_links]) })
|
339
|
+
end
|
340
|
+
rescue WIN32OLERuntimeError => msg
|
341
|
+
if msg.message =~ /800A03EC/
|
342
|
+
raise ExcelError, "user canceled or runtime error #{msg.message}"
|
343
|
+
else
|
344
|
+
raise UnexpectedError, "unexpected WIN32OLERuntimeError: #{msg.message}"
|
345
|
+
end
|
332
346
|
end
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
347
|
+
begin
|
348
|
+
# workaround for bug in Excel 2010: workbook.Open does not always return the workbook when given file name
|
349
|
+
begin
|
350
|
+
@ole_workbook = workbooks.Item(File.basename(filename))
|
351
|
+
rescue WIN32OLERuntimeError => msg
|
352
|
+
raise UnexpectedError, "unexpected WIN32OLERuntimeError: #{msg.message}"
|
353
|
+
end
|
354
|
+
if options[:force][:visible].nil? && (not options[:default][:visible].nil?)
|
355
|
+
if @excel.created
|
356
|
+
self.visible = options[:default][:visible]
|
357
|
+
else
|
358
|
+
self.window_visible = options[:default][:visible]
|
359
|
+
end
|
360
|
+
else
|
361
|
+
self.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
362
|
+
end
|
363
|
+
@ole_workbook.CheckCompatibility = options[:check_compatibility]
|
364
|
+
@excel.calculation = options[:calculation] unless options[:calculation].nil?
|
365
|
+
self.Saved = true # unless self.Saved # ToDo: this is too hard
|
366
|
+
rescue WIN32OLERuntimeError => msg
|
367
|
+
raise UnexpectedError, "unexpected WIN32OLERuntimeError: #{msg.message} #{msg.backtrace}"
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
# translating the option UpdateLinks from REO to VBA
|
374
|
+
# setting UpdateLinks works only if calculation mode is automatic,
|
375
|
+
# parameter 'UpdateLinks' has no effect
|
376
|
+
def updatelinks_vba(updatelinks_reo)
|
377
|
+
case updatelinks_reo
|
378
|
+
when :alert; RobustExcelOle::XlUpdateLinksUserSetting
|
379
|
+
when :never; RobustExcelOle::XlUpdateLinksNever
|
380
|
+
when :always; RobustExcelOle::XlUpdateLinksAlways
|
381
|
+
else RobustExcelOle::XlUpdateLinksNever
|
344
382
|
end
|
345
383
|
end
|
346
384
|
|
385
|
+
# workaround for linked workbooks for Excel 2007:
|
386
|
+
# opening and closing a dummy workbook if Excel has no workbooks.
|
387
|
+
# delay: with visible: 0.2 sec, without visible almost none
|
388
|
+
def with_workaround_linked_workbooks_excel2007(options)
|
389
|
+
workbooks = @excel.Workbooks
|
390
|
+
workaround_condition = @excel.Version.split(".").first.to_i >= 12 && workbooks.Count == 0
|
391
|
+
if workaround_condition
|
392
|
+
workbooks.Add
|
393
|
+
@excel.calculation = options[:calculation].nil? ? @excel.calculation : options[:calculation]
|
394
|
+
end
|
395
|
+
begin
|
396
|
+
#@excel.with_displayalerts(update_links_opt == :alert ? true : @excel.displayalerts) do
|
397
|
+
yield self
|
398
|
+
ensure
|
399
|
+
@excel.with_displayalerts(false){workbooks.Item(1).Close} if workaround_condition
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
347
403
|
public
|
348
404
|
|
349
405
|
# closes the workbook, if it is alive
|
@@ -391,6 +447,16 @@ module RobustExcelOle
|
|
391
447
|
|
392
448
|
public
|
393
449
|
|
450
|
+
# keeps the saved-status unchanged
|
451
|
+
def retain_saved
|
452
|
+
saved = self.Saved
|
453
|
+
begin
|
454
|
+
yield self
|
455
|
+
ensure
|
456
|
+
self.Saved = saved
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
394
460
|
def self.for_reading(*args, &block)
|
395
461
|
args = args.dup
|
396
462
|
opts = args.last.is_a?(Hash) ? args.pop : {}
|
@@ -407,7 +473,7 @@ module RobustExcelOle
|
|
407
473
|
unobtrusively(*args, &block)
|
408
474
|
end
|
409
475
|
|
410
|
-
#
|
476
|
+
# allows to modify a workbook such that its state (open/close, saved/unsaved, readonly/writable) remains unchanged
|
411
477
|
# @param [String] file the file name
|
412
478
|
# @param [Hash] if_closed an option
|
413
479
|
# @param [Hash] opts the options
|
@@ -420,13 +486,13 @@ module RobustExcelOle
|
|
420
486
|
# :if_closed : if the workbook is closed, then open it in
|
421
487
|
# :current (or :active, :reuse) -> the Excel instance of the workbook, if it exists,
|
422
488
|
# reuse another Excel, otherwise
|
423
|
-
# :hidden -> a separate Excel instance that is not visible and has no
|
489
|
+
# :hidden -> a separate Excel instance that is not visible and has no displayalerts
|
424
490
|
# <excel-instance> -> the given Excel instance
|
425
491
|
# :readonly_excel: if the workbook is opened only as ReadOnly and shall be modified, then
|
426
492
|
# true: closes it and open it as writable in the Excel instance where it was open so far
|
427
493
|
# false (default) opens it as writable in another running excel instance, if it exists,
|
428
494
|
# otherwise open in a new Excel instance.
|
429
|
-
# :visible, :
|
495
|
+
# :visible, :read_only, :update_links, :check_compatibility : see options in #open
|
430
496
|
# @return [Book] a workbook
|
431
497
|
def self.unobtrusively(file, if_closed = nil, opts = { }, &block)
|
432
498
|
if if_closed.is_a? Hash
|
@@ -435,58 +501,60 @@ module RobustExcelOle
|
|
435
501
|
end
|
436
502
|
if_closed = :current if (if_closed == :reuse || if_closed == :active)
|
437
503
|
if_closed = :current unless if_closed
|
438
|
-
options =
|
439
|
-
|
440
|
-
:readonly_excel => false,
|
441
|
-
:keep_open => false,
|
442
|
-
:check_compatibility => false
|
443
|
-
}.merge(opts)
|
504
|
+
options = process_options(opts)
|
505
|
+
opts = {:readonly_excel => false,:keep_open => false}.merge(opts)
|
444
506
|
book = bookstore.fetch(file, :prefer_writable => (not options[:read_only]))
|
445
507
|
was_not_alive_or_nil = book.nil? || (not book.alive?)
|
446
508
|
workbook = book.excel.Workbooks.Item(File.basename(file)) rescue nil
|
447
|
-
now_alive =
|
448
|
-
begin
|
449
|
-
workbook.Name
|
450
|
-
true
|
451
|
-
rescue
|
452
|
-
false
|
453
|
-
end
|
454
509
|
was_saved = was_not_alive_or_nil ? true : book.saved
|
455
|
-
was_writable = book.writable unless was_not_alive_or_nil
|
510
|
+
was_writable = book.writable unless was_not_alive_or_nil
|
511
|
+
was_check_compatibility = book.CheckCompatibility unless was_not_alive_or_nil
|
456
512
|
begin
|
457
513
|
book =
|
458
514
|
if was_not_alive_or_nil
|
459
515
|
case if_closed
|
460
516
|
when :current
|
461
|
-
open(file, :
|
517
|
+
open(file, :default => {:excel => :current}, :read_only => options[:read_only])
|
462
518
|
when :hidden
|
463
|
-
open(file, :
|
519
|
+
open(file, :force => {:excel => bookstore.hidden_excel}, :read_only => options[:read_only])
|
464
520
|
else
|
465
|
-
open(file, :
|
521
|
+
open(file, :force => {:excel => if_closed}, :read_only => options[:read_only])
|
466
522
|
end
|
467
523
|
else
|
468
524
|
if was_writable || options[:read_only]
|
469
525
|
book
|
470
526
|
else
|
471
|
-
options[:readonly_excel] ? open(file, :
|
472
|
-
open(file, :
|
527
|
+
options[:readonly_excel] ? open(file, :force => {:excel => book.excel}, :read_only => options[:read_only]) :
|
528
|
+
open(file, :force => {:excel => :new}, :read_only => options[:read_only])
|
473
529
|
end
|
474
530
|
end
|
475
|
-
#book.excel.visible = options[:visible] unless options[:visible].nil?
|
476
|
-
|
477
|
-
|
478
|
-
|
531
|
+
#book.excel.visible = options[:force][:visible] unless options[:force].nil? or options[:force][:visible].nil?
|
532
|
+
options = process_options(options)
|
533
|
+
if options[:force][:visible].nil? && (not options[:default][:visible].nil?)
|
534
|
+
if book.excel.created
|
535
|
+
book.visible = options[:default][:visible]
|
536
|
+
else
|
537
|
+
book.window_visible = options[:default][:visible]
|
538
|
+
end
|
539
|
+
else
|
540
|
+
book.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
541
|
+
end
|
542
|
+
book.CheckCompatibility = options[:check_compatibility] unless options[:check_compatibility].nil?
|
479
543
|
yield book
|
480
544
|
ensure
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
545
|
+
if book && book.alive?
|
546
|
+
unless book.saved
|
547
|
+
book.save unless options[:read_only]
|
548
|
+
book.Saved = true if was_saved && options[:read_only]
|
549
|
+
book.Saved = false unless was_saved || options[:read_only]
|
550
|
+
end
|
551
|
+
# book was open, readonly and should be modified
|
552
|
+
unless was_not_alive_or_nil || options[:read_only] || was_writable || (not options[:readonly_excel])
|
553
|
+
open(file, :force => {:excel => book.excel}, :if_obstructed => :new_excel, :read_only => true)
|
554
|
+
end
|
555
|
+
book.CheckCompatibility = was_check_compatibility unless was_check_compatibility.nil?
|
556
|
+
book.close if was_not_alive_or_nil && (not options[:keep_open])
|
486
557
|
end
|
487
|
-
@can_be_closed = true if options[:keep_open] && book
|
488
|
-
book.close if (was_not_alive_or_nil && (not now_alive) && (not options[:keep_open]) && book)
|
489
|
-
book.CheckCompatibility = old_check_compatibility if book && book.alive?
|
490
558
|
end
|
491
559
|
end
|
492
560
|
|
@@ -561,26 +629,21 @@ module RobustExcelOle
|
|
561
629
|
raise OptionInvalid, ":if_exists: invalid option: #{options[:if_exists].inspect}"
|
562
630
|
end
|
563
631
|
end
|
564
|
-
|
565
|
-
|
566
|
-
@excel.Workbooks.Item(File.basename(file))
|
567
|
-
rescue WIN32OLERuntimeError => msg
|
568
|
-
nil
|
569
|
-
end
|
570
|
-
if blocking_workbook then
|
632
|
+
other_workbook = @excel.Workbooks.Item(File.basename(file)) rescue nil
|
633
|
+
if other_workbook && (not(self.filename == other_workbook.Fullname.tr('\\','/'))) then
|
571
634
|
case options[:if_obstructed]
|
572
635
|
when :raise
|
573
|
-
raise WorkbookBlocked, "blocked by another workbook: #{
|
636
|
+
raise WorkbookBlocked, "blocked by another workbook: #{other_workbook.Fullname.tr('\\','/')}"
|
574
637
|
when :forget
|
575
638
|
# nothing
|
576
639
|
when :save
|
577
|
-
|
640
|
+
other_workbook.Save
|
578
641
|
when :close_if_saved
|
579
|
-
raise WorkbookBlocked, "blocking workbook is unsaved: #{File.basename(file).inspect}" unless
|
642
|
+
raise WorkbookBlocked, "blocking workbook is unsaved: #{File.basename(file).inspect}" unless other_workbook.Saved
|
580
643
|
else
|
581
644
|
raise OptionInvalid, ":if_obstructed: invalid option: #{options[:if_obstructed].inspect}"
|
582
645
|
end
|
583
|
-
|
646
|
+
other_workbook.Close
|
584
647
|
end
|
585
648
|
save_as_workbook(file, options)
|
586
649
|
self
|
@@ -619,7 +682,6 @@ module RobustExcelOle
|
|
619
682
|
sheet_class.new(@ole_workbook.Worksheets.Item(name))
|
620
683
|
rescue WIN32OLERuntimeError => msg
|
621
684
|
raise NameNotFound, "could not return a sheet with name #{name.inspect}"
|
622
|
-
# trace "#{msg.message}"
|
623
685
|
end
|
624
686
|
end
|
625
687
|
|
@@ -742,7 +804,7 @@ module RobustExcelOle
|
|
742
804
|
raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
|
743
805
|
end
|
744
806
|
end
|
745
|
-
if value
|
807
|
+
if value.is_a?(Bignum) #RobustExcelOle::XlErrName
|
746
808
|
return default_val if default_val
|
747
809
|
raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
|
748
810
|
end
|
@@ -794,19 +856,35 @@ module RobustExcelOle
|
|
794
856
|
@excel.visible && @ole_workbook.Windows(@ole_workbook.Name).Visible
|
795
857
|
end
|
796
858
|
|
797
|
-
# makes the window of the workbook visible or invisible
|
798
|
-
# @param [Boolean] visible_value
|
859
|
+
# makes both the Excel instance and the window of the workbook visible, or the window invisible
|
860
|
+
# @param [Boolean] visible_value determines whether the workbook shall be visible
|
799
861
|
def visible= visible_value
|
800
|
-
saved = @ole_workbook.Saved
|
801
862
|
@excel.visible = true if visible_value
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
863
|
+
self.window_visible = visible_value
|
864
|
+
end
|
865
|
+
|
866
|
+
# returns true, if the window of the workbook is set to visible, false otherwise
|
867
|
+
def window_visible
|
868
|
+
return @ole_workbook.Windows(@ole_workbook.Name).Visible
|
869
|
+
end
|
870
|
+
|
871
|
+
# makes the window of the workbook visible or invisible
|
872
|
+
# @param [Boolean] visible_value determines whether the window of the workbook shall be visible
|
873
|
+
def window_visible= visible_value
|
874
|
+
retain_saved do
|
875
|
+
@ole_workbook.Windows(@ole_workbook.Name).Visible = visible_value if @ole_workbook.Windows.Count > 0
|
806
876
|
end
|
807
|
-
@ole_workbook.Saved = saved
|
808
877
|
end
|
809
878
|
|
879
|
+
# def visible= visible_value
|
880
|
+
# retain_saved do
|
881
|
+
# @excel.visible = true if visible_value
|
882
|
+
# if @ole_workbook.Windows.Count > 0
|
883
|
+
# @ole_workbook.Windows(@ole_workbook.Name).Visible = visible_value
|
884
|
+
# end
|
885
|
+
# end
|
886
|
+
# end
|
887
|
+
|
810
888
|
# returns true, if the workbook reacts to methods, false otherwise
|
811
889
|
def alive?
|
812
890
|
begin
|
@@ -920,6 +998,4 @@ public
|
|
920
998
|
|
921
999
|
Workbook = Book
|
922
1000
|
|
923
|
-
|
924
|
-
|
925
1001
|
end
|