robust_excel_ole 1.36 → 1.37

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d53d040d2a0079556bfca8d89a531f65b75f8e27d361378e339d38ac8ec7fdf
4
- data.tar.gz: 68658a532b13b21815f61e5ce7a286b8df42693711142ee7ff9c15c26cf6fa07
3
+ metadata.gz: 646308c3740c8716d9fb91b9c0288edc6e915c060bdd713401980608d412119a
4
+ data.tar.gz: 379a3bd099724e9cd6adc2542d804d4f4737eafc47742892dbc1ba4914f7b7c2
5
5
  SHA512:
6
- metadata.gz: '08f8abee9ca47bf37d4d27e3d13ecfcb31f1ae019370450bb052911ccd5a56ec5116c007d1f1475c19a29226857281f7d9d80747c5d2e5a7ac605de5d4d96660'
7
- data.tar.gz: 7243013b9b0af1c07c0e0eebb240c448be063d55f0dc5e2e15919df474aec957c444e45211eea4c093288e429111e3057f1860d7cc49ab4ffa5d160744a490cd
6
+ metadata.gz: '02308d88008a6e7d5362b0c793f1ab4e55025b7df0d19741dbe66775450f672b654c9766ac3e49d6ec840d497b9fa39befd1f66e6d20e5a5539d6cf3eefbc276'
7
+ data.tar.gz: 874eaf4089951eb94ac101699198e35981b72084036eb171ec70eb69dc2c135951138f773844b945ff7f4ebbd8d3a4020f3bdaf3f4286f165334e270ada23118
data/Changelog CHANGED
@@ -1,6 +1,11 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [1.37] 2021-30-11
5
+
6
+ ### Added
7
+ - Excel#visible,displayalerts
8
+
4
9
  ## [1.36] 2021-29-10
5
10
 
6
11
  ### Added
@@ -42,7 +42,7 @@ The options are the following:
42
42
  +:if_blocked+:: specifies behaviour if the workbook is blocked by another book (default: +:raise+)
43
43
 
44
44
 
45
- +:read_only+:: opens in read-only mode (default: +false+)
45
+ +:read_only+:: opens in read-only (+true+) or read-write mode (+false+) (default: +false+)
46
46
 
47
47
  +:check_compatibility+:: checks compatibility when saving
48
48
 
@@ -137,14 +137,11 @@ If a workbook is open and a workbook with the same name but in different path sh
137
137
 
138
138
  The methods +open+ and +new+ connect to workbooks opened outside of RobustExcelOle as well.
139
139
 
140
- Opening linked workbooks for EXCEL 2007 is supported
140
+ Opening linked workbooks for EXCEL 2007 is supported. Changing linked, unsaved workbooks from read-only to read-write causes a query whether to save the changes. This case cannot be
141
+ controlled (e.g. with help of some options) so far.
141
142
 
142
143
  Doing updating links seems to be dependent on calculation mode: updates happen, if the calcultion mode is automatic, and does not happen, if calculation mode is manual.
143
144
 
144
- Once we have a workbook, we can set some options, e.g.
145
-
146
- workbook.for_this_workbook(visible: true, read_only: false)
147
-
148
145
 
149
146
  === Reopening a workbook
150
147
 
@@ -270,6 +267,8 @@ If the workbook is unsaved, use the option +if_unsaved+ as desribed above.
270
267
 
271
268
  workbook.writable = false, {if_unsaved: :forget}
272
269
 
270
+ Changing from read-only to read-write for linked, unsaved workbooks is not being supported yet.
271
+
273
272
  === Checking whether the workbook is alive
274
273
 
275
274
  The method +alive?+ finds out whether the Excel workbook that is referenced by the Workbook object responds to methods. For example
@@ -277,4 +276,8 @@ The method +alive?+ finds out whether the Excel workbook that is referenced by t
277
276
  workbook.alive?
278
277
  # => true
279
278
 
279
+ === Setting options
280
+
281
+ Once we have a workbook, we can set some options, e.g.
280
282
 
283
+ workbook.for_this_workbook(visible: true, read_only: false)
@@ -7,7 +7,7 @@ require "fileutils"
7
7
 
8
8
  include RobustExcelOle
9
9
 
10
- Excel.close_all
10
+ Excel.close_all(if_unsaved: :forget)
11
11
  begin
12
12
  dir = create_tmpdir
13
13
  simple_file = dir + 'workbook.xls'
@@ -26,7 +26,7 @@ begin
26
26
 
27
27
  def define_columns sheet, columns_ids
28
28
  puts "define_columns:"
29
- first_column = sheet.range("A")
29
+ first_column = sheet.range("A:A")
30
30
  puts "first_column: #{first_column}"
31
31
 
32
32
  columns_ids.each_with_index do |id,idx|
@@ -9,7 +9,7 @@ include RobustExcelOle
9
9
 
10
10
  using StringRefinement
11
11
 
12
- Excel.close_all
12
+ Excel.close_all(if_unsaved: :forget)
13
13
  begin
14
14
  dir = create_tmpdir
15
15
  table_file = dir + 'workbook_listobjects.xlsx'
@@ -79,7 +79,7 @@ begin
79
79
  book.close(:if_unsaved => :forget)
80
80
 
81
81
  ensure
82
- Excel.close_all
82
+ Excel.close_all(if_unsaved: forget)
83
83
  rm_tmp(dir)
84
84
  end
85
85
 
@@ -7,7 +7,7 @@ require "fileutils"
7
7
 
8
8
  include RobustExcelOle
9
9
 
10
- Excel.close_all
10
+ Excel.close_all(if_unsaved: :forget)
11
11
  begin
