robust_excel_ole 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +53 -116
- data/README_detail.rdoc +510 -0
- data/TodoList.md +21 -11
- data/examples/open_save_close/example_control_to_excel.rb +1 -1
- data/examples/open_save_close/example_default_excel.rb +1 -1
- data/examples/open_save_close/example_force_excel.rb +2 -2
- data/examples/open_save_close/example_if_unsaved_forget.rb +1 -1
- data/examples/open_save_close/example_if_unsaved_forget_more.rb +2 -2
- data/examples/open_save_close/example_rename_cells.rb +1 -1
- data/examples/open_save_close/example_reuse.rb +1 -1
- data/examples/open_save_close/example_simple.rb +1 -1
- data/lib/robust_excel_ole/book.rb +77 -75
- data/lib/robust_excel_ole/book_store.rb +51 -27
- data/lib/robust_excel_ole/excel.rb +0 -1
- data/lib/robust_excel_ole/version.rb +1 -1
- data/robust_excel_ole.gemspec +2 -7
- data/spec/book_spec.rb +382 -95
- data/spec/book_store_spec.rb +179 -25
- data/spec/excel_spec.rb +1 -4
- metadata +9 -88
@@ -14,9 +14,14 @@ module RobustExcelOle
|
|
14
14
|
|
15
15
|
# opens a book.
|
16
16
|
#
|
17
|
+
# when reopening a book that was opened and closed before, transparency identity is ensured:
|
18
|
+
# same Book objects refer to the same Excel files, and vice versa
|
19
|
+
#
|
17
20
|
# options:
|
18
|
-
# :default_excel if the book was already open in an Excel instance, then open it there
|
19
|
-
#
|
21
|
+
# :default_excel if the book was already open in an Excel instance, then open it there.
|
22
|
+
# Otherwise, i.e. if the book was not open before or the Excel instance
|
23
|
+
# :reuse (default) -> connect to a (the first opened) running Excel instance
|
24
|
+
# if it exists, open in a new Excel otherwise
|
20
25
|
# :new -> open in a new Excel instance
|
21
26
|
# <instance> -> open in the given Excel instance
|
22
27
|
# :force_excel no matter whether the book was already open
|
@@ -28,53 +33,62 @@ module RobustExcelOle
|
|
28
33
|
# :take_writable -> use the Excel instance in which the book is writable,
|
29
34
|
# if such an Excel instance exists
|
30
35
|
# :force_writability -> make it writable in the desired Excel
|
36
|
+
# (does not work yet)
|
31
37
|
# :if_locked_unsaved if the book is open in another Excel instance and contains unsaved changes
|
32
38
|
# :raise -> raise an exception
|
33
39
|
# :save -> save the unsaved book
|
34
40
|
# (not implemented yet)
|
35
41
|
# :if_unsaved if an unsaved book with the same name is open, then
|
36
|
-
# :raise
|
37
|
-
# :forget
|
38
|
-
# :accept
|
39
|
-
# :alert
|
40
|
-
# :new_excel
|
42
|
+
# :raise -> raise an exception
|
43
|
+
# :forget -> close the unsaved book, open the new book
|
44
|
+
# :accept -> let the unsaved book open
|
45
|
+
# :alert -> give control to Excel
|
46
|
+
# :new_excel (default) -> open the new book in a new Excel
|
41
47
|
# :if_obstructed if a book with the same name in a different path is open, then
|
42
|
-
# :raise
|
43
|
-
# :forget
|
44
|
-
# :save
|
45
|
-
# :close_if_saved
|
46
|
-
#
|
47
|
-
# :new_excel
|
48
|
-
#
|
49
|
-
# :read_only open in read-only mode (default: false)
|
48
|
+
# :raise -> raise an exception
|
49
|
+
# :forget -> close the old book, open the new book
|
50
|
+
# :save -> save the old book, close it, open the new book
|
51
|
+
# :close_if_saved -> close the old book and open the new book, if the old book is saved
|
52
|
+
# raise an exception otherwise
|
53
|
+
# :new_excel (default) -> open the new book in a new Excel
|
54
|
+
# :read_only open in read-only mode (default: false)
|
50
55
|
# :displayalerts enable DisplayAlerts in Excel (default: false)
|
51
56
|
# :visible make visibe in Excel (default: false)
|
52
|
-
#
|
53
|
-
|
54
|
-
|
55
|
-
|
57
|
+
# if :default_excel is set, then DisplayAlerts and Visible are set only if these parameters are given
|
58
|
+
|
56
59
|
def open(file, opts={ }, &block)
|
57
60
|
@options = {
|
58
61
|
:excel => :reuse,
|
59
62
|
:default_excel => :reuse,
|
60
63
|
:if_locked => :readonly,
|
61
|
-
:if_unsaved => :
|
62
|
-
:if_obstructed => :
|
64
|
+
:if_unsaved => :new_excel,
|
65
|
+
:if_obstructed => :new_excel,
|
63
66
|
:read_only => false
|
64
67
|
}.merge(opts)
|
65
68
|
#self.set_defaults(opts) ???
|
66
69
|
book = nil
|
67
70
|
if (not (@options[:force_excel] == :new && (not @options[:if_locked] == :take_writable)))
|
68
|
-
|
71
|
+
# if readonly is true, then prefer a book that is given in force_excel if this option is set
|
72
|
+
book = book_store.fetch(file, :prefer_writable => (not @options[:read_only]), :prefer_excel => (@options[:read_only] ? @options[:force_excel] : nil)) rescue nil
|
69
73
|
if book
|
70
|
-
if (not @options[:force_excel] || (@options[:force_excel] == book.excel))
|
74
|
+
if ((not @options[:force_excel]) || (@options[:force_excel] == book.excel))
|
75
|
+
if (not book.excel.alive?)
|
76
|
+
book.get_excel
|
77
|
+
end
|
71
78
|
if book.excel.alive?
|
72
79
|
# condition: :if_unsaved is not set or :accept or workbook is not unsaved
|
73
80
|
if_unsaved_not_set_or_accept_or_workbook_saved = (@options[:if_unsaved] == :accept || @options[:if_unsaved] == :raise || (not book.workbook) || book.workbook.Saved)
|
74
|
-
if ((not book.alive?) || if_unsaved_not_set_or_accept_or_workbook_saved)
|
81
|
+
if ((not book.alive?) || if_unsaved_not_set_or_accept_or_workbook_saved)
|
75
82
|
book.set_defaults(opts)
|
83
|
+
# if the book is opened with a different readonly mode in the same Excel,
|
84
|
+
# then save it, close and open the book with the new readonly mode
|
85
|
+
if (book.alive? && (not book.readonly == @options[:read_only]))
|
86
|
+
book.Save unless (book.readonly || book.saved)
|
87
|
+
book.workbook.Close if book.alive?
|
88
|
+
book.workbook = nil unless book.alive?
|
89
|
+
end
|
76
90
|
# reopen the book
|
77
|
-
book.get_workbook
|
91
|
+
book.get_workbook
|
78
92
|
end
|
79
93
|
return book if book.alive? && if_unsaved_not_set_or_accept_or_workbook_saved
|
80
94
|
end
|
@@ -107,8 +121,8 @@ module RobustExcelOle
|
|
107
121
|
:excel => :reuse,
|
108
122
|
:default_excel => :reuse,
|
109
123
|
:if_locked => :readonly,
|
110
|
-
:if_unsaved => :
|
111
|
-
:if_obstructed => :
|
124
|
+
:if_unsaved => :new_excel,
|
125
|
+
:if_obstructed => :new_excel,
|
112
126
|
:read_only => false
|
113
127
|
}.merge(opts)
|
114
128
|
end
|
@@ -203,8 +217,6 @@ module RobustExcelOle
|
|
203
217
|
end
|
204
218
|
|
205
219
|
def open_workbook
|
206
|
-
#p "open_workbook:"
|
207
|
-
#p "@file:#{@file}"
|
208
220
|
if ((not @workbook) || (@options[:if_unsaved] == :alert) || @options[:if_obstructed]) then
|
209
221
|
begin
|
210
222
|
filename = RobustExcelOle::absolute_path(@file)
|
@@ -225,10 +237,10 @@ module RobustExcelOle
|
|
225
237
|
#
|
226
238
|
# options:
|
227
239
|
# :if_unsaved if book is unsaved
|
228
|
-
# :raise
|
229
|
-
# :save
|
230
|
-
# :forget
|
231
|
-
# :alert
|
240
|
+
# :raise -> raise an exception
|
241
|
+
# :save (default) -> save the book before it is closed
|
242
|
+
# :forget -> close the book
|
243
|
+
# :alert -> give control to excel
|
232
244
|
def close(opts = {:if_unsaved => :raise})
|
233
245
|
if ((alive?) && (not @workbook.Saved) && (not @workbook.ReadOnly)) then
|
234
246
|
case opts[:if_unsaved]
|
@@ -261,37 +273,42 @@ module RobustExcelOle
|
|
261
273
|
|
262
274
|
public
|
263
275
|
|
264
|
-
# modify a book such that its state remains unchanged.
|
276
|
+
# modify a book such that its state (open/close, saved/unsaved, readonly/writable) remains unchanged.
|
265
277
|
# options:
|
266
|
-
# :visible:
|
278
|
+
# :visible: Make the book visible in the Excel (default: false)
|
267
279
|
# :keep_open: let the book open after modification (default: false)
|
268
|
-
#
|
269
|
-
#
|
270
|
-
#
|
271
|
-
#
|
280
|
+
# :read_only: Open the book unobtrusively for reading only (default: false)
|
281
|
+
# :use_this: if the book is opened only as ReadOnly and shall be modified, then
|
282
|
+
# true: close it and open it as writable in the excel instance where it was open so far
|
283
|
+
# false(default) open it as writable in another running excel instance, if it exists
|
284
|
+
# in a new excel instance, otherwise
|
272
285
|
def self.unobtrusively(file, opts = { })
|
273
286
|
options = {
|
274
287
|
:keep_open => false,
|
275
|
-
:visible => false
|
288
|
+
:visible => false,
|
289
|
+
:read_only => false,
|
290
|
+
:use_this => false
|
276
291
|
}.merge(opts)
|
277
|
-
book = book_store.fetch(file)
|
292
|
+
book = book_store.fetch(file, :prefer_writable => (not options[:read_only]))
|
278
293
|
was_not_alive_or_nil = book.nil? || (not book.alive?)
|
279
|
-
was_saved = was_not_alive_or_nil ? true : book.
|
280
|
-
was_readonly =
|
294
|
+
was_saved = was_not_alive_or_nil ? true : book.saved
|
295
|
+
was_readonly = book.readonly unless was_not_alive_or_nil
|
281
296
|
old_book = book if was_readonly
|
282
|
-
old_visible = book ? book.visible : false
|
283
|
-
begin
|
284
|
-
book = was_not_alive_or_nil ? open(file
|
285
|
-
(
|
286
|
-
|
297
|
+
old_visible = (book && book.excel.alive?) ? book.excel.visible : false
|
298
|
+
begin
|
299
|
+
book = was_not_alive_or_nil ? open(file) :
|
300
|
+
(((not was_readonly) || options[:read_only]) ? book :
|
301
|
+
(options[:use_this] ? open(file, :force_excel => book.excel) : open(file, :force_excel => :new)))
|
302
|
+
book.excel.visible = options[:visible]
|
287
303
|
yield book
|
288
304
|
ensure
|
289
|
-
book.save if (was_not_alive_or_nil || was_saved || was_readonly) && (not book.
|
290
|
-
|
305
|
+
book.save if (was_not_alive_or_nil || was_saved || (was_readonly && (not options[:read_only]))) && (not book.saved)
|
306
|
+
# book was open, readonly and shoud be modified
|
307
|
+
if (not was_not_alive_or_nil) && (not options[:read_only]) && was_readonly && options[:use_this]
|
291
308
|
book.close
|
292
|
-
|
309
|
+
open(file, :if_obstructed => :new_excel, :read_only => true)
|
293
310
|
end
|
294
|
-
book.visible = old_visible
|
311
|
+
book.excel.visible = old_visible
|
295
312
|
book.close if (was_not_alive_or_nil && (not opts[:keep_open]))
|
296
313
|
end
|
297
314
|
end
|
@@ -332,35 +349,20 @@ module RobustExcelOle
|
|
332
349
|
@workbook.Fullname.tr('\\','/') rescue nil
|
333
350
|
end
|
334
351
|
|
352
|
+
def readonly
|
353
|
+
@workbook.ReadOnly
|
354
|
+
end
|
355
|
+
|
356
|
+
def saved
|
357
|
+
@workbook.Saved
|
358
|
+
end
|
359
|
+
|
335
360
|
# returns true, if the full book names and excel appications are identical, false, otherwise
|
336
361
|
def == other_book
|
337
362
|
other_book.is_a?(Book) &&
|
338
363
|
@excel == other_book.excel &&
|
339
364
|
self.filename == other_book.filename
|
340
365
|
end
|
341
|
-
|
342
|
-
# returns if the Excel instance is visible
|
343
|
-
def visible
|
344
|
-
@excel.visible
|
345
|
-
end
|
346
|
-
|
347
|
-
# make the Excel instance visible or invisible
|
348
|
-
# option: visible_value true -> make Excel visible, false -> make Excel invisible
|
349
|
-
def visible= visible_value
|
350
|
-
@excel.visible = visible_value
|
351
|
-
end
|
352
|
-
|
353
|
-
# returns if DisplayAlerts is enabed in the Excel instance
|
354
|
-
def displayalerts
|
355
|
-
@excel.displayalerts
|
356
|
-
end
|
357
|
-
|
358
|
-
# enable in the Excel instance Dispayalerts
|
359
|
-
# option: displayalerts_value true -> enable DisplayAlerts, false -> disable DispayAlerts
|
360
|
-
def displayalerts= displayalerts_value
|
361
|
-
@excel.displayalerts = displayalerts_value
|
362
|
-
end
|
363
|
-
|
364
366
|
|
365
367
|
# saves a book.
|
366
368
|
# returns true, if successfully saved, nil otherwise
|
@@ -10,33 +10,34 @@ module RobustExcelOle
|
|
10
10
|
end
|
11
11
|
|
12
12
|
# returns a book with the given filename, if it was open once
|
13
|
-
#
|
14
|
-
# options:
|
15
|
-
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
def fetch(filename, options = { })
|
13
|
+
# prefers open books to closed books, and among them, prefers more recently opened books
|
14
|
+
# options: :prefer_writable return the writable book, if it is open (default: true)
|
15
|
+
# return the book according to the preference order mentioned above, otherwise
|
16
|
+
# :prefer_excel return the book in the given excel instance, if it exists
|
17
|
+
# proceed according to prefer_writable otherwise
|
18
|
+
def fetch(filename, options = {:prefer_writable => true })
|
19
19
|
filename_key = RobustExcelOle::canonize(filename)
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
20
|
+
weakref_books = @filename2books[filename_key]
|
21
|
+
return nil unless weakref_books
|
22
|
+
result = open_book = closed_book = nil
|
23
|
+
weakref_books.each do |wr_book|
|
24
|
+
if (not wr_book.weakref_alive?)
|
25
|
+
@filename2books[filename_key].delete(wr_book)
|
26
|
+
else
|
27
|
+
if options[:prefer_excel] && wr_book.excel == options[:prefer_excel]
|
28
|
+
result = wr_book
|
29
|
+
break
|
30
|
+
end
|
31
|
+
if wr_book.alive?
|
32
|
+
open_book = wr_book
|
33
|
+
break if ((not wr_book.readonly) && options[:prefer_writable])
|
32
34
|
else
|
33
|
-
|
35
|
+
closed_book = wr_book
|
34
36
|
end
|
35
|
-
else
|
36
|
-
closed_book = book
|
37
37
|
end
|
38
38
|
end
|
39
|
-
result
|
39
|
+
result = result ? result : (open_book ? open_book : closed_book)
|
40
|
+
result.__getobj__ if result
|
40
41
|
end
|
41
42
|
|
42
43
|
# stores a book
|
@@ -44,12 +45,29 @@ module RobustExcelOle
|
|
44
45
|
filename_key = RobustExcelOle::canonize(book.filename)
|
45
46
|
if book.stored_filename
|
46
47
|
old_filename_key = RobustExcelOle::canonize(book.stored_filename)
|
48
|
+
# deletes the weak reference to the book
|
47
49
|
@filename2books[old_filename_key].delete(book)
|
48
50
|
end
|
49
|
-
@filename2books[filename_key] |= [book]
|
51
|
+
@filename2books[filename_key] |= [WeakRef.new(book)]
|
50
52
|
book.stored_filename = book.filename
|
51
53
|
end
|
52
54
|
|
55
|
+
# returns all excel instances and the workbooks that are open in them
|
56
|
+
# first: only the stored excel instances are considered
|
57
|
+
def excel_list
|
58
|
+
excel2books = Hash.new {|hash, key| hash[key] = [] }
|
59
|
+
if @filename2books
|
60
|
+
@filename2books.each do |filename,books|
|
61
|
+
if books
|
62
|
+
books.each do |book|
|
63
|
+
excel2books[book.excel] |= [book.workbook]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
excel2books
|
69
|
+
end
|
70
|
+
|
53
71
|
# prints the book store
|
54
72
|
def print
|
55
73
|
p "@filename2books:"
|
@@ -58,10 +76,16 @@ module RobustExcelOle
|
|
58
76
|
p " filename: #{filename}"
|
59
77
|
p " books:"
|
60
78
|
p " []" if books == []
|
61
|
-
books
|
62
|
-
|
63
|
-
|
64
|
-
|
79
|
+
if books
|
80
|
+
books.each do |book|
|
81
|
+
if book.weakref_alive?
|
82
|
+
p "#{book}"
|
83
|
+
p "excel: #{book.excel}"
|
84
|
+
p "alive: #{book.alive?}"
|
85
|
+
else
|
86
|
+
p "weakref not alive"
|
87
|
+
end
|
88
|
+
end
|
65
89
|
end
|
66
90
|
end
|
67
91
|
end
|
data/robust_excel_ole.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ["traths"]
|
9
9
|
s.email = ["Thomas.Raths@gmx.net"]
|
10
10
|
s.homepage = "https://github.com/Thomas008/robust_excel_ole"
|
11
|
-
s.summary = "RobustExcelOle
|
12
|
-
s.description = "RobustExcelOle
|
11
|
+
s.summary = "RobustExcelOle processes Excel files and wraps the win32ole library."
|
12
|
+
s.description = "RobustExcelOle processes Excel files, provides all win32ole operations, convenient methods for opening, saving and closing, and implements an Excel file management system."
|
13
13
|
|
14
14
|
s.rubyforge_project = "robust_excel_ole"
|
15
15
|
|
@@ -23,11 +23,6 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
24
24
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
25
25
|
s.require_paths = ["lib"]
|
26
|
-
s.add_development_dependency "rake", '>= 0.9.2'
|
27
26
|
s.add_development_dependency "rspec", '>= 2.6.0'
|
28
|
-
s.add_development_dependency "rb-fchange", '>= 0.0.5'
|
29
|
-
s.add_development_dependency "wdm", '>= 0.0.3'
|
30
|
-
s.add_development_dependency "win32console", '>= 1.3.2'
|
31
|
-
s.add_development_dependency "guard-rspec", '>= 2.1.1'
|
32
27
|
s.required_ruby_version = '>= 1.8.6'
|
33
28
|
end
|