robust_excel_ole 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. data/README.rdoc +266 -71
  2. data/TodoList.md +33 -0
  3. data/examples/edit_sheets/example_adding_sheets.rb +7 -0
  4. data/examples/open_save_close/example_control_to_excel.rb +4 -4
  5. data/examples/open_save_close/example_default_excel.rb +49 -0
  6. data/examples/open_save_close/example_force_excel.rb +34 -0
  7. data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +1 -1
  8. data/examples/open_save_close/example_if_obstructed_forget.rb +3 -3
  9. data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
  10. data/examples/open_save_close/example_if_unsaved_forget.rb +3 -3
  11. data/examples/open_save_close/example_if_unsaved_forget_more.rb +3 -3
  12. data/examples/open_save_close/example_read_only.rb +1 -1
  13. data/examples/open_save_close/example_rename_cells.rb +69 -0
  14. data/examples/open_save_close/example_reuse.rb +8 -8
  15. data/examples/open_save_close/example_simple.rb +3 -3
  16. data/examples/open_save_close/example_unobtrusively.rb +28 -0
  17. data/examples/save_sheets/example_save_sheets.rb +2 -6
  18. data/lib/robust_excel_ole.rb +18 -0
  19. data/lib/robust_excel_ole/book.rb +356 -123
  20. data/lib/robust_excel_ole/book_store.rb +75 -0
  21. data/lib/robust_excel_ole/excel.rb +105 -53
  22. data/lib/robust_excel_ole/robustexcelole.sublime-project +8 -8
  23. data/lib/robust_excel_ole/sheet.rb +29 -1
  24. data/lib/robust_excel_ole/version.rb +1 -1
  25. data/robust_excel_ole.gemspec +3 -3
  26. data/spec/book_spec.rb +1031 -247
  27. data/spec/book_store_spec.rb +306 -0
  28. data/spec/data/book_with_blank.xls +0 -0
  29. data/spec/data/merge_cells.xls +0 -0
  30. data/spec/data/more_simple.xls +0 -0
  31. data/spec/data/simple.xls +0 -0
  32. data/spec/excel_spec.rb +145 -90
  33. data/spec/sheet_spec.rb +31 -7
  34. metadata +15 -7