12
12
  dir = create_tmpdir
13
13
  simple_file = dir + 'workbook.xls'
@@ -18,14 +18,18 @@ module User32
18
18
  typealias 'LPCSTR', 'const char*'
19
19
  typealias 'LPCWSTR', 'const wchar_t*'
20
20
  typealias 'UINT', 'unsigned int'
21
- typealias 'HANDLE', 'void*'
22
21
  typealias 'ppvObject', 'void**'
23
22
  typealias 'DWORD', 'unsigned long'
24
23
  typealias 'LPDWORD', 'DWORD*'
24
+ typealias 'PDWORD_PTR', 'DWORD**'
25
+ typealias 'WPARAM', 'UINT*'
26
+ typealias 'LPARAM', 'INT*'
27
+ typealias 'LRESULT', 'DWORD'
25
28
  # Import C functions from loaded libraries and set them as module functions
26
29
  extern 'DWORD GetWindowThreadProcessId(HWND, LPDWORD)'
27
30
  extern 'HWND FindWindowExA(HWND, HWND, LPCSTR, LPCSTR)'
28
31
  extern 'DWORD SetForegroundWindow(HWND)'
32
+ extern 'LRESULT SendMessageTimeoutA(HWND, UINT, WPARAM, LPARAM, UINT, UINT, PDWORD_PTR)'
29
33
  end
30
34
 
31
35
  module Oleacc
@@ -68,6 +72,7 @@ module RobustExcelOle
68
72
  attr_reader :ole_excel
69
73
  attr_reader :properties
70
74
  attr_reader :address_tool
75
+ attr_reader :hwnd
71
76
 
72
77
  alias ole_object ole_excel
73
78
 
@@ -127,15 +132,16 @@ module RobustExcelOle
127
132
  end
128
133
  connected = (not ole_xl.nil?) && win32ole_excel.nil?
129
134
  ole_xl ||= WIN32OLE.new('Excel.Application')
130
- hwnd = ole_xl.Hwnd
131
- stored = hwnd2excel(hwnd)
135
+ hwnd_xl = ole_xl.Hwnd
136
+ stored = hwnd2excel(hwnd_xl)
132
137
  if stored && stored.alive?
133
138
  result = stored
134
139
  else
135
140
  result = super(options)
136
141
  result.instance_variable_set(:@ole_excel, ole_xl)
142
+ result.instance_variable_set(:@hwnd, hwnd_xl)
137
143
  WIN32OLE.const_load(ole_xl, RobustExcelOle) unless RobustExcelOle.const_defined?(:CONSTANTS)
138
- @@hwnd2excel[hwnd] = WeakRef.new(result)
144
+ @@hwnd2excel[hwnd_xl] = WeakRef.new(result)
139
145
  end
140
146
  reused = options[:reuse] && stored && stored.alive?
141
147
  options = { displayalerts: :if_visible, visible: false, screenupdating: true }.merge(options) unless reused || connected
@@ -159,6 +165,7 @@ module RobustExcelOle
159
165
  opts = {visible: false, displayalerts: :if_visible}.merge(
160
166
  {visible: @properties[:visible], displayalerts: @properties[:displayalerts]}).merge(opts)
161
167
  @ole_excel = WIN32OLE.new('Excel.Application')
168
+ @hwnd = @ole_excel.Hwnd
162
169
  set_options(opts)
163
170
  if opts[:reopen_workbooks]
164
171
  workbook_class.books.each{ |book| book.open if !book.alive? && book.excel.alive? && book.excel == self }
@@ -531,13 +538,6 @@ module RobustExcelOle
531
538
  self
532
539
  end
533
540
 
534
- # @private
535
- def hwnd
536
- self.Hwnd
537
- rescue
538
- nil
539
- end
540
-
541
541
  # @private
542
542
  def self.print_hwnd2excel
543
543
  @@hwnd2excel.each do |hwnd,wr_excel|
@@ -554,11 +554,15 @@ module RobustExcelOle
554
554
 
555
555
  # returns true, if the Excel instances responds to VBA methods, false otherwise
556
556
  def alive?
557
- @ole_excel.Name
558
- true
559
- rescue
560
- # trace $!.message
561
- false
557
+ msg = 0x2008
558
+ wparam = 0
559
+ lparam = 0
560
+ flags = 0x0000 # 0x0002
561
+ duration = 5000
562
+ lpdw_result_puffer = ' ' * 32
563
+ status = User32::SendMessageTimeoutA(hwnd, msg, wparam, lparam, flags, duration, lpdw_result_puffer)
564
+ result = lpdw_result_puffer.unpack('L')[0]
565
+ status != 0
562
566
  end
563
567
 
564
568
  # returns unsaved workbooks in known (not opened by user) Excel instances
@@ -589,6 +593,11 @@ module RobustExcelOle
589
593
  end
590
594
  end
591
595
 
596
+ # returns, whether the current Excel instance is visible
597
+ def visible
598
+ @ole_excel.Visible
599
+ end
600
+
592
601
  # makes the current Excel instance visible or invisible
593
602
  def visible= visible_value
594
603
  return if visible_value.nil?
@@ -596,6 +605,11 @@ module RobustExcelOle
596
605
  @ole_excel.DisplayAlerts = @properties[:visible] if @properties[:displayalerts] == :if_visible
597
606
  end
598
607
 
608
+ # returns, wheter DisplayAlerts is enabled
609
+ def displayalerts
610
+ @ole_excel.DisplayAlerts
611
+ end
612
+
599
613
  # enables DisplayAlerts in the current Excel instance
600
614
  def displayalerts= displayalerts_value
601
615
  return if displayalerts_value.nil?
