robust_excel_ole 0.2.3 → 0.3.0

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 (34) hide show
  1. data/README.rdoc +266 -71
  2. data/TodoList.md +33 -0
  3. data/examples/edit_sheets/example_adding_sheets.rb +7 -0
  4. data/examples/open_save_close/example_control_to_excel.rb +4 -4
  5. data/examples/open_save_close/example_default_excel.rb +49 -0
  6. data/examples/open_save_close/example_force_excel.rb +34 -0
  7. data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +1 -1
  8. data/examples/open_save_close/example_if_obstructed_forget.rb +3 -3
  9. data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
  10. data/examples/open_save_close/example_if_unsaved_forget.rb +3 -3
  11. data/examples/open_save_close/example_if_unsaved_forget_more.rb +3 -3
  12. data/examples/open_save_close/example_read_only.rb +1 -1
  13. data/examples/open_save_close/example_rename_cells.rb +69 -0
  14. data/examples/open_save_close/example_reuse.rb +8 -8
  15. data/examples/open_save_close/example_simple.rb +3 -3
  16. data/examples/open_save_close/example_unobtrusively.rb +28 -0
  17. data/examples/save_sheets/example_save_sheets.rb +2 -6
  18. data/lib/robust_excel_ole.rb +18 -0
  19. data/lib/robust_excel_ole/book.rb +356 -123
  20. data/lib/robust_excel_ole/book_store.rb +75 -0
  21. data/lib/robust_excel_ole/excel.rb +105 -53
  22. data/lib/robust_excel_ole/robustexcelole.sublime-project +8 -8
  23. data/lib/robust_excel_ole/sheet.rb +29 -1
  24. data/lib/robust_excel_ole/version.rb +1 -1
  25. data/robust_excel_ole.gemspec +3 -3
  26. data/spec/book_spec.rb +1031 -247
  27. data/spec/book_store_spec.rb +306 -0
  28. data/spec/data/book_with_blank.xls +0 -0
  29. data/spec/data/merge_cells.xls +0 -0
  30. data/spec/data/more_simple.xls +0 -0
  31. data/spec/data/simple.xls +0 -0
  32. data/spec/excel_spec.rb +145 -90
  33. data/spec/sheet_spec.rb +31 -7
  34. metadata +15 -7
@@ -1,3 +1,4 @@
1
+
1
2
  # -*- coding: utf-8 -*-
2
3
 
3
4
  require 'weakref'
@@ -5,129 +6,221 @@ require 'weakref'
5
6
  module RobustExcelOle
6
7
 
7
8
  class Book
8
- attr_reader :workbook
9
-
9
+ attr_accessor :excel
10
+ attr_accessor :workbook
11
+ attr_accessor :stored_filename
10
12
 
11
13
  class << self
12
14
 
13
15
  # opens a book.
14
16
  #
15
17
  # options:
