robust_excel_ole 1.36 → 1.37

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