robust_excel_ole 0.2.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.
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+ module RobustExcelOle
3
+ class Sheet
4
+ attr_reader :sheet
5
+ include Enumerable
6
+
7
+ def initialize(win32_worksheet)
8
+ @sheet = win32_worksheet
9
+ if @sheet.ProtectContents
10
+ @sheet.Unprotect
11
+ @end_row = last_row
12
+ @end_column = last_column
13
+ @sheet.Protect
14
+ else
15
+ @end_row = last_row
16
+ @end_column = last_column
17
+ end
18
+ end
19
+
20
+ def name
21
+ @sheet.Name
22
+ end
23
+
24
+ def name= (new_name)
25
+ @sheet.Name = new_name
26
+ end
27
+
28
+ def [] y, x
29
+ yx = "#{y+1}_#{x+1}"
30
+ @cells ||= { }
31
+ @cells[yx] ||= RobustExcelOle::Cell.new(@sheet.Cells.Item(y+1, x+1))
32
+ end
33
+
34
+ def []= (y, x, value)
35
+ @sheet.Cells.Item(y+1, x+1).Value = value
36
+ end
37
+
38
+ def each
39
+ each_row do |row_range|
40
+ row_range.each do |cell|
41
+ yield cell
42
+ end
43
+ end
44
+ end
45
+
46
+ def each_row(offset = 0)
47
+ offset += 1
48
+ 1.upto(@end_row) do |row|
49
+ next if row < offset
50
+ yield RobustExcelOle::Range.new(@sheet.Range(@sheet.Cells(row, 1), @sheet.Cells(row, @end_column)))
51
+ end
52
+ end
53
+
54
+ def each_row_with_index(offset = 0)
55
+ each_row(offset) do |row_range|
56
+ yield RobustExcelOle::Range.new(row_range), (row_range.row - 1 - offset)
57
+ end
58
+ end
59
+
60
+ def each_column(offset = 0)
61
+ offset += 1
62
+ 1.upto(@end_column) do |column|
63
+ next if column < offset
64
+ yield RobustExcelOle::Range.new(@sheet.Range(@sheet.Cells(1, column), @sheet.Cells(@end_row, column)))
65
+ end
66
+ end
67
+
68
+ def each_column_with_index(offset = 0)
69
+ each_column(offset) do |column_range|
70
+ yield RobustExcelOle::Range.new(column_range), (column_range.column - 1 - offset)
71
+ end
72
+ end
73
+
74
+ def row_range(row, range = nil)
75
+ range ||= 0..@end_column - 1
76
+ RobustExcelOle::Range.new(@sheet.Range(@sheet.Cells(row + 1, range.min + 1), @sheet.Cells(row + 1, range.max + 1)))
77
+ end
78
+
79
+ def col_range(col, range = nil)
80
+ range ||= 0..@end_row - 1
81
+ RobustExcelOle::Range.new(@sheet.Range(@sheet.Cells(range.min + 1, col + 1), @sheet.Cells(range.max + 1, col + 1)))
82
+ end
83
+
84
+ def method_missing(id, *args)
85
+ @sheet.send(id, *args)
86
+ end
87
+
88
+ private
89
+ def last_row
90
+ special_last_row = @sheet.UsedRange.SpecialCells(RobustExcelOle::XlLastCell).Row
91
+ used_last_row = @sheet.UsedRange.Rows.Count
92
+
93
+ special_last_row >= used_last_row ? special_last_row : used_last_row
94
+ end
95
+
96
+ def last_column
97
+ special_last_column = @sheet.UsedRange.SpecialCells(RobustExcelOle::XlLastCell).Column
98
+ used_last_column = @sheet.UsedRange.Columns.Count
99
+
100
+ special_last_column >= used_last_column ? special_last_column : used_last_column
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ module RobustExcelOle
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,3 @@
1
+ module RobustExcelOle
2
+ VERSION = "0.2.0"
3
+ end
@@ -0,0 +1,35 @@
1
+ # -*- coding: utf-8 -*-
2
+ require "rspec"
3
+ require 'tmpdir'
4
+ require "fileutils"
5
+ require File.join(File.dirname(__FILE__), '../lib/robust_excel_ole')
6
+
7
+ module RobustExcelOle::SpecHelpers
8
+ def create_tmpdir
9
+ tmpdir = Dir.mktmpdir
10
+ FileUtils.cp_r(File.join(File.dirname(__FILE__), 'data'), tmpdir)
11
+ tmpdir + '/data'
12
+ end
13
+
14
+ def rm_tmp(tmpdir)
15
+ FileUtils.remove_entry_secure(File.dirname(tmpdir))
16
+ end
17
+
18
+ # This method is almost copy of wycats's implementation.
19
+ # http://pochi.hatenablog.jp/entries/2010/03/24
20
+ def capture(stream)
21
+ begin
22
+ stream = stream.to_s
23
+ eval "$#{stream} = StringIO.new"
24
+ yield
25
+ result = eval("$#{stream}").string
26
+ ensure
27
+ eval("$#{stream} = #{stream.upcase}")
28
+ end
29
+ result
30
+ end
31
+ end
32
+
33
+ RSpec.configure do |config|
34
+ config.include RobustExcelOle::SpecHelpers
35
+ end
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8; mode: ruby -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "robust_excel_ole/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "robust_excel_ole"
7
+ s.version = RobustExcelOle::VERSION
8
+ s.authors = ["traths"]
9
+ s.email = ["traths@cs.uni-potsdam.de"]
10
+ s.homepage = "https://github.com/Thomas008/robust_excel_ole"
11
+ s.summary = "RobustExcelOle is a wrapper library that specializes in the operation of Excel win32ole."
12
+ s.description = "RobustExcelOle is to wrap the win32ole, and easy to use Excel operations with ruby. Detailed description please see the README."
13
+
14
+ s.rubyforge_project = "robust_excel_ole"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.rdoc_options += [
18
+ '--main', 'README.rdoc',
19
+ '--charset', 'utf-8'
20
+ ]
21
+ s.extra_rdoc_files = ['README.rdoc', 'LICENSE']
22
+
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ s.add_development_dependency "rake", '>= 0.9.2'
27
+ 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
+ end
@@ -0,0 +1,29 @@
1
+ #'require 'lib/robust_excel_ole'
2
+ require File.join(File.dirname(__FILE__), './lib/robust_excel_ole')
3
+ book = RobustExcelOle::Book.open('./map1.xls', :read_only => false)
4
+ sheet = book[0]
5
+ cell = sheet[0,0]
6
+ puts "cell: #{cell}"
7
+ i = 0
8
+ sheet.each do |cell|
9
+ i = i + 1
10
+ puts "#{i}. Zelle: #{cell} Wert: #{cell.value}"
11
+ end
12
+ i = 0
13
+ sheet.each_row do |row|
14
+ i = i + 1
15
+ puts "#{i}. Reihe: #{row}"
16
+ end
17
+ i = 0
18
+ sheet.each_column do |column|
19
+ i = i + 1
20
+ puts "#{i}. Spalte: #{column}"
21
+ end
22
+ a = column_range[1]
23
+ #row = row_range[0]
24
+ #puts "row: #{r}"
25
+ book.save('./map2.xls', :if_exists => :overwrite)
26
+ book.save('./map2.xls', :if_exists => :excel)
27
+ book.save './map2.xls'
28
+ book.save
29
+ book.close
data/spec/book_spec.rb ADDED
@@ -0,0 +1,867 @@
1
+
2
+ # -*- coding: utf-8 -*-
3
+
4
+ require File.join(File.dirname(__FILE__), './spec_helper')
5
+
6
+
7
+ $VERBOSE = nil
8
+
9
+ describe RobustExcelOle::Book do
10
+
11
+ before(:all) do
12
+ excel_app = RobustExcelOle::ExcelApp.new(:reuse => true)
13
+ open_books = excel_app == nil ? 0 : excel_app.Workbooks.Count
14
+ puts "*** open books *** : #{open_books}" if open_books > 0
15
+ RobustExcelOle::ExcelApp.close_all
16
+ end
17
+
18
+
19
+ before do
20
+ @dir = create_tmpdir
21
+ @simple_file = @dir + '/simple.xls'
22
+ @simple_save_file = @dir + '/simple_save_file.xls'
23
+ end
24
+
25
+ after do
26
+ #RobustExcelOle::ExcelApp.close_all
27
+ rm_tmp(@dir)
28
+ end
29
+
30
+
31
+ context "class methods" do
32
+ context "create file" do
33
+ it "simple file with default" do
34
+ expect {
35
+ @book = RobustExcelOle::Book.new(@simple_file)
36
+ }.to_not raise_error
37
+ @book.should be_a RobustExcelOle::Book
38
+ @book.close
39
+ end
40
+ end
41
+ end
42
+
43
+ describe "open" do
44
+
45
+ context "with non-existing file" do
46
+ it "should raise an exception" do
47
+ File.delete @simple_save_file rescue nil
48
+ expect {
49
+ RobustExcelOle::Book.open(@simple_save_file)
50
+ }.to raise_error(ExcelErrorOpen, "file #{@simple_save_file} not found")
51
+ end
52
+ end
53
+
54
+ context "with standard options" do
55
+ before do
56
+ @book = RobustExcelOle::Book.open(@simple_file)
57
+ end
58
+
59
+ after do
60
+ @book.close
61
+ end
62
+
63
+ it "should say that it lives" do
64
+ @book.should be_alive
65
+ end
66
+ end
67
+
68
+ context "with excel_app" do
69
+ before do
70
+ @new_book = RobustExcelOle::Book.open(@simple_file)
71
+ end
72
+ after do
73
+ @new_book.close
74
+ end
75
+ it "should provide the excel application of the book" do
76
+ excel_app = @new_book.excel_app
77
+ excel_app.class.should == RobustExcelOle::ExcelApp
78
+ excel_app.should be_a RobustExcelOle::ExcelApp
79
+ end
80
+ end
81
+
82
+ context "with :read_only" do
83
+ it "should be able to save, if :read_only => false" do
84
+ book = RobustExcelOle::Book.open(@simple_file, :read_only => false)
85
+ book.should be_a RobustExcelOle::Book
86
+ expect {
87
+ book.save_as(@simple_save_file, :if_exists => :overwrite)
88
+ }.to_not raise_error
89
+ book.close
90
+ end
91
+
92
+ it "should be able to save, if :read_only is set to default value" do
93
+ book = RobustExcelOle::Book.open(@simple_file)
94
+ book.should be_a RobustExcelOle::Book
95
+ expect {
96
+ book.save_as(@simple_save_file, :if_exists => :overwrite)
97
+ }.to_not raise_error
98
+ book.close
99
+ end
100
+
101
+ it "should raise an error, if :read_only => true" do
102
+ book = RobustExcelOle::Book.open(@simple_file, :read_only => true)
103
+ book.should be_a RobustExcelOle::Book
104
+ expect {
105
+ book.save_as(@simple_save_file, :if_exists => :overwrite)
106
+ }.to raise_error
107
+ book.close
108
+ end
109
+ end
110
+
111
+ context "with block" do
112
+ it 'block parameter should be instance of RobustExcelOle::Book' do
113
+ RobustExcelOle::Book.open(@simple_file) do |book|
114
+ book.should be_a RobustExcelOle::Book
115
+ end
116
+ end
117
+ end
118
+
119
+ context "with WIN32OLE#GetAbsolutePathName" do
120
+ it "'~' should be HOME directory" do
121
+ path = '~/Abrakadabra.xlsx'
122
+ expected_path = Regexp.new(File.expand_path(path).gsub(/\//, "."))
123
+ expect {
124
+ RobustExcelOle::Book.open(path)
125
+ }.to raise_error(ExcelErrorOpen, "file #{path} not found")
126
+ end
127
+ end
128
+
129
+ context "with an already opened book" do
130
+
131
+ before do
132
+ @book = RobustExcelOle::Book.open(@simple_file)
133
+ end
134
+
135
+ after do
136
+ @book.close
137
+ end
138
+
139
+ context "with an already saved book" do
140
+ possible_options = [:read_only, :raise, :accept, :forget, nil]
141
+ possible_options.each do |options_value|
142
+ context "with :if_unsaved => #{options_value} and in the same and different path" do
143
+ before do
144
+ @new_book = RobustExcelOle::Book.open(@simple_file, :reuse=> true, :if_unsaved => options_value)
145
+ different_file = @dir + '/different_simple.xls'
146
+ @different_book = RobustExcelOle::Book.new(different_file, :reuse=> true, :if_unsaved => options_value)
147
+ end
148
+ after do
149
+ @new_book.close
150
+ @different_book.close
151
+ end
152
+ it "should open without problems " do
153
+ @new_book.should be_a RobustExcelOle::Book
154
+ @different_book.should be_a RobustExcelOle::Book
155
+ end
156
+ it "should belong to the same Excel application" do
157
+ @new_book.excel_app.should == @book.excel_app
158
+ @different_book.excel_app.should == @book.excel_app
159
+ end
160
+ end
161
+ end
162
+ end
163
+
164
+ context "with an unsaved book" do
165
+
166
+ before do
167
+ @book = RobustExcelOle::Book.open(@simple_file)
168
+ @sheet = @book[0]
169
+ @book.add_sheet(@sheet, :as => 'copyed_name')
170
+ end
171
+
172
+ after do
173
+ @book.close(:if_unsaved => :forget)
174
+ @new_book.close rescue nil
175
+ end
176
+
177
+ it "should raise an error, if :if_unsaved is :raise" do
178
+ expect {
179
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved => :raise)
180
+ }.to raise_error(ExcelErrorOpen, "book is already open but not saved (#{File.basename(@simple_file)})")
181
+ end
182
+
183
+ it "should let the book open, if :if_unsaved is :accept" do
184
+ expect {
185
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved => :accept)
186
+ }.to_not raise_error
187
+ @book.should be_alive
188
+ @new_book.should be_alive
189
+ @new_book.filename.should == @book.filename
190
+ end
191
+
192
+ it "should open book and close old book, if :if_unsaved is :forget" do
193
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved => :forget)
194
+ @book.should_not be_alive
195
+ @new_book.should be_alive
196
+ @new_book.filename.downcase.should == @simple_file.downcase
197
+ end
198
+
199
+ context "with :if_unsaved => :excel" do
200
+ before do
201
+ @key_sender = IO.popen 'ruby "' + File.join(File.dirname(__FILE__), '/helpers/key_sender.rb') + '" "Microsoft Office Excel" ' , "w"
202
+ end
203
+
204
+ after do
205
+ @key_sender.close
206
+ end
207
+
208
+ it "should open the new book and close the unsaved book, if user answers 'yes'" do
209
+ # "Yes" is the default. --> language independent
210
+ @key_sender.puts "{enter}"
211
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved => :excel)
212
+ @book.should_not be_alive
213
+ @new_book.should be_alive
214
+ @new_book.filename.downcase.should == @simple_file.downcase
215
+ end
216
+
217
+ it "should not open the new book and not close the unsaved book, if user answers 'no'" do
218
+ # "No" is right to "Yes" (the default). --> language independent
219
+ # strangely, in the "no" case, the question will sometimes be repeated three times
220
+ #@book.excel_app.Visible = true
221
+ @key_sender.puts "{right}{enter}"
222
+ @key_sender.puts "{right}{enter}"
223
+ @key_sender.puts "{right}{enter}"
224
+ expect{
225
+ RobustExcelOle::Book.open(@simple_file, :if_unsaved => :excel)
226
+ }.to raise_error(ExcelUserCanceled, "open: canceled by user")
227
+ @book.should be_alive
228
+ end
229
+ end
230
+
231
+ it "should open the book in a new excel application, if :if_unsaved is :new_app" do
232
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved => :new_app)
233
+ @book.should be_alive
234
+ @new_book.should be_alive
235
+ @new_book.filename.should == @book.filename
236
+ @new_book.excel_app.should_not == @book.excel_app
237
+ @new_book.close
238
+ end
239
+
240
+ it "should raise an error, if :if_unsaved is default" do
241
+ expect {
242
+ @new_book = RobustExcelOle::Book.open(@simple_file)
243
+ }.to raise_error(ExcelErrorOpen, "book is already open but not saved (#{File.basename(@simple_file)})")
244
+ end
245
+
246
+ it "should raise an error, if :if_unsaved is invalid option" do
247
+ expect {
248
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved => :invalid_option)
249
+ }.to raise_error(ExcelErrorOpen, ":if_unsaved: invalid option")
250
+ end
251
+
252
+ end
253
+ end
254
+
255
+ context "with an unsaved book in a different path" do
256
+
257
+ before do
258
+ simple_file_other_path = @dir + '/more_data/simple.xls'
259
+ @book = RobustExcelOle::Book.open(simple_file_other_path)
260
+ @sheet = @book[0]
261
+ @book.add_sheet(@sheet, :as => 'copyed_name')
262
+ end
263
+
264
+ after do
265
+ @book.close(:if_unsaved => :forget)
266
+ @new_book.close rescue nil
267
+ end
268
+
269
+ it "should raise an error, if :if_unsaved_other_book is :raise" do
270
+ expect {
271
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved_other_book => :raise)
272
+ }.to raise_error(ExcelErrorOpen, "blocked by an unsaved book with the same name in a different path")
273
+ end
274
+
275
+ it "should let the book open, if :if_unsaved_other_book is :save" do
276
+ expect {
277
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved_other_book => :save)
278
+ }.to_not raise_error
279
+ @book.should be_alive
280
+ @new_book.should be_alive
281
+ @new_book.filename.should == @book.filename
282
+ end
283
+
284
+ it "should close the other book and open the new book, if :if_unsaved_other_book is :forget" do
285
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved_other_book => :forget)
286
+ @book.should_not be_alive
287
+ @new_book.should be_alive
288
+ @new_book.filename.downcase.should == @simple_file.downcase
289
+ end
290
+
291
+ it "should open the book in a new excel application, if :if_unsaved_other_book is :new_app" do
292
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved_other_book => :new_app)
293
+ @book.should be_alive
294
+ @new_book.should be_alive
295
+ @new_book.filename.should_not == @book.filename
296
+ @new_book.excel_app.should_not == @book.excel_app
297
+ @new_book.close
298
+ end
299
+
300
+ it "should raise an error, if :if_unsaved_other_book is default" do
301
+ expect {
302
+ @new_book = RobustExcelOle::Book.open(@simple_file)
303
+ }.to raise_error(ExcelErrorOpen, "blocked by an unsaved book with the same name in a different path")
304
+ end
305
+
306
+ it "should raise an error, if :if_unsaved_other_book is invalid option" do
307
+ expect {
308
+ @new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved_other_book => :invalid_option)
309
+ }.to raise_error(ExcelErrorOpen, ":if_unsaved_other_book: invalid option")
310
+ end
311
+
312
+ end
313
+ end
314
+
315
+ describe "close" do
316
+
317
+ context "with saved book" do
318
+ before do
319
+ @book = RobustExcelOle::Book.open(@simple_file)
320
+ end
321
+
322
+ it "should close book" do
323
+ expect{
324
+ @book.close
325
+ }.to_not raise_error
326
+ @book.should_not be_alive
327
+ end
328
+ end
329
+
330
+ context "with unsaved book" do
331
+ before do
332
+ @book = RobustExcelOle::Book.open(@simple_file)
333
+ @sheet_count = @book.workbook.Worksheets.Count
334
+ @book.add_sheet(@sheet, :as => 'copyed_name')
335
+ @sheet = @book[0]
336
+ end
337
+
338
+ after do
339
+ @book.close(:if_unsaved => :forget) rescue nil
340
+ end
341
+
342
+ it "should raise error with option :raise" do
343
+ expect{
344
+ @book.close(:if_unsaved => :raise)
345
+ }.to raise_error(ExcelErrorClose, "book is unsaved (#{File.basename(@simple_file)})")
346
+ end
347
+
348
+ it "should close the book and leave its file untouched with option :forget" do
349
+ ole_workbook = @book.workbook
350
+ excel_app = @book.excel_app
351
+ expect {
352
+ @book.close(:if_unsaved => :forget)
353
+ }.to change {excel_app.Workbooks.Count }.by(-1)
354
+ @book.workbook.should == nil
355
+ @book.should_not be_alive
356
+ expect{
357
+ ole_workbook.Name}.to raise_error(WIN32OLERuntimeError)
358
+ new_book = RobustExcelOle::Book.open(@simple_file)
359
+ begin
360
+ new_book.workbook.Worksheets.Count.should == @sheet_count
361
+ ensure
362
+ new_book.close
363
+ end
364
+ end
365
+
366
+ it "should save the book before close with option :save" do
367
+ ole_workbook = @book.workbook
368
+ excel_app = @book.excel_app
369
+ expect {
370
+ @book.close(:if_unsaved => :save)
371
+ }.to change {excel_app.Workbooks.Count }.by(-1)
372
+ @book.workbook.should == nil
373
+ @book.should_not be_alive
374
+ expect{
375
+ ole_workbook.Name}.to raise_error(WIN32OLERuntimeError)
376
+ new_book = RobustExcelOle::Book.open(@simple_file)
377
+ begin
378
+ new_book.workbook.Worksheets.Count.should == @sheet_count + 1
379
+ ensure
380
+ new_book.close
381
+ end
382
+ end
383
+
384
+ context "with :if_unsaved => :excel" do
385
+ before do
386
+ @key_sender = IO.popen 'ruby "' + File.join(File.dirname(__FILE__), '/helpers/key_sender.rb') + '" "Microsoft Excel" ' , "w"
387
+ end
388
+
389
+ after do
390
+ @key_sender.close
391
+ end
392
+
393
+ possible_answers = [:yes, :no, :cancel]
394
+ possible_answers.each_with_index do |answer, position|
395
+ it "should" + (answer == :yes ? "" : " not") + " the unsaved book and" + (answer == :cancel ? " not" : "") + " close it" + "if user answers '#{answer}'" do
396
+ # "Yes" is the default. "No" is right of "Yes", "Cancel" is right of "No" --> language independent
397
+ @key_sender.puts "{right}" * position + "{enter}"
398
+ ole_workbook = @book.workbook
399
+ excel_app = @book.excel_app
400
+ displayalert_value = @book.excel_app.DisplayAlerts
401
+ if answer == :cancel then
402
+ expect {
403
+ @book.close(:if_unsaved => :excel)
404
+ }.to raise_error(ExcelUserCanceled, "close: canceled by user")
405
+ @book.workbook.Saved.should be_false
406
+ @book.workbook.should_not == nil
407
+ @book.should be_alive
408
+ else
409
+ expect {
410
+ @book.close(:if_unsaved => :excel)
411
+ }.to change {@book.excel_app.Workbooks.Count }.by(-1)
412
+ @book.workbook.should == nil
413
+ @book.should_not be_alive
414
+ expect{ole_workbook.Name}.to raise_error(WIN32OLERuntimeError)
415
+ end
416
+ new_book = RobustExcelOle::Book.open(@simple_file, :if_unsaved => :forget)
417
+ begin
418
+ new_book.workbook.Worksheets.Count.should == @sheet_count + (answer==:yes ? 1 : 0)
419
+ new_book.excel_app.DisplayAlerts.should == displayalert_value
420
+ ensure
421
+ new_book.close
422
+ end
423
+ end
424
+ end
425
+ end
426
+
427
+ it "should raise error for default" do
428
+ expect{
429
+ @book.close
430
+ }.to raise_error(ExcelErrorClose, "book is unsaved (#{File.basename(@simple_file)})")
431
+ end
432
+
433
+ it "should raise error for invalid option" do
434
+ expect{
435
+ @book.close(:if_unsaved => :invalid)
436
+ }.to raise_error(ExcelErrorClose, ":if_unsaved: invalid option")
437
+ end
438
+ end
439
+ end
440
+
441
+ describe "save" do
442
+
443
+ context "with simple save" do
444
+ it "should save for a file opened without :read_only" do
445
+ @book = RobustExcelOle::Book.open(@simple_file)
446
+ @book.add_sheet(@sheet, :as => 'copyed_name')
447
+ @new_sheet_count = @book.workbook.Worksheets.Count
448
+ expect {
449
+ @book.save
450
+ }.to_not raise_error
451
+ @book.workbook.Worksheets.Count.should == @new_sheet_count
452
+ @book.close
453
+ end
454
+
455
+ it "should raise error with read_only" do
456
+ @book = RobustExcelOle::Book.open(@simple_file, :read_only => true)
457
+ expect {
458
+ @book.save
459
+ }.to raise_error(IOError,
460
+ "Not opened for writing(open with :read_only option)")
461
+ @book.close
462
+ end
463
+ end
464
+
465
+ context "with open with read only" do
466
+ before do
467
+ @book = RobustExcelOle::Book.open(@simple_file, :read_only => true)
468
+ end
469
+
470
+ after do
471
+ @book.close
472
+ end
473
+
474
+ it {
475
+ expect {
476
+ @book.save_as(@simple_file)
477
+ }.to raise_error(IOError,
478
+ "Not opened for writing(open with :read_only option)")
479
+ }
480
+ end
481
+
482
+ context "with argument" do
483
+ before do
484
+ RobustExcelOle::Book.open(@simple_file) do |book|
485
+ book.save_as(@simple_save_file, :if_exists => :overwrite)
486
+ end
487
+ end
488
+
489
+ it "should save to 'simple_save_file.xlsx'" do
490
+ File.exist?(@simple_save_file).should be_true
491
+ end
492
+ end
493
+
494
+ context "with different extensions" do
495
+ before do
496
+ @book = RobustExcelOle::Book.open(@simple_file)
497
+ end
498
+
499
+ after do
500
+ @book.close
501
+ end
502
+
503
+ possible_extensions = ['xls', 'xlsm', 'xlsx']
504
+ possible_extensions.each do |extensions_value|
505
+ it "should save to 'simple_save_file.#{extensions_value}'" do
506
+ simple_save_file = @dir + '/simple_save_file.' + extensions_value
507
+ File.delete simple_save_file rescue nil
508
+ @book.save_as(simple_save_file, :if_exists => :overwrite)
509
+ File.exist?(simple_save_file).should be_true
510
+ new_book = RobustExcelOle::Book.open(simple_save_file)
511
+ new_book.should be_a RobustExcelOle::Book
512
+ new_book.close
513
+ end
514
+ end
515
+ end
516
+
517
+ # options :overwrite, :raise, :excel, no option, invalid option
518
+ possible_displayalerts = [true, false]
519
+ possible_displayalerts.each do |displayalert_value|
520
+ context "with displayalerts=#{displayalert_value}" do
521
+ before do
522
+ @book = RobustExcelOle::Book.open(@simple_file, :displayalerts => displayalert_value)
523
+ end
524
+
525
+ after do
526
+ @book.close
527
+ end
528
+
529
+ it "should save to simple_save_file.xls with :if_exists => :overwrite" do
530
+ File.delete @simple_save_file rescue nil
531
+ File.open(@simple_save_file,"w") do | file |
532
+ file.puts "garbage"
533
+ end
534
+ @book.save_as(@simple_save_file, :if_exists => :overwrite)
535
+ File.exist?(@simple_save_file).should be_true
536
+ new_book = RobustExcelOle::Book.open(@simple_save_file)
537
+ new_book.should be_a RobustExcelOle::Book
538
+ new_book.close
539
+ end
540
+
541
+ it "should save to 'simple_save_file.xls' with :if_exists => :raise" do
542
+ dirname, basename = File.split(@simple_save_file)
543
+ File.delete @simple_save_file rescue nil
544
+ File.open(@simple_save_file,"w") do | file |
545
+ file.puts "garbage"
546
+ end
547
+ File.exist?(@simple_save_file).should be_true
548
+ booklength = File.size?(@simple_save_file)
549
+ expect {
550
+ @book.save_as(@simple_save_file, :if_exists => :raise)
551
+ }.to raise_error(ExcelErrorSave, 'book already exists: ' + basename)
552
+ File.exist?(@simple_save_file).should be_true
553
+ (File.size?(@simple_save_file) == booklength).should be_true
554
+ end
555
+
556
+ context "with :if_exists => :excel" do
557
+ before do
558
+ File.delete @simple_save_file rescue nil
559
+ File.open(@simple_save_file,"w") do | file |
560
+ file.puts "garbage"
561
+ end
562
+ @garbage_length = File.size?(@simple_save_file)
563
+ @key_sender = IO.popen 'ruby "' + File.join(File.dirname(__FILE__), '/helpers/key_sender.rb') + '" "Microsoft Excel" ' , "w"
564
+ end
565
+
566
+ after do
567
+ @key_sender.close
568
+ end
569
+
570
+ it "should save if user answers 'yes'" do
571
+ # "Yes" is to the left of "No", which is the default. --> language independent
572
+ @key_sender.puts "{left}{enter}" #, :initial_wait => 0.2, :if_target_missing=>"Excel window not found")
573
+ @book.save_as(@simple_save_file, :if_exists => :excel)
574
+ File.exist?(@simple_save_file).should be_true
575
+ File.size?(@simple_save_file).should > @garbage_length
576
+ new_book = RobustExcelOle::Book.open(@simple_save_file)
577
+ new_book.should be_a RobustExcelOle::Book
578
+ @book.excel_app.DisplayAlerts.should == displayalert_value
579
+ new_book.close
580
+ end
581
+
582
+ it "should not save if user answers 'no'" do
583
+ # Just give the "Enter" key, because "No" is the default. --> language independent
584
+ # strangely, in the "no" case, the question will sometimes be repeated three times
585
+ @key_sender.puts "{enter}"
586
+ @key_sender.puts "{enter}"
587
+ @key_sender.puts "{enter}"
588
+ #@key_sender.puts "%{n}" #, :initial_wait => 0.2, :if_target_missing=>"Excel window not found")
589
+ @book.save_as(@simple_save_file, :if_exists => :excel)
590
+ File.exist?(@simple_save_file).should be_true
591
+ File.size?(@simple_save_file).should == @garbage_length
592
+ end
593
+
594
+ it "should not save and raise an exception if user answers 'cancel'" do
595
+ # Just give the "Enter" key, because "No" is the default. --> language independent
596
+ # strangely, in the "no" case, the question will sometimes be repeated three times
597
+ @key_sender.puts "{right}{enter}"
598
+ @key_sender.puts "{right}{enter}"
599
+ @key_sender.puts "{right}{enter}"
600
+ expect{
601
+ @book.save_as(@simple_save_file, :if_exists => :excel)
602
+ }.to raise_error(ExcelUserCanceled, "save: canceled by user")
603
+ File.exist?(@simple_save_file).should be_true
604
+ File.size?(@simple_save_file).should == @garbage_length
605
+ new_book = RobustExcelOle::Book.open(@simple_save_file)
606
+ new_book.should be_a RobustExcelOle::Book
607
+ @book.excel_app.DisplayAlerts.should == displayalert_value
608
+ new_book.close
609
+ end
610
+
611
+
612
+ it "should report save errors and leave DisplayAlerts unchanged" do
613
+ #@key_sender.puts "{left}{enter}" #, :initial_wait => 0.2, :if_target_missing=>"Excel window not found")
614
+ @book.workbook.Close
615
+ expect{
616
+ @book.save_as(@simple_save_file, :if_exists => :excel)
617
+ }.to raise_error(ExcelErrorSaveUnknown)
618
+ File.exist?(@simple_save_file).should be_true
619
+ File.size?(@simple_save_file).should == @garbage_length
620
+ @book.excel_app.DisplayAlerts.should == displayalert_value
621
+ end
622
+
623
+
624
+ end
625
+
626
+ it "should save to 'simple_save_file.xls' with :if_exists => nil" do
627
+ dirname, basename = File.split(@simple_save_file)
628
+ File.delete @simple_save_file rescue nil
629
+ File.open(@simple_save_file,"w") do | file |
630
+ file.puts "garbage"
631
+ end
632
+ File.exist?(@simple_save_file).should be_true
633
+ booklength = File.size?(@simple_save_file)
634
+ expect {
635
+ @book.save_as(@simple_save_file)
636
+ }.to raise_error(ExcelErrorSave, 'book already exists: ' + basename)
637
+ File.exist?(@simple_save_file).should be_true
638
+ (File.size?(@simple_save_file) == booklength).should be_true
639
+ end
640
+
641
+ it "should save to 'simple_save_file.xls' with :if_exists => :invalid_option" do
642
+ File.delete @simple_save_file rescue nil
643
+ @book.save_as(@simple_save_file)
644
+ expect {
645
+ @book.save_as(@simple_save_file, :if_exists => :invalid_option)
646
+ }.to raise_error(ExcelErrorSave, ':if_exists: invalid option')
647
+ end
648
+ end
649
+ end
650
+ end
651
+
652
+ describe "== , alive?, filename, absolute_path" do
653
+
654
+ context "with absolute_path" do
655
+ before do
656
+ @book = RobustExcelOle::Book.open(@simple_file)
657
+ end
658
+
659
+ after do
660
+ @book.close
661
+ end
662
+
663
+ it "should return right absoute path name" do
664
+ @book.absolute_path(@simple_file).gsub("\\","/").should == @book.filename
665
+ end
666
+ end
667
+
668
+ context "with alive?" do
669
+
670
+ before do
671
+ @book = RobustExcelOle::Book.open(@simple_file)
672
+ end
673
+
674
+ after do
675
+ @book.close
676
+ end
677
+
678
+ it "should return true, if book is alive" do
679
+ @book.should be_alive
680
+ end
681
+
682
+ it "should return false, if book is dead" do
683
+ @book.close
684
+ @book.should_not be_alive
685
+ end
686
+
687
+ end
688
+
689
+ context "with filename" do
690
+
691
+ before do
692
+ @book = RobustExcelOle::Book.open(@simple_file)
693
+ end
694
+
695
+ after do
696
+ @book.close
697
+ end
698
+
699
+ it "should return full file name" do
700
+ @book.filename.should == @simple_file
701
+ end
702
+
703
+ it "should return nil for dead book" do
704
+ @book.close
705
+ @book.filename.should == nil
706
+ end
707
+
708
+ end
709
+
710
+ context "with ==" do
711
+
712
+ before do
713
+ @book = RobustExcelOle::Book.open(@simple_file)
714
+ end
715
+
716
+ after do
717
+ @book.close
718
+ @new_book.close rescue nil
719
+ end
720
+
721
+ it "should be true with two identical books" do
722
+ @new_book = RobustExcelOle::Book.open(@simple_file)
723
+ @new_book.should == @book
724
+ end
725
+
726
+ it "should be false with two different books" do
727
+ different_file = @dir + '/different_simple.xls'
728
+ @new_book = RobustExcelOle::Book.new(different_file)
729
+ @new_book.should_not == @book
730
+ end
731
+
732
+ it "should be false with same book names but different paths" do
733
+ simple_file_other_path = @dir + '/more_data/simple.xls'
734
+ @new_book = RobustExcelOle::Book.new(simple_file_other_path, :reuse => false)
735
+ @new_book.should_not == @book
736
+ end
737
+
738
+ it "should be false with same book names but different excel apps" do
739
+ @new_book = RobustExcelOle::Book.new(@simple_file, :reuse => false)
740
+ @new_book.should_not == @book
741
+ end
742
+
743
+ it "should be false with non-Books" do
744
+ @book.should_not == "hallo"
745
+ @book.should_not == 7
746
+ @book.should_not == nil
747
+ end
748
+ end
749
+
750
+ end
751
+
752
+ describe "#add_sheet" do
753
+ before do
754
+ @book = RobustExcelOle::Book.open(@simple_file)
755
+ @sheet = @book[0]
756
+ end
757
+
758
+ after do
759
+ @book.close(:if_unsaved => :forget)
760
+ end
761
+
762
+ context "only first argument" do
763
+ it "should add worksheet" do
764
+ expect { @book.add_sheet @sheet }.to change{ @book.workbook.Worksheets.Count }.from(3).to(4)
765
+ end
766
+
767
+ it "should return copyed sheet" do
768
+ sheet = @book.add_sheet @sheet
769
+ copyed_sheet = @book.workbook.Worksheets.Item(@book.workbook.Worksheets.Count)
770
+ sheet.name.should eq copyed_sheet.name
771
+ end
772
+ end
773
+
774
+ context "with first argument" do
775
+ context "with second argument is {:as => 'copyed_name'}" do
776
+ it "copyed sheet name should be 'copyed_name'" do
777
+ @book.add_sheet(@sheet, :as => 'copyed_name').name.should eq 'copyed_name'
778
+ end
779
+ end
780
+
781
+ context "with second argument is {:before => @sheet}" do
782
+ it "should add the first sheet" do
783
+ @book.add_sheet(@sheet, :before => @sheet).name.should eq @book[0].name
784
+ end
785
+ end
786
+
787
+ context "with second argument is {:after => @sheet}" do
788
+ it "should add the first sheet" do
789
+ @book.add_sheet(@sheet, :after => @sheet).name.should eq @book[1].name
790
+ end
791
+ end
792
+
793
+ context "with second argument is {:before => @book[2], :after => @sheet}" do
794
+ it "should arguments in the first is given priority" do
795
+ @book.add_sheet(@sheet, :before => @book[2], :after => @sheet).name.should eq @book[2].name
796
+ end
797
+ end
798
+
799
+ end
800
+
801
+ context "without first argument" do
802
+ context "second argument is {:as => 'new sheet'}" do
803
+ it "should return new sheet" do
804
+ @book.add_sheet(:as => 'new sheet').name.should eq 'new sheet'
805
+ end
806
+ end
807
+
808
+ context "second argument is {:before => @sheet}" do
809
+ it "should add the first sheet" do
810
+ @book.add_sheet(:before => @sheet).name.should eq @book[0].name
811
+ end
812
+ end
813
+
814
+ context "second argument is {:after => @sheet}" do
815
+ it "should add the second sheet" do
816
+ @book.add_sheet(:after => @sheet).name.should eq @book[1].name
817
+ end
818
+ end
819
+
820
+ end
821
+
822
+ context "without argument" do
823
+ it "should add empty sheet" do
824
+ expect { @book.add_sheet }.to change{ @book.workbook.Worksheets.Count }.from(3).to(4)
825
+ end
826
+
827
+ it "should return copyed sheet" do
828
+ sheet = @book.add_sheet
829
+ copyed_sheet = @book.workbook.Worksheets.Item(@book.workbook.Worksheets.Count)
830
+ sheet.name.should eq copyed_sheet.name
831
+ end
832
+ end
833
+ end
834
+
835
+ describe 'access sheet' do
836
+ before do
837
+ @book = RobustExcelOle::Book.open(@simple_file)
838
+ end
839
+
840
+ after do
841
+ @book.close
842
+ end
843
+
844
+ it 'with sheet name' do
845
+ @book['Sheet1'].should be_kind_of RobustExcelOle::Sheet
846
+ end
847
+
848
+ it 'with integer' do
849
+ @book[0].should be_kind_of RobustExcelOle::Sheet
850
+ end
851
+
852
+ it 'with block' do
853
+ @book.each do |sheet|
854
+ sheet.should be_kind_of RobustExcelOle::Sheet
855
+ end
856
+ end
857
+
858
+ context 'open with block' do
859
+ it {
860
+ RobustExcelOle::Book.open(@simple_file) do |book|
861
+ book['Sheet1'].should be_a RobustExcelOle::Sheet
862
+ end
863
+ }
864
+ end
865
+ end
866
+
867
+ end