16
- # :read_only open in read-only mode (default: false)
17
- # :if_unsaved if an unsaved book with the same name is open, then
18
- # :raise -> raise an exception (default)
19
- # :forget -> close the unsaved book, open the new book
20
- # :accept -> let the unsaved book open
21
- # :alert -> give control to excel
22
- # :new_app -> open the new book in a new excel application
23
- # :if_obstructed if a book with the same name in a different path is open, then
24
- # :raise -> raise an exception (default)
25
- # :forget -> close the old book, open the new book
26
- # :save -> save the old book, close it, open the new book
27
- # :close_if_saved -> close the old book and open the new book, if the old book is saved
28
- # raise an exception otherwise
29
- # :new_app -> open the new book in a new excel application
30
- # :reuse use a running Excel-application (default: true)
31
- # :excel an Excel application (default: nil)
32
- # :displayalerts allow display alerts in Excel (default: false)
33
- # :visible make visibe in Excel (default: false)
34
- def open(file, options={ :reuse => true}, &block)
35
- new(file, options, &block)
36
- end
18
+ # :default_excel if the book was already open in an Excel instance, then open it there, otherwise:
19
+ # :reuse (default) -> connect to a running Excel instance if it exists, open in a new Excel otherwise
20
+ # :new -> open in a new Excel instance
21
+ # <instance> -> open in the given Excel instance
22
+ # :force_excel no matter whether the book was already open
23
+ # :new (default) -> open in a new Excel
24
+ # <instance> -> open in the given Excel instance
25
+ # :if_locked if the book is open in another Excel instance, then
26
+ # :readonly (default) -> open the book as readonly, if is should be opened in a new Excel,
27
+ # use the old book otherwise
28
+ # :take_writable -> use the Excel instance in which the book is writable,
29
+ # if such an Excel instance exists
30
+ # :force_writability -> make it writable in the desired Excel
31
+ # :if_locked_unsaved if the book is open in another Excel instance and contains unsaved changes
32
+ # :raise -> raise an exception
33
+ # :save -> save the unsaved book
34
+ # (not implemented yet)
35
+ # :if_unsaved if an unsaved book with the same name is open, then
36
+ # :raise (default) -> raise an exception
37
+ # :forget -> close the unsaved book, open the new book
38
+ # :accept -> let the unsaved book open
39
+ # :alert -> give control to Excel
40
+ # :new_excel -> open the new book in a new Excel
41
+ # :if_obstructed if a book with the same name in a different path is open, then
42
+ # :raise (default) -> raise an exception
43
+ # :forget -> close the old book, open the new book
44
+ # :save -> save the old book, close it, open the new book
45
+ # :close_if_saved -> close the old book and open the new book, if the old book is saved
46
+ # raise an exception otherwise
47
+ # :new_excel -> open the new book in a new Excel
48
+ # :reuse_excel -> try the next free running Excel, if it exists, open a new Excel, else
49
+ # :read_only open in read-only mode (default: false)
50
+ # :displayalerts enable DisplayAlerts in Excel (default: false)
51
+ # :visible make visibe in Excel (default: false)
52
+ # If :default_excel is set, then DisplayAlerts and Visible are set only if these parameters are given,
53
+ # not set by default
37
54
 
55
+
56
+ def open(file, opts={ }, &block)
57
+ @options = {
58
+ :excel => :reuse,
59
+ :default_excel => :reuse,
60
+ :if_locked => :readonly,
61
+ :if_unsaved => :raise,
62
+ :if_obstructed => :raise,
63
+ :read_only => false
64
+ }.merge(opts)
65
+ #self.set_defaults(opts) ???
66
+ book = nil
67
+ if (not (@options[:force_excel] == :new && (not @options[:if_locked] == :take_writable)))
68
+ book = book_store.fetch(file, :readonly_excel => (@options[:read_only] ? @options[:force_excel] : nil)) rescue nil
69
+ if book
70
+ if (not @options[:force_excel] || (@options[:force_excel] == book.excel))
71
+ if book.excel.alive?
72
+ # condition: :if_unsaved is not set or :accept or workbook is not unsaved
73
+ 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)
75
+ book.set_defaults(opts)
76
+ # reopen the book
77
+ book.get_workbook
78
+ end
79
+ return book if book.alive? && if_unsaved_not_set_or_accept_or_workbook_saved
80
+ end
81
+ end
82
+ end
83
+ end
84
+ @options[:excel] = @options[:force_excel] ? @options[:force_excel] : @options[:default_excel]
85
+ new(file, @options, &block)
86
+ end
38
87
  end
39
88
 
40
89
  def initialize(file, opts={ }, &block)