@@ -0,0 +1,306 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require File.join(File.dirname(__FILE__), './spec_helper')
4
+
5
+ RSpec.configure do |config|
6
+
7
+ config.mock_with :rspec do |mocks|
8
+ mocks.syntax = :should
9
+ end
10
+ end
11
+
12
+
13
+ $VERBOSE = nil
14
+
15
+ include RobustExcelOle
16
+ module RobustExcelOle
17
+ class MockBookstore
18
+ def fetch(filename, options = { })
19
+ nil
20
+ end
21
+ def store(book)
22
+ end
23
+ def print
24
+ puts "MockBookstore is always empty"
25
+ end
26
+ end
27
+ end
28
+
29
+
30
+ $mock_bookstore = MockBookstore.new
31
+
32
+ class Book
33
+ @@bookstore = $mock_bookstore
34
+ end
35
+
36
+
37
+ describe BookStore do
38
+
39
+ before(:all) do
40
+ excel = Excel.new(:reuse => true)
41
+ open_books = excel == nil ? 0 : excel.Workbooks.Count
42
+ puts "*** open books *** : #{open_books}" if open_books > 0
43
+ Excel.close_all
44
+ end
45
+
46
+ before do
47
+ @bookstore = BookStore.new
48
+ @dir = create_tmpdir
49
+ @simple_file = @dir + '/simple.xls'
50
+ @simple_save_file = @dir + '/simple_save.xls'
51
+ @different_file = @dir + '/different_simple.xls'
52
+ @simple_file_other_path = @dir + '/more_data/simple.xls'
53
+ end
54
+
55
+ after do
56
+ Excel.close_all
57
+ rm_tmp(@dir)
58
+ end
59
+
60
+ describe "create bookstore" do
61
+ context "with standard" do
62
+ it "should create book store" do
63
+ expect {
64
+ @book_store = BookStore.new
65
+ }.to_not raise_error
66
+ @book_store.should be_a BookStore
67
+ end
68
+ end
69
+ end
70
+
71
+ describe "Mock-Test" do
72
+ it "should never store any book" do
73
+ b1 = Book.open(@simple_file)
74
+ b2 = Book.open(@simple_file)
75
+ b2.object_id.should_not == b1.object_id
76
+ end
77
+ end
78
+
79
+
80
+ describe "fetch" do
81
+
82
+ context "with one open book" do
83
+
84
+ before do
85
+ @book = Book.open(@simple_file)
86
+ end
87
+
88
+ after do
89
+ @book.close
90
+ end
91
+
92
+ it "should do simple store and fetch" do
93
+ @bookstore.store(@book)
94
+ new_book = @bookstore.fetch(@simple_file)
95
+ new_book.should be_a Book
96
+ new_book.should be_alive
97
+ new_book.should == @book
98
+ new_book.close
99
+ end
100
+
101
+ it "should fetch one book several times" do
102
+ @bookstore.store(@book)
103
+ book1 = @bookstore.fetch(@simple_file)
104
+ book2 = @bookstore.fetch(@simple_file)
105
+ expect(book1).to be_a Book
106
+ book1.should be_alive
107
+ book1.should == @book
108
+ book2.should be_a Book
109
+ book2.should be_alive
110
+ book2.should == @book
111
+ book1.should == book2
112
+ book1.close
113
+ book2.close
114
+ end
115
+
116
+ it "should fetch nothing without stóring before" do
117
+ new_book = @bookstore.fetch(@simple_file)
118
+ new_book.should == nil
119
+ end
120
+
121
+ it "should fetch nothing when fetching a different book" do
122
+ @bookstore.store(@book)
123
+ new_book = @bookstore.fetch(@different_file)
124
+ new_book.should == nil
125
+ end
126
+
127
+ it "should fetch nothing when fetching a non-existing book" do
128
+ @bookstore.store(@book)
129
+ new_book = @bookstore.fetch("foo")
130
+ new_book.should == nil
131
+ end
132
+
133
+ end
134
+
135
+ context "with several books" do
136
+
137
+ before do
138
+ @book = Book.open(@simple_file)
139
+ @bookstore.store(@book)
140
+ end
141
+
142
+ after do
143
+ @book.close
144
+ @book2.close(:if_unsaved => :forget)
145
+ end
146
+
147
+ it "should store and open two different books" do
148
+ @book2 = Book.open(@different_file)
149
+ @bookstore.store(@book2)
150
+ new_book = @bookstore.fetch(@simple_file)
151
+ new_book2 = @bookstore.fetch(@different_file)
152
+ new_book.should be_a Book
153
+ new_book.should be_alive
154
+ new_book.should == @book
155
+ new_book2.should be_a Book
156
+ new_book2.should be_alive
157
+ new_book2.should == @book2
158
+ new_book.should_not == new_book2
159
+ new_book.close
160
+ new_book2.close
161
+ end
162
+
163
+ it "should fetch the first, writable book" do
164
+ @book2 = Book.open(@simple_file, :force_excel => :new)
165
+ @bookstore.store(@book2)
166
+ @book.ReadOnly.should be_false
167
+ @book2.ReadOnly.should be_true
168
+ new_book = @bookstore.fetch(@simple_file)
169
+ new_book.should == @book
170
+ new_book.should_not == @book2
171
+ new_book.close
172
+ end
173
+
174
+ it "should fetch the writable book even if the readonly book has unsaved changes" do
175
+ @book2 = Book.open(@simple_file, :force_excel => :new)
176
+ sheet = @book2[0]
177
+ @bookstore.store(@book2)
178
+ sheet[0,0] = sheet[0,0].value == "simple" ? "complex" : "simple"
179
+ @book.ReadOnly.should be_false
180
+ @book2.ReadOnly.should be_true
181
+ @book2.Saved. should be_false
182
+ new_book = @bookstore.fetch(@simple_file)
183
+ new_book.should == @book
184
+ new_book.should_not == @book2
185
+ new_book.close
186
+ end
187
+
188
+ end
189
+
190
+ context "with readonly book" do
191
+
192
+ before do
193
+ @book = Book.open(@simple_file, :read_only => true)
194
+ @bookstore.store(@book)
195
+ end
196
+
197
+ after do
198
+ @book.close
199
+ @book2.close(:if_unsaved => :forget)
200
+ end
201
+
202
+ it "should fetch the second, writable book" do
203
+ @book2 = Book.open(@simple_file, :force_excel => :new)
204
+ @bookstore.store(@book2)
205
+ @book.ReadOnly.should be_true
206
+ @book2.ReadOnly.should be_false
207
+ new_book = @bookstore.fetch(@simple_file)
208
+ new_book.should == @book2
209
+ new_book.should_not == @book
210
+ new_book.close
211
+ end
212
+
213
+ it "should fetch the recent readonly book when there are only readonly books" do
214
+ @book2 = Book.open(@simple_file, :force_excel => :new, :read_only => true)
215
+ @bookstore.store(@book2)
216
+ @book.ReadOnly.should be_true
217
+ @book2.ReadOnly.should be_true
218
+ new_book = @bookstore.fetch(@simple_file)
219
+ new_book.should == @book2
220
+ new_book.should_not == @book
221
+ new_book.close
222
+ end
223
+
224
+ it "should fetch the second readonly book with unsaved changes" do
225
+ @book2 = Book.open(@simple_file, :force_excel => :new, :read_only => true)
226
+ sheet = @book2[0]
227
+ @bookstore.store(@book2)
228
+ sheet[0,0] = sheet[0,0].value == "simple" ? "complex" : "simple"
229
+ @book.ReadOnly.should be_true
230
+ @book2.ReadOnly.should be_true
231
+ @book2.Saved.should be_false
232
+ new_book = @bookstore.fetch(@simple_file)
233
+ new_book.should == @book2
234
+ new_book.should_not == @book
235
+ new_book.close
236
+ end
237
+
238
+ it "should fetch the second, writable book, if a writable, a readonly and an unsaved readonly book exist" do
239
+ @book2 = Book.open(@simple_file, :force_excel => :new)
240
+ @book3 = Book.open(@simple_file, :force_excel => :new)
241
+ @bookstore.store(@book2)
242
+ @bookstore.store(@book3)
243
+ sheet = @book3[0]
244
+ sheet[0,0] = sheet[0,0].value == "simple" ? "complex" : "simple"
245
+ @book.ReadOnly.should be_true
246
+ @book2.ReadOnly.should be_false
247
+ @book3.ReadOnly.should be_true
248
+ @book3.Saved.should be_false
249
+ new_book = @bookstore.fetch(@simple_file)
250
+ new_book.should == @book2
251
+ new_book.should_not == @book
252
+ new_book.should_not == @book3
253
+ new_book.close
254
+ end
255
+ end
256
+
257
+ context "with changing file name" do
258
+
259
+ before do
260
+ @book = Book.open(@simple_file)
261
+ @book.save_as(@simple_save_file, :if_exists => :overwrite)
262
+ @bookstore = @book.book_store
263
+ end
264
+
265
+ after do
266
+ @book.close
267
+ end
268
+
269
+ it "should return only book with correct file name" do
270
+ book1 = @bookstore.fetch(@simple_save_file)
271
+ book1.should == @book
272
+ end
273
+
274
+ it "should return only book with correct file name" do
275
+ book1 = @bookstore.fetch(@simple_file)
276
+ book1.should == nil
277
+ end
278
+ end
279
+
280
+ context "with given excel instance and fetching readonly" do
281
+
282
+ before do
283
+ @book = Book.open(@simple_file)
284
+ @bookstore.store(@book)
285
+ @book2 = Book.open(@simple_file, :force_excel => :new)
286
+ @bookstore.store(@book2)
287
+ end
288
+
289
+ after do
290
+ @book.close
291
+ end
292
+
293
+ it "should fetch the book in the given excel instance" do
294
+ @book.ReadOnly.should be_false
295
+ @book2.ReadOnly.should be_true
296
+ book_new = @bookstore.fetch(@simple_file, :excel => @book2.excel)
297
+ book_new.should be_a Book
298
+ book_new.should be_alive
299
+ book_new.should == @book2
300
+ end
301
+
302
+ end
303
+
304
+
305
+ end
306
+ end
Binary file
Binary file
Binary file
data/spec/data/simple.xls CHANGED
Binary file
data/spec/excel_spec.rb CHANGED
@@ -8,65 +8,61 @@ module RobustExcelOle
8
8
 
