robust_excel_ole 0.3.1 → 0.3.2

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.
Files changed (36) hide show
  1. data/README.rdoc +69 -56
  2. data/README_detail.rdoc +44 -34
  3. data/TodoList.md +8 -6
  4. data/examples/edit_sheets/example_access_sheets_and_cells.rb +6 -6
  5. data/examples/edit_sheets/example_adding_sheets.rb +2 -2
  6. data/examples/edit_sheets/example_ranges.rb +3 -3
  7. data/examples/open_save_close/example_control_to_excel.rb +2 -2
  8. data/examples/open_save_close/example_default_excel.rb +2 -2
  9. data/examples/open_save_close/example_force_excel.rb +1 -1
  10. data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +4 -4
  11. data/examples/open_save_close/example_if_obstructed_forget.rb +2 -2
  12. data/examples/open_save_close/example_if_obstructed_save.rb +2 -2
  13. data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
  14. data/examples/open_save_close/example_if_unsaved_forget.rb +1 -1
  15. data/examples/open_save_close/example_if_unsaved_forget_more.rb +1 -1
  16. data/examples/open_save_close/example_read_only.rb +2 -2
  17. data/examples/open_save_close/example_rename_cells.rb +1 -1
  18. data/examples/open_save_close/example_reuse.rb +3 -3
  19. data/examples/open_save_close/example_simple.rb +2 -2
  20. data/examples/open_save_close/example_unobtrusively.rb +1 -1
  21. data/lib/robust_excel_ole/book.rb +97 -128
  22. data/lib/robust_excel_ole/book_store.rb +23 -23
  23. data/lib/robust_excel_ole/excel.rb +12 -14
  24. data/lib/robust_excel_ole/version.rb +1 -1
  25. data/spec/book_spec.rb +462 -289
  26. data/spec/book_store_spec.rb +36 -55
  27. data/spec/data/book_with_blank.xls +0 -0
  28. data/spec/data/{different_simple.xls → different_workbook.xls} +0 -0
  29. data/spec/data/merge_cells.xls +0 -0
  30. data/spec/data/{more_simple.xls → more_workbook.xls} +0 -0
  31. data/spec/data/protected_sheet.xls +0 -0
  32. data/spec/data/{simple.xls → workbook.xls} +0 -0
  33. data/spec/data/{simple.xlsm → workbook.xlsm} +0 -0
  34. data/spec/data/{simple.xlsx → workbook.xlsx} +0 -0
  35. data/spec/excel_spec.rb +40 -0
  36. metadata +9 -9
@@ -10,7 +10,7 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- simple_file = dir + 'simple.xls'
13
+ simple_file = dir + 'workbook.xls'
14
14
  book1 = Book.open(simple_file) # open a book in a new Excel instance since no Excel is open
15
15
  book1.excel.visible = true # make current Excel visible
16
16
  sleep 2
@@ -10,12 +10,12 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- file_name = dir + 'simple.xls'
14
- other_file_name = dir + 'more_data/simple.xls'
13
+ file_name = dir + 'workbook.xls'
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
17
  sheet = book[0]
18
- first_cell = sheet[0,0].value # access a sheet
18
+ first_cell = sheet[0,0].Value # access a sheet
19
19
  sheet[0,0] = first_cell == "simple" ? "complex" : "simple" # change a cell
20
20
  sleep 1
21
21
  begin
@@ -27,7 +27,7 @@ begin
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
29
  new_sheet = new_book[0]
30
- new_first_cell = new_sheet[0,0].value
30
+ new_first_cell = new_sheet[0,0].Value
31
31
  puts "the old book was saved" unless new_first_cell == first_cell
32
32
  new_book.close # close the books
33
33
  ensure
@@ -10,8 +10,8 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- file_name = dir + 'simple.xls'
14
- other_file_name = dir + 'more_data/simple.xls'
13
+ file_name = dir + 'workbook.xls'
14
+ other_file_name = dir + 'more_data/workbook.xls'
15
15
  book = Book.open(file_name, :visible => true) # open a book, make Excel application visible
16
16
  sleep 3
17
17
  begin
@@ -10,8 +10,8 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- file_name = dir + 'simple.xls'
14
- other_file_name = dir + 'more_data/simple.xls'
13
+ file_name = dir + 'workbook.xls'
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
17
  sheet = book[0]
@@ -10,7 +10,7 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- file_name = dir + 'simple.xls'
13
+ file_name = dir + 'workbook.xls'
14
14
  book = Book.open(file_name) # open a book
