robust_excel_ole 0.4 → 0.5
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.
- 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
|