robust_excel_ole 1.10 → 1.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +8 -0
- data/README.rdoc +6 -4
- data/docs/README_open.rdoc +18 -13
- data/lib/robust_excel_ole/bookstore.rb +95 -9
- data/lib/robust_excel_ole/excel.rb +12 -7
- data/lib/robust_excel_ole/general.rb +20 -7
- data/lib/robust_excel_ole/range.rb +6 -0
- data/lib/robust_excel_ole/reo_common.rb +8 -0
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +201 -165
- data/lib/robust_excel_ole/worksheet.rb +6 -0
- data/spec/bookstore_spec.rb +92 -2
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/excel_spec.rb +86 -3
- data/spec/range_spec.rb +12 -0
- data/spec/workbook_spec.rb +56 -3
- data/spec/workbook_specs/workbook_open_spec.rb +332 -195
- data/spec/workbook_specs/workbook_unobtr_spec.rb +41 -1
- data/spec/worksheet_spec.rb +14 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 344c336ba61c5f1b98839047f69cbbac1ddef451291fa32260c47218421d78cc
|
4
|
+
data.tar.gz: 169a63ca7cb3d582443aa046228797cc946e9f47f45e97019b21504f8a897384
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc9e189d01012805dd02d668c833e96b9597997b518a2b9ce6beb671969e007d8cae5d362a045fbd439a4368cf7ddfdfee66b535d60e9b4e9c68db7a99023989
|
7
|
+
data.tar.gz: 1e04fa12bc2e5956fb0efa68a92b185557b8180909da820517ab55affd3bf8154d297aa9a2b0eaa8e8a161fc31972560ea74f5beefa2fc51225f45b392c122fc
|
data/Changelog
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
|
5
|
+
## [1.11]
|
6
|
+
|
7
|
+
### Added
|
8
|
+
- Range#==, Worksheet#==
|
9
|
+
- Workbook#open: options :if_blocked is synonym to :if_obstructed
|
10
|
+
- Simplified Code
|
11
|
+
|
4
12
|
## [1.10]
|
5
13
|
|
6
14
|
### Added
|
data/README.rdoc
CHANGED
@@ -9,7 +9,7 @@ RobustExcelOle works by sending VBA methods via Win32OLE. It keeps track of Exce
|
|
9
9
|
|
10
10
|
== Requirements
|
11
11
|
|
12
|
-
|
12
|
+
Ruby 2.1 or higher. Most functions run on Ruby 1.8.6, too.
|
13
13
|
|
14
14
|
== Installation
|
15
15
|
|
@@ -134,6 +134,8 @@ or, using abbreviations,
|
|
134
134
|
|
135
135
|
workbook = Workbook.open('spec/data/workbook.xls', :v => true)
|
136
136
|
|
137
|
+
Note that Workbook.open can also connect to workbooks which were not opened via RobustExcelOle (but had been opened before by some user).
|
138
|
+
|
137
139
|
For more details about opening workbooks see {README_open}[https://github.com/Thomas008/robust_excel_ole/blob/master/docs/README_open.rdoc]
|
138
140
|
|
139
141
|
We can do a simple save
|
@@ -234,7 +236,7 @@ Similarly, if the user has opened a workbook that has the same name but a differ
|
|
234
236
|
|
235
237
|
workbook1 = Workbook.open('spec/data/workbook.xls')
|
236
238
|
# do something
|
237
|
-
workbook2 = Workbook.open('spec/data/more/workbook.xls', :
|
239
|
+
workbook2 = Workbook.open('spec/data/more/workbook.xls', :if_blocked => :forget)
|
238
240
|
|
239
241
|
For more details about opening and closing workbooks in Excel instances see {README_open}[https://github.com/Thomas008/robust_excel_ole/blob/master/docs/README_open.rdoc]
|
240
242
|
|
@@ -309,7 +311,7 @@ For more details about reading and writing contents of cells and ranges see {REA
|
|
309
311
|
|
310
312
|
RobustExcelOle runs in jruby as well. You can call the console via the command +jreo+. However, note that, due to some restrictions of the library jruby-win32ole, there are some restrictions. So we had implemented some adaptions and workarounds. Some issues still remain when running under jruby:
|
311
313
|
|
312
|
-
1. Excel.current or Excel.new(:reuse => true) does not connect to an already running Excel instance, unless some workbook has been opened via RobustExcelOle. 2. Excel.kill_all does work, Excel.close_all does not work. 3. When providing an absolute path, you have to state the "/" ("C:/abc.xls" works, "C:abc" does not work)
|
314
|
+
1. Excel.current or Excel.new(:reuse => true) does not connect to an already running Excel instance, unless some workbook has been opened via RobustExcelOle. 2. Excel.kill_all does work, Excel.close_all does not work. 3. When providing an absolute path, you have to state the "/" ("C:/abc.xls" works, "C:abc" does not work).
|
313
315
|
|
314
316
|
|
315
317
|
|
@@ -329,7 +331,7 @@ You can run the examples included in the directory +examples+, e.g.
|
|
329
331
|
|
330
332
|
This project RobustExcelOle is work in progress. We are happy to implement further features. So we invite you to send your pull requests. We then strive to realize them as soon as possible. If you have any feedback, or you find use cases that RobustExcelOle does not satisfy, please let us know.
|
331
333
|
|
332
|
-
RobustExcelOle is being tested for Excel 2010. It can be used for any recent Excel Office version.
|
334
|
+
RobustExcelOle is being tested for Excel 2010 and Excel 2013. It can be used for any recent Excel Office version. Most functions should run on Excel 2007 as well.
|
333
335
|
|
334
336
|
RobustExcelOle has been optimised with help of the rubocop and the rcov tool.
|
335
337
|
|
data/docs/README_open.rdoc
CHANGED
@@ -25,23 +25,24 @@ The options are the following:
|
|
25
25
|
|
26
26
|
+:excel+ and +:visible+ are options stated in +:default+ or +:force+
|
27
27
|
|
28
|
-
+:excel+::
|
28
|
+
+:excel+:: specifies the Excel instance.
|
29
29
|
|
30
|
-
+:visible+::
|
30
|
+
+:visible+:: makes the workbook visible or invisible
|
31
31
|
|
32
|
-
+:if_unsaved+::
|
32
|
+
+:if_unsaved+:: specifies behaviour if the workbook was unsaved (default: +:raise+)
|
33
33
|
|
34
|
-
+:
|
34
|
+
+:if_blocked:: specifies behaviour if the workbook is blocked by another book (default: +:raise+)
|
35
35
|
|
36
|
-
+:read_only+:: open in read-only mode (default: +false+)
|
37
36
|
|
38
|
-
+:
|
37
|
+
+:read_only+:: opens in read-only mode (default: +false+)
|
39
38
|
|
40
|
-
+:
|
39
|
+
+:check_compatibility:: checks compatibility when saving
|
41
40
|
|
42
|
-
+:
|
41
|
+
+:calculation+:: forces the calculation mode to be manual (:manual) or automatic (:automatic)
|
43
42
|
|
44
|
-
|
43
|
+
+:if_absent+:: specifies behaviour if the workbook with the given file name does not exist if the workbook does not exist (default: +create+)
|
44
|
+
|
45
|
+
You can use the following abbreviations or synonyms: +:f+ for +:force+, +:d+ for +:default+, +:e+ for +:excel+, and +:v+ for +:visible+, +:if_obstructed+ for +:if_blocked+. Finally you can leave out the option +:force+ or +:f+.
|
45
46
|
|
46
47
|
The option +:excel+ :
|
47
48
|
|
@@ -57,7 +58,7 @@ If a workbook contains unsaved changes and a new workbook with the same file nam
|
|
57
58
|
+:new_excel+:: Open the new workbook in a new Excel instance
|
58
59
|
+:alert+:: Give control to Excel.
|
59
60
|
|
60
|
-
The option +:
|
61
|
+
The option +:if_blocked+ :
|
61
62
|
|
62
63
|
If a workbook is open and a new workbook with same name and a different path is open, then
|
63
64
|
|
@@ -122,9 +123,9 @@ If a workbook contains unsaved changes and a workbook with the same filename sha
|
|
122
123
|
|
123
124
|
book = Workbook.open('spec/data/workbook.xls', :if_unsaved => :accept)
|
124
125
|
|
125
|
-
If a workbook is open and a workbook with the same name but in different path shall be opened, i.e. the first workbook blocks opening the other workbook, then the option +:
|
126
|
+
If a workbook is open and a workbook with the same name but in different path shall be opened, i.e. the first workbook blocks opening the other workbook, then the option +:if_blocked+ handles this situation, e.g.
|
126
127
|
|
127
|
-
book = Workbook.open('path/workbook.xls', :
|
128
|
+
book = Workbook.open('path/workbook.xls', :if_blocked => :forget)
|
128
129
|
|
129
130
|
Remarks:
|
130
131
|
|
@@ -150,6 +151,10 @@ A Workbook object can be created when giving an Excel workbook.
|
|
150
151
|
|
151
152
|
book = Workbook.new(win32ole_workbook)
|
152
153
|
|
154
|
+
Note that only a restricted number of options can be considered, e.g. +:visible+
|
155
|
+
|
156
|
+
book = Workbook.new(win32ole_workbook, :visible => true)
|
157
|
+
|
153
158
|
=== Unobtrusively modifying a workbook
|
154
159
|
|
155
160
|
The method +unobtrusively+ enables the user to read or modify a workbook, no matter if it is open in some Excel instance, if it is saved or unsaved, and if it is writable or not. When opening a workbook unobtrusively, its status remains unchanged. This status includes, whether the workbook is opened or closed, saved or unsaved, readonly or writable, visible or invisible, calculation mode is automatic or manual, and checking compatibility is turned on or off.
|
@@ -182,7 +187,7 @@ The methods +for_reading+ and +for_modifying+ indicate unobtrusively reading or
|
|
182
187
|
sheet[1,1] = "c"
|
183
188
|
end
|
184
189
|
|
185
|
-
|
190
|
+
Note, that the methods +unobtrusively+, +for_reading+ and +for_modifying+ work not only for workbooks opened via RobustExcelOle, but do also connect to workbooks opened outside RobustExcelOle.
|
186
191
|
|
187
192
|
=== Retaining the saved-status
|
188
193
|
|
@@ -16,24 +16,25 @@ module RobustExcelOle
|
|
16
16
|
book.excel
|
17
17
|
end
|
18
18
|
|
19
|
-
# returns a
|
19
|
+
# returns a workbook with the given filename, if it was open once
|
20
20
|
# @param [String] filename the file name
|
21
21
|
# @param [Hash] options the options
|
22
22
|
# @option option [Boolean] :prefer_writable
|
23
23
|
# @option option [Boolean] :prefer_excel
|
24
|
-
# prefers open
|
24
|
+
# prefers open workbooks to closed workbooks, and among them, prefers more recently opened workbooks
|
25
25
|
# excludes hidden Excel instance
|
26
|
-
# options: :prefer_writable returns the writable
|
27
|
-
# otherwise returns the
|
28
|
-
# :prefer_excel returns the
|
26
|
+
# options: :prefer_writable returns the writable workbook, if it is open (default: true)
|
27
|
+
# otherwise returns the workbook according to the preference order mentioned above
|
28
|
+
# :prefer_excel returns the workbook in the given Excel instance, if it exists,
|
29
29
|
# otherwise proceeds according to prefer_writable
|
30
30
|
def fetch(filename, options = { :prefer_writable => true })
|
31
31
|
return nil unless filename
|
32
32
|
|
33
33
|
filename = General.absolute_path(filename)
|
34
34
|
filename_key = General.canonize(filename)
|
35
|
-
weakref_books = @filename2books[filename_key]
|
36
|
-
|
35
|
+
weakref_books = @filename2books[filename_key]
|
36
|
+
weakref_books = consider_networkpaths(filename_key) if weakref_books.empty? || weakref_books.nil?
|
37
|
+
return nil if weakref_books.nil? || weakref_books.empty?
|
37
38
|
|
38
39
|
result = open_book = closed_book = nil
|
39
40
|
weakref_books = weakref_books.map { |wr_book| wr_book if wr_book.weakref_alive? }.compact
|
@@ -44,8 +45,7 @@ module RobustExcelOle
|
|
44
45
|
begin
|
45
46
|
@filename2books[filename_key].delete(wr_book)
|
46
47
|
rescue
|
47
|
-
|
48
|
-
# trace "Warning: deleting dead reference failed: file: #{filename.inspect}"
|
48
|
+
trace "Warning: deleting dead reference failed: file: #{filename.inspect}"
|
49
49
|
end
|
50
50
|
else
|
51
51
|
book = wr_book.__getobj__
|
@@ -67,6 +67,92 @@ module RobustExcelOle
|
|
67
67
|
result
|
68
68
|
end
|
69
69
|
|
70
|
+
def consider_networkpaths(filename)
|
71
|
+
network = WIN32OLE.new('WScript.Network')
|
72
|
+
drives = network.enumnetworkdrives
|
73
|
+
drive_letter, filename_after_drive_letter = filename.split(':')
|
74
|
+
# if filename starts with a drive letter not c and this drive exists,
|
75
|
+
# then if there is the corresponding host_share_path in the bookstore,
|
76
|
+
# then take the corresponding workbooks
|
77
|
+
# otherwise (there is an usual file path) find in the bookstore the workbooks of which filenames
|
78
|
+
# ends with the latter part of the given filename (after the drive letter)
|
79
|
+
if drive_letter != 'c' && drive_letter != filename
|
80
|
+
for i in 0 .. drives.Count-1
|
81
|
+
next if i % 2 == 1
|
82
|
+
if drives.Item(i).gsub(':','').downcase == drive_letter
|
83
|
+
hostname_share = drives.Item(i+1).gsub('\\','/').gsub('//','').downcase
|
84
|
+
break
|
85
|
+
end
|
86
|
+
end
|
87
|
+
found_filename = nil
|
88
|
+
@filename2books.each do |stored_filename,_|
|
89
|
+
if hostname_share && stored_filename
|
90
|
+
if stored_filename[0] == '/'
|
91
|
+
index_hostname = stored_filename[1,stored_filename.length].index('/')+2
|
92
|
+
index_hostname_share = stored_filename[index_hostname,stored_filename.length].index('/')
|
93
|
+
hostname_share_in_stored_filename = stored_filename[1,index_hostname+index_hostname_share-1]
|
94
|
+
if hostname_share_in_stored_filename == hostname_share
|
95
|
+
found_filename = stored_filename
|
96
|
+
break
|
97
|
+
end
|
98
|
+
elsif found_filename.nil? && stored_filename.end_with?(filename_after_drive_letter)
|
99
|
+
found_filename = stored_filename
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
elsif filename[0] == '/'
|
104
|
+
# if filename starts with a host name and share, and this is an existing host name share path,
|
105
|
+
# then if there are workbooks with the corresponding drive letter,
|
106
|
+
# then take these workbooks,
|
107
|
+
# otherwise (there is an usual file path) find in the bookstore the workbooks of which filenames
|
108
|
+
# ends with the latter part of the given filename (after the drive letter)
|
109
|
+
index_hostname = filename[1,filename.length].index('/')+2
|
110
|
+
index_hostname_share = filename[index_hostname,filename.length].index('/')
|
111
|
+
hostname_share_in_filename = filename[1,index_hostname+index_hostname_share-1]
|
112
|
+
filename_after_hostname_share = filename[index_hostname+index_hostname_share+1, filename.length]
|
113
|
+
require 'socket'
|
114
|
+
hostname = Socket.gethostname
|
115
|
+
if hostname_share_in_filename[0,hostname_share_in_filename.index('/')] == hostname.downcase
|
116
|
+
for i in 0 .. drives.Count-1
|
117
|
+
next if i % 2 == 1
|
118
|
+
hostname_share = drives.Item(i+1).gsub('\\','/').gsub('//','').downcase
|
119
|
+
if hostname_share == hostname_share_in_filename
|
120
|
+
drive_letter = drives.Item(i).gsub(':','').downcase
|
121
|
+
break
|
122
|
+
end
|
123
|
+
end
|
124
|
+
@filename2books.each do |stored_filename,_|
|
125
|
+
if stored_filename
|
126
|
+
if drive_letter && stored_filename.start_with?(drive_letter.downcase) && stored_filename.end_with?(filename_after_hostname_share)
|
127
|
+
found_filename = stored_filename
|
128
|
+
break
|
129
|
+
elsif found_filename.nil? && stored_filename.end_with?(filename_after_hostname_share)
|
130
|
+
found_filename = stored_filename
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
else
|
136
|
+
# if filename is an usual file path,
|
137
|
+
# then find in the bookstore a workbook of which filename starts with
|
138
|
+
# a drive letter or a host name
|
139
|
+
@filename2books.each do |stored_filename,_|
|
140
|
+
drive_letter, _ = stored_filename.split(':')
|
141
|
+
stored_filename_end = if drive_letter != stored_filename && drive_letter != 'c'
|
142
|
+
stored_filename[stored_filename.index(':')+1,stored_filename.length]
|
143
|
+
elsif stored_filename[0] == '/'
|
144
|
+
index_after_hostname = stored_filename[1,stored_filename.length].index('/')
|
145
|
+
stored_filename[index_after_hostname+1, stored_filename.length]
|
146
|
+
end
|
147
|
+
if stored_filename_end && filename.end_with?(stored_filename_end)
|
148
|
+
found_filename = stored_filename
|
149
|
+
break
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
@filename2books[found_filename]
|
154
|
+
end
|
155
|
+
|
70
156
|
# stores a workbook
|
71
157
|
# @param [Workbook] book a given book
|
72
158
|
def store(book)
|
@@ -76,14 +76,15 @@ module RobustExcelOle
|
|
76
76
|
ole_xl = win32ole_excel unless win32ole_excel.nil?
|
77
77
|
options = { :reuse => true }.merge(options)
|
78
78
|
#ole_xl = current_excel if options[:reuse] == true
|
79
|
-
if options[:reuse] == true
|
80
|
-
ole_xl = if RUBY_PLATFORM =~ /java/
|
81
|
-
excel_instance = known_excel_instance
|
82
|
-
|
79
|
+
if options[:reuse] == true && ole_xl.nil?
|
80
|
+
ole_xl = if RUBY_PLATFORM =~ /java/
|
81
|
+
excel_instance = known_excel_instance if excel_instance.nil?
|
82
|
+
excel_instance.ole_excel unless excel_instance.nil?
|
83
83
|
else
|
84
84
|
current_excel
|
85
85
|
end
|
86
86
|
end
|
87
|
+
connected = (not ole_xl.nil?)
|
87
88
|
ole_xl ||= WIN32OLE.new('Excel.Application')
|
88
89
|
hwnd = ole_xl.HWnd
|
89
90
|
stored = hwnd2excel(hwnd)
|
@@ -98,11 +99,11 @@ module RobustExcelOle
|
|
98
99
|
|
99
100
|
unless options.is_a? WIN32OLE
|
100
101
|
begin
|
101
|
-
reused = options[:reuse] && stored && stored.alive?
|
102
|
-
|
102
|
+
reused = options[:reuse] && stored && stored.alive?
|
103
|
+
if (not reused) && (not connected)
|
103
104
|
options = { :displayalerts => :if_visible, :visible => false, :screenupdating => true }.merge(options)
|
104
105
|
end
|
105
|
-
result.visible = options[:visible] unless options[:visible].nil?
|
106
|
+
result.visible = options[:visible] unless options[:visible].nil?
|
106
107
|
result.displayalerts = options[:displayalerts] unless options[:displayalerts].nil?
|
107
108
|
result.calculation = options[:calculation] unless options[:calculation].nil?
|
108
109
|
result.screenupdating = options[:screenupdating] unless options[:screenupdating].nil?
|
@@ -423,6 +424,10 @@ module RobustExcelOle
|
|
423
424
|
processes.select { |p| p.name == 'EXCEL.EXE' }.size
|
424
425
|
end
|
425
426
|
|
427
|
+
def self.known_excels_number
|
428
|
+
@@hwnd2excel.size
|
429
|
+
end
|
430
|
+
|
426
431
|
# returns an Excel instance
|
427
432
|
def self.known_excel_instance
|
428
433
|
@@hwnd2excel.each do |hwnd, wr_excel|
|
@@ -67,13 +67,26 @@ class WIN32OLE
|
|
67
67
|
|
68
68
|
# promoting WIN32OLE objects to RobustExcelOle objects
|
69
69
|
def to_reo
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
70
|
+
begin
|
71
|
+
self.Hwnd
|
72
|
+
RobustExcelOle::Excel.new(self)
|
73
|
+
rescue
|
74
|
+
begin
|
75
|
+
self.FullName
|
76
|
+
RobustExcelOle::Workbook.new(self)
|
77
|
+
rescue
|
78
|
+
begin
|
79
|
+
self.Copy
|
80
|
+
RobustExcelOle::Worksheet.new(self)
|
81
|
+
rescue
|
82
|
+
begin
|
83
|
+
self.Address
|
84
|
+
RobustExcelOle::Range.new(self)
|
85
|
+
rescue
|
86
|
+
self
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
77
90
|
end
|
78
91
|
end
|
79
92
|
end
|
@@ -213,6 +213,12 @@ module RobustExcelOle
|
|
213
213
|
end
|
214
214
|
end
|
215
215
|
|
216
|
+
def == other_range
|
217
|
+
other_range.is_a?(Range) &&
|
218
|
+
self.worksheet == other_range.worksheet
|
219
|
+
self.Address == other_range.Address
|
220
|
+
end
|
221
|
+
|
216
222
|
# @private
|
217
223
|
def self.worksheet_class
|
218
224
|
@worksheet_class ||= begin
|
@@ -74,6 +74,14 @@ module RobustExcelOle
|
|
74
74
|
class WorkbookBeingUsed < WorkbookREOError
|
75
75
|
end
|
76
76
|
|
77
|
+
# @private
|
78
|
+
class WorkbookConnectingNotAliveError < WorkbookREOError
|
79
|
+
end
|
80
|
+
|
81
|
+
# @private
|
82
|
+
class WorkbookConnectingBlockingError < WorkbookREOError
|
83
|
+
end
|
84
|
+
|
77
85
|
# @private
|
78
86
|
class FileNotFound < FileREOError
|
79
87
|
end
|
@@ -14,7 +14,6 @@ module RobustExcelOle
|
|
14
14
|
attr_accessor :excel
|
15
15
|
attr_accessor :ole_workbook
|
16
16
|
attr_accessor :stored_filename
|
17
|
-
attr_accessor :options
|
18
17
|
attr_accessor :modified_cells
|
19
18
|
attr_reader :workbook
|
20
19
|
|
@@ -31,137 +30,116 @@ module RobustExcelOle
|
|
31
30
|
:update_links => :never
|
32
31
|
}.freeze
|
33
32
|
|
34
|
-
ABBREVIATIONS = [[:default,:d], [:force, :f], [:excel, :e], [:visible, :v]
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
book.ensure_excel(options) # unless book.excel.alive?
|
98
|
-
# if the ReadOnly status shall be changed, save, close and reopen it
|
99
|
-
if book.alive? && ((!book.writable && !(options[:read_only])) ||
|
100
|
-
(book.writable && options[:read_only]))
|
101
|
-
book.save if book.writable && !book.saved
|
102
|
-
book.close(:if_unsaved => :forget)
|
103
|
-
end
|
104
|
-
# reopens the book if it was closed
|
105
|
-
book.ensure_workbook(file,options) unless book.alive?
|
106
|
-
book.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
107
|
-
book.CheckCompatibility = options[:check_compatibility] unless options[:check_compatibility].nil?
|
108
|
-
book.excel.calculation = options[:calculation] unless options[:calculation].nil?
|
109
|
-
return book
|
110
|
-
end
|
33
|
+
ABBREVIATIONS = [[:default,:d], [:force, :f], [:excel, :e], [:visible, :v],
|
34
|
+
[:if_obstructed, :if_blocked]].freeze
|
35
|
+
|
36
|
+
|
37
|
+
# opens a workbook.
|
38
|
+
# @param [String] file the file name
|
39
|
+
# @param [Hash] opts the options
|
40
|
+
# @option opts [Hash] :default or :d
|
41
|
+
# @option opts [Hash] :force or :f
|
42
|
+
# @option opts [Symbol] :if_unsaved :raise (default), :forget, :accept, :alert, :excel, or :new_excel
|
43
|
+
# @option opts [Symbol] :if_obstructed :raise (default), :forget, :save, :close_if_saved, or _new_excel
|
44
|
+
# @option opts [Symbol] :if_absent :raise (default) or :create
|
45
|
+
# @option opts [Boolean] :read_only true (default) or false
|
46
|
+
# @option opts [Boolean] :update_links :never (default), :always, :alert
|
47
|
+
# @option opts [Boolean] :calculation :manual, :automatic, or nil (default)
|
48
|
+
# options:
|
49
|
+
# :default : if the workbook was already open before, then use (unchange) its properties,
|
50
|
+
# otherwise, i.e. if the workbook cannot be reopened, use the properties stated in :default
|
51
|
+
# :force : no matter whether the workbook was already open before, use the properties stated in :force
|
52
|
+
# :default and :force contain: :excel, :visible
|
53
|
+
# :excel :current (or :active or :reuse)
|
54
|
+
# -> connects to a running (the first opened) Excel instance,
|
55
|
+
# excluding the hidden Excel instance, if it exists,
|
56
|
+
# otherwise opens in a new Excel instance.
|
57
|
+
# :new -> opens in a new Excel instance
|
58
|
+
# <excel-instance> -> opens in the given Excel instance
|
59
|
+
# :visible true, false, or nil (default)
|
60
|
+
# alternatives: :default_excel, :force_excel, :visible, :d, :f, :e, :v
|
61
|
+
# :if_unsaved if an unsaved workbook with the same name is open, then
|
62
|
+
# :raise -> raises an exception
|
63
|
+
# :forget -> close the unsaved workbook, open the new workbook
|
64
|
+
# :accept -> lets the unsaved workbook open
|
65
|
+
# :alert or :excel -> gives control to Excel
|
66
|
+
# :new_excel -> opens the new workbook in a new Excel instance
|
67
|
+
# :if_obstructed if a workbook with the same name in a different path is open, then
|
68
|
+
# or :raise -> raises an exception
|
69
|
+
# :if_blocked :forget -> closes the old workbook, open the new workbook
|
70
|
+
# :save -> saves the old workbook, close it, open the new workbook
|
71
|
+
# :close_if_saved -> closes the old workbook and open the new workbook, if the old workbook is saved,
|
72
|
+
# otherwise raises an exception.
|
73
|
+
# :new_excel -> opens the new workbook in a new Excel instance
|
74
|
+
# :if_absent :raise -> raises an exception , if the file does not exists
|
75
|
+
# :create -> creates a new Excel file, if it does not exists
|
76
|
+
# :read_only true -> opens in read-only mode
|
77
|
+
# :visible true -> makes the workbook visible
|
78
|
+
# :check_compatibility true -> check compatibility when saving
|
79
|
+
# :update_links true -> user is being asked how to update links, false -> links are never updated
|
80
|
+
# @return [Workbook] a representation of a workbook
|
81
|
+
def self.open(file, opts = { }, &block)
|
82
|
+
raise(FileNameNotGiven, 'filename is nil') if file.nil?
|
83
|
+
raise(FileNotFound, "file #{General.absolute_path(file).inspect} is a directory") if File.directory?(file)
|
84
|
+
options = process_options(opts)
|
85
|
+
book = nil
|
86
|
+
if options[:force][:excel] != :new
|
87
|
+
# if readonly is true, then prefer a book that is given in force_excel if this option is set
|
88
|
+
forced_excel = if RUBY_PLATFORM !~ /java/
|
89
|
+
(options[:force][:excel].nil? || options[:force][:excel] == :current) ?
|
90
|
+
excel_class.new(:reuse => true) : excel_of(options[:force][:excel])
|
91
|
+
end
|
92
|
+
begin
|
93
|
+
book = if File.exists?(file)
|
94
|
+
bookstore.fetch(file, :prefer_writable => !(options[:read_only]),
|
95
|
+
:prefer_excel => (options[:read_only] ? forced_excel : nil))
|
111
96
|
end
|
97
|
+
rescue
|
98
|
+
trace "#{$!.message}"
|
112
99
|
end
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
if book && book.alive?
|
130
|
-
open(filename, opts)
|
131
|
-
#book.visible = opts[:force][:visible] unless opts[:force].nil? || opts[:force][:visible].nil?
|
132
|
-
#book.excel.calculation = opts[:calculation] unless opts[:calculation].nil?
|
133
|
-
#book.excel.displayalerts = opts[:calculation] unless opts[:calculation].nil?
|
100
|
+
if book
|
101
|
+
if (!(options[:force][:excel]) || (forced_excel == book.excel)) &&
|
102
|
+
!(book.alive? && !book.saved && (options[:if_unsaved] != :accept))
|
103
|
+
book.ensure_excel(options) # unless book.excel.alive?
|
104
|
+
# if the ReadOnly status shall be changed, save, close and reopen it
|
105
|
+
# removed the feature for the next time
|
106
|
+
if book.alive? && ((!book.writable && !(options[:read_only])) ||
|
107
|
+
(book.writable && options[:read_only]))
|
108
|
+
book.save if book.writable && !book.saved
|
109
|
+
book.close(:if_unsaved => :forget)
|
110
|
+
end
|
111
|
+
# reopens the book if it was closed
|
112
|
+
book.ensure_workbook(file,options) unless book.alive?
|
113
|
+
book.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
114
|
+
book.CheckCompatibility = options[:check_compatibility] unless options[:check_compatibility].nil?
|
115
|
+
book.excel.calculation = options[:calculation] unless options[:calculation].nil?
|
134
116
|
return book
|
135
|
-
else
|
136
|
-
super(filename,opts)
|
137
117
|
end
|
138
118
|
end
|
139
|
-
else
|
140
|
-
super
|
141
119
|
end
|
120
|
+
new(file, options, &block)
|
142
121
|
end
|
143
|
-
|
122
|
+
|
144
123
|
# creates a new Workbook object, if a file name is given
|
145
124
|
# Promotes the win32ole workbook to a Workbook object, if a win32ole-workbook is given
|
146
125
|
# @param [Variant] file_or_workbook file name or workbook
|
147
|
-
# @param [Hash] opts
|
126
|
+
# @param [Hash] opts
|
148
127
|
# @option opts [Symbol] see above
|
149
128
|
# @return [Workbook] a workbook
|
150
129
|
def initialize(file_or_workbook, options = { }, &block)
|
151
|
-
|
152
|
-
if file_or_workbook.is_a? WIN32OLE
|
130
|
+
options = self.class.process_options(options)
|
131
|
+
if file_or_workbook.is_a? WIN32OLE
|
153
132
|
workbook = file_or_workbook
|
154
133
|
@ole_workbook = workbook
|
155
134
|
# use the Excel instance where the workbook is opened
|
156
|
-
|
157
|
-
@excel = excel_class.new(
|
158
|
-
@excel.visible = options[force][:visible] unless options[:force][:visible].nil?
|
135
|
+
ole_excel = WIN32OLE.connect(workbook.Fullname).Application rescue nil
|
136
|
+
@excel = excel_class.new(ole_excel)
|
137
|
+
@excel.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
159
138
|
@excel.calculation = options[:calculation] unless options[:calculation].nil?
|
160
|
-
ensure_excel(options)
|
161
139
|
else
|
162
|
-
|
140
|
+
filename = file_or_workbook
|
163
141
|
ensure_excel(options)
|
164
|
-
ensure_workbook(
|
142
|
+
ensure_workbook(filename, options)
|
165
143
|
end
|
166
144
|
bookstore.store(self)
|
167
145
|
@modified_cells = []
|
@@ -177,7 +155,7 @@ module RobustExcelOle
|
|
177
155
|
end
|
178
156
|
end
|
179
157
|
|
180
|
-
private
|
158
|
+
private
|
181
159
|
|
182
160
|
# translates abbreviations and synonyms and merges with default options
|
183
161
|
def self.process_options(options, proc_opts = {:use_defaults => true})
|
@@ -241,45 +219,81 @@ module RobustExcelOle
|
|
241
219
|
public
|
242
220
|
|
243
221
|
# @private
|
244
|
-
|
222
|
+
# ensures an excel but not for jruby if current Excel shall be used
|
223
|
+
def ensure_excel(options)
|
224
|
+
excel_option = options[:force][:excel].nil? ? options[:default][:excel] : options[:force][:excel]
|
225
|
+
@excel = if excel_option == :new
|
226
|
+
excel_class.new(:reuse => false)
|
227
|
+
elsif excel_option.nil? || excel_option == :current
|
228
|
+
excel_class.new(:reuse => true) unless RUBY_PLATFORM =~ /java/
|
229
|
+
else #elsif excel_options.is_a?(WIN32OLE) || excel_option.is_a?(Excel) #excel_option.respond_to?(:Hwnd)
|
230
|
+
self.class.excel_of(excel_option)
|
231
|
+
end
|
245
232
|
if @excel && @excel.alive?
|
246
|
-
@excel.
|
247
|
-
|
233
|
+
@excel.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
234
|
+
@excel.calculation = options[:calculation] unless options[:calculation].nil?
|
248
235
|
end
|
249
|
-
excel_option = options[:force].nil? || options[:force][:excel].nil? ? options[:default][:excel] : options[:force][:excel]
|
250
|
-
@excel = self.class.excel_of(excel_option) unless excel_option == :current || excel_option == :new || excel_option == :reserved_new
|
251
|
-
excel_class.new(:reuse => false) if (excel_option == :reserved_new) && Excel.known_excel_instances.empty?
|
252
|
-
@excel = excel_class.new(:reuse => (excel_option == :current)) unless @excel && @excel.alive?
|
253
|
-
@excel
|
254
236
|
end
|
255
237
|
|
256
238
|
|
257
239
|
# @private
|
240
|
+
# restriction for jruby: does not manage conflicts with blocking or unsaved workbooks
|
258
241
|
def ensure_workbook(filename, options)
|
259
|
-
|
260
|
-
|
261
|
-
if File.directory?(filename)
|
262
|
-
raise(FileNotFound, "file #{General.absolute_path(filename).inspect} is a directory")
|
263
|
-
end
|
242
|
+
return if @ole_workook && alive?
|
243
|
+
filename = @stored_filename ? @stored_filename : filename
|
264
244
|
manage_nonexisting_file(filename,options)
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
245
|
+
if RUBY_PLATFORM =~ /java/ && (options[:force][:excel].nil? || options[:force][:excel] == :current)
|
246
|
+
begin
|
247
|
+
connect(filename,options)
|
248
|
+
rescue WorkbookConnectingNotAliveError
|
249
|
+
raise WorkbookNotSaved, "workbook is already open but not saved: #{File.basename(filename).inspect}"
|
250
|
+
rescue WorkbookConnectingBlockingError # can't find moniker
|
251
|
+
raise WorkbookBlocked, "can't open workbook #{filename}"+
|
252
|
+
"\nbecause it is being blocked by a workbook with the same name in a different path."
|
253
|
+
end
|
269
254
|
else
|
270
|
-
|
255
|
+
workbooks = @excel.Workbooks
|
256
|
+
@ole_workbook = workbooks.Item(File.basename(filename)) rescue nil if @ole_workbook.nil?
|
257
|
+
if @ole_workbook
|
258
|
+
manage_blocking_or_unsaved_workbook(filename,options)
|
259
|
+
else
|
260
|
+
if options[:force][:excel].nil? || options[:force][:excel] == :current
|
261
|
+
connect(filename,options)
|
262
|
+
else
|
263
|
+
open_or_create_workbook(filename,options)
|
264
|
+
end
|
265
|
+
end
|
271
266
|
end
|
267
|
+
set_options(options)
|
272
268
|
end
|
273
269
|
|
274
270
|
private
|
275
271
|
|
276
272
|
# @private
|
277
|
-
|
273
|
+
# connects to an unknown workbook and returns true, if it exists
|
274
|
+
def connect(filename,options)
|
275
|
+
abs_filename = General.absolute_path(filename).tr('/','\\')
|
276
|
+
@ole_workbook = begin
|
277
|
+
WIN32OLE.connect(abs_filename)
|
278
|
+
rescue
|
279
|
+
raise WorkbookConnectingBlockingError
|
280
|
+
end
|
281
|
+
ole_excel = begin
|
282
|
+
WIN32OLE.connect(@ole_workbook.Fullname).Application
|
283
|
+
rescue
|
284
|
+
raise WorkbookConnectingNotAliveError
|
285
|
+
end
|
286
|
+
@excel = excel_class.new(ole_excel)
|
287
|
+
end
|
288
|
+
|
289
|
+
# @private
|
290
|
+
def manage_nonexisting_file(filename,options)
|
278
291
|
return if File.exist?(filename)
|
292
|
+
abs_filename = General.absolute_path(filename).tr('/','\\')
|
279
293
|
if options[:if_absent] == :create
|
280
|
-
excel.
|
294
|
+
ensure_excel({:force[:excel] => :new}.merge(options)) if RUBY_PLATFORM !~ /java/
|
295
|
+
@excel.Workbooks.Add
|
281
296
|
empty_ole_workbook = excel.Workbooks.Item(excel.Workbooks.Count)
|
282
|
-
abs_filename = General.absolute_path(filename).tr('/','\\')
|
283
297
|
begin
|
284
298
|
empty_ole_workbook.SaveAs(abs_filename)
|
285
299
|
rescue # WIN32OLERuntimeError => msg
|
@@ -310,7 +324,7 @@ module RobustExcelOle
|
|
310
324
|
manage_blocking_workbook(filename,options)
|
311
325
|
else
|
312
326
|
unless @ole_workbook.Saved
|
313
|
-
|
327
|
+
# workbook open and writable, not obstructed by another workbook, but not saved
|
314
328
|
manage_unsaved_workbook(filename,options)
|
315
329
|
end
|
316
330
|
end
|
@@ -320,12 +334,13 @@ module RobustExcelOle
|
|
320
334
|
def manage_blocking_workbook(filename,options)
|
321
335
|
case options[:if_obstructed]
|
322
336
|
when :raise
|
323
|
-
raise WorkbookBlocked, "
|
324
|
-
|
325
|
-
|
326
|
-
|
337
|
+
raise WorkbookBlocked, "can't open workbook #{filename},
|
338
|
+
because it is being blocked by #{@ole_workbook.Fullname.tr('\\','/')} with the same name in a different path." +
|
339
|
+
"\nHint: Use the option :if_blocked with values :forget or :save,
|
340
|
+
to allow automatic closing of the old workbook (without or with saving before, respectively),
|
341
|
+
before the new workbook is being opened."
|
327
342
|
when :forget
|
328
|
-
@ole_workbook.Close
|
343
|
+
@excel.with_displayalerts(false) { @ole_workbook.Close }
|
329
344
|
@ole_workbook = nil
|
330
345
|
open_or_create_workbook(filename, options)
|
331
346
|
when :save
|
@@ -345,11 +360,12 @@ module RobustExcelOle
|
|
345
360
|
@excel = excel_class.new(:reuse => false)
|
346
361
|
open_or_create_workbook(filename, options)
|
347
362
|
else
|
348
|
-
raise OptionInvalid, ":
|
363
|
+
raise OptionInvalid, ":if_blocked: invalid option: #{options[:if_obstructed].inspect}" +
|
349
364
|
"\nHint: Valid values are :raise, :forget, :save, :close_if_saved, :new_excel"
|
350
365
|
end
|
351
366
|
end
|
352
367
|
|
368
|
+
# @private
|
353
369
|
def manage_unsaved_workbook(filename,options)
|
354
370
|
case options[:if_unsaved]
|
355
371
|
when :raise
|
@@ -357,7 +373,7 @@ module RobustExcelOle
|
|
357
373
|
"\nHint: Save the workbook or open the workbook using option :if_unsaved with values :forget and :accept to
|
358
374
|
close the unsaved workbook and reopen it, or to let the unsaved workbook open, respectively"
|
359
375
|
when :forget
|
360
|
-
@ole_workbook.Close
|
376
|
+
@excel.with_displayalerts(false) { @ole_workbook.Close }
|
361
377
|
@ole_workbook = nil
|
362
378
|
open_or_create_workbook(filename, options)
|
363
379
|
when :accept
|
@@ -373,8 +389,6 @@ module RobustExcelOle
|
|
373
389
|
end
|
374
390
|
end
|
375
391
|
|
376
|
-
private
|
377
|
-
|
378
392
|
# @private
|
379
393
|
def open_or_create_workbook(filename, options)
|
380
394
|
if !@ole_workbook || (options[:if_unsaved] == :alert) || options[:if_obstructed]
|
@@ -404,18 +418,6 @@ module RobustExcelOle
|
|
404
418
|
rescue WIN32OLERuntimeError => msg
|
405
419
|
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message}"
|
406
420
|
end
|
407
|
-
if options[:force][:visible].nil? && !options[:default][:visible].nil?
|
408
|
-
if @excel.created
|
409
|
-
self.visible = options[:default][:visible]
|
410
|
-
else
|
411
|
-
self.window_visible = options[:default][:visible]
|
412
|
-
end
|
413
|
-
else
|
414
|
-
self.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
415
|
-
end
|
416
|
-
@ole_workbook.CheckCompatibility = options[:check_compatibility]
|
417
|
-
@excel.calculation = options[:calculation] unless options[:calculation].nil?
|
418
|
-
self.Saved = true # unless self.Saved # ToDo: this is too hard
|
419
421
|
rescue WIN32OLERuntimeError => msg
|
420
422
|
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message} #{msg.backtrace}"
|
421
423
|
end
|
@@ -423,6 +425,23 @@ module RobustExcelOle
|
|
423
425
|
end
|
424
426
|
end
|
425
427
|
|
428
|
+
# @private
|
429
|
+
def set_options(options)
|
430
|
+
if options[:force][:visible].nil? && !options[:default][:visible].nil?
|
431
|
+
if @excel.created
|
432
|
+
self.visible = options[:default][:visible]
|
433
|
+
else
|
434
|
+
self.window_visible = options[:default][:visible]
|
435
|
+
end
|
436
|
+
else
|
437
|
+
self.visible = options[:force][:visible] unless options[:force][:visible].nil?
|
438
|
+
end
|
439
|
+
@excel.calculation = options[:calculation] unless options[:calculation].nil?
|
440
|
+
@ole_workbook.CheckCompatibility = options[:check_compatibility]
|
441
|
+
@ole_workbook.Saved = true # unless self.Saved # ToDo: this is too hard
|
442
|
+
end
|
443
|
+
|
444
|
+
# @private
|
426
445
|
# translating the option UpdateLinks from REO to VBA
|
427
446
|
# setting UpdateLinks works only if calculation mode is automatic,
|
428
447
|
# parameter 'UpdateLinks' has no effect
|
@@ -435,6 +454,7 @@ module RobustExcelOle
|
|
435
454
|
end
|
436
455
|
end
|
437
456
|
|
457
|
+
# @private
|
438
458
|
# workaround for linked workbooks for Excel 2007:
|
439
459
|
# opening and closing a dummy workbook if Excel has no workbooks.
|
440
460
|
# delay: with visible: 0.2 sec, without visible almost none
|
@@ -504,6 +524,7 @@ module RobustExcelOle
|
|
504
524
|
|
505
525
|
private
|
506
526
|
|
527
|
+
# @private
|
507
528
|
def close_workbook
|
508
529
|
@ole_workbook.Close if alive?
|
509
530
|
@ole_workbook = nil unless alive?
|
@@ -537,9 +558,9 @@ module RobustExcelOle
|
|
537
558
|
unobtrusively(*args, &block)
|
538
559
|
end
|
539
560
|
|
561
|
+
|
540
562
|
# allows to read or modify a workbook such that its state remains unchanged
|
541
563
|
# state comprises: open, saved, writable, visible, calculation mode, check compatibility
|
542
|
-
# remarks: works only for workbooks opened with RobustExcelOle
|
543
564
|
# @param [String] file the file name
|
544
565
|
# @param [Hash] opts the options
|
545
566
|
# @option opts [Variant] :if_closed :current (default), :new or an Excel instance
|
@@ -557,7 +578,7 @@ module RobustExcelOle
|
|
557
578
|
prefer_writable = ((!(opts[:read_only]) || opts[:writable] == true) &&
|
558
579
|
!(opts[:read_only].nil? && opts[:writable] == false))
|
559
580
|
do_not_write = (opts[:read_only] || (opts[:read_only].nil? && opts[:writable] == false))
|
560
|
-
book = bookstore.fetch(file, :prefer_writable => prefer_writable)
|
581
|
+
book = bookstore.fetch(file, :prefer_writable => prefer_writable)
|
561
582
|
was_open = book && book.alive?
|
562
583
|
if was_open
|
563
584
|
was_saved = book.saved
|
@@ -746,7 +767,11 @@ module RobustExcelOle
|
|
746
767
|
# closes a given file if it is open
|
747
768
|
# @options opts [Symbol] :if_unsaved
|
748
769
|
def self.close(file, opts = {:if_unsaved => :raise})
|
749
|
-
book =
|
770
|
+
book = begin
|
771
|
+
bookstore.fetch(file)
|
772
|
+
rescue
|
773
|
+
nil
|
774
|
+
end
|
750
775
|
book.close(opts) if book && book.alive?
|
751
776
|
end
|
752
777
|
|
@@ -758,7 +783,11 @@ module RobustExcelOle
|
|
758
783
|
|
759
784
|
# saves a given file under a new name if it is open
|
760
785
|
def self.save_as(file, new_file, opts = { })
|
761
|
-
book =
|
786
|
+
book = begin
|
787
|
+
bookstore.fetch(file)
|
788
|
+
rescue
|
789
|
+
nil
|
790
|
+
end
|
762
791
|
book.save_as(new_file, opts) if book && book.alive?
|
763
792
|
end
|
764
793
|
|
@@ -807,11 +836,12 @@ module RobustExcelOle
|
|
807
836
|
sheet.Copy({ after_or_before.to_s => base_sheet.ole_worksheet })
|
808
837
|
else
|
809
838
|
@ole_workbook.Worksheets.Add({ after_or_before.to_s => base_sheet.ole_worksheet })
|
839
|
+
#@ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count).Activate
|
810
840
|
end
|
811
841
|
else
|
812
842
|
# workaround for jruby
|
813
843
|
if after_or_before == :before
|
814
|
-
if sheet
|
844
|
+
if sheet
|
815
845
|
sheet.Copy(base_sheet.ole_worksheet)
|
816
846
|
else
|
817
847
|
ole_workbook.Worksheets.Add(base_sheet.ole_worksheet)
|
@@ -835,10 +865,14 @@ module RobustExcelOle
|
|
835
865
|
end
|
836
866
|
end
|
837
867
|
end
|
838
|
-
rescue WIN32OLERuntimeError
|
839
|
-
|
868
|
+
rescue #WIN32OLERuntimeError
|
869
|
+
trace "#{$!.message}"
|
870
|
+
raise WorksheetREOError, "could not add given worksheet #{sheet.inspect}"
|
840
871
|
end
|
841
|
-
|
872
|
+
#ole_sheet = @excel.Activesheet
|
873
|
+
ole_sheet = ole_workbook.Activesheet
|
874
|
+
#ole_sheet = ole_sheet.nil? ? ole_workbook.Worksheets.Item(ole_workbook.Worksheets.Count) : ole_sheet
|
875
|
+
new_sheet = worksheet_class.new(ole_sheet)
|
842
876
|
new_sheet.name = new_sheet_name if new_sheet_name
|
843
877
|
new_sheet
|
844
878
|
end
|
@@ -942,8 +976,10 @@ module RobustExcelOle
|
|
942
976
|
end
|
943
977
|
|
944
978
|
# makes both the Excel instance and the window of the workbook visible, or the window invisible
|
979
|
+
# does not do anything if geben visible_value is nil
|
945
980
|
# @param [Boolean] visible_value determines whether the workbook shall be visible
|
946
981
|
def visible= visible_value
|
982
|
+
return if visible_value.nil?
|
947
983
|
@excel.visible = true if visible_value
|
948
984
|
self.window_visible = visible_value
|
949
985
|
end
|