robust_excel_ole 0.3.0 → 0.3.1
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/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
|