@@ -726,7 +740,7 @@ module RobustExcelOle
726
740
 
727
741
  # @private
728
742
  def to_s
729
- "#<Excel: #{hwnd}#{ ("not alive" unless alive?)}>"
743
+ "#<Excel: #{hwnd}#{ (" not alive" unless alive?)}>"
730
744
  end
731
745
 
732
746
  # @private
@@ -237,7 +237,7 @@ module General
237
237
  return filename unless filename[0,2] == "//"
238
238
  hostname = filename[0,filename[3,filename.length].index('/')+3]
239
239
  filename_wo_hostname = filename[hostname.length+1,filename.length]
240
- abs_filename = absolute_path(filename_wo_hostname).tr('\\','/').tr('C:/','c$/')
240
+ abs_filename = absolute_path(filename_wo_hostname).tr('\\','/').sub('C:/','c$/')
241
241
  adapted_filename = hostname + "/" + abs_filename
242
242
  NetworkDrive.get_all_drives.each do |d|
243
243
  new_filename = filename.sub(/#{(Regexp.escape(d.network_name))}/i,d.drive_letter)
@@ -1,3 +1,3 @@
1
1
  module RobustExcelOle
2
- VERSION = "1.36"
2
+ VERSION = "1.37"
3
3
  end
@@ -164,12 +164,12 @@ module RobustExcelOle
164
164
  raise ExcelREOError, "could not determine the Excel instance\n#{$!.message}"
165
165
  end
166
166
  @excel = excel_class.new(ole_excel)
167
- filename = @ole_workbook.Fullname.tr('\\','/')
167
+ file_name = @ole_workbook.Fullname.tr('\\','/')
168
168
  else
169
- filename = file_or_workbook
170
- ensure_workbook(filename, opts)
169
+ file_name = file_or_workbook
170
+ ensure_workbook(file_name, opts)
171
171
  end
172
- apply_options(filename, opts)
172
+ apply_options(file_name, opts)
173
173
  store_myself
174
174
  if block_given?
175
175
  begin
@@ -244,7 +244,7 @@ module RobustExcelOle
244
244
  end
245
245
 
246
246
  # @private
247
- def ensure_workbook(filename, options)
247
+ def ensure_workbook(file_name, options)
248
248
  set_was_open options, true
249
249
  return if (@ole_workbook && alive? && (options[:read_only].nil? || @ole_workbook.ReadOnly == options[:read_only]))
250
250
  set_was_open options, false
@@ -252,35 +252,35 @@ module RobustExcelOle
252
252
  ((options[:read_only]==true && self.ReadOnly==false) || (options[:read_only]==false && self.ReadOnly==true))
253
253
  raise OptionInvalid, ":if_unsaved:accept and change of read-only mode is not possible"
254
254
  end
255
- filename = @stored_filename ? @stored_filename : filename
256
- manage_nonexisting_file(filename,options)
255
+ file_name = @stored_filename ? @stored_filename : file_name
256
+ manage_nonexisting_file(file_name,options)
257
257
  excel_option = options[:force][:excel].nil? ? options[:default][:excel] : options[:force][:excel]
258
258
  ensure_excel(options)
259
259
  workbooks = @excel.Workbooks
260
- @ole_workbook = workbooks.Item(File.basename(filename)) rescue nil if @ole_workbook.nil?
260
+ @ole_workbook = workbooks.Item(File.basename(file_name)) rescue nil if @ole_workbook.nil?
261
261
  if @ole_workbook && alive?
262
262
  set_was_open options, true
263
- #open_or_create_workbook(filename,options) if (!options[:read_only].nil?) && options[:read_only]
264
- manage_changing_readonly_mode(options) if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
265
- manage_blocking_or_unsaved_workbook(filename,options)
263
+ #open_or_create_workbook(file_name,options) if (!options[:read_only].nil?) && options[:read_only]
264
+ manage_changing_readonly_mode(file_name, options) if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
265
+ manage_blocking_or_unsaved_workbook(file_name,options)
266
266
  else
267
267
  if (excel_option.nil? || excel_option == :current) &&
268
- !(::CONNECT_JRUBY_BUG && filename[0] == '/')
269
- connect(filename,options)
268
+ !(::CONNECT_JRUBY_BUG && file_name[0] == '/')
269
+ connect(file_name,options)
270
270
  else
271
- open_or_create_workbook(filename,options)
271
+ open_or_create_workbook(file_name,options)
272
272
  end
273
273
  end
274
274
  end
275
275
 
276
276
  private
277
277
 
278
- # applies options to workbook named with filename
279
- def apply_options(filename, options)
278
+ # applies options to workbook named with file_name
279
+ def apply_options(file_name, options)
280
280
  # changing read-only mode
281
281
  if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
282
- # ensure_workbook(filename, options)
283
- manage_changing_readonly_mode(options)
282
+ # ensure_workbook(file_name, options)
283
+ manage_changing_readonly_mode(file_name, options)
284
284
  end
285
285
  retain_saved do
286
286
  self.visible = options[:force][:visible].nil? ? @excel.Visible : options[:force][:visible]
@@ -290,10 +290,10 @@ module RobustExcelOle
290
290
  end
291
291
 
292
292
  # connects to an unknown workbook
293
- def connect(filename, options)
293
+ def connect(file_name, options)
294
294
  workbooks_number = excel_class.instance_count==0 ? 0 : excel_class.current.Workbooks.Count
295
295
  @ole_workbook = begin
296
- WIN32OLE.connect(General.absolute_path(filename))
296
+ WIN32OLE.connect(General.absolute_path(file_name))
297
297
  rescue
298
298
  if $!.message =~ /moniker/
299
299
  raise WorkbookConnectingBlockingError, "some workbook is blocking when connecting"
@@ -314,21 +314,37 @@ module RobustExcelOle
314
314
  @excel = excel_class.new(ole_excel)
315
315
  end
316
316
 
317
- def manage_changing_readonly_mode(options)
317
+ def manage_changing_readonly_mode(file_name, options)
318
318
  if !ole_workbook.Saved && options[:read_only]
319
319
  manage_unsaved_workbook_when_changing_readonly_mode(options)
320
320
  end
321
- change_readonly_mode(options)
321
+ change_readonly_mode(file_name, options)
322
322
  end
323
323
 
324
- def change_readonly_mode(options)
324
+ def change_readonly_mode(file_name, options)
325
325
  read_write_value = options[:read_only] ? RobustExcelOle::XlReadOnly : RobustExcelOle::XlReadWrite
326
326
  give_control_to_excel = !ole_workbook.Saved && options[:read_only] &&
327
327
  (options[:if_unsaved] == :excel || options[:if_unsaved] == :alert)
328
328
  displayalerts = give_control_to_excel ? true : @excel.Displayalerts
329
+ # applying ChangeFileAccess to a linked unsaved workbook to change to read-write
330
+ # causes a query
331
+ # how to check whether the workbook contains links?
332
+ #if options[:read_only]==false && !@ole_workbook.Saved # && @ole_workbook.LinkSources(RobustExcelOle::XlExcelLinks) # workbook linked
333
+ # # @ole_workbook.Saved = true
334
+ # raise WorkbookNotSaved, "linked workbook cannot be changed to read-write if it is unsaved"
335
+ #end
329
336
  @excel.with_displayalerts(displayalerts) {
330
- @ole_workbook.ChangeFileAccess('Mode' => read_write_value)
337
+ begin
338
+ @ole_workbook.ChangeFileAccess('Mode' => read_write_value)
339
+ rescue WIN32OLERuntimeError
340
+ raise WorkbookReadOnly, "cannot change read-only mode"
341
+ end
331
342
  }
343
+ # managing Excel bug:
344
+ # if the workbook is linked, then ChangeFileAccess to read-write kills the workbook
345
+ # if the linked workbook is unsaved, then ChangeFileAccess causes a query
346
+ # this query cannot be avoided or controlled so far (see above)
347
+ open_or_create_workbook(file_name, options) unless alive?
332
348
  end
333
349
 
334
350
  def manage_unsaved_workbook_when_changing_readonly_mode(options)
@@ -353,9 +369,9 @@ module RobustExcelOle
353
369
  end
354
370
  end
355
371
 
356
- def manage_nonexisting_file(filename, options)
357
- return if File.exist?(filename)
358
- abs_filename = General.absolute_path(filename)
372
+ def manage_nonexisting_file(file_name, options)
373
+ return if File.exist?(file_name)
374
+ abs_filename = General.absolute_path(file_name)
359
375
  if options[:if_absent] == :create
360
376
  ensure_excel(options) unless @excel && @excel.alive?
361
377
  @excel.Workbooks.Add
@@ -363,7 +379,7 @@ module RobustExcelOle
363
379
  begin
364
380
  empty_ole_workbook.SaveAs(abs_filename)
365
381
  rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
366
- raise FileNotFound, "could not save workbook with filename #{filename.inspect}"
382
+ raise FileNotFound, "could not save workbook with filename #{file_name.inspect}"
367
383
  end
368
384
  else
369
385
  raise FileNotFound, "file #{abs_filename.inspect} not found" +
@@ -371,90 +387,90 @@ module RobustExcelOle
371
387
  end
372
388
  end
373
389
 
374
- def manage_blocking_or_unsaved_workbook(filename, options)
375
- filename = General.absolute_path(filename)
376
- filename = General.canonize(filename)
390
+ def manage_blocking_or_unsaved_workbook(file_name, options)
391
+ file_name = General.absolute_path(file_name)
392
+ file_name = General.canonize(file_name)
377
393
  previous_file = General.canonize(@ole_workbook.Fullname.gsub('\\','/'))
378
- obstructed_by_other_book = (File.basename(filename) == File.basename(previous_file)) &&
379
- (File.dirname(filename) != File.dirname(previous_file))
394
+ obstructed_by_other_book = (File.basename(file_name) == File.basename(previous_file)) &&
395
+ (File.dirname(file_name) != File.dirname(previous_file))
380
396
  if obstructed_by_other_book
381
397
  # workbook is being obstructed by a workbook with same name and different path
382
- manage_blocking_workbook(filename,options)
398
+ manage_blocking_workbook(file_name,options)
383
399
  else
384
400
  unless @ole_workbook.Saved
385
401
  # workbook open and writable, not obstructed by another workbook, but not saved
386
- manage_unsaved_workbook(filename,options)
402
+ manage_unsaved_workbook(file_name,options)
387
403
  end
388
404
  end
389
405
  end
390
406
 
391
- def manage_blocking_workbook(filename, options)
407
+ def manage_blocking_workbook(file_name, options)
392
408
  blocked_filename = -> { General.canonize(@ole_workbook.Fullname.tr('\\','/')) }
393
409
  case options[:if_obstructed]
394
410
  when :raise
395
- raise WorkbookBlocked, "can't open workbook #{filename},
411
+ raise WorkbookBlocked, "can't open workbook #{file_name},
396
412
  because it is being blocked by #{blocked_filename.call} with the same name in a different path." +
397
413
  "\nHint: Use the option :if_blocked with values :forget or :save,
398
414
  to allow automatic closing of the blocking workbook (without or with saving before, respectively),
399
415
  before reopening the workbook."
400
416
  when :forget
401
- manage_forgetting_workbook(filename, options)
417
+ manage_forgetting_workbook(file_name, options)
402
418
  when :accept
403
419
  # do nothing
404
420
  when :save
405
- manage_saving_workbook(filename, options)
421
+ manage_saving_workbook(file_name, options)
406
422
  when :close_if_saved
407
423
  if !@ole_workbook.Saved
408
424
  raise WorkbookBlocked, "workbook with the same name in a different path is unsaved: #{blocked_filename.call}" +
409
425
  "\nHint: Use the option if_blocked: :save to save the workbook"
410
426
  else
411
- manage_forgetting_workbook(filename, options)
427
+ manage_forgetting_workbook(file_name, options)
412
428
  end
413
429
  when :new_excel
414
- manage_new_excel(filename, options)
430
+ manage_new_excel(file_name, options)
415
431
  else
416
432
  raise OptionInvalid, ":if_blocked: invalid option: #{options[:if_obstructed].inspect}" +
417
433
  "\nHint: Valid values are :raise, :forget, :save, :close_if_saved, :new_excel"
418
434
  end
419
435
  end
420
436
 
421
- def manage_unsaved_workbook(filename, options)
437
+ def manage_unsaved_workbook(file_name, options)
422
438
  case options[:if_unsaved]
423
439
  when :raise
424
- raise WorkbookNotSaved, "workbook is already open but not saved: #{File.basename(filename).inspect}" +
440
+ raise WorkbookNotSaved, "workbook is already open but not saved: #{File.basename(file_name).inspect}" +
425
441
  "\nHint: Use the option :if_unsaved with values :forget to close the unsaved workbook,
426
442
  :accept to let it open, or :save to save it, respectivly"
427
443
  when :forget
428
- manage_forgetting_workbook(filename, options)
444
+ manage_forgetting_workbook(file_name, options)
429
445
  when :accept
430
446
  # do nothing
431
447
  when :save
432
- manage_saving_workbook(filename, options)
448
+ manage_saving_workbook(file_name, options)
433
449
  when :alert, :excel
434
- @excel.with_displayalerts(true) { open_or_create_workbook(filename,options) }
450
+ @excel.with_displayalerts(true) { open_or_create_workbook(file_name,options) }
435
451
  when :new_excel
436
- manage_new_excel(filename, options)
452
+ manage_new_excel(file_name, options)
437
453
  else
438
454
  raise OptionInvalid, ":if_unsaved: invalid option: #{options[:if_unsaved].inspect}" +
439
455
  "\nHint: Valid values are :raise, :forget, :save, :accept, :alert, :excel, :new_excel"
440
456
  end
441
457
  end
442
458
 
443
- def manage_forgetting_workbook(filename, options)
459
+ def manage_forgetting_workbook(file_name, options)
444
460
  @excel.with_displayalerts(false) { @ole_workbook.Close }
445
461
  @ole_workbook = nil
446
- open_or_create_workbook(filename, options)
462
+ open_or_create_workbook(file_name, options)
447
463
  end
448
464
 
449
- def manage_saving_workbook(filename, options)
465
+ def manage_saving_workbook(file_name, options)
450
466
  save unless @ole_workbook.Saved
451
- manage_forgetting_workbook(filename, options) if options[:if_obstructed] == :save
467
+ manage_forgetting_workbook(file_name, options) if options[:if_obstructed] == :save
452
468
  end
453
469
 
454
- def manage_new_excel(filename, options)
470
+ def manage_new_excel(file_name, options)
455
471
  @excel = excel_class.new(reuse: false)
456
472
  @ole_workbook = nil
457
- open_or_create_workbook(filename, options)
473
+ open_or_create_workbook(file_name, options)
458
474
  end
459
475
 
460
476
  def explore_workbook_error(msg, want_change_readonly = nil)
@@ -473,10 +489,10 @@ module RobustExcelOle
473
489
  end
474
490
  end
475
491
 
476
- def open_or_create_workbook(filename, options)
492
+ def open_or_create_workbook(file_name, options)
477
493
  return if @ole_workbook && options[:if_unsaved] != :alert && options[:if_unsaved] != :excel &&
478
494
  (options[:read_only].nil? || options[:read_only]==@ole_workbook.ReadOnly )
479
- abs_filename = General.absolute_path(filename)
495
+ abs_filename = General.absolute_path(file_name)
480
496
  workbooks = begin
481
497
  @excel.Workbooks
482
498
  rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
@@ -493,7 +509,7 @@ module RobustExcelOle
493
509
  end
494
510
  # workaround for bug in Excel 2010: workbook.Open does not always return the workbook when given file name
495
511
  @ole_workbook = begin
496
- workbooks.Item(File.basename(filename))
512
+ workbooks.Item(File.basename(file_name))
497
513
  rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
498
514
  raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message}"
