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.
@@ -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