90
+ raise ExcelErrorOpen, "file #{file} not found" unless File.exist?(file)
91
+ set_defaults(opts)
92
+ @file = file
93
+ get_excel
94
+ get_workbook
95
+ book_store.store(self)
96
+ if block
97
+ begin
98
+ yield self
99
+ ensure
100
+ close
101
+ end
102
+ end
103
+ end
104
+
105
+ def set_defaults(opts)
41
106
  @options = {
42
- :reuse => true,
43
- :excel => nil,
44
- :read_only => false,
45
- :if_unsaved => :raise,
46
- :if_obstructed => :raise
107
+ :excel => :reuse,
108
+ :default_excel => :reuse,
109
+ :if_locked => :readonly,
110
+ :if_unsaved => :raise,
111
+ :if_obstructed => :raise,
112
+ :read_only => false
47
113
  }.merge(opts)
48
- excel_options = {:reuse => true}.merge(opts).delete_if{|k,v|
49
- k== :read_only || k== :if_unsaved || k == :if_obstructed}
50
- if not File.exist?(file)
51
- raise ExcelErrorOpen, "file #{file} not found"
114
+ end
115
+
116
+ def get_excel
117
+ if @options[:excel] == :reuse
118
+ @excel = Excel.new(:reuse => true)
119
+ end
120
+ @excel_options = nil
121
+ if (not @excel)
122
+ if @options[:excel] == :new
123
+ @excel_options = {:displayalerts => false, :visible => false}.merge(@options)
124
+ @excel_options[:reuse] = false
125
+ @excel = Excel.new(@excel_options)
126
+ else
127
+ @excel = @options[:excel]
128
+ end
52
129
  end
53
- @excel = @options[:excel] ? excel_options[:excel] : Excel.new(excel_options)
54
- workbooks = @excel.Workbooks
55
- @workbook = workbooks.Item(File.basename(file)) rescue nil
130
+ # if :excel => :new or (:excel => :reuse but could not reuse)
131
+ # keep the old values for :visible and :displayalerts, set them only if the parameters are given
132
+ if (not @excel_options)
133
+ @excel.displayalerts = @options[:displayalerts] unless @options[:displayalerts].nil?
134
+ @excel.visible = @options[:visible] unless @options[:visible].nil?
135
+ end
136
+ end
137
+
138
+ def get_workbook
139
+ @workbook = @excel.Workbooks.Item(File.basename(@file)) rescue nil
56
140
  if @workbook then
57
- obstructed_by_other_book = (File.basename(file) == File.basename(@workbook.Fullname)) &&
58
- (not (RobustExcelOle::absolute_path(file) == @workbook.Fullname))
141
+ obstructed_by_other_book = (File.basename(@file) == File.basename(@workbook.Fullname)) &&
142
+ (not (RobustExcelOle::absolute_path(@file) == @workbook.Fullname))
143
+ # if book is obstructed by a book with same name and different path
59
144
  if obstructed_by_other_book then
60
- # @workbook is not the desired workbook
61
145
  case @options[:if_obstructed]
62
146
  when :raise
63
147
  raise ExcelErrorOpen, "blocked by a book with the same name in a different path"
64
148
  when :forget
65
149
  @workbook.Close
150
+ @workbook = nil
151
+ open_workbook
66
152
  when :save
67
153
  save unless @workbook.Saved
68
154
  @workbook.Close
155
+ @workbook = nil
156
+ open_workbook
69
157
  when :close_if_saved
70
158
  if (not @workbook.Saved) then
71
159
  raise ExcelErrorOpen, "book with the same name in a different path is unsaved"
72
160
  else
73
161
  @workbook.Close
162
+ @workbook = nil
163
+ open_workbook
74
164
  end
75
- when :new_app
76
- excel_options[:reuse] = false
77
- @excel = Excel.new(excel_options)
78
- @workbook = nil
165
+ when :new_excel
166
+ @excel_options = {:displayalerts => false, :visible => false}.merge(@options)
167
+ @excel_options[:reuse] = false
168
+ @excel = Excel.new(@excel_options)
169
+ open_workbook
79
170
  else
80
171
  raise ExcelErrorOpen, ":if_obstructed: invalid option"
81
172
  end
82
173
  else
83
- # book open, not saved, not obstructed by an other book
174
+ # book open, not obstructed by an other book, but not saved
84
175
  if (not @workbook.Saved) then
