robust_excel_ole 1.13 → 1.14
Sign up to get free protection for your applications and to get access to all the features.
- 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 = { })
|