robust_excel_ole 1.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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, :force_excel => :new, :visible => true)
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, :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
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, :default_excel => new_excel, :visible => true) # open another book
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, :default_excel => :new, :visible => true) # open another book
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, :force_excel => :new, :visible => true) # open another book in a new Excel instance,
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, :force_excel => new_excel, :visible => true) # open another book in the new Excel instance
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
- DEFAULT_OPEN_OPTS = {
18
- :default_excel => :current,
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
- }
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 [Variant] :default_excel :current (or :active, or :reuse) (default), :new, or <excel-instance>
33
- # @option opts [Variant] :force_excel :current, :new, or <excel-instance>
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] :visible true or false (default)
46
+ # @option opts [Boolean] :calculation :manual, :automatic, or nil (default)
40
47
  # options:
41
- # :default_excel if the workbook was already open in an Excel instance, then open it in that Excel instance,
42
- # where it was opened most recently
43
- # Otherwise, i.e. if the workbook was not open before or the Excel instance is not alive
44
- # :current -> connects to a running (the first opened) Excel instance,
45
- # (or :active, :reuse) excluding the hidden Excel instance, if it exists,
46
- # otherwise opens in a new Excel instance.
47
- # :new -> opens in a new Excel instance
48
- # <excel-instance> -> opens in the given Excel instance
49
- # :force_excel no matter whether the workbook was already open
50
- # :new -> opens in a new Exceö instance
51
- # :current (or :active, :reuse) -> opens in the current Excel instance
52
- # <excel-instance> -> opens in the given Excel instance
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
- # :update_links true -> user is being asked how to update links, false -> links are never updated
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 = DEFAULT_OPEN_OPTS.merge(opts)
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[:force_excel] == :new))
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[:force_excel]
81
- options[:force_excel] == :current ? excel_class.new(:reuse => true) : excel_of(options[:force_excel])
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[:force_excel]) || (forced_excel == book.excel)) &&
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 = DEFAULT_OPEN_OPTS.merge(opts)
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].nil? ? book.excel.visible : options[:visible]
96
- #book.visible = options[:visible] unless options[:visible].nil?
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
- #book.visible = opts[:visible] unless opts[:visible].nil?
118
- book.visible = opts[:visible].nil? ? book.excel.visible : opts[:visible]
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 = DEFAULT_OPEN_OPTS.merge(opts)
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
- # if the Excel could not be promoted, then create it
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
- #workbook.visible = options[:visible] unless options[:visible].nil?
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
- return if @excel && @excel.alive?
206
- options[:excel] = options[:force_excel] ? options[:force_excel] : options[:default_excel]
207
- options[:excel] = :current if (options[:excel] == :reuse || options[:excel] == :active)
208
- @excel = self.class.excel_of(options[:excel]) unless (options[:excel] == :current || options[:excel] == :new)
209
- @excel = excel_class.new(:reuse => (options[:excel] == :current)) unless (@excel && @excel.alive?)
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
- excel_options = {:visible => false}.merge(options)
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
- # book is not open
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
- workbooks.Item(1).Close if @excel.Version.split(".").first.to_i >= 12 && count == 0
326
- rescue WIN32OLERuntimeError => msg
327
- # trace "WIN32OLERuntimeError: #{msg.message}"
328
- if msg.message =~ /800A03EC/
329
- raise ExcelError, "user canceled or runtime error"
330
- else
331
- raise UnexpectedError, "unknown WIN32OLERuntimeError"
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
- end
334
- begin
335
- # workaround for bug in Excel 2010: workbook.Open does not always return the workbook with given file name
336
- @ole_workbook = workbooks.Item(File.basename(filename))
337
- self.visible = options[:visible].nil? ? @excel.visible : options[:visible]
338
- #self.visible = options[:visible] unless options[:visible].nil?
339
- #@ole_workbook.UpdateLinks = update_links_opt
340
- @ole_workbook.CheckCompatibility = options[:check_compatibility]
341
- rescue WIN32OLERuntimeError
342
- raise FileNotFound, "cannot find the file #{File.basename(filename).inspect}"
343
- end
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
- # modifies a workbook such that its state (open/close, saved/unsaved, readonly/writable) remains unchanged
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 displayaslerts
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, :readl_only, :update_links, :check_compatibility : see options in #open
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
- :read_only => false,
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, :default_excel => :current, :read_only => options[:read_only])
517
+ open(file, :default => {:excel => :current}, :read_only => options[:read_only])
462
518
  when :hidden
463
- open(file, :force_excel => bookstore.hidden_excel, :read_only => options[:read_only])
519
+ open(file, :force => {:excel => bookstore.hidden_excel}, :read_only => options[:read_only])
464
520
  else
465
- open(file, :force_excel => if_closed, :read_only => options[:read_only])
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, :force_excel => book.excel, :read_only => options[:read_only]) :
472
- open(file, :force_excel => :new, :read_only => options[:read_only])
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
- book.visible = options[:visible].nil? ? book.excel.visible : options[:visible]
477
- old_check_compatibility = book.CheckCompatibility
478
- book.CheckCompatibility = options[:check_compatibility]
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
- was_saved_or_appeared = was_saved || was_not_alive_or_nil || (not was_writable)
482
- book.save if book && (not book.saved) && (not options[:read_only]) && was_saved_or_appeared
483
- # book was open, readonly and shoud be modified
484
- if (not was_not_alive_or_nil) && (not options[:read_only]) && (not was_writable) && options[:readonly_excel]
485
- open(file, :force_excel => book.excel, :if_obstructed => :new_excel, :read_only => true)
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
- blocking_workbook =
565
- begin
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: #{blocking_workbook.Fullname.tr('\\','/')}"
636
+ raise WorkbookBlocked, "blocked by another workbook: #{other_workbook.Fullname.tr('\\','/')}"
574
637
  when :forget
575
638
  # nothing
576
639
  when :save
577
- blocking_workbook.Save
640
+ other_workbook.Save
578
641
  when :close_if_saved
579
- raise WorkbookBlocked, "blocking workbook is unsaved: #{File.basename(file).inspect}" unless blocking_workbook.Saved
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
- blocking_workbook.Close
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 == RobustExcelOle::XlErrName # -2146826259
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 value that determines whether the workbook shall be visible
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
- if @excel.Visible
803
- if @ole_workbook.Windows.Count > 0
804
- @ole_workbook.Windows(@ole_workbook.Name).Visible = visible_value
805
- end
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