85
- #p "book not saved"
86
176
  case @options[:if_unsaved]
87
177
  when :raise
88
- raise ExcelErrorOpen, "book is already open but not saved (#{File.basename(file)})"
178
+ raise ExcelErrorOpen, "book is already open but not saved (#{File.basename(@file)})"
89
179
  when :forget
90
180
  @workbook.Close
181
+ @workbook = nil
182
+ open_workbook
91
183
  when :accept
92
- #nothing
184
+ # do nothing
93
185
  when :alert
94
- old_displayalerts = @excel.DisplayAlerts # :nodoc:
95
- @excel.DisplayAlerts = true # :nodoc:
96
- when :new_app
97
- excel_options[:reuse] = false
98
- @excel = Excel.new(excel_options)
99
- @workbook = nil
186
+ @excel.with_displayalerts true do
187
+ open_workbook
188
+ end
189
+ when :new_excel
190
+ @excel_options = {:displayalerts => false, :visible => false}.merge(@options)
191
+ @excel_options[:reuse] = false
192
+ @excel = Excel.new(@excel_options)
193
+ open_workbook
100
194
  else
101
195
  raise ExcelErrorOpen, ":if_unsaved: invalid option"
102
196
  end
103
197
  end
104
198
  end
199
+ else
200
+ # book is not open
201
+ open_workbook
105
202
  end
106
- begin
107
- # if book not open (was not open,was closed with option :forget or shall be opened in new application)
108
- # or :if_unsaved => :alert
109
- if ((not alive?) || (@options[:if_unsaved] == :alert)) then
110
- begin
111
- @workbook = @excel.Workbooks.Open(RobustExcelOle::absolute_path(file),{ 'ReadOnly' => @options[:read_only] })
112
- rescue WIN32OLERuntimeError
113
- raise ExcelUserCanceled, "open: canceled by user"
114
- end
115
- end
116
- ensure
117
- if @options[:if_unsaved] == :alert then
118
- @excel.DisplayAlerts = old_displayalerts # :nodoc:
119
- end
120
- end
121
- if block
203
+ end
204
+
205
+ def open_workbook
206
+ #p "open_workbook:"
207
+ #p "@file:#{@file}"
208
+ if ((not @workbook) || (@options[:if_unsaved] == :alert) || @options[:if_obstructed]) then
122
209
  begin
123
- yield self
124
- ensure
125
- close
210
+ filename = RobustExcelOle::absolute_path(@file)
211
+ workbooks = @excel.Workbooks
212
+ workbooks.Open(filename,{ 'ReadOnly' => @options[:read_only] })
213
+ # workaround for bug in Excel 2010: workbook.Open does not always return
214
+ # the workbook with given file name
215
+ @workbook = workbooks.Item(File.basename(filename))
216
+ #rescue BookStoreError => e
217
+ # raise ExcelUserCanceled, "open: canceled by user: #{e}"
218
+ rescue WIN32OLERuntimeError
219
+ raise ExcelUserCanceled, "open: canceled by user"
126
220
  end
127
221
  end
128
- @workbook
129
222
  end
130
-
223
+
131
224
  # closes the book, if it is alive
132
225
  #
133
226
  # options:
@@ -137,35 +230,92 @@ module RobustExcelOle
137
230
  # :forget -> close the book
138
231
  # :alert -> give control to excel
139
232
  def close(opts = {:if_unsaved => :raise})
140
- if ((alive?) && (not @workbook.Saved) && (not @options[:read_only])) then
233
+ if ((alive?) && (not @workbook.Saved) && (not @workbook.ReadOnly)) then
141
234
  case opts[:if_unsaved]
142
235
  when :raise
143
- raise ExcelErrorClose, "book is unsaved (#{File.basename(filename)})"
236
+ raise ExcelErrorClose, "book is unsaved (#{File.basename(self.stored_filename)})"
144
237
  when :save
145
238
  save
239
+ close_workbook
146
240
  when :forget
