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.
- data/README.rdoc +266 -71
- data/TodoList.md +33 -0
- data/examples/edit_sheets/example_adding_sheets.rb +7 -0
- data/examples/open_save_close/example_control_to_excel.rb +4 -4
- data/examples/open_save_close/example_default_excel.rb +49 -0
- data/examples/open_save_close/example_force_excel.rb +34 -0
- data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +1 -1
- data/examples/open_save_close/example_if_obstructed_forget.rb +3 -3
- data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
- data/examples/open_save_close/example_if_unsaved_forget.rb +3 -3
- 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 +69 -0
- data/examples/open_save_close/example_reuse.rb +8 -8
- data/examples/open_save_close/example_simple.rb +3 -3
- data/examples/open_save_close/example_unobtrusively.rb +28 -0
- data/examples/save_sheets/example_save_sheets.rb +2 -6
- data/lib/robust_excel_ole.rb +18 -0
- data/lib/robust_excel_ole/book.rb +356 -123
- data/lib/robust_excel_ole/book_store.rb +75 -0
- data/lib/robust_excel_ole/excel.rb +105 -53
- data/lib/robust_excel_ole/robustexcelole.sublime-project +8 -8
- data/lib/robust_excel_ole/sheet.rb +29 -1
- data/lib/robust_excel_ole/version.rb +1 -1
- data/robust_excel_ole.gemspec +3 -3
- data/spec/book_spec.rb +1031 -247
- data/spec/book_store_spec.rb +306 -0
- data/spec/data/book_with_blank.xls +0 -0
- data/spec/data/merge_cells.xls +0 -0
- data/spec/data/more_simple.xls +0 -0
- data/spec/data/simple.xls +0 -0
- data/spec/excel_spec.rb +145 -90
- data/spec/sheet_spec.rb +31 -7
- 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
|
-
|
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
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
|
35
|
-
|
36
|
-
|
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
|
-
:
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:if_unsaved
|
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
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
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 :
|
76
|
-
excel_options
|
77
|
-
@
|
78
|
-
@
|
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
|
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
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
@
|
99
|
-
@
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
-
|
124
|
-
|
125
|
-
|
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 @
|
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(
|
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
|
-
|
241
|
+
close_workbook
|
148
242
|
when :alert
|
149
|
-
|
150
|
-
|
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
|
-
|
157
|
-
|
158
|
-
|
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
|
161
|
-
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
234
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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))
|