robust_excel_ole 1.13 → 1.14
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 +14 -4
- data/README.rdoc +34 -43
- data/___dummy_workbook.xls +0 -0
- data/docs/README_excel.rdoc +2 -2
- data/docs/README_open.rdoc +51 -34
- data/docs/README_ranges.rdoc +80 -80
- data/docs/README_save_close.rdoc +9 -9
- data/docs/README_sheet.rdoc +17 -17
- data/lib/robust_excel_ole.rb +3 -1
- data/lib/robust_excel_ole/excel.rb +38 -33
- data/lib/robust_excel_ole/reo_common.rb +1 -2
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +110 -83
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/workbook_spec.rb +2 -2
- data/spec/workbook_specs/workbook_open_spec.rb +36 -8
- data/spec/workbook_specs/workbook_unobtr_spec.rb +379 -16
- metadata +3 -2
data/docs/README_save_close.rdoc
CHANGED
@@ -6,17 +6,17 @@
|
|
6
6
|
|
7
7
|
Imagine, you have opened a workbook with
|
8
8
|
|
9
|
-
|
9
|
+
workbook = Workbook.open('spec/data/workbook.xls', :visible => true)
|
10
10
|
|
11
11
|
and have modified it.
|
12
12
|
|
13
13
|
You can save the workbook by
|
14
14
|
|
15
|
-
|
15
|
+
workbook.save
|
16
16
|
|
17
17
|
If you want to save a workbook with a file name, then use
|
18
18
|
|
19
|
-
|
19
|
+
workbook.save_as('new_workbook.xls')
|
20
20
|
|
21
21
|
The options and respective valid values are the following:
|
22
22
|
|
@@ -33,19 +33,19 @@ If a workbook with the file name already exists, then
|
|
33
33
|
|
34
34
|
For example, you want to save a workbook and overwrite the file if it exists before, then use
|
35
35
|
|
36
|
-
|
36
|
+
workbook.save_as('another_workbook.xls', :if_exists => :overwrite)
|
37
37
|
|
38
38
|
If a workbook blocks the workbook that should be saved, then the former one can be saved and closed before.
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
40
|
+
workbook = Workbook.open('spec/data/workbook.xls')
|
41
|
+
workbook2 = Workbook.open('spec/data/another_workbook.xls')
|
42
|
+
workbook2.save_as('dir/workbook.xls', :if_exists => :overwrite, :if_obstructed => :save)
|
43
43
|
|
44
44
|
=== Closing a workbook.
|
45
45
|
|
46
46
|
You can close the workbook with the command
|
47
47
|
|
48
|
-
|
48
|
+
workbook.close
|
49
49
|
|
50
50
|
There is one option: +:if_unsaved+ . It can have one of the following values:
|
51
51
|
|
@@ -62,7 +62,7 @@ The option specifies: If the workbook is unsaved, then
|
|
62
62
|
|
63
63
|
You can open a workbook with given file name.
|
64
64
|
|
65
|
-
|
65
|
+
workbook = Workbook.open('spec/data/workbook.xls')
|
66
66
|
|
67
67
|
You can save a workbook with given file name, if it is open.
|
68
68
|
|
data/docs/README_sheet.rdoc
CHANGED
@@ -6,30 +6,30 @@ Worksheets are represented by Worksheet objects.
|
|
6
6
|
|
7
7
|
Assume you have opened a workbook
|
8
8
|
|
9
|
-
|
9
|
+
workbook = Workbook.open('spec/data/workbook.xls', :visible => true)
|
10
10
|
|
11
11
|
=== Accessing a worksheet.
|
12
12
|
|
13
13
|
You can access a worksheet by giving the number
|
14
14
|
|
15
|
-
|
15
|
+
worksheet = book.sheet(1)
|
16
16
|
|
17
17
|
or its name
|
18
18
|
|
19
|
-
|
19
|
+
worksheet = book.sheet('Sheet1')
|
20
20
|
|
21
21
|
You can get the first and last worksheet with
|
22
22
|
|
23
|
-
|
23
|
+
worksheet = book.first_sheet
|
24
24
|
|
25
25
|
and
|
26
26
|
|
27
|
-
|
27
|
+
worksheet = book.last_sheet
|
28
28
|
|
29
|
-
You can access all
|
29
|
+
You can access all Worksheet objects by using the methods Workbook#each.
|
30
30
|
|
31
|
-
|
32
|
-
# do something with
|
31
|
+
workbook.each do |worksheet|
|
32
|
+
# do something with worksheet
|
33
33
|
end
|
34
34
|
|
35
35
|
Once you have got a Sheet object (in RobustExcelOle), you can apply all VBA methods that you would apply to a VBA Worksheet object
|
@@ -40,38 +40,38 @@ For some common and complex tasks you can apply methods of RobustExcelOle.
|
|
40
40
|
|
41
41
|
You can read and change the worksheet name.
|
42
42
|
|
43
|
-
|
43
|
+
worksheet1.name
|
44
44
|
# => "Sheet1"
|
45
45
|
|
46
|
-
|
46
|
+
worksheet1.name = "new_sheet"
|
47
47
|
|
48
48
|
=== Adding and copying a worksheet.
|
49
49
|
|
50
50
|
You can add (append) an empty worksheet using
|
51
51
|
|
52
|
-
|
52
|
+
workbook.add_empty_sheet
|
53
53
|
|
54
54
|
Additionally you can name it.
|
55
55
|
|
56
|
-
|
56
|
+
workbook.add_empty_sheet(:as => 'sheet_name')
|
57
57
|
|
58
58
|
You can specify the position of the added empty worksheet.
|
59
59
|
|
60
|
-
|
60
|
+
workbook.add_empty_sheet(:as => 'new_name', :before => another_sheet)
|
61
61
|
|
62
62
|
You can copy a worksheet and add it.
|
63
63
|
|
64
|
-
|
64
|
+
workbook.copy_sheet sheet
|
65
65
|
|
66
66
|
Additionally you can specify a name and a position.
|
67
67
|
|
68
|
-
|
68
|
+
workbook.copy_sheet(sheet, :as => 'new_name', :after => another_sheet)
|
69
69
|
|
70
70
|
If you want to copy a worksheet, if a worksheet +sheet+ is given, and add an empty worksheet, if no worksheet is given, then use
|
71
71
|
|
72
|
-
|
72
|
+
workbook.add_or_copy_sheet
|
73
73
|
|
74
|
-
|
74
|
+
workbook.add_or_copy_sheet(sheet, :as => 'new_name', :after => another_sheet)
|
75
75
|
|
76
76
|
Note, that running in jruby, due to some restrictions of jruby, there is a workaround when adding or copy a worksheet at the end (appending): the last worksheet is being copied and deleted afterwards, in order to serve as a dummy worksheet. This may cause a different behaviour.
|
77
77
|
|
data/lib/robust_excel_ole.rb
CHANGED
@@ -14,5 +14,7 @@ require File.join(File.dirname(__FILE__), 'robust_excel_ole/worksheet')
|
|
14
14
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/cell')
|
15
15
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/range')
|
16
16
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/cygwin') if RUBY_PLATFORM =~ /cygwin/
|
17
|
-
#+#require "robust_excel_ole/version"
|
18
17
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/version')
|
18
|
+
|
19
|
+
include RobustExcelOle
|
20
|
+
include General
|
@@ -76,12 +76,7 @@ module RobustExcelOle
|
|
76
76
|
ole_xl = win32ole_excel unless win32ole_excel.nil?
|
77
77
|
options = { :reuse => true }.merge(options)
|
78
78
|
if options[:reuse] == true && ole_xl.nil?
|
79
|
-
ole_xl =
|
80
|
-
excel_instance = known_excel_instance
|
81
|
-
excel_instance.ole_excel unless excel_instance.nil?
|
82
|
-
else
|
83
|
-
current_excel
|
84
|
-
end
|
79
|
+
ole_xl = current_ole_excel
|
85
80
|
end
|
86
81
|
connected = (not ole_xl.nil?) && win32ole_excel.nil?
|
87
82
|
ole_xl ||= WIN32OLE.new('Excel.Application')
|
@@ -142,33 +137,6 @@ module RobustExcelOle
|
|
142
137
|
|
143
138
|
private
|
144
139
|
|
145
|
-
# returns a Win32OLE object that represents a Excel instance to which Excel connects
|
146
|
-
# connects to the first opened Excel instance
|
147
|
-
# if this Excel instance is being closed, then Excel creates a new Excel instance
|
148
|
-
# @private
|
149
|
-
def self.current_excel
|
150
|
-
result = if result.nil?
|
151
|
-
begin
|
152
|
-
WIN32OLE.connect('Excel.Application')
|
153
|
-
rescue
|
154
|
-
nil
|
155
|
-
end
|
156
|
-
end
|
157
|
-
if result
|
158
|
-
begin
|
159
|
-
result.Visible # send any method, just to see if it responds
|
160
|
-
rescue
|
161
|
-
trace 'dead excel ' + (begin
|
162
|
-
"Window-handle = #{result.HWnd}"
|
163
|
-
rescue
|
164
|
-
'without window handle'
|
165
|
-
end)
|
166
|
-
return nil
|
167
|
-
end
|
168
|
-
end
|
169
|
-
result
|
170
|
-
end
|
171
|
-
|
172
140
|
# retain the saved status of all workbooks
|
173
141
|
# @private
|
174
142
|
def retain_saved_workbooks
|
@@ -424,6 +392,43 @@ module RobustExcelOle
|
|
424
392
|
@@hwnd2excel.size
|
425
393
|
end
|
426
394
|
|
395
|
+
#private
|
396
|
+
|
397
|
+
# returns a Win32OLE object that represents a Excel instance to which Excel connects
|
398
|
+
# connects to the first opened Excel instance
|
399
|
+
# if this Excel instance is being closed, then Excel creates a new Excel instance
|
400
|
+
# @private
|
401
|
+
def self.current_ole_excel
|
402
|
+
if JRUBY_BUG_CONNECT
|
403
|
+
result = known_excel_instance
|
404
|
+
if result.nil?
|
405
|
+
if excels_number > 0
|
406
|
+
dummy_ole_workbook = WIN32OLE.connect(General.absolute_path('___dummy_workbook.xls')) rescue nil
|
407
|
+
result = dummy_ole_workbook.Application
|
408
|
+
visible_status = result.Visible
|
409
|
+
dummy_ole_workbook.Close
|
410
|
+
dummy_ole_workbook = nil
|
411
|
+
result.Visible = visible_status
|
412
|
+
end
|
413
|
+
end
|
414
|
+
else
|
415
|
+
result = WIN32OLE.connect('Excel.Application') rescue nil
|
416
|
+
end
|
417
|
+
if result
|
418
|
+
begin
|
419
|
+
result.Visible # send any method, just to see if it responds
|
420
|
+
rescue
|
421
|
+
trace 'dead excel ' + (begin
|
422
|
+
"Window-handle = #{result.HWnd}"
|
423
|
+
rescue
|
424
|
+
'without window handle'
|
425
|
+
end)
|
426
|
+
return nil
|
427
|
+
end
|
428
|
+
end
|
429
|
+
result
|
430
|
+
end
|
431
|
+
|
427
432
|
# returns an Excel instance
|
428
433
|
def self.known_excel_instance
|
429
434
|
@@hwnd2excel.each do |hwnd, wr_excel|
|
@@ -173,8 +173,7 @@ module RobustExcelOle
|
|
173
173
|
home = homes.find { |h| !ENV[h].nil? }
|
174
174
|
reo_log_dir = ENV[home]
|
175
175
|
else
|
176
|
-
|
177
|
-
reo_log_dir = "C:/Users/User"
|
176
|
+
reo_log_dir = REO_LOG_DIR
|
178
177
|
end
|
179
178
|
File.open(reo_log_dir + '/' + REO_LOG_FILE,'a') do |file|
|
180
179
|
file.puts text
|
@@ -11,10 +11,13 @@ module RobustExcelOle
|
|
11
11
|
|
12
12
|
class Workbook < RangeOwners
|
13
13
|
|
14
|
+
#include General
|
15
|
+
|
14
16
|
attr_accessor :excel
|
15
17
|
attr_accessor :ole_workbook
|
16
18
|
attr_accessor :stored_filename
|
17
19
|
attr_accessor :color_if_modified
|
20
|
+
attr_accessor :was_open
|
18
21
|
attr_reader :workbook
|
19
22
|
|
20
23
|
alias ole_object ole_workbook
|
@@ -39,7 +42,7 @@ module RobustExcelOle
|
|
39
42
|
|
40
43
|
|
41
44
|
# opens a workbook.
|
42
|
-
# @param [String]
|
45
|
+
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
43
46
|
# @param [Hash] opts the options
|
44
47
|
# @option opts [Hash] :default or :d
|
45
48
|
# @option opts [Hash] :force or :f
|
@@ -106,7 +109,8 @@ module RobustExcelOle
|
|
106
109
|
rescue
|
107
110
|
trace "#{$!.message}"
|
108
111
|
end
|
109
|
-
if book
|
112
|
+
if book
|
113
|
+
book.was_open = book.alive?
|
110
114
|
# drop the fetched workbook if it shall be opened in another Excel instance
|
111
115
|
# or the workbook is an unsaved workbook that should not be accepted
|
112
116
|
if (options[:force][:excel].nil? || options[:force][:excel] == :current || forced_excel == book.excel) &&
|
@@ -226,51 +230,33 @@ module RobustExcelOle
|
|
226
230
|
raise ExcelREOError, "excel is not alive" unless @excel && @excel.alive?
|
227
231
|
end
|
228
232
|
|
229
|
-
# @private
|
230
|
-
# restriction for jruby: does not manage conflicts with blocking or unsaved workbooks
|
233
|
+
# @private
|
231
234
|
def ensure_workbook(filename, options)
|
232
|
-
if options[:if_unsaved]==:accept &&
|
233
|
-
((options[:read_only]==true && self.ReadOnly==false) || (options[:read_only]==false && self.ReadOnly==true))
|
234
|
-
raise OptionInvalid, ":if_unsaved:accept and change of read-only mode is not possible"
|
235
|
-
end
|
236
235
|
unless @ole_workbook && alive?
|
237
236
|
filename = @stored_filename ? @stored_filename : filename
|
238
237
|
manage_nonexisting_file(filename,options)
|
239
238
|
excel_option = options[:force][:excel].nil? ? options[:default][:excel] : options[:force][:excel]
|
240
|
-
|
241
|
-
|
242
|
-
|
239
|
+
ensure_excel(options)
|
240
|
+
workbooks = @excel.Workbooks
|
241
|
+
@ole_workbook = workbooks.Item(File.basename(filename)) rescue nil if @ole_workbook.nil?
|
242
|
+
if @ole_workbook
|
243
|
+
@was_open = true
|
244
|
+
manage_blocking_or_unsaved_workbook(filename,options)
|
245
|
+
else
|
246
|
+
if excel_option.nil? || excel_option == :current &&
|
247
|
+
(!JRUBY_BUG_CONNECT || filename[0] != '/')
|
243
248
|
connect(filename,options)
|
244
|
-
|
245
|
-
|
246
|
-
rescue WorkbookConnectingBlockingError
|
247
|
-
raise WorkbookBlocked, "can't open workbook #{filename}"+
|
248
|
-
"\nbecause it is being blocked by a workbook with the same name in a different path."
|
249
|
-
rescue WorkbookConnectingUnknownError
|
250
|
-
raise WorkbookREOError, "can't connect to workbook #{filename}"
|
249
|
+
else
|
250
|
+
open_or_create_workbook(filename,options)
|
251
251
|
end
|
252
|
-
|
253
|
-
else
|
254
|
-
ensure_excel(options)
|
255
|
-
workbooks = @excel.Workbooks
|
256
|
-
@ole_workbook = workbooks.Item(File.basename(filename)) rescue nil if @ole_workbook.nil?
|
257
|
-
if @ole_workbook
|
258
|
-
manage_blocking_or_unsaved_workbook(filename,options)
|
259
|
-
else
|
260
|
-
if excel_option.nil? || excel_option == :current &&
|
261
|
-
(!JRUBY_BUG_CONNECT || filename[0] != '/')
|
262
|
-
connect(filename,options)
|
263
|
-
else
|
264
|
-
open_or_create_workbook(filename,options)
|
265
|
-
end
|
266
|
-
end
|
267
|
-
end
|
252
|
+
end
|
268
253
|
end
|
269
254
|
end
|
270
255
|
|
271
256
|
# @private
|
272
257
|
def set_options(filename, options)
|
273
258
|
if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
259
|
+
#raise OptionInvalid, ":if_unsaved:accept and changing read-only mode is not possible" if options[:if_unsaved]==:accept
|
274
260
|
@excel.with_displayalerts(false) { @ole_workbook.Close }
|
275
261
|
@ole_workbook = nil
|
276
262
|
open_or_create_workbook(filename, options)
|
@@ -282,11 +268,17 @@ module RobustExcelOle
|
|
282
268
|
end
|
283
269
|
end
|
284
270
|
|
271
|
+
|
285
272
|
private
|
286
273
|
|
287
274
|
# @private
|
288
|
-
# connects to an unknown workbook
|
275
|
+
# connects to an unknown workbook
|
289
276
|
def connect(filename,options)
|
277
|
+
excels_number = excel_class.excels_number
|
278
|
+
workbooks_number = if excels_number>0
|
279
|
+
excel_class.current.Workbooks.Count
|
280
|
+
else 0
|
281
|
+
end
|
290
282
|
abs_filename = General.absolute_path(filename)
|
291
283
|
@ole_workbook = begin
|
292
284
|
WIN32OLE.connect(abs_filename)
|
@@ -307,10 +299,13 @@ module RobustExcelOle
|
|
307
299
|
end
|
308
300
|
end
|
309
301
|
@excel = excel_class.new(ole_excel)
|
302
|
+
excels_number_after = excel_class.excels_number
|
303
|
+
workbooks_number_after = ole_excel.Workbooks.Count
|
304
|
+
@was_open = (excels_number_after==excels_number) && (workbooks_number_after==workbooks_number)
|
310
305
|
end
|
311
306
|
|
312
307
|
# @private
|
313
|
-
def manage_nonexisting_file(filename,options)
|
308
|
+
def manage_nonexisting_file(filename,options)
|
314
309
|
return if File.exist?(filename)
|
315
310
|
abs_filename = General.absolute_path(filename)
|
316
311
|
if options[:if_absent] == :create
|
@@ -566,75 +561,107 @@ module RobustExcelOle
|
|
566
561
|
unobtrusively(*args, &block)
|
567
562
|
end
|
568
563
|
|
569
|
-
|
570
564
|
# allows to read or modify a workbook such that its state remains unchanged
|
571
565
|
# state comprises: open, saved, writable, visible, calculation mode, check compatibility
|
572
|
-
# @param [String]
|
566
|
+
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
573
567
|
# @param [Hash] opts the options
|
574
568
|
# @option opts [Variant] :if_closed :current (default), :new or an Excel instance
|
575
|
-
# @option opts [Boolean] :read_only true/false, open the workbook in read-only/read-write modus (save changes)
|
576
|
-
# @option opts [Boolean] :writable true/false changes of the workbook shall be saved/not saved
|
577
|
-
# @option opts [Boolean] :
|
578
|
-
# write permissions shall be opened :current (default), :new or an Excel instance
|
579
|
-
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening
|
569
|
+
# @option opts [Boolean] :read_only true/false (default), open the workbook in read-only/read-write modus (save changes)
|
570
|
+
# @option opts [Boolean] :writable true (default)/false changes of the workbook shall be saved/not saved
|
571
|
+
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening (default: false)
|
580
572
|
# @return [Workbook] a workbook
|
581
|
-
def self.unobtrusively(
|
573
|
+
def self.unobtrusively(file_or_workbook, opts = { })
|
582
574
|
opts = process_options(opts, :use_defaults => false)
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
book = bookstore.fetch(file, :prefer_writable => prefer_writable)
|
591
|
-
was_open = book && book.alive?
|
592
|
-
if was_open
|
593
|
-
was_saved = book.saved
|
594
|
-
was_writable = book.writable
|
575
|
+
raise OptionInvalid, 'contradicting options' if opts[:writable] && opts[:read_only]
|
576
|
+
opts = opts.merge({:force => {:excel => opts[:if_closed]}, :if_closed => :current,
|
577
|
+
:if_unsaved => :accept, :keep_open => false})
|
578
|
+
opts = opts.merge({:read_only => opts[:read_only]}) unless opts[:read_only].nil?
|
579
|
+
file = (file_or_workbook.is_a? WIN32OLE) ? file_or_workbook.Fullname.tr('\\','/') : file_or_workbook
|
580
|
+
begin
|
581
|
+
book = open(file)
|
595
582
|
was_visible = book.visible
|
596
|
-
|
583
|
+
was_writable = book.writable
|
584
|
+
was_saved = book.saved
|
597
585
|
was_check_compatibility = book.check_compatibility
|
598
|
-
|
599
|
-
|
586
|
+
was_calculation = book.excel.calculation
|
587
|
+
book.set_options(file,opts)
|
588
|
+
if !was_saved && ((opts[:writable] && !was_writable) || (opts[:read_only] && was_writable))
|
600
589
|
raise NotImplementedREOError, 'unsaved read-only workbook shall be written'
|
601
590
|
end
|
602
|
-
|
591
|
+
yield book
|
592
|
+
ensure
|
593
|
+
if book && book.alive?
|
594
|
+
do_not_write = (opts[:read_only] || (opts[:read_only].nil? && opts[:writable] == false))
|
595
|
+
book.save unless was_saved || do_not_write || book.ReadOnly
|
596
|
+
# open and close if the read_only mode has changed
|
597
|
+
if (opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable)
|
598
|
+
book = open(file, :read_only => !was_writable, :if_unsaved => :forget)
|
599
|
+
end
|
600
|
+
if book.was_open
|
601
|
+
book.visible = was_visible
|
602
|
+
book.CheckCompatibility = was_check_compatibility
|
603
|
+
book.excel.calculation = was_calculation
|
604
|
+
end
|
605
|
+
book.Saved = (was_saved || !book.was_open)
|
606
|
+
book.close unless book.was_open || opts[:keep_open]
|
607
|
+
end
|
603
608
|
end
|
604
|
-
|
609
|
+
end
|
610
|
+
|
611
|
+
# allows to read or modify a workbook such that its state remains unchanged
|
612
|
+
# state comprises: open, saved, writable, visible, calculation mode, check compatibility
|
613
|
+
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
614
|
+
# @param [Hash] opts the options
|
615
|
+
# @option opts [Variant] :if_closed :current (default), :new or an Excel instance
|
616
|
+
# @option opts [Boolean] :read_only true/false (default), open the workbook in read-only/read-write modus (save changes)
|
617
|
+
# @option opts [Boolean] :writable true (default)/false changes of the workbook shall be saved/not saved
|
618
|
+
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening (default: false)
|
619
|
+
# @return [Workbook] a workbook
|
620
|
+
=begin
|
621
|
+
def self.unobtrusively(file_or_workbook, opts = { })
|
622
|
+
book = new(file_or_workbook)
|
623
|
+
book.unobtrusively(opts)
|
624
|
+
end
|
625
|
+
=end
|
626
|
+
|
627
|
+
def unobtrusively(opts = { })
|
628
|
+
opts = process_options(opts, :use_defaults => false)
|
629
|
+
raise OptionInvalid, 'contradicting options' if opts[:writable] && opts[:read_only]
|
630
|
+
opts = opts.merge({:force => {:excel => opts[:if_closed]}, :if_closed => :current,
|
631
|
+
:if_unsaved => :accept, :keep_open => false})
|
632
|
+
opts = opts.merge({:read_only => opts[:read_only]}) unless opts[:read_only].nil?
|
633
|
+
file = stored_filename
|
605
634
|
begin
|
606
|
-
book =
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
opts = opts.merge({:force => {:excel => opts[:if_closed]}, :read_only => do_not_write})
|
616
|
-
open(file, opts)
|
617
|
-
end
|
635
|
+
book = open(file, opts)
|
636
|
+
was_visible = book.visible
|
637
|
+
was_saved = book.saved
|
638
|
+
was_writable = book.was_writable
|
639
|
+
was_check_compatibility = book.CheckCompatibility
|
640
|
+
was_calculation = book.excel.calculation
|
641
|
+
if !was_saved && ((opts[:writable] && !was_writable) || (opts[:read_only] && was_writable))
|
642
|
+
raise NotImplementedREOError, 'unsaved read-only workbook shall be written'
|
643
|
+
end
|
618
644
|
yield book
|
619
645
|
ensure
|
620
646
|
if book && book.alive?
|
647
|
+
do_not_write = (opts[:read_only] || (opts[:read_only].nil? && opts[:writable] == false))
|
621
648
|
book.save unless book.saved || do_not_write || book.ReadOnly
|
622
|
-
if
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
649
|
+
# open and close if the read_only mode has changed
|
650
|
+
if (opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable)
|
651
|
+
book = open(file, :read_only => !was_writable, :if_unsaved => :forget)
|
652
|
+
end
|
653
|
+
if book.was_open
|
654
|
+
book.visible = was_visible
|
655
|
+
book.CheckCompatibility = was_check_compatibility
|
628
656
|
book.excel.calculation = was_calculation
|
629
|
-
book.CheckCompatibility = was_check_compatibility
|
630
|
-
# book.visible = was_visible # not necessary
|
631
657
|
end
|
632
|
-
book.Saved = (was_saved || !was_open)
|
633
|
-
book.close unless was_open || opts[:keep_open]
|
658
|
+
book.Saved = (was_saved || !book.was_open)
|
659
|
+
book.close unless book.was_open || opts[:keep_open]
|
634
660
|
end
|
635
661
|
end
|
636
662
|
end
|
637
663
|
|
664
|
+
|
638
665
|
# reopens a closed workbook
|
639
666
|
# @options options
|
640
667
|
def reopen(options = { })
|