147
- #nothing
241
+ close_workbook
148
242
  when :alert
149
- old_displayalerts = @excel.DisplayAlerts # :nodoc:
150
- @excel.DisplayAlerts = true # :nodoc:
243
+ @excel.with_displayalerts true do
244
+ close_workbook
245
+ end
151
246
  else
152
247
  raise ExcelErrorClose, ":if_unsaved: invalid option"
153
248
  end
249
+ else
250
+ close_workbook
154
251
  end
252
+ raise ExcelUserCanceled, "close: canceled by user" if alive? && opts[:if_unsaved] == :alert && (not @workbook.Saved)
253
+ end
254
+
255
+ private
256
+
257
+ def close_workbook
258
+ @workbook.Close if alive?
259
+ @workbook = nil unless alive?
260
+ end
261
+
262
+ public
263
+
264
+ # modify a book such that its state remains unchanged.
265
+ # options:
266
+ # :visible: Make the book visible in the Excel (default: false)
267
+ # :keep_open: let the book open after modification (default: false)
268
+ # if the book is read_only and modified (unsaved), then
269
+ # only the saved version of the book is unobtrusively modified,
270
+ # not the current changed version
271
+ # returns the block result
272
+ def self.unobtrusively(file, opts = { })
273
+ options = {
274
+ :keep_open => false,
275
+ :visible => false
276
+ }.merge(opts)
277
+ book = book_store.fetch(file)
278
+ was_not_alive_or_nil = book.nil? || (not book.alive?)
279
+ was_saved = was_not_alive_or_nil ? true : book.Saved
280
+ was_readonly = was_not_alive_or_nil ? false : book.ReadOnly
281
+ old_book = book if was_readonly
282
+ old_visible = book ? book.visible : false
155
283
  begin
156
- @workbook.Close if alive?
157
- @workbook = nil unless alive?
158
- raise ExcelUserCanceled, "close: canceled by user" if alive? && opts[:if_unsaved] == :alert && (not @workbook.Saved)
284
+ book = was_not_alive_or_nil ? open(file, :if_obstructed => :new_excel) :
285
+ (was_readonly ? open(file, :force_excel => :new) : book)
286
+ book.visible = options[:visible]
287
+ yield book
159
288
  ensure
160
- if opts[:if_unsaved] == :alert then
161
- @excel.DisplayAlerts = old_displayalerts # :nodoc:
289
+ book.save if (was_not_alive_or_nil || was_saved || was_readonly) && (not book.Saved)
290
+ if was_readonly
291
+ book.close
292
+ book = old_book
162
293
  end
294
+ book.visible = old_visible
295
+ book.close if (was_not_alive_or_nil && (not opts[:keep_open]))
163
296
  end
164
- #@excel.Workbooks.Close
165
- #@excel.Quit
166
297
  end
167
298
 
168
- # returns true, if the work book is alive, false otherwise
299
+ # returns the contents of a range or cell with given name
300
+ def nvalue(name)
301
+ begin
302
+ item = self.Names.Item(name)
303
+ rescue WIN32OLERuntimeError
304
+ raise ExcelErrorNValue, "name #{name} not in #{File.basename(self.stored_filename)}"
305
+ end
306
+ begin
307
+ referstorange = item.RefersToRange
308
+ rescue WIN32OLERuntimeError
309
+ raise ExcelErrorNValue, "range error in #{File.basename(self.stored_filename)}"
310
+ end
311
+ begin
312
+ value = referstorange.Value
313
+ rescue WIN32OLERuntimeError
314
+ raise ExcelErrorNValue, "value error in #{File.basename(self.stored_filename)}"
315
+ end
316
+ end
317
+
318
+ # returns true, if the workbook reacts to methods, false otherwise
169
319
  def alive?
170
320
  begin
171
321
  @workbook.Name
@@ -177,7 +327,7 @@ module RobustExcelOle
177
327
  end
178
328
  end
179
329
 