499
515
  end
@@ -536,8 +552,8 @@ module RobustExcelOle
536
552
  # creates, i.e., opens a new, empty workbook, and saves it under a given filename
537
553
  # @param [String] filename the filename under which the new workbook should be saved
538
554
  # @param [Hash] opts the options as in Workbook::open
539
- def self.create(filename, opts = { })
540
- open(filename, if_absent: :create)
555
+ def self.create(file_name, opts = { })
556
+ open(file_name, if_absent: :create)
541
557
  end
542
558
 
543
559
  # closes the workbook, if it is alive
@@ -656,11 +672,10 @@ module RobustExcelOle
656
672
  open_opts[:was_open] = nil
657
673
  book = open(file, open_opts)
658
674
  was_visible = book.visible
659
- was_writable = book.writable
660
675
  was_saved = book.saved
661
676
  was_check_compatibility = book.check_compatibility
662
677
  was_calculation = book.excel.properties[:calculation]
663
- #opts[:read_only] = !opts[:writable] unless (!opts[:read_only].nil? || opts[:writable].nil? || open_opts[:was_open])
678
+ was_writable = book.writable
664
679
  if (opts[:read_only].nil? && !opts[:writable].nil? && !open_opts[:was_open] && (was_saved || opts[:if_unsaved]==:save))