15
15
  sheet = book[0] # access a sheet
16
16
  sheet[0,0] = sheet[0,0].value == "simple" ? "complex" : "simple" # change a cell
@@ -10,7 +10,7 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- file_name = dir + 'simple.xls'
13
+ file_name = dir + 'workbook.xls'
14
14
  book = Book.open(file_name) # open a book
15
15
  book.excel.visible = true # make current Excel visible
16
16
  sleep 1
@@ -10,7 +10,7 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- file_name = dir + 'simple.xls'
13
+ file_name = dir + 'workbook.xls'
14
14
  book = Book.open(file_name) # open a book
15
15
  book.excel.visible = true # make current Excel visible
16
16
  sleep
@@ -9,8 +9,8 @@ include RobustExcelOle
9
9
  Excel.close_all
10
10
  begin
11
11
  dir = create_tmpdir
12
- file_name = dir + 'simple.xls'
13
- other_file_name = dir + 'different_simple.xls'
12
+ file_name = dir + 'workbook.xls'
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
15
  sheet = book[0] # access a sheet
16
16
  sleep 1
@@ -10,7 +10,7 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- file_name = dir + 'simple.xls'
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
16
  sheet = book[0]
@@ -9,9 +9,9 @@ include RobustExcelOle
9
9
  Excel.close_all
10
10
  begin
11
11
  dir = create_tmpdir
12
- file_name1 = dir + 'simple.xls'
13
- file_name2 = dir + 'different_simple.xls'
14
- file_name3 = dir + 'different_simple.xls'
12
+ file_name1 = dir + 'workbook.xls'
13
+ file_name2 = dir + 'different_workbook.xls'
14
+ file_name3 = dir + 'different_workbook.xls'
15
15
  file_name4 = dir + 'book_with_blank.xls'
16
16
  book1 = Book.open(file_name1) # open a book in a new Excel instance since no Excel is open
17
17
  book1.excel.visible = true # make current Excel visible
@@ -10,8 +10,8 @@ include RobustExcelOle
10
10
  Excel.close_all
11
11
  begin
12
12
  dir = create_tmpdir
13
- file_name = dir + 'simple.xls'
14
- other_file_name = dir + 'different_simple.xls'
13
+ file_name = dir + 'workbook.xls'
14
+ other_file_name = dir + 'different_workbook.xls'
15
15
  book = Book.open(file_name) # open a book. default: :read_only => false
16
16
  book.excel.visible = true # make current Excel visible
17
17
  sheet = book[0] # access a sheet
@@ -9,7 +9,7 @@ include RobustExcelOle
9
9
  Excel.close_all
10
10
  begin
11
11
  dir = create_tmpdir
12
- simple_file = dir + 'simple.xls'
12
+ simple_file = dir + 'workbook.xls'
13
13
  book = Book.open(simple_file, :visible => true) # open a book, make Excel visible
14
14
  old_sheet = book[0]
15
15
  p "1st cell: #{old_sheet[0,0].value}"
@@ -9,6 +9,16 @@ module RobustExcelOle
9
9
  attr_accessor :excel
10
10
  attr_accessor :workbook
11
11
  attr_accessor :stored_filename
12
+ attr_accessor :options
13
+
14
+ DEFAULT_OPEN_OPTS = {
15
+ :excel => :reuse,
16
+ :default_excel => :reuse,
17
+ :if_locked => :readonly,
18
+ :if_unsaved => :raise,
19
+ :if_obstructed => :raise,
20
+ :read_only => false
21
+ }
12
22
 
13
23
  class << self
14
24
 
@@ -19,91 +29,63 @@ module RobustExcelOle
19
29
  #
20
30
  # options:
21
31
  # :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
32
+ # Otherwise, i.e. if the book was not open before or the Excel instance is not alive
33
+ # :reuse (default) -> connect to a (the first opened) running Excel instance,
34
+ # excluding the hidden Excel instance, if it exists,
35
+ # otherwise open in a new Excel instance.
25
36
  # :new -> open in a new Excel instance
26
37
  # <instance> -> open in the given Excel instance
27
38
  # :force_excel no matter whether the book was already open
28
39
  # :new (default) -> open in a new Excel
29
40
  # <instance> -> open in the given Excel instance