9
9
  describe Excel do
10
10
 
11
- context "app creation" do
12
- after do
13
- Excel.close_all
14
- end
11
+ before do
12
+ Excel.close_all
13
+ end
15
14
 
15
+ context "excel creation" do
16
+
16
17
  def creation_ok? # :nodoc: #
17
- @app.alive?.should == true
18
- @app.Visible.should == false
19
- @app.DisplayAlerts.should == false
20
- @app.Name.should == "Microsoft Excel"
18
+ @excel.alive?.should be_true
19
+ @excel.Visible.should be_false
20
+ @excel.DisplayAlerts.should be_false
21
+ @excel.Name.should == "Microsoft Excel"
21
22
  end
22
23
 
23
24
  it "should work with 'new' " do
24
- @app = Excel.new
25
+ @excel = Excel.new
25
26
  creation_ok?
26
27
  end
27
28
 
28
29
  it "should work with 'new' " do
29
- @app = Excel.new(:reuse => false)
30
+ @excel = Excel.new(:reuse => false)
30
31
  creation_ok?
31
32
  end
32
33
 
33
34
  it "should work with 'create' " do
34
- @app = Excel.create
35
+ @excel = Excel.create
35
36
  creation_ok?
36
37
  end
37
38
 
38
39
  end
39
40
 