665
680
  opts[:read_only] = !opts[:writable]
666
681
  end
@@ -668,13 +683,14 @@ module RobustExcelOle
668
683
  yield book
669
684
  ensure
670
685
  if book && book.alive?
686
+ was_open = open_opts[:was_open]
671
687
  do_not_write = opts[:read_only] || opts[:writable]==false
672
688
  book.save unless book.saved || do_not_write || !book.writable
673
- if ((opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable))
689
+ if was_open && ((opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable))
674
690
  book.send :apply_options, file, opts.merge({read_only: !was_writable,
675
691
  if_unsaved: (opts[:writable]==false ? :forget : :save)})
676
692
  end
677
- was_open = open_opts[:was_open]
693
+ #was_open = open_opts[:was_open]
678
694
  if was_open
679
695
  book.visible = was_visible
680
696
  book.CheckCompatibility = was_check_compatibility
@@ -1018,7 +1034,7 @@ module RobustExcelOle
1018
1034
 
1019
1035
  # returns the full file name of the workbook
1020
1036
  def filename
1021
- @filename ||= General.canonize(@ole_workbook.Fullname.tr('\\','/')) rescue nil
1037
+ General.canonize(@ole_workbook.Fullname.tr('\\','/')) rescue nil
1022
1038
  end
1023
1039
 