30
- # :if_locked if the book is open in another Excel instance, then
31
- # :readonly (default) -> open the book as readonly, if is should be opened in a new Excel,
32
- # use the old book otherwise
33
- # :take_writable -> use the Excel instance in which the book is writable,
34
- # if such an Excel instance exists
35
- # :force_writability -> make it writable in the desired Excel
36
- # (does not work yet)
37
- # :if_locked_unsaved if the book is open in another Excel instance and contains unsaved changes
38
- # :raise -> raise an exception
39
- # :save -> save the unsaved book
40
- # (not implemented yet)
41
41
  # :if_unsaved if an unsaved book with the same name is open, then
42
- # :raise -> raise an exception
42
+ # :raise (default) -> raise an exception
43
43
  # :forget -> close the unsaved book, open the new book
44
44
  # :accept -> let the unsaved book open
45
45
  # :alert -> give control to Excel
46
- # :new_excel (default) -> open the new book in a new Excel
46
+ # :new_excel -> open the new book in a new Excel
47
47
  # :if_obstructed if a book with the same name in a different path is open, then
48
- # :raise -> raise an exception
48
+ # :raise (default) -> raise an exception
49
49
  # :forget -> close the old book, open the new book
50
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
51
+ # :close_if_saved -> close the old book and open the new book, if the old book is saved,
52
+ # otherwise raise an exception.
53
+ # :new_excel -> open the new book in a new Excel
54
+ # :if_absent :create -> creates a new Excel file, if it does not exists
55
+ # :raise -> raises an exception , if the file does not exists
54
56
  # :read_only open in read-only mode (default: false)
55
57
  # :displayalerts enable DisplayAlerts in Excel (default: false)
56
- # :visible make visibe in Excel (default: false)
58
+ # :visible make visible in Excel (default: false)
57
59
  # if :default_excel is set, then DisplayAlerts and Visible are set only if these parameters are given
58
-
60
+
59
61
  def open(file, opts={ }, &block)
60
- @options = {
61
- :excel => :reuse,
62
- :default_excel => :reuse,
63
- :if_locked => :readonly,
64
- :if_unsaved => :new_excel,
65
- :if_obstructed => :new_excel,
66
- :read_only => false
67
- }.merge(opts)
68
- #self.set_defaults(opts) ???
62
+ current_options = DEFAULT_OPEN_OPTS.merge(opts)
69
63
  book = nil
70
- if (not (@options[:force_excel] == :new && (not @options[:if_locked] == :take_writable)))
64
+ if (not (current_options[:force_excel] == :new && (not current_options[:if_locked] == :take_writable)))
71
65
  # 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
66
+ book = book_store.fetch(file, :prefer_writable => (not current_options[:read_only]),
67
+ :prefer_excel => (current_options[:read_only] ? current_options[:force_excel] : nil)) rescue nil
73
68
  if book
74
- if ((not @options[:force_excel]) || (@options[:force_excel] == book.excel))
75
- if (not book.excel.alive?)
76
- book.get_excel
77
- end
78
- if book.excel.alive?
79
- # condition: :if_unsaved is not set or :accept or workbook is not unsaved
80
- if_unsaved_not_set_or_accept_or_workbook_saved = (@options[:if_unsaved] == :accept || @options[:if_unsaved] == :raise || (not book.workbook) || book.workbook.Saved)
81
- if ((not book.alive?) || if_unsaved_not_set_or_accept_or_workbook_saved)
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
90
- # reopen the book
91
- book.get_workbook
92
- end
93
- return book if book.alive? && if_unsaved_not_set_or_accept_or_workbook_saved
94
- end
69
+ if (((not current_options[:force_excel]) || (current_options[:force_excel] == book.excel)) &&
70
+ (not (book.alive? && (not book.saved) && (not current_options[:if_unsaved] == :accept))))
71
+ book.options = DEFAULT_OPEN_OPTS.merge(opts)
72
+ book.get_excel unless book.excel.alive?
73
+ # if the book is opened as readonly and should be opened as writable, then close it and open the book with the new readonly mode
74
+ book.close if (book.alive? && (not book.writable) && (not current_options[:read_only]))
75
+ # reopen the book
76
+ book.get_workbook unless book.alive?
77
+ return book
95
78
  end
96
79
  end
97
80
  end
98
- @options[:excel] = @options[:force_excel] ? @options[:force_excel] : @options[:default_excel]
99
- new(file, @options, &block)
81
+ current_options[:excel] = current_options[:force_excel] ? current_options[:force_excel] : current_options[:default_excel]
82
+ new(file, current_options, &block)
100
83
  end
101
84
  end
102
85
 
103
86
  def initialize(file, opts={ }, &block)
