robust_excel_ole 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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