robust_excel_ole 1.27 → 1.32
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.
- checksums.yaml +4 -4
- data/Changelog +36 -2
- data/README.rdoc +121 -19
- data/___dummy_workbook.xls +0 -0
- data/benchmarking/creek_example.rb +1 -1
- data/benchmarking/reo_example.rb +1 -1
- data/benchmarking/reo_example1.rb +1 -1
- data/benchmarking/reo_example2.rb +1 -1
- data/benchmarking/roo_example.rb +1 -1
- data/benchmarking/simple_xlsx_reader_example.rb +1 -1
- data/benchmarking/spreadsheet_example.rb +1 -1
- data/bin/jreo +19 -0
- data/bin/reo +19 -0
- data/docs/README_excel.rdoc +16 -24
- data/docs/README_listobjects.rdoc +176 -0
- data/docs/README_open.rdoc +20 -16
- data/docs/README_ranges.rdoc +72 -55
- data/docs/README_save_close.rdoc +3 -3
- data/docs/README_sheet.rdoc +19 -20
- data/examples/example_ruby_library.rb +2 -2
- data/examples/introductory_examples/example_open.rb +11 -0
- data/examples/introductory_examples/example_range.rb +2 -2
- data/examples/modifying_sheets/example_access_sheets_and_cells.rb +6 -6
- data/examples/modifying_sheets/example_add_names.rb +1 -1
- data/examples/modifying_sheets/example_concating.rb +1 -1
- data/examples/modifying_sheets/example_copying.rb +2 -2
- data/examples/modifying_sheets/example_listobjects.rb +86 -0
- data/examples/modifying_sheets/example_naming.rb +1 -1
- data/examples/modifying_sheets/example_ranges.rb +1 -1
- data/examples/open_save_close/example_control_to_excel.rb +1 -1
- data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +1 -1
- data/examples/open_save_close/example_if_obstructed_save.rb +3 -3
- data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
- data/examples/open_save_close/example_if_unsaved_forget.rb +3 -3
- data/examples/open_save_close/example_if_unsaved_forget_more.rb +4 -4
- data/examples/open_save_close/example_read_only.rb +1 -1
- data/examples/open_save_close/example_simple.rb +1 -1
- data/examples/open_save_close/example_unobtrusively.rb +3 -3
- data/lib/robust_excel_ole.rb +19 -16
- data/lib/robust_excel_ole/address_tool.rb +54 -44
- data/lib/robust_excel_ole/base.rb +9 -6
- data/lib/robust_excel_ole/bookstore.rb +3 -17
- data/lib/robust_excel_ole/cell.rb +17 -22
- data/lib/robust_excel_ole/cygwin.rb +2 -0
- data/lib/robust_excel_ole/excel.rb +136 -201
- data/lib/robust_excel_ole/general.rb +249 -238
- data/lib/robust_excel_ole/list_object.rb +186 -210
- data/lib/robust_excel_ole/list_row.rb +155 -0
- data/lib/robust_excel_ole/range.rb +130 -94
- data/lib/robust_excel_ole/range_owners.rb +54 -135
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +230 -196
- data/lib/robust_excel_ole/worksheet.rb +254 -133
- data/lib/spec_helper.rb +1 -1
- data/robust_excel_ole.gemspec +4 -3
- data/spec/address_tool_spec.rb +2 -2
- data/spec/base_spec.rb +19 -17
- data/spec/bookstore_spec.rb +3 -4
- data/spec/cell_spec.rb +10 -10
- data/spec/cygwin_spec.rb +1 -1
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/excel_spec.rb +133 -86
- data/spec/general_spec.rb +79 -18
- data/spec/list_object_spec.rb +259 -81
- data/spec/list_row_spec.rb +218 -0
- data/spec/range_spec.rb +75 -41
- data/spec/spec_helper.rb +16 -2
- data/spec/workbook_spec.rb +87 -46
- data/spec/workbook_specs/workbook_all_spec.rb +9 -28
- data/spec/workbook_specs/workbook_close_spec.rb +1 -1
- data/spec/workbook_specs/workbook_misc_spec.rb +52 -45
- data/spec/workbook_specs/workbook_open_spec.rb +103 -50
- data/spec/workbook_specs/workbook_save_spec.rb +22 -23
- data/spec/workbook_specs/workbook_sheet_spec.rb +4 -4
- data/spec/workbook_specs/workbook_subclass_spec.rb +1 -1
- data/spec/workbook_specs/workbook_unobtr_spec.rb +553 -395
- data/spec/worksheet_spec.rb +544 -308
- metadata +38 -3
- data/lib/reo_console.rb +0 -42
@@ -14,17 +14,15 @@ module RobustExcelOle
|
|
14
14
|
# @param [Hash] opts the options
|
15
15
|
# @option opts [Symbol] :default the default value that is provided if no contents could be returned
|
16
16
|
# @return [Variant] the contents of a range with given name
|
17
|
-
def
|
17
|
+
def namevalue_global(name, opts = { default: :__not_provided })
|
18
18
|
name_obj = begin
|
19
|
-
|
19
|
+
get_name_object(name)
|
20
20
|
rescue NameNotFound => msg
|
21
|
-
return opts[:default] unless opts[:default] == :__not_provided
|
22
21
|
raise
|
23
22
|
end
|
24
23
|
ole_range = name_obj.RefersToRange
|
25
24
|
worksheet = self if self.is_a?(Worksheet)
|
26
25
|
value = begin
|
27
|
-
#name_obj.RefersToRange.Value
|
28
26
|
if !::RANGES_JRUBY_BUG
|
29
27
|
ole_range.Value
|
30
28
|
else
|
@@ -33,11 +31,9 @@ module RobustExcelOle
|
|
33
31
|
end
|
34
32
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
35
33
|
sheet = if self.is_a?(Worksheet) then self
|
36
|
-
|
37
|
-
elsif self.is_a?(Excel) then self.workbook.sheet(1)
|
34
|
+
elsif self.is_a?(Workbook) then self.sheet(1)
|
38
35
|
end
|
39
36
|
begin
|
40
|
-
#sheet.Evaluate(name_obj.Name).Value
|
41
37
|
# does it result in a range?
|
42
38
|
ole_range = sheet.Evaluate(name_obj.Name)
|
43
39
|
if !::RANGES_JRUBY_BUG
|
@@ -63,111 +59,42 @@ module RobustExcelOle
|
|
63
59
|
# @param [String] name the name of a range
|
64
60
|
# @param [Variant] value the contents of the range
|
65
61
|
# @option opts [Symbol] :color the color of the range when set
|
66
|
-
def
|
67
|
-
begin
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value )
|
83
|
-
end
|
62
|
+
def set_namevalue_global(name, value, opts = { })
|
63
|
+
name_obj = begin
|
64
|
+
get_name_object(name)
|
65
|
+
rescue NameNotFound => msg
|
66
|
+
raise
|
67
|
+
end
|
68
|
+
ole_range = name_obj.RefersToRange
|
69
|
+
ole_range.Interior.ColorIndex = opts[:color] unless opts[:color].nil?
|
70
|
+
if !::RANGES_JRUBY_BUG
|
71
|
+
ole_range.Value = value
|
72
|
+
else
|
73
|
+
address_r1c1 = ole_range.AddressLocal(true,true,XlR1C1)
|
74
|
+
row, col = address_tool.as_integer_ranges(address_r1c1)
|
75
|
+
row.each_with_index do |r,i|
|
76
|
+
col.each_with_index do |c,j|
|
77
|
+
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:pop) ? value[i][j] : value )
|
84
78
|
end
|
85
79
|
end
|
86
|
-
value
|
87
|
-
rescue #WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
88
|
-
raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{self.inspect}"
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# returns the contents of a range with a locally defined name
|
93
|
-
# evaluates the formula if the contents is a formula
|
94
|
-
# if the name could not be found or the range or value could not be determined,
|
95
|
-
# then return default value, if provided, raise error otherwise
|
96
|
-
# @param [String] name the name of a range
|
97
|
-
# @param [Hash] opts the options
|
98
|
-
# @option opts [Symbol] :default the default value that is provided if no contents could be returned
|
99
|
-
# @return [Variant] the contents of a range with given name
|
100
|
-
def namevalue(name, opts = { :default => :__not_provided })
|
101
|
-
return namevalue_glob(name, opts) if self.is_a?(Workbook)
|
102
|
-
begin
|
103
|
-
ole_range = self.Range(name)
|
104
|
-
rescue # WIN32OLERuntimeError, VBAMethodMissingError, Java::OrgRacobCom::ComFailException
|
105
|
-
return opts[:default] unless opts[:default] == :__not_provided
|
106
|
-
raise NameNotFound, "name #{name.inspect} not in #{self.inspect}"
|
107
|
-
end
|
108
|
-
begin
|
109
|
-
worksheet = self if self.is_a?(Worksheet)
|
110
|
-
#value = ole_range.Value
|
111
|
-
value = if !::RANGES_JRUBY_BUG
|
112
|
-
ole_range.Value
|
113
|
-
else
|
114
|
-
values = RobustExcelOle::Range.new(ole_range, worksheet).v
|
115
|
-
(values.size==1 && values.first.size==1) ? values.first.first : values
|
116
|
-
end
|
117
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
118
|
-
return opts[:default] unless opts[:default] == :__not_provided
|
119
|
-
raise RangeNotEvaluatable, "cannot determine value of range named #{name.inspect} in #{self.inspect}"
|
120
|
-
end
|
121
|
-
if value == -2146828288 + RobustExcelOle::XlErrName
|
122
|
-
return opts[:default] unless opts[:default] == __not_provided
|
123
|
-
raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{File.basename(workbook.stored_filename).inspect rescue nil}"
|
124
80
|
end
|
125
|
-
return opts[:default] unless (opts[:default] == :__not_provided) || value.nil?
|
126
81
|
value
|
127
|
-
|
128
|
-
|
129
|
-
# assigns a value to a range given a locally defined name
|
130
|
-
# @param [String] name the name of a range
|
131
|
-
# @param [Variant] value the assigned value
|
132
|
-
# @option opts [Symbol] :color the color of the cell when set
|
133
|
-
def set_namevalue(name, value, opts = { })
|
134
|
-
begin
|
135
|
-
return set_namevalue_glob(name, value, opts) if self.is_a?(Workbook)
|
136
|
-
ole_range = self.Range(name)
|
137
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException, VBAMethodMissingError
|
138
|
-
raise NameNotFound, "name #{name.inspect} not in #{self.inspect}"
|
139
|
-
end
|
140
|
-
begin
|
141
|
-
ole_range.Interior.ColorIndex = opts[:color] unless opts[:color].nil?
|
142
|
-
if !::RANGES_JRUBY_BUG
|
143
|
-
ole_range.Value = value
|
144
|
-
else
|
145
|
-
address_r1c1 = ole_range.AddressLocal(true,true,XlR1C1)
|
146
|
-
row, col = address_tool.as_integer_ranges(address_r1c1)
|
147
|
-
row.each_with_index do |r,i|
|
148
|
-
col.each_with_index do |c,j|
|
149
|
-
ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value)
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
value
|
154
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
155
|
-
raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{self.inspect}"
|
156
|
-
end
|
82
|
+
rescue #WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
83
|
+
raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{self.inspect}\n#{$!.message}"
|
157
84
|
end
|
158
85
|
|
159
86
|
# @private
|
160
|
-
def nameval(name, opts = { :
|
161
|
-
|
87
|
+
def nameval(name, opts = { default: :__not_provided }) # :deprecated: #
|
88
|
+
namevalue_global(name, opts)
|
162
89
|
end
|
163
90
|
|
164
91
|
# @private
|
165
92
|
def set_nameval(name, value) # :deprecated: #
|
166
|
-
|
93
|
+
set_namevalue_global(name, value)
|
167
94
|
end
|
168
95
|
|
169
96
|
# @private
|
170
|
-
def rangeval(name, opts = { :
|
97
|
+
def rangeval(name, opts = { default: :__not_provided }) # :deprecated: #
|
171
98
|
namevalue(name, opts)
|
172
99
|
end
|
173
100
|
|
@@ -192,53 +119,45 @@ module RobustExcelOle
|
|
192
119
|
# @params [Address] address of the range
|
193
120
|
def add_name(name, addr, addr_deprecated = :__not_provided)
|
194
121
|
addr = [addr,addr_deprecated] unless addr_deprecated == :__not_provided
|
195
|
-
|
196
|
-
self.Names.Add(name, nil, true, nil, nil, nil, nil, nil, nil, '=' + address_tool.as_r1c1(addr))
|
197
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
198
|
-
raise RangeNotEvaluatable, "cannot add name #{name.inspect} to range #{addr.inspect}"
|
199
|
-
end
|
122
|
+
self.Names.Add(name, nil, true, nil, nil, nil, nil, nil, nil, '=' + address_tool.as_r1c1(addr))
|
200
123
|
name
|
124
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
125
|
+
raise RangeNotEvaluatable, "cannot add name #{name.inspect} to range #{addr.inspect}\n#{$!.message}"
|
201
126
|
end
|
202
127
|
|
203
|
-
|
204
|
-
|
128
|
+
alias set_name add_name # :deprecated :#
|
129
|
+
|
130
|
+
# renames an Excel object
|
131
|
+
# @param [String] old_name the previous name of the Excel object
|
132
|
+
# @param [String] new_name the new name of the Excel object
|
133
|
+
def rename_name(old_name, new_name)
|
134
|
+
item = get_name_object(old_name)
|
135
|
+
item.Name = new_name
|
136
|
+
rescue RobustExcelOle::NameNotFound
|
137
|
+
raise
|
138
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
139
|
+
raise UnexpectedREOError, "name error with name #{old_name.inspect} in #{File.basename(self.stored_filename).inspect}\n#{$!.message}"
|
205
140
|
end
|
206
141
|
|
207
|
-
#
|
208
|
-
# @param [String] name the previous range name
|
209
|
-
# @param [String] new_name the new range name
|
210
|
-
def rename_range(name, new_name)
|
211
|
-
begin
|
212
|
-
item = self.Names.Item(name)
|
213
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
214
|
-
raise NameNotFound, "name #{name.inspect} not in #{File.basename(self.stored_filename).inspect}"
|
215
|
-
end
|
216
|
-
begin
|
217
|
-
item.Name = new_name
|
218
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
219
|
-
raise UnexpectedREOError, "name error in #{File.basename(self.stored_filename).inspect}"
|
220
|
-
end
|
221
|
-
end
|
142
|
+
alias rename_range rename_name # :deprecated :#
|
222
143
|
|
223
|
-
# deletes a name of
|
224
|
-
# @param [String] name
|
225
|
-
# @param [String] new_name the new range name
|
144
|
+
# deletes a name of an Excel object
|
145
|
+
# @param [String] name the name of the Excel object
|
226
146
|
def delete_name(name)
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
end
|
147
|
+
item = get_name_object(name)
|
148
|
+
item.Delete
|
149
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException
|
150
|
+
raise UnexpectedREOError, "name error with name #{name.inspect} in #{File.basename(self.stored_filename).inspect}\n#{$!.message}"
|
151
|
+
end
|
152
|
+
|
153
|
+
# @return [Array] defined names
|
154
|
+
def names
|
155
|
+
self.Names.to_a.map(&:name)
|
156
|
+
end
|
238
157
|
|
239
158
|
private
|
240
159
|
|
241
|
-
def
|
160
|
+
def get_name_object(name)
|
242
161
|
self.Names.Item(name)
|
243
162
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException, VBAMethodMissingError
|
244
163
|
begin
|
@@ -11,25 +11,27 @@ module RobustExcelOle
|
|
11
11
|
|
12
12
|
class Workbook < RangeOwners
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
include Enumerable
|
15
|
+
|
16
16
|
attr_reader :ole_workbook
|
17
17
|
attr_reader :excel
|
18
18
|
attr_reader :stored_filename
|
19
19
|
|
20
20
|
alias ole_object ole_workbook
|
21
21
|
|
22
|
+
using ToReoRefinement
|
23
|
+
|
22
24
|
CORE_DEFAULT_OPEN_OPTS = {
|
23
|
-
:
|
24
|
-
:
|
25
|
-
:
|
25
|
+
default: {excel: :current},
|
26
|
+
force: {},
|
27
|
+
update_links: :never
|
26
28
|
}.freeze
|
27
29
|
|
28
30
|
DEFAULT_OPEN_OPTS = {
|
29
|
-
:
|
30
|
-
:
|
31
|
-
:
|
32
|
-
:
|
31
|
+
if_unsaved: :raise,
|
32
|
+
if_obstructed: :raise,
|
33
|
+
if_absent: :raise,
|
34
|
+
if_exists: :raise
|
33
35
|
}.merge(CORE_DEFAULT_OPEN_OPTS).freeze
|
34
36
|
|
35
37
|
ABBREVIATIONS = [
|
@@ -42,7 +44,7 @@ module RobustExcelOle
|
|
42
44
|
|
43
45
|
|
44
46
|
# opens a workbook.
|
45
|
-
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
47
|
+
# @param [String,Pathname] file_or_workbook a file name (string or pathname) or WIN32OLE workbook
|
46
48
|
# @param [Hash] opts the options
|
47
49
|
# @option opts [Hash] :default or :d
|
48
50
|
# @option opts [Hash] :force or :f
|
@@ -89,7 +91,7 @@ module RobustExcelOle
|
|
89
91
|
process_options(opts)
|
90
92
|
case file_or_workbook
|
91
93
|
when NilClass
|
92
|
-
raise FileNameNotGiven,
|
94
|
+
raise FileNameNotGiven, "filename is nil"
|
93
95
|
when WIN32OLE
|
94
96
|
file = file_or_workbook.Fullname.tr('\\','/')
|
95
97
|
when Workbook
|
@@ -101,7 +103,7 @@ module RobustExcelOle
|
|
101
103
|
file = file_or_workbook.to_path
|
102
104
|
raise FileNotFound, "file #{General.absolute_path(file).inspect} is a directory" if File.directory?(file)
|
103
105
|
else
|
104
|
-
raise TypeREOError,
|
106
|
+
raise TypeREOError, "given object is neither a filename, a Win32ole, nor a Workbook object"
|
105
107
|
end
|
106
108
|
# try to fetch the workbook from the bookstore
|
107
109
|
set_was_open opts, file_or_workbook.is_a?(WIN32OLE)
|
@@ -110,14 +112,14 @@ module RobustExcelOle
|
|
110
112
|
# if readonly is true, then prefer a book that is given in force_excel if this option is set
|
111
113
|
forced_excel = begin
|
112
114
|
(opts[:force][:excel].nil? || opts[:force][:excel] == :current) ?
|
113
|
-
(excel_class.new(:
|
115
|
+
(excel_class.new(reuse: true) if !::CONNECT_JRUBY_BUG) : opts[:force][:excel].to_reo.excel
|
114
116
|
rescue NoMethodError
|
115
117
|
raise TypeREOError, "provided Excel option value is neither an Excel object nor a valid option"
|
116
118
|
end
|
117
119
|
begin
|
118
120
|
book = if File.exists?(file)
|
119
|
-
bookstore.fetch(file, :
|
120
|
-
:
|
121
|
+
bookstore.fetch(file, prefer_writable: !(opts[:read_only]),
|
122
|
+
prefer_excel: (opts[:read_only] ? forced_excel : nil))
|
121
123
|
end
|
122
124
|
rescue
|
123
125
|
raise
|
@@ -153,12 +155,12 @@ module RobustExcelOle
|
|
153
155
|
ole_excel = begin
|
154
156
|
@ole_workbook.Application
|
155
157
|
rescue WIN32OLERuntimeError
|
156
|
-
raise ExcelREOError,
|
158
|
+
raise ExcelREOError, "could not determine the Excel instance\n#{$!.message}"
|
157
159
|
end
|
158
160
|
@excel = excel_class.new(ole_excel)
|
159
161
|
filename = @ole_workbook.Fullname.tr('\\','/')
|
160
162
|
else
|
161
|
-
filename = file_or_workbook
|
163
|
+
filename = file_or_workbook
|
162
164
|
ensure_workbook(filename, opts)
|
163
165
|
end
|
164
166
|
apply_options(filename, opts)
|
@@ -182,7 +184,7 @@ module RobustExcelOle
|
|
182
184
|
self.class.set_was_open(hash, value)
|
183
185
|
end
|
184
186
|
|
185
|
-
def self.process_options(opts, proc_opts = {:
|
187
|
+
def self.process_options(opts, proc_opts = {use_defaults: true})
|
186
188
|
translate(opts)
|
187
189
|
default_opts = (proc_opts[:use_defaults] ? DEFAULT_OPEN_OPTS : CORE_DEFAULT_OPEN_OPTS).dup
|
188
190
|
translate(default_opts)
|
@@ -224,9 +226,9 @@ module RobustExcelOle
|
|
224
226
|
return if @excel && @excel.alive?
|
225
227
|
excel_option = options[:force][:excel] || options[:default][:excel] || :current
|
226
228
|
@excel = if excel_option == :new
|
227
|
-
excel_class.new(:
|
229
|
+
excel_class.new(reuse: false)
|
228
230
|
elsif excel_option == :current
|
229
|
-
excel_class.new(:
|
231
|
+
excel_class.new(reuse: true)
|
230
232
|
elsif excel_option.respond_to?(:to_reo)
|
231
233
|
excel_option.to_reo.excel
|
232
234
|
else
|
@@ -235,13 +237,12 @@ module RobustExcelOle
|
|
235
237
|
raise ExcelREOError, "Excel is not alive" unless @excel && @excel.alive?
|
236
238
|
end
|
237
239
|
|
238
|
-
|
239
240
|
# @private
|
240
|
-
def ensure_workbook(filename, options)
|
241
|
+
def ensure_workbook(filename, options)
|
241
242
|
set_was_open options, true
|
242
243
|
return if (@ole_workbook && alive? && (options[:read_only].nil? || @ole_workbook.ReadOnly == options[:read_only]))
|
243
244
|
set_was_open options, false
|
244
|
-
if options[:if_unsaved]==:accept &&
|
245
|
+
if options[:if_unsaved]==:accept && alive? &&
|
245
246
|
((options[:read_only]==true && self.ReadOnly==false) || (options[:read_only]==false && self.ReadOnly==true))
|
246
247
|
raise OptionInvalid, ":if_unsaved:accept and change of read-only mode is not possible"
|
247
248
|
end
|
@@ -254,7 +255,7 @@ module RobustExcelOle
|
|
254
255
|
if @ole_workbook && alive?
|
255
256
|
set_was_open options, true
|
256
257
|
manage_blocking_or_unsaved_workbook(filename,options)
|
257
|
-
open_or_create_workbook(filename,options) if
|
258
|
+
open_or_create_workbook(filename,options) if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
258
259
|
else
|
259
260
|
if (excel_option.nil? || excel_option == :current) &&
|
260
261
|
!(::CONNECT_JRUBY_BUG && filename[0] == '/')
|
@@ -270,7 +271,6 @@ module RobustExcelOle
|
|
270
271
|
# applies options to workbook named with filename
|
271
272
|
def apply_options(filename, options)
|
272
273
|
# changing read-only mode
|
273
|
-
#ensure_workbook(filename, options) if options[:read_only] && options[:read_only] != @ole_workbook.ReadOnly
|
274
274
|
if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
275
275
|
ensure_workbook(filename, options)
|
276
276
|
end
|
@@ -283,14 +283,14 @@ module RobustExcelOle
|
|
283
283
|
|
284
284
|
# connects to an unknown workbook
|
285
285
|
def connect(filename, options)
|
286
|
-
workbooks_number = excel_class.
|
286
|
+
workbooks_number = excel_class.instance_count==0 ? 0 : excel_class.current.Workbooks.Count
|
287
287
|
@ole_workbook = begin
|
288
288
|
WIN32OLE.connect(General.absolute_path(filename))
|
289
289
|
rescue
|
290
290
|
if $!.message =~ /moniker/
|
291
291
|
raise WorkbookConnectingBlockingError, "some workbook is blocking when connecting"
|
292
292
|
else
|
293
|
-
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook"
|
293
|
+
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook\n#{$!.message}"
|
294
294
|
end
|
295
295
|
end
|
296
296
|
ole_excel = begin
|
@@ -299,7 +299,7 @@ module RobustExcelOle
|
|
299
299
|
if $!.message =~ /dispid/
|
300
300
|
raise WorkbookConnectingUnsavedError, "workbook is unsaved when connecting"
|
301
301
|
else
|
302
|
-
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook"
|
302
|
+
raise WorkbookConnectingUnknownError, "unknown error when connecting to a workbook\n#{$!.message}"
|
303
303
|
end
|
304
304
|
end
|
305
305
|
set_was_open options, (ole_excel.Workbooks.Count == workbooks_number)
|
@@ -327,7 +327,7 @@ module RobustExcelOle
|
|
327
327
|
def manage_blocking_or_unsaved_workbook(filename, options)
|
328
328
|
filename = General.absolute_path(filename)
|
329
329
|
filename = General.canonize(filename)
|
330
|
-
previous_file = General.canonize(@ole_workbook.Fullname)
|
330
|
+
previous_file = General.canonize(@ole_workbook.Fullname.gsub('\\','/'))
|
331
331
|
obstructed_by_other_book = (File.basename(filename) == File.basename(previous_file)) &&
|
332
332
|
(File.dirname(filename) != File.dirname(previous_file))
|
333
333
|
if obstructed_by_other_book
|
@@ -341,11 +341,12 @@ module RobustExcelOle
|
|
341
341
|
end
|
342
342
|
end
|
343
343
|
|
344
|
-
def manage_blocking_workbook(filename, options)
|
344
|
+
def manage_blocking_workbook(filename, options)
|
345
|
+
blocked_filename = -> { General.canonize(@ole_workbook.Fullname.tr('\\','/')) }
|
345
346
|
case options[:if_obstructed]
|
346
347
|
when :raise
|
347
348
|
raise WorkbookBlocked, "can't open workbook #{filename},
|
348
|
-
because it is being blocked by #{
|
349
|
+
because it is being blocked by #{blocked_filename.call} with the same name in a different path." +
|
349
350
|
"\nHint: Use the option :if_blocked with values :forget or :save,
|
350
351
|
to allow automatic closing of the old workbook (without or with saving before, respectively),
|
351
352
|
before the new workbook is being opened."
|
@@ -355,8 +356,8 @@ module RobustExcelOle
|
|
355
356
|
manage_saving_workbook(filename, options)
|
356
357
|
when :close_if_saved
|
357
358
|
if !@ole_workbook.Saved
|
358
|
-
raise WorkbookBlocked, "workbook with the same name in a different path is unsaved: #{
|
359
|
-
"\nHint: Use the option :
|
359
|
+
raise WorkbookBlocked, "workbook with the same name in a different path is unsaved: #{blocked_filename.call}" +
|
360
|
+
"\nHint: Use the option if_blocked: :save to save the workbook"
|
360
361
|
else
|
361
362
|
manage_forgetting_workbook(filename, options)
|
362
363
|
end
|
@@ -371,9 +372,14 @@ module RobustExcelOle
|
|
371
372
|
def manage_unsaved_workbook(filename, options)
|
372
373
|
case options[:if_unsaved]
|
373
374
|
when :raise
|
374
|
-
|
375
|
-
|
376
|
-
|
375
|
+
msg = if !options[:read_only].nil? && @ole_workbook.ReadOnly != options[:read_only]
|
376
|
+
"cannot change read-only mode of the workbook #{File.basename(filename).inspect}, because it contains unsaved changes"
|
377
|
+
else
|
378
|
+
"workbook is already open but not saved: #{File.basename(filename).inspect}"
|
379
|
+
end
|
380
|
+
raise WorkbookNotSaved, msg +
|
381
|
+
"\nHint: Use the option :if_unsaved with values :forget to close the unsaved workbook,
|
382
|
+
:accept to let it open, or :save to save it, respectivly"
|
377
383
|
when :forget
|
378
384
|
manage_forgetting_workbook(filename, options)
|
379
385
|
when :accept
|
@@ -402,46 +408,53 @@ module RobustExcelOle
|
|
402
408
|
end
|
403
409
|
|
404
410
|
def manage_new_excel(filename, options)
|
405
|
-
@excel = excel_class.new(:
|
411
|
+
@excel = excel_class.new(reuse: false)
|
406
412
|
@ole_workbook = nil
|
407
413
|
open_or_create_workbook(filename, options)
|
408
414
|
end
|
409
|
-
|
415
|
+
|
416
|
+
def explore_workbook_error(msg, want_change_readonly = nil)
|
417
|
+
if msg.message =~ /800A03EC/ && msg.message =~ /0x80020009/
|
418
|
+
# error message:
|
419
|
+
# 'This workbook is currently referenced by another workbook and cannot be closed'
|
420
|
+
# 'Diese Arbeitsmappe wird momentan von einer anderen Arbeitsmappe verwendet und kann nicht geschlossen werden.'
|
421
|
+
if want_change_readonly==true
|
422
|
+
raise WorkbookLinked, "read-only mode of this workbook cannot be changed, because it is being used by another workbook"
|
423
|
+
elsif want_change_readonly.nil?
|
424
|
+
raise WorkbookLinked, "workbook is being used by another workbook"
|
425
|
+
end
|
426
|
+
end
|
427
|
+
if msg.message !~ /800A03EC/ || msg.message !~ /0x80020009/ || want_change_readonly==false
|
428
|
+
raise UnexpectedREOError, "unknown WIN32OLERuntimeError:\n#{msg.message}"
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
410
432
|
def open_or_create_workbook(filename, options)
|
411
433
|
return if @ole_workbook && options[:if_unsaved] != :alert && options[:if_unsaved] != :excel &&
|
412
|
-
|
434
|
+
(options[:read_only].nil? || options[:read_only]==@ole_workbook.ReadOnly )
|
435
|
+
abs_filename = General.absolute_path(filename)
|
436
|
+
workbooks = begin
|
437
|
+
@excel.Workbooks
|
438
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
439
|
+
raise UnexpectedREOError, "cannot access workbooks: #{msg.message} #{msg.backtrace}"
|
440
|
+
end
|
413
441
|
begin
|
414
|
-
|
415
|
-
|
416
|
-
workbooks
|
417
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
418
|
-
raise UnexpectedREOError, "cannot access workbooks: #{msg.message} #{msg.backtrace}"
|
419
|
-
end
|
420
|
-
begin
|
421
|
-
with_workaround_linked_workbooks_excel2007(options) do
|
422
|
-
# temporary workaround until jruby-win32ole implements named parameters (Java::JavaLang::RuntimeException (createVariant() not implemented for class org.jruby.RubyHash)
|
423
|
-
workbooks.Open(abs_filename,
|
424
|
-
updatelinks_vba(options[:update_links]),
|
425
|
-
options[:read_only] )
|
426
|
-
end
|
427
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
428
|
-
# for Excel2007: for option :if_unsaved => :alert and user cancels: this error appears?
|
429
|
-
# if yes: distinguish these events
|
430
|
-
raise UnexpectedREOError, "cannot open workbook: #{msg.message} #{msg.backtrace}"
|
431
|
-
end
|
432
|
-
begin
|
433
|
-
# workaround for bug in Excel 2010: workbook.Open does not always return the workbook when given file name
|
434
|
-
begin
|
435
|
-
@ole_workbook = workbooks.Item(File.basename(filename))
|
436
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
437
|
-
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message}"
|
438
|
-
end
|
439
|
-
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
440
|
-
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message} #{msg.backtrace}"
|
442
|
+
with_workaround_linked_workbooks_excel2007(options) do
|
443
|
+
# temporary workaround until jruby-win32ole implements named parameters (Java::JavaLang::RuntimeException (createVariant() not implemented for class org.jruby.RubyHash)
|
444
|
+
workbooks.Open(abs_filename, updatelinks_vba(options[:update_links]), options[:read_only] )
|
441
445
|
end
|
446
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
447
|
+
# for Excel2007: for option :if_unsaved => :alert and user cancels: this error appears?; distinguish these events
|
448
|
+
want_change_readonly = !options[:read_only].nil? && (options[:read_only] != @ole_workbook.ReadOnly)
|
449
|
+
end
|
450
|
+
# workaround for bug in Excel 2010: workbook.Open does not always return the workbook when given file name
|
451
|
+
@ole_workbook = begin
|
452
|
+
workbooks.Item(File.basename(filename))
|
453
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
454
|
+
raise UnexpectedREOError, "WIN32OLERuntimeError: #{msg.message}"
|
442
455
|
end
|
443
|
-
end
|
444
|
-
|
456
|
+
end
|
457
|
+
|
445
458
|
# translating the option UpdateLinks from REO to VBA
|
446
459
|
# setting UpdateLinks works only if calculation mode is automatic,
|
447
460
|
# parameter 'UpdateLinks' has no effect
|
@@ -480,7 +493,7 @@ module RobustExcelOle
|
|
480
493
|
# @param [String] filename the filename under which the new workbook should be saved
|
481
494
|
# @param [Hash] opts the options as in Workbook::open
|
482
495
|
def self.create(filename, opts = { })
|
483
|
-
open(filename, :
|
496
|
+
open(filename, if_absent: :create)
|
484
497
|
end
|
485
498
|
|
486
499
|
# closes the workbook, if it is alive
|
@@ -495,34 +508,37 @@ module RobustExcelOle
|
|
495
508
|
# :alert or :excel -> gives control to excel
|
496
509
|
# @raise WorkbookNotSaved if the option :if_unsaved is :raise and the workbook is unsaved
|
497
510
|
# @raise OptionInvalid if the options is invalid
|
498
|
-
def close(opts = {:
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
close_workbook
|
507
|
-
when :forget
|
508
|
-
@excel.with_displayalerts(false) { close_workbook }
|
509
|
-
when :keep_open
|
510
|
-
# nothing
|
511
|
-
when :alert, :excel
|
512
|
-
@excel.with_displayalerts(true) { close_workbook }
|
513
|
-
else
|
514
|
-
raise OptionInvalid, ":if_unsaved: invalid option: #{opts[:if_unsaved].inspect}" +
|
515
|
-
"\nHint: Valid values are :raise, :save, :keep_open, :alert, :excel"
|
516
|
-
end
|
517
|
-
else
|
511
|
+
def close(opts = {if_unsaved: :raise})
|
512
|
+
return close_workbook unless (alive? && !@ole_workbook.Saved && writable)
|
513
|
+
case opts[:if_unsaved]
|
514
|
+
when :raise
|
515
|
+
raise WorkbookNotSaved, "workbook is unsaved: #{File.basename(self.stored_filename).inspect}" +
|
516
|
+
"\nHint: Use option :save or :forget to close the workbook with or without saving"
|
517
|
+
when :save
|
518
|
+
save
|
518
519
|
close_workbook
|
520
|
+
when :forget
|
521
|
+
@excel.with_displayalerts(false) { close_workbook }
|
522
|
+
when :keep_open
|
523
|
+
# nothing
|
524
|
+
when :alert, :excel
|
525
|
+
@excel.with_displayalerts(true) { close_workbook }
|
526
|
+
else
|
527
|
+
raise OptionInvalid, ":if_unsaved: invalid option: #{opts[:if_unsaved].inspect}" +
|
528
|
+
"\nHint: Valid values are :raise, :save, :keep_open, :alert, :excel"
|
519
529
|
end
|
520
530
|
end
|
521
531
|
|
522
532
|
private
|
523
533
|
|
524
534
|
def close_workbook
|
525
|
-
|
535
|
+
if alive?
|
536
|
+
begin
|
537
|
+
@ole_workbook.Close
|
538
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
539
|
+
explore_workbook_error(msg)
|
540
|
+
end
|
541
|
+
end
|
526
542
|
@ole_workbook = nil unless alive?
|
527
543
|
end
|
528
544
|
|
@@ -539,29 +555,31 @@ module RobustExcelOle
|
|
539
555
|
end
|
540
556
|
|
541
557
|
def for_reading(opts = { }, &block)
|
542
|
-
unobtrusively({:
|
558
|
+
unobtrusively({writable: false}.merge(opts), &block)
|
543
559
|
end
|
544
560
|
|
545
561
|
def for_modifying(opts = { }, &block)
|
546
|
-
unobtrusively({:
|
562
|
+
unobtrusively({writable: true}.merge(opts), &block)
|
547
563
|
end
|
548
564
|
|
549
565
|
def self.for_reading(arg, opts = { }, &block)
|
550
|
-
unobtrusively(arg, {:
|
566
|
+
unobtrusively(arg, {writable: false}.merge(opts), &block)
|
551
567
|
end
|
552
568
|
|
553
569
|
def self.for_modifying(arg, opts = { }, &block)
|
554
|
-
unobtrusively(arg, {:
|
570
|
+
unobtrusively(arg, {writable: true}.merge(opts), &block)
|
555
571
|
end
|
556
572
|
|
557
573
|
# allows to read or modify a workbook such that its state remains unchanged
|
558
574
|
# state comprises: open, saved, writable, visible, calculation mode, check compatibility
|
559
575
|
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
560
|
-
# @param [Hash] opts the options
|
561
|
-
# @option opts [
|
562
|
-
# @option opts [Boolean] :
|
563
|
-
#
|
576
|
+
# @param [Hash] opts the options
|
577
|
+
# @option opts [Boolean] :read_only true/false (default), force to open the workbook in read-only/read-write mode
|
578
|
+
# @option opts [Boolean] :writable true (default)/false changes of the workbook shall be saved/not saved,
|
579
|
+
# and the workbook is being opened in read-only/read-write mode by default
|
580
|
+
# (when the workbook was not open before)
|
564
581
|
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening (default: false)
|
582
|
+
# @option opts [Variant] :if_closed :current (default), :new or an Excel instance
|
565
583
|
# @return [Workbook] a workbook
|
566
584
|
def self.unobtrusively(file_or_workbook, opts = { }, &block)
|
567
585
|
file = (file_or_workbook.is_a? WIN32OLE) ? file_or_workbook.Fullname.tr('\\','/') : file_or_workbook
|
@@ -577,36 +595,37 @@ module RobustExcelOle
|
|
577
595
|
|
578
596
|
def self.unobtrusively_opening(file, opts, book_is_alive, &block)
|
579
597
|
process_options(opts)
|
580
|
-
opts = {:
|
581
|
-
raise OptionInvalid,
|
598
|
+
opts = {if_closed: :current, keep_open: false}.merge(opts)
|
599
|
+
raise OptionInvalid, "contradicting options" if opts[:writable] && opts[:read_only]
|
582
600
|
if book_is_alive.nil?
|
583
601
|
prefer_writable = ((!(opts[:read_only]) || opts[:writable] == true) &&
|
584
602
|
!(opts[:read_only].nil? && opts[:writable] == false))
|
585
|
-
known_book = bookstore.fetch(file, :
|
603
|
+
known_book = bookstore.fetch(file, prefer_writable: prefer_writable)
|
586
604
|
end
|
587
605
|
excel_opts = if (book_is_alive==false || (book_is_alive.nil? && (known_book.nil? || !known_book.alive?)))
|
588
|
-
{:
|
606
|
+
{force: {excel: opts[:if_closed]}}
|
589
607
|
else
|
590
|
-
{:
|
608
|
+
{force: {excel: opts[:force][:excel]}, default: {excel: opts[:default][:excel]}}
|
591
609
|
end
|
592
|
-
open_opts = excel_opts.merge({:
|
610
|
+
open_opts = excel_opts.merge({if_unsaved: :accept})
|
593
611
|
begin
|
594
|
-
open_opts[:was_open] = nil
|
612
|
+
open_opts[:was_open] = nil
|
595
613
|
book = open(file, open_opts)
|
596
614
|
was_visible = book.visible
|
597
615
|
was_writable = book.writable
|
598
616
|
was_saved = book.saved
|
599
617
|
was_check_compatibility = book.check_compatibility
|
600
618
|
was_calculation = book.excel.properties[:calculation]
|
619
|
+
opts[:read_only] = !opts[:writable] unless (!opts[:read_only].nil? || opts[:writable].nil? || open_opts[:was_open])
|
601
620
|
book.send :apply_options, file, opts
|
602
621
|
yield book
|
603
622
|
ensure
|
604
623
|
if book && book.alive?
|
605
624
|
do_not_write = opts[:read_only] || opts[:writable]==false
|
606
625
|
book.save unless book.saved || do_not_write || !book.writable
|
607
|
-
if
|
608
|
-
book.send :apply_options, file, opts.merge({:
|
609
|
-
:
|
626
|
+
if ((opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable))
|
627
|
+
book.send :apply_options, file, opts.merge({read_only: !was_writable,
|
628
|
+
if_unsaved: (opts[:writable]==false ? :forget : :save)})
|
610
629
|
end
|
611
630
|
was_open = open_opts[:was_open]
|
612
631
|
if was_open
|
@@ -626,20 +645,20 @@ module RobustExcelOle
|
|
626
645
|
# @options options
|
627
646
|
def reopen(options = { })
|
628
647
|
book = self.class.open(@stored_filename, options)
|
629
|
-
raise WorkbookREOError(
|
648
|
+
raise WorkbookREOError("cannot reopen workbook\n#{$!.message}") unless book && book.alive?
|
630
649
|
book
|
631
650
|
end
|
632
651
|
|
633
652
|
# simple save of a workbook.
|
634
653
|
# @return [Boolean] true, if successfully saved, nil otherwise
|
635
654
|
def save(opts = { }) # option opts is deprecated #
|
636
|
-
raise ObjectNotAlive,
|
637
|
-
raise WorkbookReadOnly,
|
655
|
+
raise ObjectNotAlive, "workbook is not alive" unless alive?
|
656
|
+
raise WorkbookReadOnly, "Not opened for writing (opened with :read_only option)" if @ole_workbook.ReadOnly
|
638
657
|
begin
|
639
658
|
@ole_workbook.Save
|
640
659
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
641
660
|
if msg.message =~ /SaveAs/ && msg.message =~ /Workbook/
|
642
|
-
raise WorkbookNotSaved,
|
661
|
+
raise WorkbookNotSaved, "workbook not saved"
|
643
662
|
else
|
644
663
|
raise UnexpectedREOError, "unknown WIN32OLERuntimeError:\n#{msg.message}"
|
645
664
|
end
|
@@ -665,64 +684,72 @@ module RobustExcelOle
|
|
665
684
|
# otherwise raises an exception
|
666
685
|
# @return [Workbook], the book itself, if successfully saved, raises an exception otherwise
|
667
686
|
def save_as(file, options = { })
|
668
|
-
raise FileNameNotGiven,
|
669
|
-
raise ObjectNotAlive,
|
670
|
-
raise WorkbookReadOnly,
|
687
|
+
raise FileNameNotGiven, "filename is nil" if file.nil?
|
688
|
+
raise ObjectNotAlive, "workbook is not alive" unless alive?
|
689
|
+
raise WorkbookReadOnly, "Not opened for writing (opened with :read_only option)" if @ole_workbook.ReadOnly
|
671
690
|
raise(FileNotFound, "file #{General.absolute_path(file).inspect} is a directory") if File.directory?(file)
|
672
|
-
self.class.process_options(options)
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
raise FileAlreadyExists, "file already exists: #{File.basename(file).inspect}" +
|
693
|
-
"\nHint: Use option :if_exists => :overwrite, if you want to overwrite the file"
|
691
|
+
self.class.process_options(options)
|
692
|
+
begin
|
693
|
+
saveas_manage_if_exists(file, options)
|
694
|
+
saveas_manage_if_blocked(file, options)
|
695
|
+
save_as_workbook(file, options)
|
696
|
+
rescue AlreadyManaged
|
697
|
+
nil
|
698
|
+
end
|
699
|
+
self
|
700
|
+
end
|
701
|
+
|
702
|
+
private
|
703
|
+
|
704
|
+
def saveas_manage_if_exists(file, options)
|
705
|
+
return unless File.exist?(file)
|
706
|
+
case options[:if_exists]
|
707
|
+
when :overwrite
|
708
|
+
if file == self.filename
|
709
|
+
save
|
710
|
+
raise AlreadyManaged
|
694
711
|
else
|
695
|
-
|
696
|
-
|
712
|
+
begin
|
713
|
+
File.delete(file)
|
714
|
+
rescue Errno::EACCES
|
715
|
+
raise WorkbookBeingUsed, "workbook is open and being used in an Excel instance"
|
716
|
+
end
|
697
717
|
end
|
718
|
+
when :alert, :excel
|
719
|
+
@excel.with_displayalerts(true){ save_as_workbook(file, options) }
|
720
|
+
raise AlreadyManaged
|
721
|
+
when :raise
|
722
|
+
raise FileAlreadyExists, "file already exists: #{File.basename(file).inspect}" +
|
723
|
+
"\nHint: Use option if_exists: :overwrite, if you want to overwrite the file"
|
724
|
+
else
|
725
|
+
raise OptionInvalid, ":if_exists: invalid option: #{options[:if_exists].inspect}" +
|
726
|
+
"\nHint: Valid values are :raise, :overwrite, :alert, :excel"
|
698
727
|
end
|
728
|
+
end
|
729
|
+
|
730
|
+
def saveas_manage_if_blocked(file, options)
|
699
731
|
other_workbook = @excel.Workbooks.Item(File.basename(file)) rescue nil
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
end
|
715
|
-
else
|
716
|
-
raise OptionInvalid, ":if_blocked: invalid option: #{options[:if_obstructed].inspect}" +
|
717
|
-
"\nHint: Valid values are :raise, :forget, :save, :close_if_saved"
|
732
|
+
return unless other_workbook && self.filename != other_workbook.Fullname.tr('\\','/')
|
733
|
+
case options[:if_obstructed]
|
734
|
+
when :raise
|
735
|
+
raise WorkbookBlocked, "blocked by another workbook: #{other_workbook.Fullname.tr('\\','/')}" +
|
736
|
+
"\nHint: Use the option :if_blocked with values :forget or :save to
|
737
|
+
close or save and close the blocking workbook"
|
738
|
+
when :forget
|
739
|
+
# nothing
|
740
|
+
when :save
|
741
|
+
other_workbook.Save
|
742
|
+
when :close_if_saved
|
743
|
+
unless other_workbook.Saved
|
744
|
+
raise WorkbookBlocked, "blocking workbook is unsaved: #{File.basename(file).inspect}" +
|
745
|
+
"\nHint: Use option if_blocked: :save to save the blocking workbooks"
|
718
746
|
end
|
719
|
-
|
747
|
+
else
|
748
|
+
raise OptionInvalid, "if_blocked: invalid option: #{options[:if_obstructed].inspect}" +
|
749
|
+
"\nHint: Valid values are :raise, :forget, :save, :close_if_saved"
|
720
750
|
end
|
721
|
-
|
722
|
-
|
723
|
-
end
|
724
|
-
|
725
|
-
private
|
751
|
+
other_workbook.Close
|
752
|
+
end
|
726
753
|
|
727
754
|
def save_as_workbook(file, options)
|
728
755
|
dirname, basename = File.split(file)
|
@@ -743,6 +770,9 @@ module RobustExcelOle
|
|
743
770
|
end
|
744
771
|
end
|
745
772
|
|
773
|
+
class AlreadyManaged < Exception
|
774
|
+
end
|
775
|
+
|
746
776
|
def store_myself
|
747
777
|
bookstore.store(self)
|
748
778
|
@stored_filename = filename
|
@@ -752,7 +782,7 @@ module RobustExcelOle
|
|
752
782
|
|
753
783
|
# closes a given file if it is open
|
754
784
|
# @options opts [Symbol] :if_unsaved
|
755
|
-
def self.close(file, opts = {:
|
785
|
+
def self.close(file, opts = {if_unsaved: :raise})
|
756
786
|
book = begin
|
757
787
|
bookstore.fetch(file)
|
758
788
|
rescue
|
@@ -790,21 +820,20 @@ module RobustExcelOle
|
|
790
820
|
@ole_workbook.Worksheets.Count
|
791
821
|
end
|
792
822
|
|
823
|
+
# @return [Enumerator] traversing all worksheet objects
|
793
824
|
def each
|
794
|
-
|
795
|
-
|
825
|
+
if block_given?
|
826
|
+
@ole_workbook.Worksheets.lazy.each do |ole_worksheet|
|
827
|
+
yield worksheet_class.new(ole_worksheet)
|
828
|
+
end
|
829
|
+
else
|
830
|
+
to_enum(:each).lazy
|
796
831
|
end
|
797
832
|
end
|
798
833
|
|
799
|
-
def worksheets
|
800
|
-
result = []
|
801
|
-
each { |worksheet| result << worksheet }
|
802
|
-
result
|
803
|
-
end
|
804
|
-
|
805
834
|
def each_with_index(offset = 0)
|
806
835
|
i = offset
|
807
|
-
@ole_workbook.Worksheets.each do |sheet|
|
836
|
+
@ole_workbook.Worksheets.lazy.each do |sheet|
|
808
837
|
yield worksheet_class.new(sheet), i
|
809
838
|
i += 1
|
810
839
|
end
|
@@ -845,7 +874,7 @@ module RobustExcelOle
|
|
845
874
|
end
|
846
875
|
end
|
847
876
|
rescue # WIN32OLERuntimeError, NameNotFound, Java::OrgRacobCom::ComFailException
|
848
|
-
raise WorksheetREOError, "could not add given worksheet #{sheet.inspect}"
|
877
|
+
raise WorksheetREOError, "could not add given worksheet #{sheet.inspect}\n#{$!.message}"
|
849
878
|
end
|
850
879
|
new_sheet = worksheet_class.new(ole_workbook.Activesheet)
|
851
880
|
new_sheet.name = new_sheet_name if new_sheet_name
|
@@ -889,7 +918,7 @@ module RobustExcelOle
|
|
889
918
|
def range(name_or_worksheet, name_or_address = :__not_provided, address2 = :__not_provided)
|
890
919
|
if name_or_worksheet.respond_to?(:gsub)
|
891
920
|
name = name_or_worksheet
|
892
|
-
RobustExcelOle::Range.new(
|
921
|
+
RobustExcelOle::Range.new(get_name_object(name).RefersToRange)
|
893
922
|
else
|
894
923
|
begin
|
895
924
|
worksheet = name_or_worksheet.to_reo
|
@@ -904,21 +933,21 @@ module RobustExcelOle
|
|
904
933
|
# @param [String] name the name of a range
|
905
934
|
# @returns [Variant] the value of the range
|
906
935
|
def [] name
|
907
|
-
|
936
|
+
namevalue_global(name)
|
908
937
|
end
|
909
938
|
|
910
939
|
# sets the value of a range
|
911
940
|
# @param [String] name the name of the range
|
912
941
|
# @param [Variant] value the contents of the range
|
913
942
|
def []= (name, value)
|
914
|
-
|
943
|
+
set_namevalue_global(name, value)
|
915
944
|
end
|
916
945
|
|
917
946
|
# sets options
|
918
947
|
# @param [Hash] opts
|
919
948
|
def for_this_workbook(opts)
|
920
949
|
return unless alive?
|
921
|
-
self.class.process_options(opts, :
|
950
|
+
self.class.process_options(opts, use_defaults: false)
|
922
951
|
self.send :apply_options, @stored_filename, opts
|
923
952
|
end
|
924
953
|
|
@@ -1023,14 +1052,18 @@ module RobustExcelOle
|
|
1023
1052
|
|
1024
1053
|
# @private
|
1025
1054
|
def inspect
|
1026
|
-
|
1055
|
+
#{}"#<Workbook: #{("not alive " unless alive?)} #{(File.basename(self.filename) if alive?)} #{@excel}>"
|
1056
|
+
"#<Workbook: #{(alive? ? File.basename(self.filename) : "not alive")} #{@excel} >"
|
1027
1057
|
end
|
1028
1058
|
|
1059
|
+
using ParentRefinement
|
1060
|
+
using StringRefinement
|
1061
|
+
|
1029
1062
|
# @private
|
1030
1063
|
def self.excel_class
|
1031
1064
|
@excel_class ||= begin
|
1032
1065
|
module_name = self.parent_name
|
1033
|
-
"#{module_name}::Excel".constantize
|
1066
|
+
"#{module_name}::Excel".constantize
|
1034
1067
|
rescue NameError => e
|
1035
1068
|
# trace "excel_class: NameError: #{e}"
|
1036
1069
|
Excel
|
@@ -1041,7 +1074,7 @@ module RobustExcelOle
|
|
1041
1074
|
def self.worksheet_class
|
1042
1075
|
@worksheet_class ||= begin
|
1043
1076
|
module_name = self.parent_name
|
1044
|
-
"#{module_name}::Worksheet".constantize
|
1077
|
+
"#{module_name}::Worksheet".constantize
|
1045
1078
|
rescue NameError => e
|
1046
1079
|
Worksheet
|
1047
1080
|
end
|
@@ -1062,23 +1095,20 @@ module RobustExcelOle
|
|
1062
1095
|
private
|
1063
1096
|
|
1064
1097
|
def method_missing(name, *args)
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
end
|
1073
|
-
else
|
1074
|
-
begin
|
1075
|
-
@ole_workbook.send(name, *args)
|
1076
|
-
rescue NoMethodError
|
1077
|
-
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
1078
|
-
end
|
1098
|
+
super unless name.to_s[0,1] =~ /[A-Z]/
|
1099
|
+
raise ObjectNotAlive, 'method missing: workbook not alive' unless alive?
|
1100
|
+
if ::ERRORMESSAGE_JRUBY_BUG
|
1101
|
+
begin
|
1102
|
+
@ole_workbook.send(name, *args)
|
1103
|
+
rescue Java::OrgRacobCom::ComFailException
|
1104
|
+
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
1079
1105
|
end
|
1080
1106
|
else
|
1081
|
-
|
1107
|
+
begin
|
1108
|
+
@ole_workbook.send(name, *args)
|
1109
|
+
rescue NoMethodError
|
1110
|
+
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
1111
|
+
end
|
1082
1112
|
end
|
1083
1113
|
end
|
1084
1114
|
|
@@ -1094,6 +1124,10 @@ public
|
|
1094
1124
|
class WorkbookNotSaved < WorkbookREOError
|
1095
1125
|
end
|
1096
1126
|
|
1127
|
+
# @private
|
1128
|
+
class WorkbookLinked < WorkbookREOError
|
1129
|
+
end
|
1130
|
+
|
1097
1131
|
# @private
|
1098
1132
|
class WorkbookReadOnly < WorkbookREOError
|
1099
1133
|
end
|