robust_excel_ole 1.26 → 1.31
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 +17 -0
- data/README.rdoc +12 -5
- data/benchmarking/reo_example.rb +1 -1
- data/benchmarking/reo_example1.rb +1 -1
- data/benchmarking/reo_example2.rb +1 -1
- data/bin/jreo +20 -1
- data/bin/reo +20 -1
- data/docs/README_open.rdoc +8 -4
- data/docs/README_sheet.rdoc +1 -7
- data/examples/introductory_examples/example_open.rb +11 -0
- data/lib/robust_excel_ole.rb +19 -16
- data/lib/robust_excel_ole/base.rb +5 -0
- data/lib/robust_excel_ole/bookstore.rb +1 -1
- data/lib/robust_excel_ole/cell.rb +1 -1
- data/lib/robust_excel_ole/cygwin.rb +2 -0
- data/lib/robust_excel_ole/excel.rb +12 -22
- data/lib/robust_excel_ole/general.rb +270 -206
- data/lib/robust_excel_ole/list_object.rb +18 -115
- data/lib/robust_excel_ole/list_row.rb +128 -0
- data/lib/robust_excel_ole/range.rb +5 -1
- data/lib/robust_excel_ole/range_owners.rb +4 -71
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +71 -29
- data/lib/robust_excel_ole/worksheet.rb +107 -22
- data/lib/spec_helper.rb +1 -1
- data/spec/address_tool_spec.rb +2 -2
- data/spec/base_spec.rb +19 -17
- data/spec/bookstore_spec.rb +1 -1
- data/spec/cell_spec.rb +1 -1
- data/spec/cygwin_spec.rb +1 -1
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/excel_spec.rb +1 -1
- data/spec/general_spec.rb +64 -7
- data/spec/list_object_spec.rb +85 -20
- data/spec/range_spec.rb +1 -14
- data/spec/spec_helper.rb +1 -1
- data/spec/workbook_spec.rb +12 -12
- data/spec/workbook_specs/workbook_all_spec.rb +8 -28
- data/spec/workbook_specs/workbook_close_spec.rb +1 -1
- data/spec/workbook_specs/workbook_misc_spec.rb +33 -33
- data/spec/workbook_specs/workbook_open_spec.rb +56 -5
- data/spec/workbook_specs/workbook_save_spec.rb +1 -1
- data/spec/workbook_specs/workbook_sheet_spec.rb +1 -1
- data/spec/workbook_specs/workbook_subclass_spec.rb +1 -1
- data/spec/workbook_specs/workbook_unobtr_spec.rb +273 -115
- data/spec/worksheet_spec.rb +51 -19
- metadata +3 -5
- data/jreo.bat +0 -3
- data/lib/reo_console.rb +0 -68
- data/reo.bat +0 -3
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
module RobustExcelOle
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
using ToReoRefinement
|
6
|
+
using FindAllIndicesRefinement
|
7
|
+
|
8
8
|
# This class essentially wraps a Win32Ole ListObject.
|
9
9
|
# You can apply all VBA methods (starting with a capital letter)
|
10
10
|
# that you would apply for a ListObject.
|
@@ -59,121 +59,25 @@ module RobustExcelOle
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
|
63
62
|
ole_table = @ole_table
|
63
|
+
|
64
64
|
@row_class = Class.new(ListRow) do
|
65
65
|
|
66
66
|
@@ole_table = ole_table
|
67
67
|
|
68
|
-
def
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
# returns the value of the cell with given column name or number
|
73
|
-
# @param [Variant] column number or column name
|
74
|
-
# @return [Variant] value of the cell
|
75
|
-
def [] column_number_or_name
|
76
|
-
begin
|
77
|
-
ole_cell = @@ole_table.Application.Intersect(
|
78
|
-
@ole_listrow.Range, @@ole_table.ListColumns.Item(column_number_or_name).Range)
|
79
|
-
ole_cell.Value
|
80
|
-
rescue WIN32OLERuntimeError
|
81
|
-
raise TableRowError, "could not determine the value at column #{column_number_or_name}"
|
82
|
-
end
|
68
|
+
def ole_table
|
69
|
+
@@ole_table
|
83
70
|
end
|
71
|
+
|
72
|
+
end
|
84
73
|
|
74
|
+
end
|
85
75
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
rescue WIN32OLERuntimeError
|
92
|
-
raise TableRowError, "could not assign value #{value.inspect} to cell at column #{column_number_or_name}"
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# values of the row
|
97
|
-
# @return [Array] values of the row
|
98
|
-
def values
|
99
|
-
begin
|
100
|
-
@ole_listrow.Range.Value.first
|
101
|
-
rescue WIN32OLERuntimeError
|
102
|
-
raise TableError, "could not read values"
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
# sets the values of the row
|
107
|
-
# @param [Array] values of the row
|
108
|
-
def set_values values
|
109
|
-
begin
|
110
|
-
updated_values = self.values
|
111
|
-
updated_values[0,values.length] = values
|
112
|
-
@ole_listrow.Range.Value = [updated_values]
|
113
|
-
values
|
114
|
-
rescue WIN32OLERuntimeError
|
115
|
-
raise TableError, "could not set values #{values.inspect}"
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# deletes the values of the row
|
120
|
-
def delete_values
|
121
|
-
begin
|
122
|
-
@ole_listrow.Range.Value = [[].fill(nil,0..(@@ole_table.ListColumns.Count)-1)]
|
123
|
-
nil
|
124
|
-
rescue WIN32OLERuntimeError
|
125
|
-
raise TableError, "could not delete values"
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
def method_missing(name, *args)
|
130
|
-
name_str = name.to_s
|
131
|
-
core_name = name_str[-1]!='=' ? name_str : name_str[0..-2]
|
132
|
-
column_names = @@ole_table.HeaderRowRange.Value.first
|
133
|
-
column_name = column_names.find do |c|
|
134
|
-
c == core_name ||
|
135
|
-
c.gsub(/\W/,'') == core_name ||
|
136
|
-
c.replace_umlauts == core_name ||
|
137
|
-
c.gsub(/\W/,'').replace_umlauts == core_name ||
|
138
|
-
c.gsub(/\W/,'').replace_umlauts.underscore.gsub(/[^[\w\d]]/, '_').delete_multiple_underscores == core_name
|
139
|
-
end
|
140
|
-
if column_name
|
141
|
-
method_name = core_name.gsub(/\W/,'') + (name_str[-1]!='=' ? "" : "=")
|
142
|
-
define_and_call_method(column_name,method_name,*args)
|
143
|
-
else
|
144
|
-
super(name, *args)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
private
|
149
|
-
|
150
|
-
def define_and_call_method(column_name,method_name,*args)
|
151
|
-
ole_cell = @@ole_table.Application.Intersect(
|
152
|
-
@ole_listrow.Range, @@ole_table.ListColumns.Item(column_name).Range)
|
153
|
-
define_getting_setting_method(ole_cell,method_name)
|
154
|
-
self.send(method_name, *args)
|
155
|
-
end
|
156
|
-
|
157
|
-
def define_getting_setting_method(ole_cell,name)
|
158
|
-
if name[-1] != '='
|
159
|
-
self.class.define_method(name) do
|
160
|
-
ole_cell.Value
|
161
|
-
end
|
162
|
-
else
|
163
|
-
self.class.define_method(name) do |value|
|
164
|
-
ole_cell.Value = value
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
# accesses a table row object
|
171
|
-
# @param [Integer] a row number (>= 1)
|
172
|
-
# @return [ListRow] a object of dynamically constructed class with superclass ListRow
|
173
|
-
def [] row_number
|
174
|
-
@row_class.new(row_number)
|
175
|
-
end
|
176
|
-
|
76
|
+
# accesses a table row object
|
77
|
+
# @param [Integer] a row number (>= 1)
|
78
|
+
# @return [ListRow] a object of dynamically constructed class with superclass ListRow
|
79
|
+
def [] row_number
|
80
|
+
@row_class.new(row_number)
|
177
81
|
end
|
178
82
|
|
179
83
|
# @return [Array] a list of column names
|
@@ -213,7 +117,7 @@ module RobustExcelOle
|
|
213
117
|
|
214
118
|
# deletes a row
|
215
119
|
# @param [Integer] position of the old row
|
216
|
-
def delete_row(row_number)
|
120
|
+
def delete_row(row_number) # :nodoc: #
|
217
121
|
begin
|
218
122
|
@ole_table.ListRows.Item(row_number).Delete
|
219
123
|
rescue WIN32OLERuntimeError
|
@@ -223,7 +127,7 @@ module RobustExcelOle
|
|
223
127
|
|
224
128
|
# deletes a column
|
225
129
|
# @param [Variant] column number or column name
|
226
|
-
def delete_column(column_number_or_name)
|
130
|
+
def delete_column(column_number_or_name) # :nodoc: #
|
227
131
|
begin
|
228
132
|
@ole_table.ListColumns.Item(column_number_or_name).Delete
|
229
133
|
rescue WIN32OLERuntimeError
|
@@ -257,7 +161,7 @@ module RobustExcelOle
|
|
257
161
|
# renames a row
|
258
162
|
# @param [String] previous name or number of the column
|
259
163
|
# @param [String] new name of the column
|
260
|
-
def rename_column(name_or_number, new_name)
|
164
|
+
def rename_column(name_or_number, new_name) # :nodoc: #
|
261
165
|
begin
|
262
166
|
@ole_table.ListColumns.Item(name_or_number).Name = new_name
|
263
167
|
rescue
|
@@ -351,7 +255,7 @@ module RobustExcelOle
|
|
351
255
|
listrows = @ole_table.ListRows
|
352
256
|
result = []
|
353
257
|
(1..listrows.Count).each do |row_number|
|
354
|
-
row_values(row_number).
|
258
|
+
row_values(row_number).find_all_indices(value).each do |col_number|
|
355
259
|
result << @ole_table.Application.Intersect(listrows.Item(row_number).Range,
|
356
260
|
@ole_table.ListColumns.Item(col_number+1).Range).to_reo
|
357
261
|
end
|
@@ -426,6 +330,5 @@ module RobustExcelOle
|
|
426
330
|
end
|
427
331
|
|
428
332
|
Table = ListObject
|
429
|
-
TableRow = ListRow
|
430
333
|
|
431
334
|
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
module RobustExcelOle
|
4
|
+
|
5
|
+
using StringRefinement
|
6
|
+
|
7
|
+
class ListRow
|
8
|
+
|
9
|
+
def initialize(row_number)
|
10
|
+
@ole_listrow = ole_table.ListRows.Item(row_number)
|
11
|
+
end
|
12
|
+
|
13
|
+
# returns the value of the cell with given column name or number
|
14
|
+
# @param [Variant] column number or column name
|
15
|
+
# @return [Variant] value of the cell
|
16
|
+
def [] column_number_or_name
|
17
|
+
begin
|
18
|
+
ole_cell = ole_table.Application.Intersect(
|
19
|
+
@ole_listrow.Range, ole_table.ListColumns.Item(column_number_or_name).Range)
|
20
|
+
ole_cell.Value
|
21
|
+
rescue WIN32OLERuntimeError
|
22
|
+
raise TableRowError, "could not determine the value at column #{column_number_or_name}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# sets the value of the cell with given column name or number
|
27
|
+
# @param [Variant] column number or column name
|
28
|
+
# @param [Variant] value of the cell
|
29
|
+
def []=(column_number_or_name, value)
|
30
|
+
begin
|
31
|
+
ole_cell = ole_table.Application.Intersect(
|
32
|
+
@ole_listrow.Range, ole_table.ListColumns.Item(column_number_or_name).Range)
|
33
|
+
ole_cell.Value = value
|
34
|
+
rescue WIN32OLERuntimeError
|
35
|
+
raise TableRowError, "could not assign value #{value.inspect} to cell at column #{column_number_or_name}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# values of the row
|
40
|
+
# @return [Array] values of the row
|
41
|
+
def values
|
42
|
+
begin
|
43
|
+
@ole_listrow.Range.Value.first
|
44
|
+
rescue WIN32OLERuntimeError
|
45
|
+
raise TableError, "could not read values"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# sets the values of the row
|
50
|
+
# @param [Array] values of the row
|
51
|
+
def set_values values
|
52
|
+
begin
|
53
|
+
updated_values = self.values
|
54
|
+
updated_values[0,values.length] = values
|
55
|
+
@ole_listrow.Range.Value = [updated_values]
|
56
|
+
values
|
57
|
+
rescue WIN32OLERuntimeError
|
58
|
+
raise TableError, "could not set values #{values.inspect}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# deletes the values of the row
|
63
|
+
def delete_values
|
64
|
+
begin
|
65
|
+
@ole_listrow.Range.Value = [[].fill(nil,0..(ole_table.ListColumns.Count)-1)]
|
66
|
+
nil
|
67
|
+
rescue WIN32OLERuntimeError
|
68
|
+
raise TableError, "could not delete values"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def method_missing(name, *args)
|
73
|
+
name_str = name.to_s
|
74
|
+
core_name = name_str[-1]!='=' ? name_str : name_str[0..-2]
|
75
|
+
column_names = ole_table.HeaderRowRange.Value.first
|
76
|
+
column_name = column_names.find do |c|
|
77
|
+
c == core_name ||
|
78
|
+
c.gsub(/\W/,'_') == core_name ||
|
79
|
+
c.underscore == core_name ||
|
80
|
+
c.underscore.gsub(/\W/,'_') == core_name ||
|
81
|
+
c.replace_umlauts.gsub(/\W/,'_') == core_name ||
|
82
|
+
c.replace_umlauts.underscore.gsub(/\W/,'_') == core_name
|
83
|
+
end
|
84
|
+
if column_name
|
85
|
+
appended_eq = (name_str[-1]!='=' ? "" : "=")
|
86
|
+
method_name = core_name.replace_umlauts.underscore + appended_eq
|
87
|
+
define_and_call_method(column_name,method_name,*args)
|
88
|
+
else
|
89
|
+
super(name, *args)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# @private
|
94
|
+
def to_s
|
95
|
+
inspect
|
96
|
+
end
|
97
|
+
|
98
|
+
# @private
|
99
|
+
def inspect
|
100
|
+
"#<ListRow: " + "index:#{@ole_listrow.Index}" + " size:#{ole_table.ListColumns.Count}" + " #{ole_table.Name}" + ">"
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def define_and_call_method(column_name,method_name,*args)
|
106
|
+
ole_cell = ole_table.Application.Intersect(
|
107
|
+
@ole_listrow.Range, ole_table.ListColumns.Item(column_name).Range)
|
108
|
+
define_getting_setting_method(ole_cell,method_name)
|
109
|
+
self.send(method_name, *args)
|
110
|
+
end
|
111
|
+
|
112
|
+
def define_getting_setting_method(ole_cell,name)
|
113
|
+
if name[-1] != '='
|
114
|
+
self.class.define_method(name) do
|
115
|
+
ole_cell.Value
|
116
|
+
end
|
117
|
+
else
|
118
|
+
self.class.define_method(name) do |value|
|
119
|
+
ole_cell.Value = value
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
TableRow = ListRow
|
127
|
+
|
128
|
+
end
|
@@ -16,6 +16,7 @@ module RobustExcelOle
|
|
16
16
|
|
17
17
|
alias ole_object ole_range
|
18
18
|
|
19
|
+
using ToReoRefinement
|
19
20
|
|
20
21
|
def initialize(win32_range, worksheet = nil)
|
21
22
|
@ole_range = win32_range
|
@@ -221,11 +222,14 @@ module RobustExcelOle
|
|
221
222
|
to_s
|
222
223
|
end
|
223
224
|
|
225
|
+
using ParentRefinement
|
226
|
+
using StringRefinement
|
227
|
+
|
224
228
|
# @private
|
225
229
|
def self.worksheet_class
|
226
230
|
@worksheet_class ||= begin
|
227
231
|
module_name = parent_name
|
228
|
-
"#{module_name}::Worksheet".constantize
|
232
|
+
"#{module_name}::Worksheet".constantize
|
229
233
|
rescue NameError => e
|
230
234
|
Worksheet
|
231
235
|
end
|
@@ -14,7 +14,7 @@ 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
|
name_object(name)
|
20
20
|
rescue NameNotFound => msg
|
@@ -63,7 +63,7 @@ module RobustExcelOle
|
|
63
63
|
# @param [String] name the name of a range
|
64
64
|
# @param [Variant] value the contents of the range
|
65
65
|
# @option opts [Symbol] :color the color of the range when set
|
66
|
-
def
|
66
|
+
def set_namevalue_global(name, value, opts = { })
|
67
67
|
begin
|
68
68
|
name_obj = begin
|
69
69
|
name_object(name)
|
@@ -89,81 +89,14 @@ module RobustExcelOle
|
|
89
89
|
end
|
90
90
|
end
|
91
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
|
-
end
|
125
|
-
return opts[:default] unless (opts[:default] == :__not_provided) || value.nil?
|
126
|
-
value
|
127
|
-
end
|
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
|
157
|
-
end
|
158
|
-
|
159
92
|
# @private
|
160
93
|
def nameval(name, opts = { :default => :__not_provided }) # :deprecated: #
|
161
|
-
|
94
|
+
namevalue_global(name, opts)
|
162
95
|
end
|
163
96
|
|
164
97
|
# @private
|
165
98
|
def set_nameval(name, value) # :deprecated: #
|
166
|
-
|
99
|
+
set_namevalue_global(name, value)
|
167
100
|
end
|
168
101
|
|
169
102
|
# @private
|
@@ -11,14 +11,14 @@ module RobustExcelOle
|
|
11
11
|
|
12
12
|
class Workbook < RangeOwners
|
13
13
|
|
14
|
-
#include General
|
15
|
-
|
16
14
|
attr_reader :ole_workbook
|
17
15
|
attr_reader :excel
|
18
16
|
attr_reader :stored_filename
|
19
17
|
|
20
18
|
alias ole_object ole_workbook
|
21
19
|
|
20
|
+
using ToReoRefinement
|
21
|
+
|
22
22
|
CORE_DEFAULT_OPEN_OPTS = {
|
23
23
|
:default => {:excel => :current},
|
24
24
|
:force => {},
|
@@ -42,7 +42,7 @@ module RobustExcelOle
|
|
42
42
|
|
43
43
|
|
44
44
|
# opens a workbook.
|
45
|
-
# @param [String] file_or_workbook a file name or WIN32OLE workbook
|
45
|
+
# @param [String,Pathname] file_or_workbook a file name (string or pathname) or WIN32OLE workbook
|
46
46
|
# @param [Hash] opts the options
|
47
47
|
# @option opts [Hash] :default or :d
|
48
48
|
# @option opts [Hash] :force or :f
|
@@ -158,7 +158,7 @@ module RobustExcelOle
|
|
158
158
|
@excel = excel_class.new(ole_excel)
|
159
159
|
filename = @ole_workbook.Fullname.tr('\\','/')
|
160
160
|
else
|
161
|
-
filename = file_or_workbook
|
161
|
+
filename = file_or_workbook
|
162
162
|
ensure_workbook(filename, opts)
|
163
163
|
end
|
164
164
|
apply_options(filename, opts)
|
@@ -235,13 +235,12 @@ module RobustExcelOle
|
|
235
235
|
raise ExcelREOError, "Excel is not alive" unless @excel && @excel.alive?
|
236
236
|
end
|
237
237
|
|
238
|
-
|
239
238
|
# @private
|
240
|
-
def ensure_workbook(filename, options)
|
239
|
+
def ensure_workbook(filename, options)
|
241
240
|
set_was_open options, true
|
242
241
|
return if (@ole_workbook && alive? && (options[:read_only].nil? || @ole_workbook.ReadOnly == options[:read_only]))
|
243
242
|
set_was_open options, false
|
244
|
-
if options[:if_unsaved]==:accept &&
|
243
|
+
if options[:if_unsaved]==:accept && alive? &&
|
245
244
|
((options[:read_only]==true && self.ReadOnly==false) || (options[:read_only]==false && self.ReadOnly==true))
|
246
245
|
raise OptionInvalid, ":if_unsaved:accept and change of read-only mode is not possible"
|
247
246
|
end
|
@@ -254,7 +253,7 @@ module RobustExcelOle
|
|
254
253
|
if @ole_workbook && alive?
|
255
254
|
set_was_open options, true
|
256
255
|
manage_blocking_or_unsaved_workbook(filename,options)
|
257
|
-
open_or_create_workbook(filename,options) if
|
256
|
+
open_or_create_workbook(filename,options) if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
258
257
|
else
|
259
258
|
if (excel_option.nil? || excel_option == :current) &&
|
260
259
|
!(::CONNECT_JRUBY_BUG && filename[0] == '/')
|
@@ -270,7 +269,6 @@ module RobustExcelOle
|
|
270
269
|
# applies options to workbook named with filename
|
271
270
|
def apply_options(filename, options)
|
272
271
|
# changing read-only mode
|
273
|
-
#ensure_workbook(filename, options) if options[:read_only] && options[:read_only] != @ole_workbook.ReadOnly
|
274
272
|
if (!options[:read_only].nil?) && options[:read_only] != @ole_workbook.ReadOnly
|
275
273
|
ensure_workbook(filename, options)
|
276
274
|
end
|
@@ -327,7 +325,7 @@ module RobustExcelOle
|
|
327
325
|
def manage_blocking_or_unsaved_workbook(filename, options)
|
328
326
|
filename = General.absolute_path(filename)
|
329
327
|
filename = General.canonize(filename)
|
330
|
-
previous_file = General.canonize(@ole_workbook.Fullname)
|
328
|
+
previous_file = General.canonize(@ole_workbook.Fullname.gsub('\\','/'))
|
331
329
|
obstructed_by_other_book = (File.basename(filename) == File.basename(previous_file)) &&
|
332
330
|
(File.dirname(filename) != File.dirname(previous_file))
|
333
331
|
if obstructed_by_other_book
|
@@ -341,11 +339,12 @@ module RobustExcelOle
|
|
341
339
|
end
|
342
340
|
end
|
343
341
|
|
344
|
-
def manage_blocking_workbook(filename, options)
|
342
|
+
def manage_blocking_workbook(filename, options)
|
343
|
+
blocked_filename = -> { General.canonize(@ole_workbook.Fullname.tr('\\','/')) }
|
345
344
|
case options[:if_obstructed]
|
346
345
|
when :raise
|
347
346
|
raise WorkbookBlocked, "can't open workbook #{filename},
|
348
|
-
because it is being blocked by #{
|
347
|
+
because it is being blocked by #{blocked_filename.call} with the same name in a different path." +
|
349
348
|
"\nHint: Use the option :if_blocked with values :forget or :save,
|
350
349
|
to allow automatic closing of the old workbook (without or with saving before, respectively),
|
351
350
|
before the new workbook is being opened."
|
@@ -355,7 +354,7 @@ module RobustExcelOle
|
|
355
354
|
manage_saving_workbook(filename, options)
|
356
355
|
when :close_if_saved
|
357
356
|
if !@ole_workbook.Saved
|
358
|
-
raise WorkbookBlocked, "workbook with the same name in a different path is unsaved: #{
|
357
|
+
raise WorkbookBlocked, "workbook with the same name in a different path is unsaved: #{blocked_filename.call}" +
|
359
358
|
"\nHint: Use the option :if_blocked => :save to save the workbook"
|
360
359
|
else
|
361
360
|
manage_forgetting_workbook(filename, options)
|
@@ -371,9 +370,14 @@ module RobustExcelOle
|
|
371
370
|
def manage_unsaved_workbook(filename, options)
|
372
371
|
case options[:if_unsaved]
|
373
372
|
when :raise
|
374
|
-
|
375
|
-
|
376
|
-
|
373
|
+
msg = if !options[:read_only].nil? && @ole_workbook.ReadOnly != options[:read_only]
|
374
|
+
"cannot change read-only mode of the workbook #{File.basename(filename).inspect}, because it contains unsaved changes"
|
375
|
+
else
|
376
|
+
"workbook is already open but not saved: #{File.basename(filename).inspect}"
|
377
|
+
end
|
378
|
+
raise WorkbookNotSaved, msg +
|
379
|
+
"\nHint: Use the option :if_unsaved with values :forget to close the unsaved workbook,
|
380
|
+
:accept to let it open, or :save to save it, respectivly"
|
377
381
|
when :forget
|
378
382
|
manage_forgetting_workbook(filename, options)
|
379
383
|
when :accept
|
@@ -406,7 +410,24 @@ module RobustExcelOle
|
|
406
410
|
@ole_workbook = nil
|
407
411
|
open_or_create_workbook(filename, options)
|
408
412
|
end
|
409
|
-
|
413
|
+
|
414
|
+
def explore_workbook_error(msg, want_change_readonly = nil)
|
415
|
+
if msg.message =~ /800A03EC/ && msg.message =~ /0x80020009/
|
416
|
+
# error message:
|
417
|
+
# 'This workbook is currently referenced by another workbook and cannot be closed'
|
418
|
+
# 'Diese Arbeitsmappe wird momentan von einer anderen Arbeitsmappe verwendet und kann nicht geschlossen werden.'
|
419
|
+
if want_change_readonly==true
|
420
|
+
raise WorkbookLinked, "read-only mode of this workbook cannot be changed, because it is being used by another workbook"
|
421
|
+
elsif want_change_readonly.nil?
|
422
|
+
raise WorkbookLinked, "workbook is being used by another workbook"
|
423
|
+
else
|
424
|
+
raise UnexpectedREOError, "unknown WIN32OLERuntimeError:\n#{msg.message}"
|
425
|
+
end
|
426
|
+
else
|
427
|
+
raise UnexpectedREOError, "unknown WIN32OLERuntimeError:\n#{msg.message}"
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
410
431
|
def open_or_create_workbook(filename, options)
|
411
432
|
return if @ole_workbook && options[:if_unsaved] != :alert && options[:if_unsaved] != :excel &&
|
412
433
|
(options[:read_only].nil? || options[:read_only]==@ole_workbook.ReadOnly )
|
@@ -427,7 +448,8 @@ module RobustExcelOle
|
|
427
448
|
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
428
449
|
# for Excel2007: for option :if_unsaved => :alert and user cancels: this error appears?
|
429
450
|
# if yes: distinguish these events
|
430
|
-
|
451
|
+
want_change_readonly = !options[:read_only].nil? && (options[:read_only] != @ole_workbook.ReadOnly)
|
452
|
+
explore_workbook_error(msg, want_change_readonly)
|
431
453
|
end
|
432
454
|
begin
|
433
455
|
# workaround for bug in Excel 2010: workbook.Open does not always return the workbook when given file name
|
@@ -522,7 +544,14 @@ module RobustExcelOle
|
|
522
544
|
private
|
523
545
|
|
524
546
|
def close_workbook
|
525
|
-
|
547
|
+
#@ole_workbook.Close if alive?
|
548
|
+
if alive?
|
549
|
+
begin
|
550
|
+
@ole_workbook.Close
|
551
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
552
|
+
explore_workbook_error(msg)
|
553
|
+
end
|
554
|
+
end
|
526
555
|
@ole_workbook = nil unless alive?
|
527
556
|
end
|
528
557
|
|
@@ -557,11 +586,13 @@ module RobustExcelOle
|
|
557
586
|
# allows to read or modify a workbook such that its state remains unchanged
|
558
587
|
# state comprises: open, saved, writable, visible, calculation mode, check compatibility
|
559
588
|
# @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
|
-
#
|
589
|
+
# @param [Hash] opts the options
|
590
|
+
# @option opts [Boolean] :read_only true/false (default), force to open the workbook in read-only/read-write mode
|
591
|
+
# @option opts [Boolean] :writable true (default)/false changes of the workbook shall be saved/not saved,
|
592
|
+
# and the workbook is being opened in read-only/read-write mode by default
|
593
|
+
# (when the workbook was not open before)
|
564
594
|
# @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening (default: false)
|
595
|
+
# @option opts [Variant] :if_closed :current (default), :new or an Excel instance
|
565
596
|
# @return [Workbook] a workbook
|
566
597
|
def self.unobtrusively(file_or_workbook, opts = { }, &block)
|
567
598
|
file = (file_or_workbook.is_a? WIN32OLE) ? file_or_workbook.Fullname.tr('\\','/') : file_or_workbook
|
@@ -591,20 +622,24 @@ module RobustExcelOle
|
|
591
622
|
end
|
592
623
|
open_opts = excel_opts.merge({:if_unsaved => :accept})
|
593
624
|
begin
|
594
|
-
open_opts[:was_open] = nil
|
625
|
+
open_opts[:was_open] = nil
|
595
626
|
book = open(file, open_opts)
|
627
|
+
#book = open(file, :read_only => !opts[:writable]) if !opts[:writable].nil? && !open_opts[:was_open]
|
596
628
|
was_visible = book.visible
|
597
629
|
was_writable = book.writable
|
598
630
|
was_saved = book.saved
|
599
631
|
was_check_compatibility = book.check_compatibility
|
600
632
|
was_calculation = book.excel.properties[:calculation]
|
633
|
+
#opts[:read_only] = !opts[:writable] unless (opts[:writable].nil? || open_opts[:was_open])
|
634
|
+
opts[:read_only] = !opts[:writable] unless (!opts[:read_only].nil? || opts[:writable].nil? || open_opts[:was_open])
|
601
635
|
book.send :apply_options, file, opts
|
602
636
|
yield book
|
603
637
|
ensure
|
604
638
|
if book && book.alive?
|
605
639
|
do_not_write = opts[:read_only] || opts[:writable]==false
|
606
640
|
book.save unless book.saved || do_not_write || !book.writable
|
607
|
-
if
|
641
|
+
#if opts[:writable].nil? && opts[:was_open] &&
|
642
|
+
if ((opts[:read_only] && was_writable) || (!opts[:read_only] && !was_writable))
|
608
643
|
book.send :apply_options, file, opts.merge({:read_only => !was_writable,
|
609
644
|
:if_unsaved => (opts[:writable]==false ? :forget : :save)})
|
610
645
|
end
|
@@ -904,14 +939,14 @@ module RobustExcelOle
|
|
904
939
|
# @param [String] name the name of a range
|
905
940
|
# @returns [Variant] the value of the range
|
906
941
|
def [] name
|
907
|
-
|
942
|
+
namevalue_global(name)
|
908
943
|
end
|
909
944
|
|
910
945
|
# sets the value of a range
|
911
946
|
# @param [String] name the name of the range
|
912
947
|
# @param [Variant] value the contents of the range
|
913
948
|
def []= (name, value)
|
914
|
-
|
949
|
+
set_namevalue_global(name, value)
|
915
950
|
end
|
916
951
|
|
917
952
|
# sets options
|
@@ -1026,11 +1061,14 @@ module RobustExcelOle
|
|
1026
1061
|
'#<Workbook: ' + ('not alive ' unless alive?).to_s + (File.basename(self.filename) if alive?).to_s + " #{@excel}" + '>'
|
1027
1062
|
end
|
1028
1063
|
|
1064
|
+
using ParentRefinement
|
1065
|
+
using StringRefinement
|
1066
|
+
|
1029
1067
|
# @private
|
1030
1068
|
def self.excel_class
|
1031
1069
|
@excel_class ||= begin
|
1032
1070
|
module_name = self.parent_name
|
1033
|
-
"#{module_name}::Excel".constantize
|
1071
|
+
"#{module_name}::Excel".constantize
|
1034
1072
|
rescue NameError => e
|
1035
1073
|
# trace "excel_class: NameError: #{e}"
|
1036
1074
|
Excel
|
@@ -1041,7 +1079,7 @@ module RobustExcelOle
|
|
1041
1079
|
def self.worksheet_class
|
1042
1080
|
@worksheet_class ||= begin
|
1043
1081
|
module_name = self.parent_name
|
1044
|
-
"#{module_name}::Worksheet".constantize
|
1082
|
+
"#{module_name}::Worksheet".constantize
|
1045
1083
|
rescue NameError => e
|
1046
1084
|
Worksheet
|
1047
1085
|
end
|
@@ -1094,6 +1132,10 @@ public
|
|
1094
1132
|
class WorkbookNotSaved < WorkbookREOError
|
1095
1133
|
end
|
1096
1134
|
|
1135
|
+
# @private
|
1136
|
+
class WorkbookLinked < WorkbookREOError
|
1137
|
+
end
|
1138
|
+
|
1097
1139
|
# @private
|
1098
1140
|
class WorkbookReadOnly < WorkbookREOError
|
1099
1141
|
end
|