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 +4 -4
- data/Changelog +5 -0
- data/docs/README_open.rdoc +9 -6
- data/examples/modifying_sheets/example_access_sheets_and_cells.rb +1 -1
- data/examples/modifying_sheets/example_add_names.rb +1 -1
- data/examples/modifying_sheets/example_listobjects.rb +2 -2
- data/examples/modifying_sheets/example_ranges.rb +1 -1
- data/lib/robust_excel_ole/excel.rb +31 -17
- data/lib/robust_excel_ole/general.rb +1 -1
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +80 -64
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/excel_spec.rb +10 -0
- data/spec/workbook_specs/workbook_misc_spec.rb +9 -2
- data/spec/workbook_specs/workbook_open_spec.rb +58 -2
- data/spec/workbook_specs/workbook_unobtr_spec.rb +43 -32
- data/spec/worksheet_spec.rb +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 646308c3740c8716d9fb91b9c0288edc6e915c060bdd713401980608d412119a
|
4
|
+
data.tar.gz: 379a3bd099724e9cd6adc2542d804d4f4737eafc47742892dbc1ba4914f7b7c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz: '
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '02308d88008a6e7d5362b0c793f1ab4e55025b7df0d19741dbe66775450f672b654c9766ac3e49d6ec840d497b9fa39befd1f66e6d20e5a5539d6cf3eefbc276'
|
7
|
+
data.tar.gz: 874eaf4089951eb94ac101699198e35981b72084036eb171ec70eb69dc2c135951138f773844b945ff7f4ebbd8d3a4020f3bdaf3f4286f165334e270ada23118
|
data/Changelog
CHANGED
data/docs/README_open.rdoc
CHANGED
@@ -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)
|
@@ -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
|
|
@@ -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
|
-
|
131
|
-
stored = hwnd2excel(
|
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[
|
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
|
-
|
558
|
-
|
559
|
-
|
560
|
-
#
|
561
|
-
|
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('\\','/').
|
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)
|
@@ -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
|
-
|
167
|
+
file_name = @ole_workbook.Fullname.tr('\\','/')
|
168
168
|
else
|
169
|
-
|
170
|
-
ensure_workbook(
|
169
|
+
file_name = file_or_workbook
|
170
|
+
ensure_workbook(file_name, opts)
|
171
171
|
end
|
172
|
-
apply_options(
|
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(
|
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
|
-
|
256
|
-
manage_nonexisting_file(
|
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(
|
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(
|
264
|
-
manage_changing_readonly_mode(options) if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
265
|
-
manage_blocking_or_unsaved_workbook(
|
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 &&
|
269
|
-
connect(
|
268
|
+
!(::CONNECT_JRUBY_BUG && file_name[0] == '/')
|
269
|
+
connect(file_name,options)
|
270
270
|
else
|
271
|
-
open_or_create_workbook(
|
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
|
279
|
-
def apply_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(
|
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(
|
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(
|
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
|
-
|
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(
|
357
|
-
return if File.exist?(
|
358
|
-
abs_filename = General.absolute_path(
|
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 #{
|
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(
|
375
|
-
|
376
|
-
|
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(
|
379
|
-
(File.dirname(
|
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(
|
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(
|
402
|
+
manage_unsaved_workbook(file_name,options)
|
387
403
|
end
|
388
404
|
end
|
389
405
|
end
|
390
406
|
|
391
|
-
def manage_blocking_workbook(
|
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 #{
|
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(
|
417
|
+
manage_forgetting_workbook(file_name, options)
|
402
418
|
when :accept
|
403
419
|
# do nothing
|
404
420
|
when :save
|
405
|
-
manage_saving_workbook(
|
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(
|
427
|
+
manage_forgetting_workbook(file_name, options)
|
412
428
|
end
|
413
429
|
when :new_excel
|
414
|
-
manage_new_excel(
|
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(
|
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(
|
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(
|
444
|
+
manage_forgetting_workbook(file_name, options)
|
429
445
|
when :accept
|
430
446
|
# do nothing
|
431
447
|
when :save
|
432
|
-
manage_saving_workbook(
|
448
|
+
manage_saving_workbook(file_name, options)
|
433
449
|
when :alert, :excel
|
434
|
-
@excel.with_displayalerts(true) { open_or_create_workbook(
|
450
|
+
@excel.with_displayalerts(true) { open_or_create_workbook(file_name,options) }
|
435
451
|
when :new_excel
|
436
|
-
manage_new_excel(
|
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(
|
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(
|
462
|
+
open_or_create_workbook(file_name, options)
|
447
463
|
end
|
448
464
|
|
449
|
-
def manage_saving_workbook(
|
465
|
+
def manage_saving_workbook(file_name, options)
|
450
466
|
save unless @ole_workbook.Saved
|
451
|
-
manage_forgetting_workbook(
|
467
|
+
manage_forgetting_workbook(file_name, options) if options[:if_obstructed] == :save
|
452
468
|
end
|
453
469
|
|
454
|
-
def manage_new_excel(
|
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(
|
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(
|
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(
|
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(
|
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(
|
540
|
-
open(
|
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
|
-
|
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
|
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
|
-
|
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(@
|
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 == @
|
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
|
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 == [@
|
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
|
333
|
-
book.ReadOnly.should be
|
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
|
343
|
-
book.ReadOnly.should be
|
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
|
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
|
-
|
1390
|
-
|
1391
|
-
|
1392
|
-
|
1393
|
-
|
1394
|
-
|
1395
|
-
|
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
|
-
|
1700
|
-
|
1701
|
-
|
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
|
data/spec/worksheet_spec.rb
CHANGED
@@ -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"
|
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"
|
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.
|
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-
|
11
|
+
date: 2021-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|