180
- # returns the full file name of the book
330
+ # returns the full file name of the workbook
181
331
  def filename
182
332
  @workbook.Fullname.tr('\\','/') rescue nil
183
333
  end
@@ -189,9 +339,29 @@ module RobustExcelOle
189
339
  self.filename == other_book.filename
190
340
  end
191
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
192
357
 
193
- attr_reader :excel
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
194
363
 
364
+
195
365
  # saves a book.
196
366
  # returns true, if successfully saved, nil otherwise
197
367
  def save
@@ -214,35 +384,47 @@ module RobustExcelOle
214
384
  # returns true, if successfully saved, nil otherwise
215
385
  def save_as(file = nil, opts = {:if_exists => :raise} )
216
386
  raise IOError, "Not opened for writing(open with :read_only option)" if @options[:read_only]
217
- dirname, basename = File.split(file)
218
- file_format =
219
- case File.extname(basename)
220
- when '.xls' : RobustExcelOle::XlExcel8
221
- when '.xlsx': RobustExcelOle::XlOpenXMLWorkbook
222
- when '.xlsm': RobustExcelOle::XlOpenXMLWorkbookMacroEnabled
223
- end
387
+ @opts = opts
224
388
  if File.exist?(file) then
225
- case opts[:if_exists]
389
+ case @opts[:if_exists]
226
390
  when :overwrite
227
391
  begin
228
392
  File.delete(file)
229
393
  rescue Errno::EACCES
230
394
  raise ExcelErrorSave, "book is open and used in Excel"
231
395
  end
396
+ save_as_workbook(file)
232
397
  when :alert
233
- old_displayalerts = @excel.DisplayAlerts # :nodoc:
234
- @excel.DisplayAlerts = true # :nodoc:
398
+ @excel.with_displayalerts true do
399
+ save_as_workbook(file)
400
+ end
235
401
  when :raise
236
- raise ExcelErrorSave, "book already exists: #{basename}"
402
+ raise ExcelErrorSave, "book already exists: #{File.basename(file)}"
237
403
  else
238
404
  raise ExcelErrorSave, ":if_exists: invalid option"
239
405
  end
406
+ else
407
+ save_as_workbook(file)
240
408
  end
409
+ true
410
+ end
411
+
412
+ private
413
+
414
+ def save_as_workbook(file)
241
415
  begin
242
- @workbook.SaveAs(RobustExcelOle::absolute_path(File.join(dirname, basename)), file_format)
416
+ dirname, basename = File.split(file)
417
+ file_format =
418
+ case File.extname(basename)
419
+ when '.xls' : RobustExcelOle::XlExcel8
420
+ when '.xlsx': RobustExcelOle::XlOpenXMLWorkbook
421
+ when '.xlsm': RobustExcelOle::XlOpenXMLWorkbookMacroEnabled
422
+ end
423
+ @workbook.SaveAs(RobustExcelOle::absolute_path(file), file_format)
424
+ book_store.store(self)
243
425
  rescue WIN32OLERuntimeError => msg
244
426
  if msg.message =~ /SaveAs/ and msg.message =~ /Workbook/ then
245
- if opts[:if_exists] == :alert then
427
+ if @opts[:if_exists] == :alert then
246
428
  raise ExcelErrorSave, "not saved or canceled by user"
247
429
  else
248
430
  return nil
@@ -251,15 +433,11 @@ module RobustExcelOle
251
433
  else
252
434
  raise ExcelErrorSaveUnknown, "unknown WIN32OELERuntimeError:\n#{msg.message}"
253
435
  end
254
- ensure
255
- if opts[:if_exists] == :alert then
256
- @excel.DisplayAlerts = old_displayalerts # :nodoc:
257
- end
258
436
  end
259
- true
260
437
  end
261
438
 
262
-
439
+ public
440
+
263
441
  def [] sheet
264
442
  sheet += 1 if sheet.is_a? Numeric
265
443
  RobustExcelOle::Sheet.new(@workbook.Worksheets.Item(sheet))