104
- raise ExcelErrorOpen, "file #{file} not found" unless File.exist?(file)
105
- set_defaults(opts)
106
- @file = file
87
+ @options = DEFAULT_OPEN_OPTS.merge(opts)
88
+ @file = file
107
89
  get_excel
108
90
  get_workbook
109
91
  book_store.store(self)
@@ -115,17 +97,6 @@ module RobustExcelOle
115
97
  end
116
98
  end
117
99
  end
118
-
119
- def set_defaults(opts)
120
- @options = {
121
- :excel => :reuse,
122
- :default_excel => :reuse,
123
- :if_locked => :readonly,
124
- :if_unsaved => :new_excel,
125
- :if_obstructed => :new_excel,
126
- :read_only => false
127
- }.merge(opts)
128
- end
129
100
 
130
101
  def get_excel
131
102
  if @options[:excel] == :reuse
@@ -150,6 +121,7 @@ module RobustExcelOle
150
121
  end
151
122
 
152
123
  def get_workbook
124
+ raise ExcelErrorOpen, "file #{@file} not found" if ((not File.exist?(@file)) && @options[:if_absent] == :raise)
153
125
  @workbook = @excel.Workbooks.Item(File.basename(@file)) rescue nil
154
126
  if @workbook then
155
127
  obstructed_by_other_book = (File.basename(@file) == File.basename(@workbook.Fullname)) &&
@@ -162,30 +134,30 @@ module RobustExcelOle
162
134
  when :forget
163
135
  @workbook.Close
164
136
  @workbook = nil
165
- open_workbook
137
+ open_or_create_workbook
166
138
  when :save
167
139
  save unless @workbook.Saved
168
140
  @workbook.Close
169
141
  @workbook = nil
170
- open_workbook
142
+ open_or_create_workbook
171
143
  when :close_if_saved
172
144
  if (not @workbook.Saved) then
173
145
  raise ExcelErrorOpen, "book with the same name in a different path is unsaved"
174
146
  else
175
147
  @workbook.Close
176
148
  @workbook = nil
177
- open_workbook
149
+ open_or_create_workbook
178
150
  end
179
151
  when :new_excel
180
152
  @excel_options = {:displayalerts => false, :visible => false}.merge(@options)
181
153
  @excel_options[:reuse] = false
182
154
  @excel = Excel.new(@excel_options)
183
- open_workbook
155
+ open_or_create_workbook
184
156
  else
185
157
  raise ExcelErrorOpen, ":if_obstructed: invalid option"
186
158
  end
187
159
  else
188
- # book open, not obstructed by an other book, but not saved
160
+ # book open, not obstructed by an other book, but not saved and writable
189
161
  if (not @workbook.Saved) then
190
162
  case @options[:if_unsaved]
191
163
  when :raise
@@ -193,18 +165,18 @@ module RobustExcelOle
193
165
  when :forget
194
166
  @workbook.Close
195
167
  @workbook = nil
196
- open_workbook
168
+ open_or_create_workbook
197
169
  when :accept
198
170
  # do nothing
199
171
  when :alert
200
172
  @excel.with_displayalerts true do
201
- open_workbook
173
+ open_or_create_workbook
202
174
  end
203
175
  when :new_excel
204
176
  @excel_options = {:displayalerts => false, :visible => false}.merge(@options)
205
177
  @excel_options[:reuse] = false
206
178
  @excel = Excel.new(@excel_options)
207
- open_workbook
179
+ open_or_create_workbook
208
180
  else
209
181
  raise ExcelErrorOpen, ":if_unsaved: invalid option"
210
182
  end
@@ -212,37 +184,50 @@ module RobustExcelOle
212
184
  end
213
185
  else
214
186
  # book is not open
215
- open_workbook
187
+ open_or_create_workbook
216
188
  end
217
189
  end
218
190
 
219
- def open_workbook
191
+ def open_or_create_workbook
192
+ if (not File.exist?(@file))
193
+ @workbook = self.class.create(@file)
194
+ #@workbook = Excel.new(:reuse => true).generate_workbook(@file)
195
+ return
196
+ end
220
197
  if ((not @workbook) || (@options[:if_unsaved] == :alert) || @options[:if_obstructed]) then
221
198
  begin
222
199
  filename = RobustExcelOle::absolute_path(@file)
223
200
  workbooks = @excel.Workbooks
224
201
  workbooks.Open(filename,{ 'ReadOnly' => @options[:read_only] })