1024
1040
  # @returns true, if the workbook is not in read-only mode
@@ -1040,7 +1056,7 @@ module RobustExcelOle
1040
1056
  options = options.merge(unsaved_opts) if unsaved_opts
1041
1057
  options = {:read_only => !writable_value}.merge(options)
1042
1058
  if options[:read_only] != @ole_workbook.ReadOnly
1043
- manage_changing_readonly_mode(options)
1059
+ manage_changing_readonly_mode(filename, options)
1044
1060
  manage_unsaved_workbook(filename,options) if !@ole_workbook.Saved && unsaved_opts
1045
1061
  end
1046
1062
  end
Binary file
data/spec/excel_spec.rb CHANGED
@@ -75,6 +75,7 @@ module RobustExcelOle
75
75
  it "should set visible true" do
76
76
  @ole_excel.Visible.should be false
77
77
  excel = Excel.current(:visible => true)
78
+ excel.visible.should be true
78
79
  excel.Visible.should be true
79
80
  end
80
81
 
@@ -88,6 +89,7 @@ module RobustExcelOle
88
89
  @ole_excel.Visible.should be true
89
90
  excel = Excel.current(:visible => false)
90
91
  excel.Visible.should be false
92
+ excel.visible.should be false
91
93
  end
92
94
 
93
95
  it "should preserve displayalerts true" do
@@ -454,7 +456,9 @@ module RobustExcelOle
454
456
  @excel1.recreate
455
457
  @excel1.should be_a Excel
456
458
  @excel1.should be_alive
459
+ @excel1.visible.should be false
457
460
  @excel1.Visible.should be false
461
+ @excel1.displayalerts.should be false
458
462
  @excel1.DisplayAlerts.should be false
459
463
  @book1.should_not be_alive
460
464
  @book1.open
@@ -465,14 +469,20 @@ module RobustExcelOle
465
469
 
466
470
  it "should recreate an Excel instance with old visible and displayalerts values" do
467
471
  @excel1.visible = true
472
+ @excel1.Visible.should be true
473
+ @excel1.visible.should be true
468
474
  @excel1.displayalerts = true
475
+ @excel1.DisplayAlerts.should be true
476
+ @excel1.displayalerts.should be true
469
477
  @excel1.close
470
478
  @excel1.should_not be_alive
471
479
  @excel1.recreate
472
480
  @excel1.should be_a Excel
473
481
  @excel1.should be_alive
474
482
  @excel1.Visible.should be true
483
+ @excel1.visible.should be true
475
484
  @excel1.DisplayAlerts.should be true
485
+ @excel1.displayalerts.should be true
476
486
  @book1.open
477
487
  @book1.should be_alive
478
488
  @excel1.close
@@ -27,7 +27,9 @@ describe Workbook do
27
27
  @another_simple_file = @dir + '/another_workbook.xls'
28
28
  @simple_file_xlsm = @dir + '/workbook.xls'
29
29
  @simple_file_xlsx = @dir + '/workbook.xlsx'
30
+ @simple_file_copy = @dir + '/workbook_copy.xls'
30
31
  @simple_file1 = @simple_file
32
+ @simple_file_copy1 = @simple_file_copy
31
33
  end
32
34
 
33
35
  after do
@@ -1083,7 +1085,7 @@ describe Workbook do
1083
1085
  context "with filename" do
1084
1086
 
1085
1087
  before do
1086
- @book = Workbook.open(@simple_file)
1088
+ @book = Workbook.open(@simple_file1)
1087
1089
  end
1088
1090
 
1089
1091
  after do
@@ -1091,7 +1093,7 @@ describe Workbook do
1091
1093
  end
1092
1094
 
1093
1095
  it "should return full file name" do
1094
- @book.filename.should == @simple_file
1096
+ @book.filename.should == @simple_file1
1095
1097
  end