@@ -282,33 +460,88 @@ module RobustExcelOle
282
460
  after_or_before, base_sheet = opts.to_a.first || [:after, RobustExcelOle::Sheet.new(@workbook.Worksheets.Item(@workbook.Worksheets.Count))]
283
461
  base_sheet = base_sheet.sheet
284
462
  sheet ? sheet.Copy({ after_or_before.to_s => base_sheet }) : @workbook.WorkSheets.Add({ after_or_before.to_s => base_sheet })
285
-
286
463
  new_sheet = RobustExcelOle::Sheet.new(@excel.Activesheet)
287
- new_sheet.name = new_sheet_name if new_sheet_name
464
+ begin
465
+ new_sheet.name = new_sheet_name if new_sheet_name
466
+ rescue WIN32OLERuntimeError => msg
467
+ if msg.message =~ /OLE error code:800A03EC/
468
+ raise ExcelErrorSheet, "sheet name already exists"
469
+ end
470
+ end
288
471
  new_sheet
289
472
  end
290
473
 
474
+ def self.book_store
475
+ @@bookstore ||= BookStore.new
476
+ end
477
+
478
+ def book_store
479
+ self.class.book_store
480
+ end
481
+
482
+ private
483
+
484
+ def method_missing(name, *args)
485
+ if name.to_s[0,1] =~ /[A-Z]/
486
+ begin
487
+ @workbook.send(name, *args)
488
+ rescue WIN32OLERuntimeError => msg
489
+ if msg.message =~ /unknown property or method/
490
+ raise VBAMethodMissingError, "unknown VBA property or method #{name}"
491
+ else
492
+ raise msg
493
+ end
494
+ end
495
+ else
496
+ super
497
+ end
498
+ end
499
+
291
500
  end
501
+
502
+ public
292
503
 
293
- end
504
+ class ExcelErrorNValue < WIN32OLERuntimeError # :nodoc #
505
+ end
294
506
 
295
- class ExcelUserCanceled < RuntimeError # :nodoc: #
296
- end
507
+ class ExcelUserCanceled < RuntimeError # :nodoc: #
508
+ end
297
509
 
298
- class ExcelError < RuntimeError # :nodoc: #
299
- end
510
+ class ExcelError < RuntimeError # :nodoc: #
511
+ end
300
512
 
301
- class ExcelErrorSave < ExcelError # :nodoc: #
302
- end
513
+ class ExcelErrorSave < ExcelError # :nodoc: #
514
+ end
303
515
 
304
- class ExcelErrorSaveFailed < ExcelErrorSave # :nodoc: #
305
- end
516
+ class ExcelErrorSaveFailed < ExcelErrorSave # :nodoc: #
517
+ end
306
518
 
307
- class ExcelErrorSaveUnknown < ExcelErrorSave # :nodoc: #
308
- end
519
+ class ExcelErrorSaveUnknown < ExcelErrorSave # :nodoc: #
520
+ end
521
+
522
+ class ExcelErrorOpen < ExcelError # :nodoc: #
523
+ end
524
+
525
+ class ExcelErrorClose < ExcelError # :nodoc: #
526
+ end
527
+
528
+ class ExcelErrorSheet < ExcelError # :nodoc: #
529
+ end
309
530
 
310
- class ExcelErrorOpen < ExcelError # :nodoc: #
311
- end
312
531
 
313
- class ExcelErrorClose < ExcelError # :nodoc: #
314
532
  end
533
+
534
+
535
+ __END__
536
+
537
+
538
+ class Object
539
+ def update_extracted hash, key
540
+ value = hash[param_name]
541
+ self.send("#{key}=", value) if value
542
+ end
543
+ end
544
+ @excel.visible = @options[:visible] if @options[:visible]
545
+ @excel.displayalerts = @options[:dispayalerts]
546
+ @excel.update_extracted(@options, [:visible, :dispayalerts])
547
+ @excel.options.merge(@options.extract(:visible, :dispayalerts))