robust_excel_ole 0.4 → 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Changelog +15 -0
- data/README.rdoc +128 -63
- data/README_detail.rdoc +130 -60
- data/examples/edit_sheets/example_access_sheets_and_cells.rb +1 -1
- data/examples/edit_sheets/example_adding_sheets.rb +2 -2
- data/examples/edit_sheets/example_copying.rb +1 -1
- data/examples/edit_sheets/example_expanding.rb +1 -1
- data/examples/edit_sheets/example_ranges.rb +1 -1
- data/examples/edit_sheets/example_saving.rb +2 -2
- data/examples/open_save_close/example_control_to_excel.rb +1 -1
- data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +2 -2
- data/examples/open_save_close/example_if_obstructed_save.rb +2 -2
- data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
- data/examples/open_save_close/example_if_unsaved_forget.rb +2 -2
- data/examples/open_save_close/example_if_unsaved_forget_more.rb +3 -3
- data/examples/open_save_close/example_read_only.rb +1 -1
- data/examples/open_save_close/example_rename_cells.rb +1 -1
- data/examples/open_save_close/example_simple.rb +1 -1
- data/examples/open_save_close/example_unobtrusively.rb +3 -3
- data/lib/robust_excel_ole.rb +1 -0
- data/lib/robust_excel_ole/book.rb +249 -193
- data/lib/robust_excel_ole/bookstore.rb +1 -1
- data/lib/robust_excel_ole/cell.rb +1 -1
- data/lib/robust_excel_ole/excel.rb +125 -4
- data/lib/robust_excel_ole/general.rb +1 -92
- data/lib/robust_excel_ole/range.rb +1 -1
- data/lib/robust_excel_ole/reo_common.rb +37 -0
- data/lib/robust_excel_ole/sheet.rb +77 -24
- data/lib/robust_excel_ole/version.rb +1 -1
- data/spec/book_spec.rb +112 -82
- data/spec/book_specs/book_close_spec.rb +44 -1
- data/spec/book_specs/book_misc_spec.rb +97 -92
- data/spec/book_specs/book_open_spec.rb +40 -8
- data/spec/book_specs/book_save_spec.rb +77 -7
- data/spec/book_specs/book_sheet_spec.rb +290 -66
- data/spec/book_specs/book_unobtr_spec.rb +99 -73
- data/spec/bookstore_spec.rb +1 -1
- data/spec/cell_spec.rb +2 -2
- data/spec/data/another_workbook.xls +0 -0
- data/spec/data/workbook.xls +0 -0
- data/spec/excel_spec.rb +174 -23
- data/spec/general_spec.rb +3 -18
- data/spec/range_spec.rb +3 -3
- data/spec/reo_common_spec.rb +104 -0
- data/spec/sheet_spec.rb +101 -60
- metadata +6 -4
@@ -14,7 +14,7 @@ begin
|
|
14
14
|
simple_save_file = dir + 'workbook_save.xls'
|
15
15
|
File.delete simple_save_file rescue nil
|
16
16
|
book = Book.open(simple_file) # open a book
|
17
|
-
sheet = book
|
17
|
+
sheet = book.sheet(1) # access a sheet via integer
|
18
18
|
cell = sheet[1,1] # access the first cell
|
19
19
|
puts "1st cell: #{cell.Value}" # put the value of the first cell
|
20
20
|
sheet[1,1] = "complex" # write a value into a cell
|
@@ -33,7 +33,7 @@ begin
|
|
33
33
|
show_sheets
|
34
34
|
|
35
35
|
puts "adding a copy of the 2nd sheet"
|
36
|
-
sheet = @book
|
36
|
+
sheet = @book.sheet(2)
|
37
37
|
@book.add_sheet sheet
|
38
38
|
show_sheets
|
39
39
|
|
@@ -50,7 +50,7 @@ begin
|
|
50
50
|
show_sheets
|
51
51
|
|
52
52
|
puts "adding a copy of the 4th sheet before the 7th sheet and name it 'sheet_copy'"
|
53
|
-
@book.add_sheet(@book
|
53
|
+
@book.add_sheet(@book.sheet(4), :as => 'sheet_copy', :after => @book.sheet(7))
|
54
54
|
show_sheets
|
55
55
|
|
56
56
|
puts"adding a copy of the 2nd sheet and name it again 'second_sheet_copy'"
|
@@ -14,7 +14,7 @@ begin
|
|
14
14
|
simple_save_file = dir + 'workbook_save.xls'
|
15
15
|
File.delete simple_save_file rescue nil
|
16
16
|
book = Book.open(simple_file) # open a book
|
17
|
-
sheet = book
|
17
|
+
sheet = book.sheet('Sheet1') # access a sheet via the name
|
18
18
|
row_r = sheet.row_range(1) # access the whole range of the first row
|
19
19
|
col_r = sheet.col_range(1, 1..2) # access the first two cells of the range of the first column
|
20
20
|
cell = col_r[0] # access the first cell of these cells
|
@@ -25,13 +25,13 @@ begin
|
|
25
25
|
book = Book.open(file_sheet_name)
|
26
26
|
book.add_sheet sheet_orig
|
27
27
|
book.each do |sheet|
|
28
|
-
sheet.Delete
|
28
|
+
sheet.Delete unless sheet.name == sheet_orig.name
|
29
29
|
end
|
30
30
|
book.close(:if_unsaved => :save)
|
31
31
|
# alternative: delete all other sheets
|
32
32
|
#book = Book.open(file_sheet_name, :force_excel => :new, :visible => true)
|
33
33
|
#book.each do |sheet|
|
34
|
-
# book
|
34
|
+
# book.sheet(sheet.Name).Delete() unless sheet.Name == sheet_orig.Name
|
35
35
|
#end
|
36
36
|
end
|
37
37
|
end
|
@@ -14,7 +14,7 @@ begin
|
|
14
14
|
book = Book.open(file_name) # open a book
|
15
15
|
book.excel.visible = true # make current Excel visible
|
16
16
|
sleep 1
|
17
|
-
sheet = book
|
17
|
+
sheet = book.sheet(1) # access a sheet
|
18
18
|
sheet[1,1] = sheet[1,1].Value == "simple" ? "complex" : "simple" # change a cell
|
19
19
|
sleep 1
|
20
20
|
begin
|
@@ -14,7 +14,7 @@ begin
|
|
14
14
|
other_file_name = dir + 'more_data/workbook.xls'
|
15
15
|
book = Book.open(file_name, :visible => true) # open a book, make Excel visible
|
16
16
|
sleep 1
|
17
|
-
sheet = book
|
17
|
+
sheet = book.sheet(1)
|
18
18
|
first_cell = sheet[1,1].Value # access a sheet
|
19
19
|
sheet[1,1] = first_cell == "simple" ? "complex" : "simple" # change a cell
|
20
20
|
sleep 1
|
@@ -26,7 +26,7 @@ begin
|
|
26
26
|
book.save # save the unsaved book
|
27
27
|
new_book = Book.open(file_name, :if_obstructed => :close_if_saved) # open the new book, close the saved book
|
28
28
|
sleep 1
|
29
|
-
new_sheet = new_book
|
29
|
+
new_sheet = new_book.sheet(1)
|
30
30
|
new_first_cell = new_sheet[1,1].Value
|
31
31
|
puts "the old book was saved" unless new_first_cell == first_cell
|
32
32
|
new_book.close # close the books
|
@@ -14,7 +14,7 @@ begin
|
|
14
14
|
other_file_name = dir + 'more_data/workbook.xls'
|
15
15
|
book = Book.open(file_name, :visible => true) # open a book, make Excel visible
|
16
16
|
sleep 1
|
17
|
-
sheet = book
|
17
|
+
sheet = book.sheet(1)
|
18
18
|
first_cell = sheet[1,1].value # access a sheet
|
19
19
|
sheet[1,1] = first_cell == "simple" ? "complex" : "simple" # change a cell
|
20
20
|
sleep 1
|
@@ -22,7 +22,7 @@ begin
|
|
22
22
|
sleep 1 #save the old book, close it, before
|
23
23
|
old_book = Book.open(file_name, :if_obstructed => :forget ,:visible => true) # open the old book
|
24
24
|
sleep 1
|
25
|
-
old_sheet = old_book
|
25
|
+
old_sheet = old_book.sheet(1)
|
26
26
|
old_first_cell = old_sheet[1,1].value
|
27
27
|
puts "the old book was saved" unless old_first_cell == first_cell
|
28
28
|
new_book.close # close the books
|
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
dir = create_tmpdir
|
13
13
|
file_name = dir + 'workbook.xls'
|
14
14
|
book = Book.open(file_name) # open a book
|
15
|
-
sheet = book
|
15
|
+
sheet = book.sheet(1) # access a sheet
|
16
16
|
sheet[1,1] = sheet[1,1].value == "simple" ? "complex" : "simple" # change a cell
|
17
17
|
begin
|
18
18
|
new_book = Book.open(file_name) # open another book with the same file name
|
@@ -14,13 +14,13 @@ begin
|
|
14
14
|
book = Book.open(file_name) # open a book
|
15
15
|
book.excel.visible = true # make current Excel visible
|
16
16
|
sleep 1
|
17
|
-
sheet = book
|
17
|
+
sheet = book.sheet(1) # access a sheet
|
18
18
|
first_cell = sheet[1,1].value
|
19
19
|
sheet[1,1] = first_cell == "simple" ? "complex" : "simple" # change a cell
|
20
20
|
sleep 1
|
21
21
|
new_book = Book.open(file_name, :if_unsaved => :forget) # open another book with the same file name
|
22
22
|
# and close the unsaved book without saving it
|
23
|
-
sheet_new_book = new_book
|
23
|
+
sheet_new_book = new_book.sheet(1)
|
24
24
|
if (not book.alive?) && new_book.alive? && sheet_new_book[1,1].value == first_cell then # check whether the unsaved book
|
25
25
|
puts "open with :if_unsaved => :forget : the unsaved book is closed and not saved." # is closed and was not saved
|
26
26
|
end
|
@@ -14,12 +14,12 @@ begin
|
|
14
14
|
book = Book.open(file_name) # open a book
|
15
15
|
book.excel.visible = true # make current Excel visible
|
16
16
|
sleep
|
17
|
-
sheet = book
|
17
|
+
sheet = book.sheet(1) # access a sheet
|
18
18
|
first_cell = sheet[1,1].value
|
19
19
|
sheet[1,1] = first_cell == "simple" ? "complex" : "simple" # change a cell
|
20
20
|
sleep 1
|
21
21
|
new_book = Book.open(file_name, :if_unsaved => :new_excel, :visible => true) # open another book with the same file name in a new Excel
|
22
|
-
sheet_new_book = new_book
|
22
|
+
sheet_new_book = new_book.sheet(1)
|
23
23
|
if (not book.alive?) && new_book.alive? && sheet_new_book[1,1].value == first_cell then # check whether the unsaved book
|
24
24
|
puts "open with :if_unsaved => :forget : the unsaved book is closed and not saved." # is closed and was not saved
|
25
25
|
end
|
@@ -28,7 +28,7 @@ begin
|
|
28
28
|
# open another book in the running Excel application, and make Excel visible, closing the unsaved book
|
29
29
|
another_book = Book.open(file_name, :if_unsaved => :forget, :visible => true)
|
30
30
|
sleep 1
|
31
|
-
sheet_another_book = another_book
|
31
|
+
sheet_another_book = another_book.sheet(1)
|
32
32
|
sheet_another_book[1,1] = sheet_another_book[1,1].value == "simple" ? "complex" : "simple" # change a cell
|
33
33
|
another_book.close(:if_unsaved => :forget ) # close the last book without saving it.
|
34
34
|
book.close(:if_unsaved => :save) # close the first book and save it before
|
@@ -12,7 +12,7 @@ begin
|
|
12
12
|
file_name = dir + 'workbook.xls'
|
13
13
|
other_file_name = dir + 'different_workbook.xls'
|
14
14
|
book = Book.open(file_name, :read_only => true, :visible => true) # open a book with read_only and make Excel visible
|
15
|
-
sheet = book
|
15
|
+
sheet = book.sheet(1) # access a sheet
|
16
16
|
sleep 1
|
17
17
|
sheet[1,1] = sheet[1,1].value == "simple" ? "complex" : "simple" # change a cell
|
18
18
|
sleep 1
|
@@ -13,7 +13,7 @@ begin
|
|
13
13
|
file_name = dir + 'workbook.xls'
|
14
14
|
book = Book.open(file_name) # open a book. default: :read_only => false
|
15
15
|
book.excel.visible = true # make current Excel visible
|
16
|
-
sheet = book
|
16
|
+
sheet = book.sheet(1)
|
17
17
|
workbook = book.ole_workbook
|
18
18
|
fullname = workbook.Fullname
|
19
19
|
puts "fullname: #{fullname}"
|
@@ -19,7 +19,7 @@ begin
|
|
19
19
|
other_file_name = dir + 'different_workbook.xls'
|
20
20
|
book = Book.open(file_name) # open a book. default: :read_only => false
|
21
21
|
book.excel.visible = true # make current Excel visible
|
22
|
-
sheet = book
|
22
|
+
sheet = book.sheet(1) # access a sheet
|
23
23
|
sleep 1
|
24
24
|
sheet[1,1] = sheet[1,1].value == "simple" ? "complex" : "simple" # change a cell
|
25
25
|
sleep 1
|
@@ -11,14 +11,14 @@ begin
|
|
11
11
|
dir = create_tmpdir
|
12
12
|
simple_file = dir + 'workbook.xls'
|
13
13
|
book = Book.open(simple_file, :visible => true) # open a book, make Excel visible
|
14
|
-
old_sheet = book
|
14
|
+
old_sheet = book.sheet(1)
|
15
15
|
p "1st cell: #{old_sheet[1,1].value}"
|
16
16
|
sleep 2
|
17
17
|
Book.unobtrusively(simple_file) do |book| # modify the book and keep its status unchanged
|
18
|
-
sheet = book
|
18
|
+
sheet = book.sheet(1)
|
19
19
|
sheet[1,1] = sheet[1,1].value == "simple" ? "complex" : "simple"
|
20
20
|
end
|
21
|
-
new_sheet = book
|
21
|
+
new_sheet = book.sheet(1)
|
22
22
|
p "1st cell: #{new_sheet[1,1].value}"
|
23
23
|
p "book saved" if book.Saved
|
24
24
|
book.close # close the book
|
data/lib/robust_excel_ole.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "win32ole"
|
2
|
+
require File.join(File.dirname(__FILE__), 'robust_excel_ole/reo_common')
|
2
3
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/general')
|
3
4
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/excel')
|
4
5
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/bookstore')
|
@@ -4,7 +4,7 @@ require 'weakref'
|
|
4
4
|
|
5
5
|
module RobustExcelOle
|
6
6
|
|
7
|
-
class Book
|
7
|
+
class Book < REOCommon
|
8
8
|
|
9
9
|
attr_accessor :excel
|
10
10
|
attr_accessor :ole_workbook
|
@@ -21,7 +21,8 @@ module RobustExcelOle
|
|
21
21
|
:if_unsaved => :raise,
|
22
22
|
:if_obstructed => :raise,
|
23
23
|
:if_absent => :raise,
|
24
|
-
:read_only => false
|
24
|
+
:read_only => false,
|
25
|
+
:check_compatibility => true
|
25
26
|
}
|
26
27
|
|
27
28
|
class << self
|
@@ -31,7 +32,7 @@ module RobustExcelOle
|
|
31
32
|
# @param [Hash] opts the options
|
32
33
|
# @option opts [Variant] :default_excel :reuse (default), :new, or <excel-instance>
|
33
34
|
# @option opts [Variant] :force_excel :new (default), or <excel-instance>
|
34
|
-
# @option opts [Symbol] :if_unsaved :raise (default), :forget, :accept, :alert, or :new_excel
|
35
|
+
# @option opts [Symbol] :if_unsaved :raise (default), :forget, :accept, :alert, :excel, or :new_excel
|
35
36
|
# @option opts [Symbol] :if_obstructed :raise (default), :forget, :save, :close_if_saved, or _new_excel
|
36
37
|
# @option opts [Symbol] :if_absent :raise (default), or :create
|
37
38
|
# @option opts [Boolean] :read_only true (default), or false
|
@@ -52,7 +53,7 @@ module RobustExcelOle
|
|
52
53
|
# :raise -> raises an exception
|
53
54
|
# :forget -> close the unsaved workbook, open the new workbook
|
54
55
|
# :accept -> lets the unsaved workbook open
|
55
|
-
# :alert
|
56
|
+
# :alert or :excel -> gives control to Excel
|
56
57
|
# :new_excel -> opens the new workbook in a new Excel instance
|
57
58
|
# :if_obstructed if a workbook with the same name in a different path is open, then
|
58
59
|
# :raise -> raises an exception
|
@@ -66,7 +67,8 @@ module RobustExcelOle
|
|
66
67
|
#
|
67
68
|
# :read_only opens in read-only mode
|
68
69
|
# :displayalerts enables DisplayAlerts in Excel
|
69
|
-
# :visible makes visible in Excel
|
70
|
+
# :visible makes visible in Excel
|
71
|
+
# :check_compatibility check compatibility when saving
|
70
72
|
# if :default_excel is set, then DisplayAlerts and Visible are set only if these parameters are given
|
71
73
|
# @return [Book] a workbook
|
72
74
|
def open(file, opts={ }, &block)
|
@@ -114,7 +116,7 @@ module RobustExcelOle
|
|
114
116
|
end
|
115
117
|
|
116
118
|
# creates a new Book object, if a file name is given
|
117
|
-
#
|
119
|
+
# Promotes the workbook to a Book object, if a win32ole-workbook is given
|
118
120
|
# @param [Variant] file_or_workbook file name or workbook
|
119
121
|
# @param [Hash] opts the options
|
120
122
|
# @option opts [Symbol] see above
|
@@ -165,7 +167,11 @@ module RobustExcelOle
|
|
165
167
|
object.excel
|
166
168
|
end
|
167
169
|
else
|
168
|
-
|
170
|
+
begin
|
171
|
+
object.excel
|
172
|
+
rescue
|
173
|
+
raise ExcelErrorOpen, "given object is neither an Excel, a Book, nor a Win32ole"
|
174
|
+
end
|
169
175
|
end
|
170
176
|
#rescue
|
171
177
|
# trace "no Excel, Book, or WIN32OLE object representing a Workbook or an Excel instance"
|
@@ -215,7 +221,7 @@ module RobustExcelOle
|
|
215
221
|
if obstructed_by_other_book then
|
216
222
|
case options[:if_obstructed]
|
217
223
|
when :raise
|
218
|
-
raise ExcelErrorOpen, "blocked by a book with the same name in a different path: #{
|
224
|
+
raise ExcelErrorOpen, "blocked by a book with the same name in a different path: #{@ole_workbook.Fullname.tr('\\','/')}"
|
219
225
|
when :forget
|
220
226
|
@ole_workbook.Close
|
221
227
|
@ole_workbook = nil
|
@@ -227,7 +233,7 @@ module RobustExcelOle
|
|
227
233
|
open_or_create_workbook(file, options)
|
228
234
|
when :close_if_saved
|
229
235
|
if (not @ole_workbook.Saved) then
|
230
|
-
raise ExcelErrorOpen, "workbook with the same name in a different path is unsaved: #{
|
236
|
+
raise ExcelErrorOpen, "workbook with the same name in a different path is unsaved: #{@ole_workbook.Fullname.tr('\\','/')}"
|
231
237
|
else
|
232
238
|
@ole_workbook.Close
|
233
239
|
@ole_workbook = nil
|
@@ -253,7 +259,7 @@ module RobustExcelOle
|
|
253
259
|
open_or_create_workbook(file, options)
|
254
260
|
when :accept
|
255
261
|
# do nothing
|
256
|
-
when :alert
|
262
|
+
when :alert, :excel
|
257
263
|
@excel.with_displayalerts true do
|
258
264
|
open_or_create_workbook(file,options)
|
259
265
|
end
|
@@ -299,7 +305,8 @@ module RobustExcelOle
|
|
299
305
|
workbooks.Add if @excel.Version == "12.0" && count == 0
|
300
306
|
workbooks.Open(filename,{ 'ReadOnly' => options[:read_only] })
|
301
307
|
workbooks.Item(1).Close if @excel.Version == "12.0" && count == 0
|
302
|
-
|
308
|
+
workbooks.Item(1).CheckCompatibility = options[:check_compatibility]
|
309
|
+
@can_be_closed = false if @can_be_closed.nil?
|
303
310
|
rescue WIN32OLERuntimeError => msg
|
304
311
|
trace "WIN32OLERuntimeError: #{msg.message}"
|
305
312
|
if msg.message =~ /800A03EC/
|
@@ -329,7 +336,7 @@ module RobustExcelOle
|
|
329
336
|
# :save -> saves the workbook before it is closed
|
330
337
|
# :forget -> closes the workbook
|
331
338
|
# :keep_open -> keep the workbook open
|
332
|
-
# :alert
|
339
|
+
# :alert or :excel -> gives control to excel
|
333
340
|
# @raise ExcelErrorClose if the option :if_unsaved is :raise and the workbook is unsaved, or option is invalid
|
334
341
|
# @raise ExcelErrorCanceled if the user has canceled
|
335
342
|
def close(opts = {:if_unsaved => :raise})
|
@@ -344,7 +351,7 @@ module RobustExcelOle
|
|
344
351
|
close_workbook
|
345
352
|
when :keep_open
|
346
353
|
# nothing
|
347
|
-
when :alert
|
354
|
+
when :alert, :excel
|
348
355
|
@excel.with_displayalerts true do
|
349
356
|
close_workbook
|
350
357
|
end
|
@@ -354,7 +361,8 @@ module RobustExcelOle
|
|
354
361
|
else
|
355
362
|
close_workbook
|
356
363
|
end
|
357
|
-
raise ExcelUserCanceled, "close: canceled by user" if alive? &&
|
364
|
+
raise ExcelUserCanceled, "close: canceled by user" if alive? &&
|
365
|
+
(opts[:if_unsaved] == :alert || opts[:if_unsaved] == :excel) && (not @ole_workbook.Saved)
|
358
366
|
end
|
359
367
|
|
360
368
|
private
|
@@ -403,8 +411,9 @@ module RobustExcelOle
|
|
403
411
|
# true: closes it and open it as writable in the Excel instance where it was open so far
|
404
412
|
# false (default) opens it as writable in another running excel instance, if it exists,
|
405
413
|
# otherwise open in a new Excel instance.
|
406
|
-
# :displayalerts
|
407
|
-
# :visible
|
414
|
+
# :displayalerts enables DisplayAlerts in Excel
|
415
|
+
# :visible makes visible in Excel
|
416
|
+
# :check_compatibility checks compatibility when saving
|
408
417
|
# @return [Book] a workbook
|
409
418
|
def self.unobtrusively(file, if_closed = nil, opts = { }, &block)
|
410
419
|
if if_closed.is_a? Hash
|
@@ -415,7 +424,8 @@ module RobustExcelOle
|
|
415
424
|
options = {
|
416
425
|
:read_only => false,
|
417
426
|
:readonly_excel => false,
|
418
|
-
:keep_open => false
|
427
|
+
:keep_open => false,
|
428
|
+
:check_compatibility => true
|
419
429
|
}.merge(opts)
|
420
430
|
book = bookstore.fetch(file, :prefer_writable => (not options[:read_only]))
|
421
431
|
was_not_alive_or_nil = book.nil? || (not book.alive?)
|
@@ -428,7 +438,7 @@ module RobustExcelOle
|
|
428
438
|
false
|
429
439
|
end
|
430
440
|
was_saved = was_not_alive_or_nil ? true : book.saved
|
431
|
-
was_writable = book.writable unless was_not_alive_or_nil
|
441
|
+
was_writable = book.writable unless was_not_alive_or_nil
|
432
442
|
begin
|
433
443
|
book =
|
434
444
|
if was_not_alive_or_nil
|
@@ -450,15 +460,19 @@ module RobustExcelOle
|
|
450
460
|
end
|
451
461
|
book.excel.displayalerts = options[:displayalerts] unless options[:displayalerts].nil?
|
452
462
|
book.excel.visible = options[:visible] unless options[:visible].nil?
|
463
|
+
old_check_compatibility = book.CheckCompatibility
|
464
|
+
book.CheckCompatibility = options[:check_compatibility]
|
453
465
|
yield book
|
454
466
|
ensure
|
455
|
-
|
467
|
+
was_saved_or_appeared = was_saved || was_not_alive_or_nil || (not was_writable)
|
468
|
+
book.save if book && (not book.saved) && (not options[:read_only]) && was_saved_or_appeared
|
456
469
|
# book was open, readonly and shoud be modified
|
457
470
|
if (not was_not_alive_or_nil) && (not options[:read_only]) && (not was_writable) && options[:readonly_excel]
|
458
471
|
open(file, :force_excel => book.excel, :if_obstructed => :new_excel, :read_only => true)
|
459
472
|
end
|
460
473
|
@can_be_closed = true if options[:keep_open] && book
|
461
474
|
book.close if (was_not_alive_or_nil && (not now_alive) && (not options[:keep_open]) && book)
|
475
|
+
book.CheckCompatibility = old_check_compatibility if book && book.alive?
|
462
476
|
end
|
463
477
|
end
|
464
478
|
|
@@ -467,136 +481,6 @@ module RobustExcelOle
|
|
467
481
|
self.class.open(self.stored_filename)
|
468
482
|
end
|
469
483
|
|
470
|
-
# renames a range
|
471
|
-
# @param [String] name the previous range name
|
472
|
-
# @param [String] new_name the new range name
|
473
|
-
# @raise ExcelError if name is not in the file, or if new_name cannot be set
|
474
|
-
def rename_range(name, new_name)
|
475
|
-
begin
|
476
|
-
item = self.Names.Item(name)
|
477
|
-
rescue WIN32OLERuntimeError
|
478
|
-
raise ExcelError, "name #{name.inspect} not in #{File.basename(self.stored_filename).inspect}"
|
479
|
-
end
|
480
|
-
begin
|
481
|
-
item.Name = new_name
|
482
|
-
rescue WIN32OLERuntimeError
|
483
|
-
raise ExcelError, "name error in #{File.basename(self.stored_filename).inspect}"
|
484
|
-
end
|
485
|
-
end
|
486
|
-
|
487
|
-
# returns the contents of a range with given name
|
488
|
-
# @param [String] name the range name
|
489
|
-
# @param [Hash] opts the options
|
490
|
-
# @option opts [Symbol] :default the default value that is provided if no contents could be returned
|
491
|
-
# @raise ExcelError if range name is not in the workbook
|
492
|
-
# @raise SheetError if range value could not be evaluated
|
493
|
-
# @return [Variant] the contents of a range with given name
|
494
|
-
# if no contents could be returned, then return default value, if a default value was provided
|
495
|
-
# raise an error, otherwise
|
496
|
-
def nvalue(name, opts = {:default => nil})
|
497
|
-
begin
|
498
|
-
item = self.Names.Item(name)
|
499
|
-
rescue WIN32OLERuntimeError
|
500
|
-
return opts[:default] if opts[:default]
|
501
|
-
raise ExcelError, "name #{name.inspect} not in #{File.basename(self.stored_filename).inspect}"
|
502
|
-
end
|
503
|
-
begin
|
504
|
-
value = item.RefersToRange.Value
|
505
|
-
rescue WIN32OLERuntimeError
|
506
|
-
begin
|
507
|
-
sheet = self[0]
|
508
|
-
value = sheet.Evaluate(name)
|
509
|
-
rescue WIN32OLERuntimeError
|
510
|
-
return opts[:default] if opts[:default]
|
511
|
-
raise SheetError, "cannot evaluate name #{name.inspect} in sheet"
|
512
|
-
end
|
513
|
-
end
|
514
|
-
if value == -2146826259
|
515
|
-
return opts[:default] if opts[:default]
|
516
|
-
raise SheetError, "cannot evaluate name #{name.inspect} in sheet"
|
517
|
-
end
|
518
|
-
return opts[:default] if (value.nil? && opts[:default])
|
519
|
-
value
|
520
|
-
end
|
521
|
-
|
522
|
-
# sets the contents of a range with given name
|
523
|
-
# @param [String] name the range name
|
524
|
-
# @param [Variant] value the contents of the range
|
525
|
-
# @raise ExcelError if range name is not in the workbook or if a RefersToRange error occurs
|
526
|
-
def set_nvalue(name, value)
|
527
|
-
begin
|
528
|
-
item = self.Names.Item(name)
|
529
|
-
rescue WIN32OLERuntimeError
|
530
|
-
raise ExcelError, "name #{name.inspect} not in #{File.basename(self.stored_filename).inspect}"
|
531
|
-
end
|
532
|
-
begin
|
533
|
-
item.RefersToRange.Value = value
|
534
|
-
rescue WIN32OLERuntimeError
|
535
|
-
raise ExcelError, "RefersToRange error of name #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
|
536
|
-
end
|
537
|
-
end
|
538
|
-
|
539
|
-
# brings workbook to foreground, makes it available for heyboard inputs, makes the Excel instance visible
|
540
|
-
# @raise ExcelError if workbook cannot be activated
|
541
|
-
def activate
|
542
|
-
@excel.visible = true
|
543
|
-
begin
|
544
|
-
Win32API.new("user32","SetForegroundWindow","I","I").call(@excel.hwnd) # Excel 2010
|
545
|
-
@ole_workbook.Activate # Excel 2007
|
546
|
-
rescue WIN32OLERuntimeError
|
547
|
-
raise ExcelError, "cannot activate"
|
548
|
-
end
|
549
|
-
end
|
550
|
-
|
551
|
-
# returns true, if the workbook is visible, false otherwise
|
552
|
-
def visible
|
553
|
-
@excel.Windows(@ole_workbook.Name).Visible
|
554
|
-
end
|
555
|
-
|
556
|
-
# makes a workbook visible or invisible
|
557
|
-
# @param [Boolean] visible_value value that determines whether the workbook shall be visible
|
558
|
-
def visible= visible_value
|
559
|
-
saved = @ole_workbook.Saved
|
560
|
-
@excel.Windows(@ole_workbook.Name).Visible = visible_value
|
561
|
-
save if saved
|
562
|
-
end
|
563
|
-
|
564
|
-
# returns true, if the workbook reacts to methods, false otherwise
|
565
|
-
def alive?
|
566
|
-
begin
|
567
|
-
@ole_workbook.Name
|
568
|
-
true
|
569
|
-
rescue
|
570
|
-
@ole_workbook = nil # dead object won't be alive again
|
571
|
-
#t $!.message
|
572
|
-
false
|
573
|
-
end
|
574
|
-
end
|
575
|
-
|
576
|
-
# returns the full file name of the workbook
|
577
|
-
def filename
|
578
|
-
@ole_workbook.Fullname.tr('\\','/') rescue nil
|
579
|
-
end
|
580
|
-
|
581
|
-
def writable # :nodoc: #
|
582
|
-
(not @ole_workbook.ReadOnly) if @ole_workbook
|
583
|
-
end
|
584
|
-
|
585
|
-
def saved # :nodoc: #
|
586
|
-
@ole_workbook.Saved if @ole_workbook
|
587
|
-
end
|
588
|
-
|
589
|
-
# @return [Boolean] true, if the full book names and excel Instances are identical, false otherwise
|
590
|
-
def == other_book
|
591
|
-
other_book.is_a?(Book) &&
|
592
|
-
@excel == other_book.excel &&
|
593
|
-
self.filename == other_book.filename
|
594
|
-
end
|
595
|
-
|
596
|
-
def self.books
|
597
|
-
bookstore.books
|
598
|
-
end
|
599
|
-
|
600
484
|
# simple save of a workbook.
|
601
485
|
# @raise ExcelErrorSave if workbook is not alive or opened for read-only, or another error occurs
|
602
486
|
# @return [Boolean] true, if successfully saved, nil otherwise
|
@@ -618,13 +502,13 @@ module RobustExcelOle
|
|
618
502
|
# saves a workbook with a given file name.
|
619
503
|
# @param [String] file file name
|
620
504
|
# @param [Hash] opts the options
|
621
|
-
# @option opts [Symbol] :if_exists :raise (default), :overwrite, or :alert
|
505
|
+
# @option opts [Symbol] :if_exists :raise (default), :overwrite, or :alert, :excel
|
622
506
|
# @option opts [Symbol] :if_obstructed :raise (default), :forget, :save, or :close_if_saved
|
623
507
|
# options:
|
624
508
|
# :if_exists if a file with the same name exists, then
|
625
509
|
# :raise -> raises an exception, dont't write the file (default)
|
626
510
|
# :overwrite -> writes the file, delete the old file
|
627
|
-
# :alert
|
511
|
+
# :alert or :excel -> gives control to Excel
|
628
512
|
# :if_obstructed if a workbook with the same name and different path is already open and blocks the saving, then
|
629
513
|
# :raise -> raises an exception
|
630
514
|
# :forget -> closes the blocking workbook
|
@@ -634,7 +518,7 @@ module RobustExcelOle
|
|
634
518
|
# @raise ExcelErrorSave if workbook is not alive, opened in read-only mode, invalid options,
|
635
519
|
# the file already exists (with option :if_exists :raise),
|
636
520
|
# the workbook is blocked by another one (with option :if_obstructed :raise)
|
637
|
-
# @return [
|
521
|
+
# @return [Book], the book itself, if successfully saved, raises an exception otherwise
|
638
522
|
def save_as(file = nil, opts = { } )
|
639
523
|
raise ExcelErrorSave, "Workbook is not alive" if (not alive?)
|
640
524
|
raise ExcelErrorSave, "Not opened for writing (opened with :read_only option)" if @ole_workbook.ReadOnly
|
@@ -647,7 +531,7 @@ module RobustExcelOle
|
|
647
531
|
when :overwrite
|
648
532
|
if file == self.filename
|
649
533
|
save
|
650
|
-
return
|
534
|
+
return self
|
651
535
|
else
|
652
536
|
begin
|
653
537
|
File.delete(file)
|
@@ -655,12 +539,11 @@ module RobustExcelOle
|
|
655
539
|
raise ExcelErrorSave, "workbook is open and used in Excel"
|
656
540
|
end
|
657
541
|
end
|
658
|
-
when :alert
|
542
|
+
when :alert, :excel
|
659
543
|
@excel.with_displayalerts true do
|
660
544
|
save_as_workbook(file, options)
|
661
545
|
end
|
662
|
-
|
663
|
-
return
|
546
|
+
return self
|
664
547
|
when :raise
|
665
548
|
raise ExcelErrorSave, "file already exists: #{File.basename(file).inspect}"
|
666
549
|
else
|
@@ -676,7 +559,7 @@ module RobustExcelOle
|
|
676
559
|
if blocking_workbook then
|
677
560
|
case options[:if_obstructed]
|
678
561
|
when :raise
|
679
|
-
raise ExcelErrorSave, "blocked by another workbook: #{
|
562
|
+
raise ExcelErrorSave, "blocked by another workbook: #{blocking_workbook.Fullname.tr('\\','/')}"
|
680
563
|
when :forget
|
681
564
|
# nothing
|
682
565
|
when :save
|
@@ -689,7 +572,7 @@ module RobustExcelOle
|
|
689
572
|
blocking_workbook.Close
|
690
573
|
end
|
691
574
|
save_as_workbook(file, options)
|
692
|
-
|
575
|
+
self
|
693
576
|
end
|
694
577
|
|
695
578
|
private
|
@@ -707,7 +590,7 @@ module RobustExcelOle
|
|
707
590
|
bookstore.store(self)
|
708
591
|
rescue WIN32OLERuntimeError => msg
|
709
592
|
if msg.message =~ /SaveAs/ and msg.message =~ /Workbook/ then
|
710
|
-
if options[:if_exists] == :alert then
|
593
|
+
if options[:if_exists] == :alert || options[:if_exists] == :excel then
|
711
594
|
raise ExcelErrorSave, "not saved or canceled by user"
|
712
595
|
else
|
713
596
|
return nil
|
@@ -722,65 +605,238 @@ module RobustExcelOle
|
|
722
605
|
public
|
723
606
|
|
724
607
|
# returns a sheet, if a sheet name or a number is given
|
725
|
-
#
|
726
|
-
|
727
|
-
|
608
|
+
# @param [String] or [Number]
|
609
|
+
# @returns [Sheet]
|
610
|
+
def sheet(name)
|
728
611
|
begin
|
729
612
|
sheet_class.new(@ole_workbook.Worksheets.Item(name))
|
730
613
|
rescue WIN32OLERuntimeError => msg
|
731
|
-
|
732
|
-
|
733
|
-
else
|
734
|
-
raise ExcelError, "could neither return a sheet nor a value of a range when giving the name #{name.inspect}"
|
735
|
-
end
|
614
|
+
raise ExcelError, "could not return a sheet with name #{name.inspect}"
|
615
|
+
trace "#{msg.message}"
|
736
616
|
end
|
737
|
-
end
|
738
|
-
|
739
|
-
# sets the value of a range given its name
|
740
|
-
# @param [String] name the name of the range
|
741
|
-
# @param [Variant] value the contents of the range
|
742
|
-
def []= (name, value)
|
743
|
-
set_nvalue(name,value)
|
744
|
-
end
|
617
|
+
end
|
745
618
|
|
746
619
|
def each
|
747
620
|
@ole_workbook.Worksheets.each do |sheet|
|
748
621
|
yield sheet_class.new(sheet)
|
749
622
|
end
|
750
623
|
end
|
624
|
+
|
625
|
+
# copies a sheet to another position
|
626
|
+
# default: copied sheet is appended
|
627
|
+
# @param [Sheet] sheet a sheet that shall be copied
|
628
|
+
# @param [Hash] opts the options
|
629
|
+
# @option opts [Symbol] :as new name of the copied sheet
|
630
|
+
# @option opts [Symbol] :before a sheet before which the sheet shall be inserted
|
631
|
+
# @option opts [Symbol] :after a sheet after which the sheet shall be inserted
|
632
|
+
# @raise ExcelErrorSheet if the sheet name already exists
|
633
|
+
# @return [Sheet] the copied sheet
|
634
|
+
def copy_sheet(sheet, opts = { })
|
635
|
+
new_sheet_name = opts.delete(:as)
|
636
|
+
after_or_before, base_sheet = opts.to_a.first || [:after, last_sheet]
|
637
|
+
sheet.Copy({ after_or_before.to_s => base_sheet.worksheet })
|
638
|
+
new_sheet = sheet_class.new(@excel.Activesheet)
|
639
|
+
begin
|
640
|
+
new_sheet.name = new_sheet_name if new_sheet_name
|
641
|
+
rescue WIN32OLERuntimeError => msg
|
642
|
+
msg.message =~ /800A03EC/ ? raise(ExcelErrorSheet, "sheet name already exists") : raise(ExcelErrorSheetUnknown)
|
643
|
+
end
|
644
|
+
new_sheet
|
645
|
+
end
|
751
646
|
|
752
|
-
# adds
|
753
|
-
#
|
647
|
+
# adds an empty sheet
|
648
|
+
# default: empty sheet is appended
|
754
649
|
# @param [Hash] opts the options
|
755
|
-
# @option opts [Symbol] :as new name of the
|
650
|
+
# @option opts [Symbol] :as new name of the copied added sheet
|
756
651
|
# @option opts [Symbol] :before a sheet before which the sheet shall be inserted
|
757
652
|
# @option opts [Symbol] :after a sheet after which the sheet shall be inserted
|
758
653
|
# @raise ExcelErrorSheet if the sheet name already exists
|
759
654
|
# @return [Sheet] the added sheet
|
760
|
-
def
|
761
|
-
if sheet.is_a? Hash
|
762
|
-
opts = sheet
|
763
|
-
sheet = nil
|
764
|
-
end
|
655
|
+
def add_empty_sheet(opts = { })
|
765
656
|
new_sheet_name = opts.delete(:as)
|
766
|
-
|
767
|
-
|
768
|
-
base_sheet = base_sheet.worksheet
|
769
|
-
sheet ? sheet.Copy({ after_or_before.to_s => base_sheet }) : @ole_workbook.WorkSheets.Add({ after_or_before.to_s => base_sheet })
|
657
|
+
after_or_before, base_sheet = opts.to_a.first || [:after, last_sheet]
|
658
|
+
@ole_workbook.Worksheets.Add({ after_or_before.to_s => base_sheet.worksheet })
|
770
659
|
new_sheet = sheet_class.new(@excel.Activesheet)
|
771
660
|
begin
|
772
661
|
new_sheet.name = new_sheet_name if new_sheet_name
|
773
662
|
rescue WIN32OLERuntimeError => msg
|
774
|
-
|
775
|
-
raise ExcelErrorSheet, "sheet name already exists"
|
776
|
-
else
|
777
|
-
trace "#{msg.message}"
|
778
|
-
raise ExcelErrorSheetUnknown
|
779
|
-
end
|
663
|
+
msg.message =~ /800A03EC/ ? raise(ExcelErrorSheet, "sheet name already exists") : raise(ExcelErrorSheetUnknown)
|
780
664
|
end
|
781
665
|
new_sheet
|
666
|
+
end
|
667
|
+
|
668
|
+
# copies a sheet to another position if a sheet is given, or adds an empty sheet
|
669
|
+
# default: copied or empty sheet is appended, i.e. added behind the last sheet
|
670
|
+
# @param [Sheet] sheet a sheet that shall be copied (optional)
|
671
|
+
# @param [Hash] opts the options
|
672
|
+
# @option opts [Symbol] :as new name of the copied or added sheet
|
673
|
+
# @option opts [Symbol] :before a sheet before which the sheet shall be inserted
|
674
|
+
# @option opts [Symbol] :after a sheet after which the sheet shall be inserted
|
675
|
+
# @raise ExcelErrorSheet if the sheet name already exists
|
676
|
+
# @return [Sheet] the copied or added sheet
|
677
|
+
def add_or_copy_sheet(sheet = nil, opts = { })
|
678
|
+
if sheet.is_a? Hash
|
679
|
+
opts = sheet
|
680
|
+
sheet = nil
|
681
|
+
end
|
682
|
+
sheet ? copy_sheet(sheet, opts) : add_empty_sheet(opts)
|
782
683
|
end
|
783
684
|
|
685
|
+
# for compatibility to older versions
|
686
|
+
def add_sheet(sheet = nil, opts = { })
|
687
|
+
add_or_copy_sheet(sheet, opts)
|
688
|
+
end
|
689
|
+
|
690
|
+
def last_sheet
|
691
|
+
sheet_class.new(@ole_workbook.Worksheets.Item(@ole_workbook.Worksheets.Count))
|
692
|
+
end
|
693
|
+
|
694
|
+
def first_sheet
|
695
|
+
sheet_class.new(@ole_workbook.Worksheets.Item(1))
|
696
|
+
end
|
697
|
+
|
698
|
+
# returns the value of a range
|
699
|
+
# @param [String] name the name of a range
|
700
|
+
# @returns [Variant] the value of the range
|
701
|
+
def [] name
|
702
|
+
nameval(name)
|
703
|
+
end
|
704
|
+
|
705
|
+
# sets the value of a range
|
706
|
+
# @param [String] name the name of the range
|
707
|
+
# @param [Variant] value the contents of the range
|
708
|
+
def []= (name, value)
|
709
|
+
set_nameval(name,value)
|
710
|
+
end
|
711
|
+
|
712
|
+
# returns the contents of a range with given name
|
713
|
+
# evaluates formula contents of the range is a formula
|
714
|
+
# if no contents could be returned, then return default value, if provided, raise error otherwise
|
715
|
+
# @param [String] name the name of the range
|
716
|
+
# @param [Hash] opts the options
|
717
|
+
# @option opts [Symbol] :default the default value that is provided if no contents could be returned
|
718
|
+
# @raise ExcelError if range name is not in the workbook or if range value could not be evaluated
|
719
|
+
# @return [Variant] the contents of a range with given name
|
720
|
+
def nameval(name, opts = {:default => nil})
|
721
|
+
begin
|
722
|
+
name_obj = self.Names.Item(name)
|
723
|
+
rescue WIN32OLERuntimeError
|
724
|
+
return opts[:default] if opts[:default]
|
725
|
+
raise ExcelError, "name #{name.inspect} not in #{File.basename(self.stored_filename).inspect}"
|
726
|
+
end
|
727
|
+
begin
|
728
|
+
value = name_obj.RefersToRange.Value
|
729
|
+
rescue WIN32OLERuntimeError
|
730
|
+
begin
|
731
|
+
value = self.sheet(1).Evaluate(name_obj.Name)
|
732
|
+
rescue WIN32OLERuntimeError
|
733
|
+
return opts[:default] if opts[:default]
|
734
|
+
raise SheetError, "cannot evaluate name #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
|
735
|
+
end
|
736
|
+
end
|
737
|
+
if value == -2146826259
|
738
|
+
return opts[:default] if opts[:default]
|
739
|
+
raise SheetError, "cannot evaluate name #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
|
740
|
+
end
|
741
|
+
return opts[:default] if (value.nil? && opts[:default])
|
742
|
+
value
|
743
|
+
end
|
744
|
+
|
745
|
+
# sets the contents of a range
|
746
|
+
# @param [String] name the name of a range
|
747
|
+
# @param [Variant] value the contents of the range
|
748
|
+
# @raise ExcelError if range name is not in the workbook or if value could not be assigned to range
|
749
|
+
def set_nameval(name, value)
|
750
|
+
begin
|
751
|
+
name_obj = self.Names.Item(name)
|
752
|
+
rescue WIN32OLERuntimeError
|
753
|
+
raise ExcelError, "name #{name.inspect} not in #{File.basename(self.stored_filename).inspect}"
|
754
|
+
end
|
755
|
+
begin
|
756
|
+
name_obj.RefersToRange.Value = value
|
757
|
+
rescue WIN32OLERuntimeError
|
758
|
+
raise ExcelError, "cannot assign value to range named #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
|
759
|
+
end
|
760
|
+
end
|
761
|
+
|
762
|
+
# renames a range
|
763
|
+
# @param [String] name the previous range name
|
764
|
+
# @param [String] new_name the new range name
|
765
|
+
# @raise ExcelError if name is not in the file, or if new_name cannot be set
|
766
|
+
def rename_range(name, new_name)
|
767
|
+
begin
|
768
|
+
item = self.Names.Item(name)
|
769
|
+
rescue WIN32OLERuntimeError
|
770
|
+
raise ExcelError, "name #{name.inspect} not in #{File.basename(self.stored_filename).inspect}"
|
771
|
+
end
|
772
|
+
begin
|
773
|
+
item.Name = new_name
|
774
|
+
rescue WIN32OLERuntimeError
|
775
|
+
raise ExcelError, "name error in #{File.basename(self.stored_filename).inspect}"
|
776
|
+
end
|
777
|
+
end
|
778
|
+
|
779
|
+
# brings workbook to foreground, makes it available for heyboard inputs, makes the Excel instance visible
|
780
|
+
# @raise ExcelError if workbook cannot be activated
|
781
|
+
def activate
|
782
|
+
@excel.visible = true
|
783
|
+
begin
|
784
|
+
Win32API.new("user32","SetForegroundWindow","I","I").call(@excel.hwnd) # Excel 2010
|
785
|
+
@ole_workbook.Activate # Excel 2007
|
786
|
+
rescue WIN32OLERuntimeError
|
787
|
+
raise ExcelError, "cannot activate"
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
791
|
+
# returns true, if the workbook is visible, false otherwise
|
792
|
+
def visible
|
793
|
+
@excel.Windows(@ole_workbook.Name).Visible
|
794
|
+
end
|
795
|
+
|
796
|
+
# makes a workbook visible or invisible
|
797
|
+
# @param [Boolean] visible_value value that determines whether the workbook shall be visible
|
798
|
+
def visible= visible_value
|
799
|
+
saved = @ole_workbook.Saved
|
800
|
+
@excel.Windows(@ole_workbook.Name).Visible = visible_value
|
801
|
+
save if saved
|
802
|
+
end
|
803
|
+
|
804
|
+
# returns true, if the workbook reacts to methods, false otherwise
|
805
|
+
def alive?
|
806
|
+
begin
|
807
|
+
@ole_workbook.Name
|
808
|
+
true
|
809
|
+
rescue
|
810
|
+
@ole_workbook = nil # dead object won't be alive again
|
811
|
+
#t $!.message
|
812
|
+
false
|
813
|
+
end
|
814
|
+
end
|
815
|
+
|
816
|
+
# returns the full file name of the workbook
|
817
|
+
def filename
|
818
|
+
@ole_workbook.Fullname.tr('\\','/') rescue nil
|
819
|
+
end
|
820
|
+
|
821
|
+
def writable # :nodoc: #
|
822
|
+
(not @ole_workbook.ReadOnly) if @ole_workbook
|
823
|
+
end
|
824
|
+
|
825
|
+
def saved # :nodoc: #
|
826
|
+
@ole_workbook.Saved if @ole_workbook
|
827
|
+
end
|
828
|
+
|
829
|
+
# @return [Boolean] true, if the full book names and excel Instances are identical, false otherwise
|
830
|
+
def == other_book
|
831
|
+
other_book.is_a?(Book) &&
|
832
|
+
@excel == other_book.excel &&
|
833
|
+
self.filename == other_book.filename
|
834
|
+
end
|
835
|
+
|
836
|
+
def self.books
|
837
|
+
bookstore.books
|
838
|
+
end
|
839
|
+
|
784
840
|
def self.bookstore # :nodoc: #
|
785
841
|
@@bookstore ||= Bookstore.new
|
786
842
|
end
|