1096
1098
 
1097
1099
  it "should return nil for dead book" do
@@ -1099,6 +1101,11 @@ describe Workbook do
1099
1101
  @book.filename.should == nil
1100
1102
  end
1101
1103
 
1104
+ it "should return right filename when saved as another file name" do
1105
+ @book.save_as(@simple_file_copy1)
1106
+ @book.filename.should == @simple_file_copy1
1107
+ end
1108
+
1102
1109
  end
1103
1110
 
1104
1111
  context "with ==" do
@@ -370,11 +370,63 @@ describe Workbook do
370
370
  }.to raise_error(WorkbookLinked)
371
371
  end
372
372
 
373
- it "should raise error when trying to change the read-only mode of the linked workbook" do
373
+ it "should change read-only mode of the linked workbook to read-only" do
374
374
  book2 = Workbook.open(@sub_file, :read_only => true)
375
375
  book2.ReadOnly.should be true
376
376
  end
377
+
378
+ it "should change read-only mode of the main workbook to read-only" do
379
+ book1 = Workbook.open(@main_file, :read_only => true)
380
+ book1.ReadOnly.should be true
381
+ end
382
+
377
383
  end
384
+
385
+ context "with read-only linked workbook" do
386
+
387
+ before do
388
+ @book1 = Workbook.open(@main_file, read_only: true, visible: true)
389
+ end
390
+
391
+ it "should change read-only mode of the main workbook to read-write" do
392
+ book2 = Workbook.open(@main_file, :read_only => false)
393
+ book2.ReadOnly.should be false
394
+ end
395
+
396
+ # here an query occurs whether to save the changes
397
+ # so far this case is not being controlled with help of options
398
+ it "should change read-only mode of the unsaved main workbook to read-write" do
399
+ book1.sheet(1)[1,1] = "foo"
400
+ book1 = Workbook.open(@main_file, :read_only => false)
401
+ book1.ReadOnly.should be false
402
+ book1.Saved.should be false
403
+ end
404
+
405
+ it "should change read-only mode of the main unsaved workbook to read-write" do
406
+ book2 = Workbook.open(@sub_file, :read_only => false)
407
+ book2.ReadOnly.should be false
408
+ end
409
+
410
+ it "should change read-only mode of the main workbook to read-write" do
411
+ book1 = Workbook.open(@main_file, :read_only => false)
412
+ book1.ReadOnly.should be false
413
+ end
414
+
415
+ end
416
+
417
+ context "with read-only" do
418
+
419
+ before do
420
+ @book1 = Workbook.open(@main_file, :read_only => true)
421
+ end
422
+
423
+ it "should change read-only mode from read-only to read-write" do
424
+ expect{
425
+ Workbook.open(@main_file, :read_only => false)
426
+ }.to_not raise_error
427
+ end
428
+ end
429
+
378
430
  end
379
431
 
380
432
  describe "basic tests with xlsx-workbooks" do
@@ -3165,9 +3217,11 @@ describe Workbook do
3165
3217
  before do
3166
3218
  @new_book = Workbook.open(@simple_file)
3167
3219
  end
3220
+
3168
3221
  after do
3169
3222
  @new_book.close
3170
3223
  end
3224
+
3171
3225
  it "should provide the excel instance of the book" do
3172
3226
  excel = @new_book.excel
3173
3227
  excel.class.should == Excel
@@ -3329,6 +3383,7 @@ describe Workbook do
3329
3383
  end
3330
3384
 
3331
3385
  it "should open xlsx file" do
3386
+
3332
3387
  book = Workbook.open(@simple_file_xlsx, :visible => true)
3333
3388
  book.close
3334
3389
  end
@@ -3380,4 +3435,5 @@ describe Workbook do
3380
3435
  end
3381
3436
  end
3382
3437
  end
3383
- end
3438
+ end
3439
+
@@ -311,6 +311,24 @@ describe Workbook do
311
311
 
312
312
  context "with no books" do
313
313
 
314
+ it "should open the linked workbook" do
315
+ Workbook.unobtrusively(@sub_file, :writable => true) do |book|
316
+ book.ReadOnly.should be false
317
+ book.filename.should == @sub_file
318
+ end
319
+ Excel.current.workbooks.should == []
320
+ end
321
+
322
+ it "should open the workbook and its linked workbook" do
323
+ Workbook.unobtrusively(@main_file, :writable => true) do |book|
324
+ book.ReadOnly.should be false
325
+ book.filename.should == @main_file
326
+ book.excel.workbooks.map{|b| b.filename}.should == [@main_file, @sub_file]
327
+ end
328
+ Excel.current.workbooks.map{|b| b.filename}.should == [@sub_file]
329
+ end
330
+
331
+
314
332
  it "should open the linked workbook in read-only" do
315
333
  Workbook.unobtrusively(@sub_file, :writable => false) do |book|
316
334
  book.ReadOnly.should be true
@@ -323,14 +341,14 @@ describe Workbook do
323
341
  Workbook.unobtrusively(@main_file, :writable => false) do |book|
324
342
  book.ReadOnly.should be true
325
343
  book.filename.should == @main_file
326
- book.excel.workbooks.map{|b| b.filename}.should == [@sub_file, @main_file]
344
+ book.excel.workbooks.map{|b| b.filename}.should == [@main_file, @sub_file]
327
345
  end
328
346
  Excel.current.workbooks.map{|b| b.filename}.should == [@sub_file]
329
347
  end
330
348
 
331
349
  it "should not write the linked workbook and close it" do