40
- context "with existing app" do
41
+ context "with existing excel" do
41
42
 
42
43
  before do
43
- Excel.close_all
44
- @app1 = Excel.create
44
+ @excel1 = Excel.create
45
45
  end
46
46
 
47
- after do
48
- Excel.close_all
47
+ it "should create different excel" do
48
+ excel2 = Excel.create
49
+ #puts "@excel1 #{@excel1.Hwnd}"
50
+ #puts "excel2 #{excel2.Hwnd}"
51
+ excel2.Hwnd.should_not == @excel1.Hwnd
49
52
  end
50
53
 
51
- it "should create different app" do
52
- app2 = Excel.create
53
- #puts "@app1 #{@app1.Hwnd}"
54
- #puts "app2 #{app2.Hwnd}"
55
- app2.Hwnd.should_not == @app1.Hwnd
54
+ it "should reuse existing excel" do
55
+ excel2 = Excel.current
56
+ #puts "@excel1 #{@excel1.Hwnd}"
57
+ #puts "excel2 #{excel2.Hwnd}"
58
+ excel2.Hwnd.should == @excel1.Hwnd
56
59
  end
57
60
 
58
- it "should reuse existing app" do
59
- app2 = Excel.current
60
- #puts "@app1 #{@app1.Hwnd}"
61
- #puts "app2 #{app2.Hwnd}"
62
- app2.Hwnd.should == @app1.Hwnd
63
- end
64
-
65
- it "should reuse existing app with default options for 'new'" do
66
- app2 = Excel.new
67
- #puts "@app1 #{@app1.Hwnd}"
68
- #puts "app2 #{app2.Hwnd}"
69
- app2.Hwnd.should == @app1.Hwnd
61
+ it "should reuse existing excel with default options for 'new'" do
62
+ excel2 = Excel.new
63
+ #puts "@excel1 #{@excel1.Hwnd}"
64
+ #puts "excel2 #{excel2.Hwnd}"
65
+ excel2.Hwnd.should == @excel1.Hwnd
70
66
  end
71
67
 
72
68
  end
@@ -75,17 +71,17 @@ module RobustExcelOle
75
71
  def direct_excel_creation_helper # :nodoc: #
76
72
  expect { WIN32OLE.connect("Excel.Application") }.to raise_error
77
73
  sleep 0.1
78
- exl1 = WIN32OLE.new("Excel.Application")
79
- exl1.Workbooks.Add
80
- exl2 = WIN32OLE.new("Excel.Application")
81
- exl2.Workbooks.Add
74
+ excel1 = WIN32OLE.new("Excel.Application")
75
+ excel1.Workbooks.Add
76
+ excel2 = WIN32OLE.new("Excel.Application")
77
+ excel2.Workbooks.Add
82
78
  expect { WIN32OLE.connect("Excel.Application") }.to_not raise_error
83
79
  end
84
80
 
85
81
  it "simple file with default" do
86
- RobustExcelOle::Excel.close_all
82
+ Excel.close_all
87
83
  direct_excel_creation_helper
88
- RobustExcelOle::Excel.close_all
84
+ Excel.close_all
89
85
  sleep 0.1
90
86
  expect { WIN32OLE.connect("Excel.Application") }.to raise_error
91
87
  end
@@ -93,89 +89,145 @@ module RobustExcelOle
93
89
 
94
90
  describe "==" do
95
91
  before do
96
- Excel.close_all
97
- @app1 = Excel.create
98
- end
99
-
100
- after do
101
- Excel.close_all
92
+ @excel1 = Excel.create
102
93
  end
103
94
 
104
- it "should be true with two identical excel applications" do
105
- app2 = Excel.current
106
- app2.should == @app1
95
+ it "should be true with two identical excel instances" do
96
+ excel2 = Excel.current
97
+ excel2.should == @excel1
107
98
  end
108
99
 
109
- it "should be false with two different excel applications" do
110
- app2 = Excel.create
111
- app2.should_not == @app1
100
+ it "should be false with two different excel instances" do
101
+ excel2 = Excel.create
102
+ excel2.should_not == @excel1
112
103
  end
113
104
 
114
105
  it "should be false with non-Excel objects" do
115
- @app1.should_not == "hallo"
116
- @app1.should_not == 7
117
- @app1.should_not == nil
106
+ @excel1.should_not == "hallo"
107
+ @excel1.should_not == 7
108
+ @excel1.should_not == nil
118
109
  end
119
110
 
120
111
  end
121
112
 
113
+ context "with Visible and DisplayAlerts" do
122
114
 
123
- context "with :excel" do
124
-
125
- before do
126
- Excel.close_all
115
+ it "should create Excel visible" do
116
+ excel = Excel.new(:visible => true)
117
+ excel.Visible.should be_true
118
+ excel.visible.should be_true
119
+ excel.DisplayAlerts.should be_false
120
+ excel.displayalerts.should be_false
121
+ excel.visible = false
122
+ excel.Visible.should be_false
123
+ excel.visible.should be_false
124
+ end
125
+
126
+ it "should create Excel with DispayAlerts enabled" do
127
+ excel = Excel.new(:displayalerts => true)
128
+ excel.DisplayAlerts.should be_true
129
+ excel.displayalerts.should be_true
130
+ excel.Visible.should be_false
131
+ excel.visible.should be_false
132
+ excel.displayalerts = false
133
+ excel.DisplayAlerts.should be_false
134
+ excel.displayalerts.should be_false
135
+ end
136
+
137
+ it "should keep visible and displayalerts values when reusing Excel" do
138
+ excel = Excel.new(:visible => true)
139
+ excel.visible.should be_true
140
+ excel.displayalerts.should be_false
141
+ excel2 = Excel.new(:displayalerts => true)
142
+ excel2.should == excel
143
+ excel.visible.should be_true
144
+ excel.displayalerts.should be_true
145
+ end
146
+
147
+ it "should keep displayalerts and visible values when reusing Excel" do
148
+ excel = Excel.new(:displayalerts => true)
149
+ excel.visible.should be_false
150
+ excel.displayalerts.should be_true
151
+ excel2 = Excel.new(:visible => true)
152
+ excel2.should == excel
153
+ excel.visible.should be_true
154
+ excel.displayalerts.should be_true
127
155
  end
128
156
 
129
- after (:each) do
130
- Excel.close_all
131
- end
157
+ end
132
158
 