202
+ rescue WIN32OLERuntimeError
203
+ raise ExcelUserCanceled, "open: canceled by user"
204
+ end
205
+ begin
225
206
  # workaround for bug in Excel 2010: workbook.Open does not always return
226
207
  # the workbook with given file name
227
208
  @workbook = workbooks.Item(File.basename(filename))
228
- #rescue BookStoreError => e
229
- # raise ExcelUserCanceled, "open: canceled by user: #{e}"
230
- rescue WIN32OLERuntimeError
231
- raise ExcelUserCanceled, "open: canceled by user"
209
+ rescue WIN32OLERuntimeError
210
+ raise ExcelErrorOpen, "open: item error"
232
211
  end
233
212
  end
234
213
  end
235
214
 
215
+ # generate, save and close an empty workbook
216
+ def self.create(file)
217
+ @workbook = Excel.new(:reuse => true).generate_workbook(file)
218
+ @workbook
219
+ end
220
+
236
221
  # closes the book, if it is alive
237
222
  #
238
223
  # options:
239
224
  # :if_unsaved if book is unsaved
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
225
+ # :raise (default) -> raise an exception
226
+ # :save -> save the book before it is closed
227
+ # :forget -> close the book
228
+ # :alert -> give control to excel
244
229
  def close(opts = {:if_unsaved => :raise})
245
- if ((alive?) && (not @workbook.Saved) && (not @workbook.ReadOnly)) then
230
+ if (alive? && (not @workbook.Saved) && writable) then
246
231
  case opts[:if_unsaved]
247
232
  when :raise
248
233
  raise ExcelErrorClose, "book is unsaved (#{File.basename(self.stored_filename)})"
@@ -275,38 +260,38 @@ module RobustExcelOle
275
260
 
276
261
  # modify a book such that its state (open/close, saved/unsaved, readonly/writable) remains unchanged.
277
262
  # options:
278
- # :visible: Make the book visible in the Excel (default: false)
279
- # :keep_open: let the book open after modification (default: false)
263
+ # :if_closed : :hidden (default) : open closed books in one separate Excel instance that is not visible and has no displayaslerts
264
+ # :reuse : open closed books in the Excel instance of the book, if it exists, reuse another Excel, otherwise
280
265
  # :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
266
+ # :use_readonly_excel: if the book is opened only as ReadOnly and shall be modified, then
282
267
  # 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
268
+ # false (default) open it as writable in another running excel instance, if it exists,
269
+ # otherwise open in a new excel instance.
270
+ # :keep_open: let the book open after unobtrusively opening (default: false)
285
271
  def self.unobtrusively(file, opts = { })
286
272
  options = {
287
- :keep_open => false,
288
- :visible => false,
273
+ :if_closed => :hidden,
289
274
  :read_only => false,
290
- :use_this => false
275
+ :use_readonly_excel => false,
276
+ :keep_open => false,
291
277
  }.merge(opts)
292
278
  book = book_store.fetch(file, :prefer_writable => (not options[:read_only]))
293
279
  was_not_alive_or_nil = book.nil? || (not book.alive?)
294
280
  was_saved = was_not_alive_or_nil ? true : book.saved
295
- was_readonly = book.readonly unless was_not_alive_or_nil
296
- old_book = book if was_readonly
281
+ was_writable = book.writable unless was_not_alive_or_nil
297
282
  old_visible = (book && book.excel.alive?) ? book.excel.visible : false
298
283
  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]
284
+ book = was_not_alive_or_nil ?
285
+ (options[:if_closed] == :hidden ? open(file, :force_excel => book_store.ensure_hidden_excel) : open(file)) :
286
+ ((was_writable || options[:read_only]) ? book :
287
+ (options[:use_readonly_excel] ? open(file, :force_excel => book.excel) : open(file, :force_excel => :new)))
288
+ book.excel.visible = opts[:visible] unless opts[:visible].nil?
303
289
  yield book
304
290
  ensure
305
- book.save if (was_not_alive_or_nil || was_saved || (was_readonly && (not options[:read_only]))) && (not book.saved)
291
+ book.save if (was_not_alive_or_nil || was_saved || ((not was_writable) && (not options[:read_only]))) && (not book.saved)
306
292
  # 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]
308
- book.close
309
- open(file, :if_obstructed => :new_excel, :read_only => true)
293
+ if (not was_not_alive_or_nil) && (not options[:read_only]) && (not was_writable) && options[:use_readonly_excel]
294
+ open(file, :force_excel => book.excel, :if_obstructed => :new_excel, :read_only => true)
310
295
  end
311
296
  book.excel.visible = old_visible
312
297
  book.close if (was_not_alive_or_nil && (not opts[:keep_open]))
@@ -349,15 +334,15 @@ module RobustExcelOle
349
334
  @workbook.Fullname.tr('\\','/') rescue nil
350
335
  end
351
336
 
352
- def readonly
353
- @workbook.ReadOnly
337
+ def writable
338
+ (not @workbook.ReadOnly) if @workbook
354
339
  end
355
340
 
356
341
  def saved
357
- @workbook.Saved
342
+ @workbook.Saved if @workbook
358
343
  end
359
344
 
360
- # returns true, if the full book names and excel appications are identical, false, otherwise
345
+ # returns true, if the full book names and excel appications are identical, false otherwise
361
346
  def == other_book
362
347
  other_book.is_a?(Book) &&
363
348
  @excel == other_book.excel &&
@@ -530,20 +515,4 @@ public
530
515
  class ExcelErrorSheet < ExcelError # :nodoc: #
531
516
  end
532
517
 
533
-
534
- end
535
-
536
-
537
- __END__
538
-
539
-
540
- class Object
541
- def update_extracted hash, key
542
- value = hash[param_name]
543
- self.send("#{key}=", value) if value
544
- end
545
- end
546
- @excel.visible = @options[:visible] if @options[:visible]
547
- @excel.displayalerts = @options[:dispayalerts]
548
- @excel.update_extracted(@options, [:visible, :dispayalerts])
549
- @excel.options.merge(@options.extract(:visible, :dispayalerts))
518
+ end
@@ -7,14 +7,16 @@ module RobustExcelOle
7
7
 
8
8
  def initialize
9
9
  @filename2books = Hash.new {|hash, key| hash[key] = [] }
10
+ @hidden_excel_instance = nil
10
11
  end
11
12
 
12
13
  # returns a book with the given filename, if it was open once
13
14
  # prefers open books to closed books, and among them, prefers more recently opened books
15
+ # excludes hidden Excel instance
14
16
  # 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
17
+ # otherwise return the book according to the preference order mentioned above
18
+ # :prefer_excel return the book in the given excel instance, if it exists,
19
+ # otherwise proceed according to prefer_writable
18
20
  def fetch(filename, options = {:prefer_writable => true })
19
21
  filename_key = RobustExcelOle::canonize(filename)
20
22
  weakref_books = @filename2books[filename_key]
@@ -24,20 +26,22 @@ module RobustExcelOle
24
26
  if (not wr_book.weakref_alive?)
25
27
  @filename2books[filename_key].delete(wr_book)
26
28
  else
27
- if options[:prefer_excel] && wr_book.excel == options[:prefer_excel]
28
- result = wr_book
29
+ book = wr_book.__getobj__
30
+ next if book.excel == try_hidden_excel
31
+ if options[:prefer_excel] && book.excel == options[:prefer_excel]
32
+ result = book
29
33
  break
30
34
  end
31
- if wr_book.alive?
32
- open_book = wr_book
33
- break if ((not wr_book.readonly) && options[:prefer_writable])
35
+ if book.alive?
36
+ open_book = book
37
+ break if (book.writable && options[:prefer_writable])
34
38
  else
35
- closed_book = wr_book
39
+ closed_book = book
36
40
  end
37
41
  end
38
42
  end
39
43
  result = result ? result : (open_book ? open_book : closed_book)
40
- result.__getobj__ if result
44
+ result if result
41
45
  end
42
46
 
43
47
  # stores a book
@@ -52,20 +56,16 @@ module RobustExcelOle
52
56
  book.stored_filename = book.filename
53
57
  end
54
58
 
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
59
+ # creates and returns a separate Excel instance with Visible and DisplayAlerts false
60
+ def ensure_hidden_excel
61
+ unless (@hidden_excel_instance && @hidden_excel_instance.weakref_alive? && @hidden_excel_instance.__getobj__.alive?)
62
+ @hidden_excel_instance = WeakRef.new(Excel.create)
67
63
  end
68
- excel2books
64
+ @hidden_excel_instance.__getobj__
65
+ end
66
+
67
+ def try_hidden_excel
68
+ @hidden_excel_instance.__getobj__ if (@hidden_excel_instance && @hidden_excel_instance.weakref_alive? && @hidden_excel_instance.__getobj__.alive?)
69
69
  end
70
70
 
71
71
  # prints the book store