332
- Workbook.unobtrusively(@sub_file, :writable => false) do |book|
333
- book.ReadOnly.should be true
350
+ Workbook.unobtrusively(@sub_file) do |book|
351
+ book.ReadOnly.should be false
334
352
  book.filename.should == @sub_file
335
353
  @old_value = book.sheet(1)[1,1]
336
354
  book.sheet(1)[1,1] = book.sheet(1)[1,1] == "foo" ? "bar" : "foo"
@@ -339,8 +357,8 @@ describe Workbook do
339
357
  end
340
358
 
341
359
  it "should not write the main workbook and close the linked file as well" do
342
- Workbook.unobtrusively(@main_file, :writable => false) do |book|
343
- book.ReadOnly.should be true
360
+ Workbook.unobtrusively(@main_file) do |book|
361
+ book.ReadOnly.should be false
344
362
  book.filename.should == @main_file
345
363
  @old_value = book.sheet(1)[1,1]
346
364
  book.sheet(1)[1,1] = book.sheet(1)[1,1] == "foo" ? "bar" : "foo"
@@ -362,7 +380,7 @@ describe Workbook do
362
380
  end
363
381
  end
364
382
 
365
- it "should force to read-only" do
383
+ it "should raise error, when forcing the linked workbook to read-only" do
366
384
  expect{
367
385
  Workbook.unobtrusively(@sub_file, :read_only => true) do
368
386
  end
@@ -946,20 +964,6 @@ describe Workbook do
946
964
  }.to raise_error(WorkbookNotSaved)
947
965
  end
948
966
 
949
- =begin
950
- it "should remain writable" do
951
- Workbook.unobtrusively(@unsaved_file, :read_only => true, :if_unsaved => :save) do |book|
952
- book.saved.should be true
953
- book.visible.should be true
954
- book.writable.should be false
955
- end
956
- ole_wb = WIN32OLE.connect(@abs_filename)
957
- ole_wb.Saved.should be false
958
- @ole_e1.Visible.should be true
959
- ole_wb.ReadOnly.should be false
960
- end
961
- =end
962
-
963
967
  it "should remain unsaved when modifying" do
964
968
  Workbook.unobtrusively(@unsaved_file) do |book|
965
969
  book.sheet(1)[1,1] = "bar" #book.sheet(1)[1,1] == "foo" ? "bar" : "foo"
@@ -1386,15 +1390,13 @@ describe Workbook do
1386
1390
  end
1387
1391
 
1388
1392
  it "should force to read-only" do
1389
- expect{
1390
- Workbook.unobtrusively(@simple_file1, :if_unsaved => :forget, :read_only => true) do |book|
1391
- book.ReadOnly.should be true
1392
- book.should == @book
1393
- book.filename.should == @book.filename
1394
- book.excel.should == @book.excel
1395
- book.sheet(1)[1,1] = book.sheet(1)[1,1] == "foo" ? "bar" : "foo"
1396
- end
1397
- }.to raise_error(WorkbookReadOnly)
1393
+ Workbook.unobtrusively(@simple_file1, :if_unsaved => :forget, :read_only => true) do |book|
1394
+ book.ReadOnly.should be true
1395
+ book.should == @book
1396
+ book.filename.should == @book.filename
1397
+ book.excel.should == @book.excel
1398
+ book.sheet(1)[1,1] = book.sheet(1)[1,1] == "foo" ? "bar" : "foo"
1399
+ end
1398
1400
  end
1399
1401
 
1400
1402
 
@@ -1696,9 +1698,18 @@ describe Workbook do
1696
1698
  end
1697
1699
 
1698
1700
  it "should open as read-only" do
1699
- expect{
1700
- Workbook.unobtrusively(@simple_file1, :if_unsaved => :accept, :read_only => false, :writable => false)
1701
- }.to raise_error(OptionInvalid)
1701
+ Workbook.unobtrusively(@simple_file1, :if_unsaved => :accept, :read_only => false, :writable => false) do |book|
1702
+ book.Readonly.should be false
1703
+ book.Saved.should be false
1704
+ book.sheet(1)[1,1].should == @old_value
1705
+ book.sheet(1)[1,1] = book.sheet(1)[1,1] == "foo" ? "bar" : "foo"
1706
+ end
1707
+ @book.ReadOnly.should be true
1708
+ @book.Saved.should be false
1709
+ @book.sheet(1)[1,1].should_not == @old_value
1710
+ @book.close(if_unsaved: :forget)
1711
+ book2 = Workbook.open(@simple_file1)
1712
+ book2.sheet(1)[1,1].should_not == @old_value
1702
1713
  end
1703
1714
 
1704
1715
  it "should remain read-only and not write, even with :writable => true" do
@@ -315,13 +315,13 @@ describe Worksheet do
315
315
  it "should raise an error if name not defined" do
316
316
  expect {
317
317
  @sheet1.namevalue_global("foo")
318
- }.to raise_error(NameNotFound, /name "foo" not in/)
318
+ }.to raise_error(NameNotFound, /cannot find name "foo"/)
319
319
  end
320
320
 
321
321
  it "should raise an error of coordinates are given instead of a defined name" do
322
322
  expect {
323
323
  @sheet1.namevalue_global("A1")
324
- }.to raise_error(NameNotFound, /name "A1" not in/)
324
+ }.to raise_error(NameNotFound, /cannot find name "A1"/)
325
325
  end
326
326
 
327
327
  it "should return default value for a range with empty contents" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: robust_excel_ole
3
3
  version: !ruby/object:Gem::Version
4
- version: '1.36'
4
+ version: '1.37'
5
5
  platform: ruby
6
6
  authors:
7
7
  - traths
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-10-29 00:00:00.000000000 Z
11
+ date: 2021-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry