robust_excel_ole 0.6.1 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Changelog +8 -0
- data/README.rdoc +7 -4
- data/README_detail.rdoc +7 -3
- data/lib/reo_console.rb +1 -1
- data/lib/robust_excel_ole.rb +1 -0
- data/lib/robust_excel_ole/book.rb +26 -22
- data/lib/robust_excel_ole/excel.rb +38 -21
- data/lib/robust_excel_ole/general.rb +2 -1
- data/lib/robust_excel_ole/reo_common.rb +0 -3
- data/lib/robust_excel_ole/version.rb +1 -1
- data/spec/book_spec.rb +16 -15
- data/spec/book_specs/book_misc_spec.rb +22 -8
- data/spec/book_specs/book_open_spec.rb +3 -3
- data/spec/book_specs/book_save_spec.rb +1 -1
- data/spec/book_specs/book_sheet_spec.rb +12 -6
- data/spec/book_specs/book_unobtr_spec.rb +5 -11
- data/spec/data/another_workbook.xls +0 -0
- data/spec/data/different_workbook.xls +0 -0
- data/spec/data/workbook.xls +0 -0
- data/spec/excel_spec.rb +247 -102
- data/spec/general_spec.rb +1 -1
- data/spec/reo_common_spec.rb +5 -1
- metadata +4 -4
data/Changelog
CHANGED
data/README.rdoc
CHANGED
@@ -184,12 +184,11 @@ or
|
|
184
184
|
|
185
185
|
book.set_nameval("name") = "value"
|
186
186
|
|
187
|
-
===
|
187
|
+
=== Bringing a workbook to the focus.
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
book.activate
|
189
|
+
Make the Excel instance and the workbook visible and make it available for keyboard inputs.
|
192
190
|
|
191
|
+
book.focus
|
193
192
|
|
194
193
|
=== Making the window of the workbook visible
|
195
194
|
|
@@ -419,6 +418,10 @@ Making all workbooks invisible.
|
|
419
418
|
|
420
419
|
excel1.workbooks_visible false
|
421
420
|
|
421
|
+
=== Bringing an Excel instance to the focus
|
422
|
+
|
423
|
+
Set the window of an Excel instance to the foreground.
|
424
|
+
|
422
425
|
=== Closing an Excel
|
423
426
|
|
424
427
|
excel = Excel.current
|
data/README_detail.rdoc
CHANGED
@@ -268,11 +268,11 @@ or
|
|
268
268
|
|
269
269
|
book.set_nameval("name") = "value"
|
270
270
|
|
271
|
-
===
|
271
|
+
=== Bringing a workbook to the focus.
|
272
272
|
|
273
|
-
|
273
|
+
Make the Excel instance and the workbook visible and make it available for keyboard inputs.
|
274
274
|
|
275
|
-
book.
|
275
|
+
book.focus
|
276
276
|
|
277
277
|
=== Make the window of the workbook visible.
|
278
278
|
|
@@ -496,6 +496,10 @@ Enabling DisplayAlerts whenever the Excel instance is visible.
|
|
496
496
|
|
497
497
|
excel3 = Excel.current(:reuse => true, :displayalerts => :if_visible)
|
498
498
|
|
499
|
+
=== Bringing an Excel instance to the focus
|
500
|
+
|
501
|
+
Set the window of an Excel instance to the foreground.
|
502
|
+
|
499
503
|
=== Closing an Excel
|
500
504
|
|
501
505
|
excel = Excel.current
|
data/lib/reo_console.rb
CHANGED
data/lib/robust_excel_ole.rb
CHANGED
@@ -10,3 +10,4 @@ require File.join(File.dirname(__FILE__), 'robust_excel_ole/range')
|
|
10
10
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/cygwin') if RUBY_PLATFORM =~ /cygwin/
|
11
11
|
#+#require "robust_excel_ole/version"
|
12
12
|
require File.join(File.dirname(__FILE__), 'robust_excel_ole/version')
|
13
|
+
#
|
@@ -20,7 +20,7 @@ module RobustExcelOle
|
|
20
20
|
:if_obstructed => :raise,
|
21
21
|
:if_absent => :raise,
|
22
22
|
:read_only => false,
|
23
|
-
:check_compatibility =>
|
23
|
+
:check_compatibility => false,
|
24
24
|
:update_links => :never
|
25
25
|
}
|
26
26
|
|
@@ -92,7 +92,8 @@ module RobustExcelOle
|
|
92
92
|
book.close if (book.alive? && (not book.writable) && (not options[:read_only]))
|
93
93
|
# reopens the book
|
94
94
|
book.ensure_workbook(file,options) unless book.alive?
|
95
|
-
book.visible = options[:visible]
|
95
|
+
book.visible = options[:visible].nil? ? book.excel.visible : options[:visible]
|
96
|
+
#book.visible = options[:visible] unless options[:visible].nil?
|
96
97
|
return book
|
97
98
|
end
|
98
99
|
end
|
@@ -113,7 +114,8 @@ module RobustExcelOle
|
|
113
114
|
if filename
|
114
115
|
book = bookstore.fetch(filename)
|
115
116
|
if book && book.alive?
|
116
|
-
book.visible = opts[:visible] unless opts[:visible].nil?
|
117
|
+
#book.visible = opts[:visible] unless opts[:visible].nil?
|
118
|
+
book.visible = opts[:visible].nil? ? book.excel.visible : opts[:visible]
|
117
119
|
return book
|
118
120
|
end
|
119
121
|
end
|
@@ -183,7 +185,8 @@ module RobustExcelOle
|
|
183
185
|
filename = General::absolute_path(file)
|
184
186
|
ole_workbook = WIN32OLE.connect(filename)
|
185
187
|
workbook = Book.new(ole_workbook)
|
186
|
-
workbook.visible = options[:visible] unless options[:visible].nil?
|
188
|
+
#workbook.visible = options[:visible] unless options[:visible].nil?
|
189
|
+
workbook.visible = options[:visible].nil? ? workbook.excel.visible : options[:visible]
|
187
190
|
update_links_opt =
|
188
191
|
case options[:update_links]
|
189
192
|
when :alert; RobustExcelOle::XlUpdateLinksUserSetting
|
@@ -212,7 +215,7 @@ module RobustExcelOle
|
|
212
215
|
if options[:if_absent] == :create
|
213
216
|
@ole_workbook = excel_class.current.generate_workbook(file)
|
214
217
|
else
|
215
|
-
raise FileNotFound, "file #{file.inspect} not found"
|
218
|
+
raise FileNotFound, "file #{General::absolute_path(file).inspect} not found"
|
216
219
|
end
|
217
220
|
end
|
218
221
|
@ole_workbook = @excel.Workbooks.Item(File.basename(file)) rescue nil
|
@@ -295,13 +298,13 @@ module RobustExcelOle
|
|
295
298
|
raise UnexpectedError, "unknown RuntimeError"
|
296
299
|
end
|
297
300
|
rescue WeakRef::RefError => msg
|
298
|
-
raise
|
301
|
+
raise WeakRef::RefError, "#{msg.message}"
|
299
302
|
end
|
300
303
|
# workaround for linked workbooks for Excel 2007:
|
301
304
|
# opening and closing a dummy workbook if Excel has no workbooks.
|
302
305
|
# delay: with visible: 0.2 sec, without visible almost none
|
303
306
|
count = workbooks.Count
|
304
|
-
if @excel.Version
|
307
|
+
if @excel.Version.split(".").first.to_i >= 12 && count == 0
|
305
308
|
workbooks.Add
|
306
309
|
#@excel.set_calculation(:automatic)
|
307
310
|
end
|
@@ -318,7 +321,7 @@ module RobustExcelOle
|
|
318
321
|
@excel.with_displayalerts(update_links_opt == :alert ? true : @excel.displayalerts) do
|
319
322
|
workbooks.Open(filename, { 'ReadOnly' => options[:read_only] , 'UpdateLinks' => update_links_opt } )
|
320
323
|
end
|
321
|
-
workbooks.Item(1).Close if @excel.Version
|
324
|
+
workbooks.Item(1).Close if @excel.Version.split(".").first.to_i >= 12 && count == 0
|
322
325
|
rescue WIN32OLERuntimeError => msg
|
323
326
|
# trace "WIN32OLERuntimeError: #{msg.message}"
|
324
327
|
if msg.message =~ /800A03EC/
|
@@ -330,7 +333,8 @@ module RobustExcelOle
|
|
330
333
|
begin
|
331
334
|
# workaround for bug in Excel 2010: workbook.Open does not always return the workbook with given file name
|
332
335
|
@ole_workbook = workbooks.Item(File.basename(filename))
|
333
|
-
self.visible = options[:visible]
|
336
|
+
self.visible = options[:visible].nil? ? @excel.visible : options[:visible]
|
337
|
+
#self.visible = options[:visible] unless options[:visible].nil?
|
334
338
|
#@ole_workbook.UpdateLinks = update_links_opt
|
335
339
|
@ole_workbook.CheckCompatibility = options[:check_compatibility]
|
336
340
|
rescue WIN32OLERuntimeError
|
@@ -434,7 +438,7 @@ module RobustExcelOle
|
|
434
438
|
:read_only => false,
|
435
439
|
:readonly_excel => false,
|
436
440
|
:keep_open => false,
|
437
|
-
:check_compatibility =>
|
441
|
+
:check_compatibility => false
|
438
442
|
}.merge(opts)
|
439
443
|
book = bookstore.fetch(file, :prefer_writable => (not options[:read_only]))
|
440
444
|
was_not_alive_or_nil = book.nil? || (not book.alive?)
|
@@ -467,7 +471,8 @@ module RobustExcelOle
|
|
467
471
|
open(file, :force_excel => :new, :read_only => options[:read_only])
|
468
472
|
end
|
469
473
|
end
|
470
|
-
book.excel.visible = options[:visible] unless options[:visible].nil?
|
474
|
+
#book.excel.visible = options[:visible] unless options[:visible].nil?
|
475
|
+
book.visible = options[:visible].nil? ? book.excel.visible : options[:visible]
|
471
476
|
old_check_compatibility = book.CheckCompatibility
|
472
477
|
book.CheckCompatibility = options[:check_compatibility]
|
473
478
|
yield book
|
@@ -525,7 +530,7 @@ module RobustExcelOle
|
|
525
530
|
# @return [Book], the book itself, if successfully saved, raises an exception otherwise
|
526
531
|
def save_as(file, opts = { } )
|
527
532
|
raise FileNameNotGiven, "filename is nil" if file.nil?
|
528
|
-
raise ObjectNotAlive, "workbook is not alive"
|
533
|
+
raise ObjectNotAlive, "workbook is not alive" unless alive?
|
529
534
|
raise WorkbookReadOnly, "Not opened for writing (opened with :read_only option)" if @ole_workbook.ReadOnly
|
530
535
|
options = {
|
531
536
|
:if_exists => :raise,
|
@@ -777,15 +782,10 @@ module RobustExcelOle
|
|
777
782
|
end
|
778
783
|
|
779
784
|
# brings workbook to foreground, makes it available for heyboard inputs, makes the Excel instance visible
|
780
|
-
def
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
SetForegroundWindow.call(@excel.Hwnd)
|
785
|
-
@ole_workbook.Activate # Excel 2007
|
786
|
-
rescue WIN32OLERuntimeError => msg
|
787
|
-
raise UnexpectedError, "cannot activate: #{message.msg}"
|
788
|
-
end
|
785
|
+
def focus
|
786
|
+
self.visible = true
|
787
|
+
@excel.focus
|
788
|
+
@ole_workbook.Activate
|
789
789
|
end
|
790
790
|
|
791
791
|
# returns true, if the workbook is visible, false otherwise
|
@@ -798,7 +798,11 @@ module RobustExcelOle
|
|
798
798
|
def visible= visible_value
|
799
799
|
saved = @ole_workbook.Saved
|
800
800
|
@excel.visible = true if visible_value
|
801
|
-
|
801
|
+
if @excel.Visible
|
802
|
+
if @ole_workbook.Windows.Count > 0
|
803
|
+
@ole_workbook.Windows(@ole_workbook.Name).Visible = visible_value
|
804
|
+
end
|
805
|
+
end
|
802
806
|
@ole_workbook.Saved = saved
|
803
807
|
end
|
804
808
|
|
@@ -65,6 +65,8 @@ module RobustExcelOle
|
|
65
65
|
if stored
|
66
66
|
result = stored
|
67
67
|
else
|
68
|
+
options[:visible] = options[:visible].nil? ? ole_xl.Visible : options[:visible]
|
69
|
+
options[:displayalerts] = options[:displayalerts].nil? ? :if_visible : options[:displayalerts]
|
68
70
|
result = super(options)
|
69
71
|
result.instance_variable_set(:@ole_excel, ole_xl)
|
70
72
|
WIN32OLE.const_load(ole_xl, RobustExcelOle) unless RobustExcelOle.const_defined?(:CONSTANTS)
|
@@ -72,16 +74,19 @@ module RobustExcelOle
|
|
72
74
|
end
|
73
75
|
|
74
76
|
unless options.is_a? WIN32OLE
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
77
|
+
begin
|
78
|
+
reused = options[:reuse] && (not stored.nil?)
|
79
|
+
options = { :displayalerts => :if_visible, :visible => false}.merge(options) unless reused
|
80
|
+
visible_value = (reused && options[:visible].nil?) ? result.Visible : options[:visible]
|
81
|
+
displayalerts_value = (reused && options[:displayalerts].nil?) ?
|
82
|
+
((result.displayalerts == :if_visible) ? :if_visible : result.DisplayAlerts) : options[:displayalerts]
|
83
|
+
ole_xl.Visible = visible_value
|
84
|
+
ole_xl.DisplayAlerts = (displayalerts_value == :if_visible) ? visible_value : displayalerts_value
|
85
|
+
result.instance_variable_set(:@visible, visible_value)
|
86
|
+
result.instance_variable_set(:@displayalerts, displayalerts_value)
|
87
|
+
rescue WIN32OLERuntimeError
|
88
|
+
raise ExcelError, "cannot access Excel"
|
89
|
+
end
|
85
90
|
end
|
86
91
|
result
|
87
92
|
end
|
@@ -156,6 +161,7 @@ module RobustExcelOle
|
|
156
161
|
end
|
157
162
|
|
158
163
|
# closes Excel instances opened via RobustExcelOle
|
164
|
+
# @return [Fixnum] number of closed Excel instances
|
159
165
|
# @param [Hash] options the options
|
160
166
|
# @option options [Symbol] :if_unsaved :raise, :save, :forget, or :alert
|
161
167
|
# @option options [Boolean] :hard
|
@@ -175,15 +181,21 @@ module RobustExcelOle
|
|
175
181
|
:kill_if_timeout => false
|
176
182
|
}.merge(options)
|
177
183
|
timeout = false
|
178
|
-
number =
|
184
|
+
number = @@hwnd2excel.size
|
185
|
+
unsaved_workbooks = false
|
179
186
|
begin
|
180
187
|
status = Timeout::timeout(60) {
|
181
188
|
@@hwnd2excel.each do |hwnd, wr_excel|
|
182
189
|
excel = wr_excel.__getobj__
|
183
|
-
|
190
|
+
begin
|
191
|
+
excel.close(options)
|
192
|
+
rescue UnsavedWorkbooks
|
193
|
+
unsaved_workbooks = true
|
194
|
+
end
|
195
|
+
sleep 0.2
|
184
196
|
end
|
185
|
-
|
186
|
-
free_all_ole_objects if excels_number > 0
|
197
|
+
raise UnsavedWorkbooks, "Excel contains unsaved workbooks" if unsaved_workbooks
|
198
|
+
free_all_ole_objects if excels_number > 0 #&& (not unsaved_workbooks)
|
187
199
|
# close also interactively opened Excels, but for unsaved workbooks: hangs as soon sending a VBA method
|
188
200
|
#while (n = excels_number) > 0 do
|
189
201
|
# ole_xl = current_excel
|
@@ -416,11 +428,12 @@ module RobustExcelOle
|
|
416
428
|
end
|
417
429
|
|
418
430
|
def print_workbooks
|
419
|
-
self.Workbooks.each {|w|
|
431
|
+
self.Workbooks.each {|w| trace "#{w.Name} #{w}"}
|
420
432
|
end
|
421
433
|
|
422
434
|
# generates, saves, and closes empty workbook
|
423
|
-
def generate_workbook file_name
|
435
|
+
def generate_workbook file_name
|
436
|
+
raise FileNameNotGiven, "filename is nil" if file_name.nil?
|
424
437
|
self.Workbooks.Add
|
425
438
|
empty_workbook = self.Workbooks.Item(self.Workbooks.Count)
|
426
439
|
filename = General::absolute_path(file_name).gsub("/","\\")
|
@@ -429,7 +442,7 @@ module RobustExcelOle
|
|
429
442
|
empty_workbook.SaveAs(filename)
|
430
443
|
rescue WIN32OLERuntimeError => msg
|
431
444
|
if msg.message =~ /SaveAs/ and msg.message =~ /Workbook/ then
|
432
|
-
raise
|
445
|
+
raise FileNotFound, "could not save workbook with filename #{file_name.inspect}"
|
433
446
|
else
|
434
447
|
# todo some time: find out when this occurs :
|
435
448
|
raise UnexpectedError, "unknown WIN32OELERuntimeError with filename #{file_name.inspect}: \n#{msg.message}"
|
@@ -475,10 +488,13 @@ module RobustExcelOle
|
|
475
488
|
end
|
476
489
|
end
|
477
490
|
|
478
|
-
|
479
|
-
def foremost_window
|
491
|
+
def focus
|
480
492
|
self.visible = true
|
481
|
-
#
|
493
|
+
#if not Windows10 then
|
494
|
+
Win32API.new("user32","SetForegroundWindow","I","I").call(@ole_excel.Hwnd)
|
495
|
+
#else
|
496
|
+
#Win32API.new("user32","SetForegroundWindow","","I").call
|
497
|
+
#end
|
482
498
|
end
|
483
499
|
|
484
500
|
# sets calculation mode in a block
|
@@ -587,10 +603,11 @@ module RobustExcelOle
|
|
587
603
|
raise RangeNotEvaluatable, "cannot determine value of range named #{name.inspect}"
|
588
604
|
end
|
589
605
|
return opts[:default] if (value.nil? && opts[:default])
|
606
|
+
raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect}" if value == -2146826259
|
590
607
|
value
|
591
608
|
end
|
592
609
|
|
593
|
-
# assigns a value to a range given a defined
|
610
|
+
# assigns a value to a range given a defined local name
|
594
611
|
# @param [String] name the range name
|
595
612
|
# @param [Variant] value the assigned value
|
596
613
|
def set_rangeval(name,value)
|
data/spec/book_spec.rb
CHANGED
@@ -33,7 +33,7 @@ describe Book do
|
|
33
33
|
|
34
34
|
after do
|
35
35
|
Excel.kill_all
|
36
|
-
rm_tmp(@dir)
|
36
|
+
#rm_tmp(@dir)
|
37
37
|
end
|
38
38
|
|
39
39
|
describe "create file" do
|
@@ -381,7 +381,7 @@ describe Book do
|
|
381
381
|
if :if_obstructed is :close_if_saved" do
|
382
382
|
expect{
|
383
383
|
@new_book = Book.open(@simple_file1, :if_obstructed => :close_if_saved)
|
384
|
-
}.to raise_error(
|
384
|
+
}.to raise_error(WorkbookBlocked, /workbook with the same name in a different path is unsaved/)
|
385
385
|
@book.save
|
386
386
|
@new_book = Book.open(@simple_file1, :if_obstructed => :close_if_saved)
|
387
387
|
@book.should_not be_alive
|
@@ -409,7 +409,7 @@ describe Book do
|
|
409
409
|
File.delete @simple_save_file rescue nil
|
410
410
|
expect {
|
411
411
|
Book.open(@simple_save_file)
|
412
|
-
}.to raise_error(
|
412
|
+
}.to raise_error(FileNotFound, "file #{General::absolute_path(@simple_save_file).gsub("/","\\").inspect} not found")
|
413
413
|
end
|
414
414
|
end
|
415
415
|
|
@@ -901,7 +901,7 @@ describe Book do
|
|
901
901
|
book.excel.should_not == @book.excel
|
902
902
|
book.excel.should_not == new_excel
|
903
903
|
book.excel.visible.should be_false
|
904
|
-
book.excel.displayalerts.should
|
904
|
+
book.excel.displayalerts.should == :if_visible
|
905
905
|
end
|
906
906
|
new_book = Book.open(@simple_file1, :visible => true)
|
907
907
|
sheet = new_book.sheet(1)
|
@@ -1077,7 +1077,7 @@ describe Book do
|
|
1077
1077
|
end
|
1078
1078
|
end
|
1079
1079
|
|
1080
|
-
describe "alive?, filename, ==,
|
1080
|
+
describe "alive?, filename, ==, focus, saved" do
|
1081
1081
|
|
1082
1082
|
context "with alive?" do
|
1083
1083
|
|
@@ -1133,12 +1133,12 @@ describe Book do
|
|
1133
1133
|
end
|
1134
1134
|
end
|
1135
1135
|
|
1136
|
-
context "with
|
1136
|
+
context "with focus" do
|
1137
1137
|
|
1138
1138
|
before do
|
1139
1139
|
@key_sender = IO.popen 'ruby "' + File.join(File.dirname(__FILE__), '/helpers/key_sender.rb') + '" "Microsoft Office Excel" ' , "w"
|
1140
1140
|
@book = Book.open(@simple_file, :visible => true)
|
1141
|
-
@book2 = Book.open(@another_simple_file, :
|
1141
|
+
@book2 = Book.open(@another_simple_file, :visible => true)
|
1142
1142
|
end
|
1143
1143
|
|
1144
1144
|
after do
|
@@ -1147,22 +1147,22 @@ describe Book do
|
|
1147
1147
|
@key_sender.close
|
1148
1148
|
end
|
1149
1149
|
|
1150
|
-
it "should
|
1150
|
+
it "should bring a book to focus" do
|
1151
1151
|
sheet = @book.sheet(2)
|
1152
1152
|
sheet.Activate
|
1153
1153
|
sheet[2,3].Activate
|
1154
1154
|
sheet2 = @book2.sheet(2)
|
1155
1155
|
sheet2.Activate
|
1156
1156
|
sheet2[3,2].Activate
|
1157
|
-
|
1158
|
-
@book2.activate
|
1157
|
+
@book2.focus
|
1159
1158
|
@key_sender.puts "{a}{enter}"
|
1160
|
-
sleep
|
1159
|
+
sleep 0.2
|
1161
1160
|
sheet2[3,2].Value.should == "a"
|
1162
|
-
|
1163
|
-
@book.
|
1161
|
+
@book.focus
|
1162
|
+
@book.Windows(1).Visible.should be_true
|
1163
|
+
@book.Windows(@book.Name).Visible.should be_true
|
1164
1164
|
@key_sender.puts "{a}{enter}"
|
1165
|
-
sleep
|
1165
|
+
sleep 0.2
|
1166
1166
|
sheet[2,3].Value.should == "a"
|
1167
1167
|
Excel.current.should == @book.excel
|
1168
1168
|
end
|
@@ -1198,7 +1198,8 @@ describe Book do
|
|
1198
1198
|
|
1199
1199
|
context "with second argument is {:before => @book.sheet(3), :after => @sheet}" do
|
1200
1200
|
it "should arguments in the first is given priority" do
|
1201
|
-
@book.add_sheet(@sheet, :before => @book.sheet(3), :after => @sheet)
|
1201
|
+
@book.add_sheet(@sheet, :before => @book.sheet(3), :after => @sheet)
|
1202
|
+
@book.Worksheets.Count.should == 4
|
1202
1203
|
end
|
1203
1204
|
end
|
1204
1205
|
end
|