133
- it "should reuse in given excel app" do
134
- app1 = Excel.new(:reuse => false)
135
- app2 = Excel.new(:reuse => false)
136
- app3 = Excel.new(:excel => app1)
137
- app4 = Excel.new(:excel => app2)
138
- app3.should == app1
139
- app4.should == app2
159
+
160
+ context "with displayalerts" do
161
+ before do
162
+ @excel1 = Excel.new(:displayalerts => true)
163
+ @excel2 = Excel.new(:displayalerts => false, :reuse => false)
164
+ end
165
+
166
+ it "should turn off displayalerts" do
167
+ @excel1.DisplayAlerts.should be_true
168
+ begin
169
+ @excel1.with_displayalerts false do
170
+ @excel1.DisplayAlerts.should be_false
171
+ raise TestError, "any_error"
172
+ end
173
+ rescue TestError
174
+ @excel1.DisplayAlerts.should be_true
175
+ end
176
+ end
177
+
178
+ it "should turn on displayalerts" do
179
+ @excel2.DisplayAlerts.should be_false
180
+ begin
181
+ @excel1.with_displayalerts true do
182
+ @excel1.DisplayAlerts.should be_true
183
+ raise TestError, "any_error"
184
+ end
185
+ rescue TestError
186
+ @excel2.DisplayAlerts.should be_false
187
+ end
140
188
  end
141
189
 
142
190
  end
143
191
 
144
- context "with Visible and DisplayAlerts" do
145
-
192
+ context "method delegation for capitalized methods" do
146
193
  before do
147
- Excel.close_all
194
+ @excel1 = Excel.new
148
195
  end
149
196
 
150
- after (:each) do
151
- Excel.close_all
197
+ it "should raise WIN32OLERuntimeError" do
198
+ expect{ @excel1.NonexistingMethod }.to raise_error(VBAMethodMissingError)
152
199
  end
153
200
 
154
- it "should be visible" do
155
- app = Excel.new(:visible => true)
156
- app.Visible.should == true
157
- app.DisplayAlerts.should == false
201
+ it "should raise NoMethodError for uncapitalized methods" do
202
+ expect{ @excel1.nonexisting_method }.to raise_error(NoMethodError)
158
203
  end
204
+ end
159
205
 
160
- it "should displayalerts" do
161
- app = Excel.new(:displayalerts => true)
162
- app.DisplayAlerts.should == true
163
- app.Visible.should == false
206
+ context "with hwnd and hwnd2excel" do
207
+
208
+ before do
209
+ @excel1 = Excel.new
210
+ @excel2 = Excel.new(:reuse => false)
164
211
  end
165
212
 
166
- it "should visible and displayalerts" do
167
- app = Excel.new(:visible => true)
168
- app.Visible.should == true
169
- app.DisplayAlerts.should == false
170
- app2 = Excel.new(:displayalerts => true)
171
- app2.Visible.should == true
172
- app2.DisplayAlerts.should == true
213
+ it "should yield the correct hwnd" do
214
+ @excel1.Hwnd.should == @excel1.hwnd
215
+ @excel2.Hwnd.should == @excel2.hwnd
173
216
  end
174
217
 
218
+ it "should provide the same excel instances" do
219
+ @excel1.should_not == @excel2
220
+ excel3 = Excel.hwnd2excel(@excel1.hwnd)
221
+ excel4 = Excel.hwnd2excel(@excel2.hwnd)
222
+ @excel1.should == excel3
223
+ @excel2.should == excel4
224
+ excel3.should_not == excel4
225
+ end
175
226
  end
176
-
177
227
  end
178
228
 
229
+
230
+
179
231
  describe "RobustExcelOle" do
180
232
  context "#absolute_path" do
181
233
  it "should work" do
@@ -185,7 +237,7 @@ module RobustExcelOle
185
237
  RobustExcelOle::absolute_path("C:abc").should == File.expand_path("abc").gsub("/","\\")
186
238
  end
187
239
 
188
- it "should return right absoute path name" do
240
+ it "should return right absolute path name" do
189
241
  @filename = 'C:/Dokumente und Einstellungen/Zauberthomas/Eigene Dateien/robust_excel_ole/spec/book_spec.rb'
190
242
  RobustExcelOle::absolute_path(@filename).gsub("\\","/").should == @filename
191
243
  end
@@ -194,3 +246,6 @@ module RobustExcelOle
194
246
  end
195
247
 
196
248
  end
249
+
250
+ class TestError < RuntimeError
251
+ end