robust_excel_ole 1.19.11 → 1.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +7 -1
- data/README.rdoc +5 -33
- data/bin/jreo +13 -10
- data/bin/reo +13 -10
- data/jreo.bat +1 -1
- data/lib/reo_console.rb +13 -10
- data/lib/robust_excel_ole/bookstore.rb +4 -3
- data/lib/robust_excel_ole/cell.rb +11 -0
- data/lib/robust_excel_ole/excel.rb +1 -1
- data/lib/robust_excel_ole/general.rb +67 -24
- data/lib/robust_excel_ole/list_object.rb +281 -31
- data/lib/robust_excel_ole/range.rb +60 -100
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +12 -8
- data/lib/robust_excel_ole/worksheet.rb +16 -2
- data/reo.bat +3 -0
- data/spec/bookstore_spec.rb +1 -1
- data/spec/general_spec.rb +17 -6
- data/spec/list_object_spec.rb +226 -13
- data/spec/workbook_spec.rb +12 -0
- data/spec/workbook_specs/workbook_misc_spec.rb +2 -2
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5739475bb50983be2c17b084b939ec1143d9508f280dfd8bf80445d5fbce521
|
4
|
+
data.tar.gz: 1ecdceba6d53cf8a231d81425ca2c8f9b02a6fff2f6e2ad4aa90813b1223febf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a4b326afc9230578f4f10bbbd4b2bb12d0536b3104ed0cc897b96a7ed3afe8ee6016181aa0603c8c9f260fa1966b19cd5b9ab07af5dda8312f9b7b363ee7ac7a
|
7
|
+
data.tar.gz: 06b76a2ecbab24b208d449d858329eb997e6375b2e5533c2ee0525fc1316ca249aa4594a9feb70525a9f492ba92153fdd9264caa23a6ec3c1af02547debab2d8
|
data/Changelog
CHANGED
@@ -1,8 +1,14 @@
|
|
1
1
|
# Change Log
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
|
4
|
+
## [1.22] 2020-10-08
|
4
5
|
|
5
|
-
## [1.
|
6
|
+
## [1.21] 2020-05-08
|
7
|
+
|
8
|
+
### Added
|
9
|
+
- Range#rows, columns
|
10
|
+
|
11
|
+
## [1.20] 2020-23-07
|
6
12
|
|
7
13
|
### Changed
|
8
14
|
- using pry in console
|
data/README.rdoc
CHANGED
@@ -11,7 +11,7 @@ It supports handling workbooks across Excel instances by keeping track of workbo
|
|
11
11
|
|
12
12
|
Library references are supported.
|
13
13
|
|
14
|
-
RobustExcelOle works by sending VBA methods via
|
14
|
+
RobustExcelOle works by sending VBA methods via WIN32OlE.
|
15
15
|
Therefore, it runs on Windows only.
|
16
16
|
|
17
17
|
== Features
|
@@ -27,7 +27,6 @@ RobustExcelOle supports
|
|
27
27
|
- availability of all VBA methods
|
28
28
|
- availability of the Excel constants (in form if Ruby constants: Excel constant.capitalize)
|
29
29
|
- all standard Excel file formats (.xlsx, .xls, .xlsm)
|
30
|
-
- list objects
|
31
30
|
- reopening workbooks after closing them
|
32
31
|
- unobtrusively opening workbooks, i.e. opening and processing workbooks
|
33
32
|
while preserving their status, e.g. saved, readonly
|
@@ -77,10 +76,10 @@ Let's open a workbook.
|
|
77
76
|
|
78
77
|
workbook = Workbook.open 'spec/data/workbook.xls'
|
79
78
|
|
80
|
-
Now we have a Workbook object that wraps a WIN32OLE object. That is,
|
79
|
+
Now we have a Workbook object that wraps a WIN32OLE object. That is, we can send any WIN32OLE (VBA) method to it. See
|
81
80
|
https://docs.microsoft.com/en-us/office/vba/api/excel.workbook#methods.
|
82
81
|
|
83
|
-
For example,
|
82
|
+
For example, we can determine the name of the workbook.
|
84
83
|
|
85
84
|
workbook.Name
|
86
85
|
# => "workbook.xls"
|
@@ -122,11 +121,11 @@ RobustExcelOle allows unobtrusively reading and modifying workbooks, i.e. access
|
|
122
121
|
# do something
|
123
122
|
end
|
124
123
|
|
125
|
-
|
124
|
+
We can also create a new, empty workbook.
|
126
125
|
|
127
126
|
Workbook.create('spec/data/new_workbook.xls', :visible => true)
|
128
127
|
|
129
|
-
Moreover,
|
128
|
+
Moreover, we can open the workbook using a block, similar to, e.g., +File.open+.
|
130
129
|
|
131
130
|
Workbook.open('spec/data/workbook.xls') do |workbook|
|
132
131
|
# do something
|
@@ -318,33 +317,6 @@ and set another value to that range.
|
|
318
317
|
|
319
318
|
For more details about reading and writing contents of cells and ranges see {README_ranges}[https://github.com/Thomas008/robust_excel_ole/blob/master/docs/README_ranges.rdoc]
|
320
319
|
|
321
|
-
=== Reading and writing list objects
|
322
|
-
|
323
|
-
We can define a list object (or table) from scratch.
|
324
|
-
|
325
|
-
table = ListObject.new(worksheet, "table 1", [1,1], 3,["Person","Amount"])
|
326
|
-
|
327
|
-
This command creates a list object in worksheet named "table 1", with upper left corner at position [1,1] (first cell), with 3 rows and the columns "Person" and "Amount".
|
328
|
-
|
329
|
-
A row in this table can be accessed with help of [], e.g.
|
330
|
-
|
331
|
-
table[1]
|
332
|
-
|
333
|
-
Now we can set and get the value of a cell of the table, e.g.
|
334
|
-
|
335
|
-
table[1].person = "John"
|
336
|
-
table[1].person
|
337
|
-
# => "John"
|
338
|
-
|
339
|
-
Likewise we can get a table with help of an existing Win32OlE table.
|
340
|
-
|
341
|
-
ole_listobject = worksheet.ListObjects.Item("Table 1")
|
342
|
-
table = ListObject.new(ole_listobject)
|
343
|
-
|
344
|
-
r4 = t4[1]
|
345
|
-
r4.person
|
346
|
-
# =>
|
347
|
-
r.person = "John"
|
348
320
|
|
349
321
|
=== More things
|
350
322
|
|
data/bin/jreo
CHANGED
@@ -2,23 +2,26 @@
|
|
2
2
|
# -*- jruby -*-
|
3
3
|
|
4
4
|
require 'pry'
|
5
|
-
require '../lib/robust_excel_ole'
|
5
|
+
require '../robust_excel_ole/lib/robust_excel_ole'
|
6
6
|
|
7
7
|
include REO
|
8
8
|
include General
|
9
9
|
|
10
|
-
puts 'REO console started'
|
11
|
-
puts
|
12
|
-
|
13
10
|
# some pry configuration
|
14
11
|
Pry.config.windows_console_warning = false
|
15
|
-
Pry.config.
|
12
|
+
#Pry.config.history_save = true
|
16
13
|
Pry.config.color = false
|
17
14
|
#Pry.editor = 'notepad' # 'subl', 'vi'
|
18
15
|
#Pry.config.prompt =
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
#
|
16
|
+
#[
|
17
|
+
#->(_obj, _nest_level, _) { ">> " },
|
18
|
+
#->(*) { " " }
|
19
|
+
#]
|
23
20
|
|
24
|
-
|
21
|
+
hooks = Pry::Hooks.new
|
22
|
+
|
23
|
+
hooks.add_hook :when_started, :hook12 do
|
24
|
+
puts 'REO console started'
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
Pry.start(nil, hooks: hooks)
|
data/bin/reo
CHANGED
@@ -2,23 +2,26 @@
|
|
2
2
|
# -*- ruby -*-
|
3
3
|
|
4
4
|
require 'pry'
|
5
|
-
require '../lib/robust_excel_ole'
|
5
|
+
require '../robust_excel_ole/lib/robust_excel_ole'
|
6
6
|
|
7
7
|
include REO
|
8
8
|
include General
|
9
9
|
|
10
|
-
puts 'REO console started'
|
11
|
-
puts
|
12
|
-
|
13
10
|
# some pry configuration
|
14
11
|
Pry.config.windows_console_warning = false
|
15
|
-
Pry.config.
|
12
|
+
#Pry.config.history_save = true
|
16
13
|
Pry.config.color = false
|
17
14
|
#Pry.editor = 'notepad' # 'subl', 'vi'
|
18
15
|
#Pry.config.prompt =
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
#
|
16
|
+
#[
|
17
|
+
#->(_obj, _nest_level, _) { ">> " },
|
18
|
+
#->(*) { " " }
|
19
|
+
#]
|
23
20
|
|
24
|
-
|
21
|
+
hooks = Pry::Hooks.new
|
22
|
+
|
23
|
+
hooks.add_hook :when_started, :hook12 do
|
24
|
+
puts 'REO console started'
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
Pry.start(nil, hooks: hooks)
|
data/jreo.bat
CHANGED
data/lib/reo_console.rb
CHANGED
@@ -1,21 +1,24 @@
|
|
1
1
|
require 'pry'
|
2
|
-
require 'robust_excel_ole'
|
2
|
+
require '../robust_excel_ole/lib/robust_excel_ole'
|
3
3
|
|
4
4
|
include REO
|
5
5
|
include General
|
6
6
|
|
7
|
-
puts 'REO console started'
|
8
|
-
puts
|
9
|
-
|
10
7
|
# some pry configuration
|
11
8
|
Pry.config.windows_console_warning = false
|
12
|
-
Pry.config.
|
9
|
+
#Pry.config.history_save = true
|
13
10
|
Pry.config.color = false
|
14
11
|
#Pry.editor = 'notepad' # 'subl', 'vi'
|
15
12
|
#Pry.config.prompt =
|
16
|
-
#
|
17
|
-
|
18
|
-
|
19
|
-
#
|
13
|
+
#[
|
14
|
+
#->(_obj, _nest_level, _) { ">> " },
|
15
|
+
#->(*) { " " }
|
16
|
+
#]
|
20
17
|
|
21
|
-
|
18
|
+
hooks = Pry::Hooks.new
|
19
|
+
|
20
|
+
hooks.add_hook :when_started, :hook12 do
|
21
|
+
puts 'REO console started'
|
22
|
+
puts
|
23
|
+
end
|
24
|
+
Pry.start(nil, hooks: hooks)
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module RobustExcelOle
|
4
4
|
|
5
|
+
# @private
|
5
6
|
class Bookstore < Base
|
6
7
|
|
7
8
|
def initialize
|
@@ -31,7 +32,7 @@ module RobustExcelOle
|
|
31
32
|
def fetch(filename, options = { :prefer_writable => true })
|
32
33
|
return nil unless filename
|
33
34
|
filename = General.absolute_path(filename)
|
34
|
-
filename_key = General.canonize(filename)
|
35
|
+
filename_key = General.canonize(filename).downcase
|
35
36
|
weakref_books = @filename2books[filename_key]
|
36
37
|
return nil if weakref_books.nil? || weakref_books.empty?
|
37
38
|
|
@@ -69,9 +70,9 @@ module RobustExcelOle
|
|
69
70
|
# stores a workbook
|
70
71
|
# @param [Workbook] book a given book
|
71
72
|
def store(book)
|
72
|
-
filename_key = General.canonize(book.filename)
|
73
|
+
filename_key = General.canonize(book.filename).downcase
|
73
74
|
if book.stored_filename
|
74
|
-
old_filename_key = General.canonize(book.stored_filename)
|
75
|
+
old_filename_key = General.canonize(book.stored_filename).downcase
|
75
76
|
# deletes the weak reference to the book
|
76
77
|
@filename2books[old_filename_key].delete(book)
|
77
78
|
end
|
@@ -20,10 +20,21 @@ module RobustExcelOle
|
|
20
20
|
self.Value = value
|
21
21
|
end
|
22
22
|
|
23
|
+
# @private
|
23
24
|
def ole_cell
|
24
25
|
@ole_range = @ole_range.MergeArea.Item(1,1) if @ole_range.MergeCells
|
25
26
|
end
|
26
27
|
|
28
|
+
# @private
|
29
|
+
def to_s
|
30
|
+
"#<Cell:" + " (#{@ole_range.Row},#{@ole_range.Column})" + ">"
|
31
|
+
end
|
32
|
+
|
33
|
+
# @private
|
34
|
+
def inspect
|
35
|
+
self.to_s[0..-2] + " #{@ole_range.Parent.Name}" + ">"
|
36
|
+
end
|
37
|
+
|
27
38
|
private
|
28
39
|
|
29
40
|
# @private
|
@@ -701,7 +701,7 @@ module RobustExcelOle
|
|
701
701
|
# @param [String] name the name of the range
|
702
702
|
# @param [Variant] value the contents of the range
|
703
703
|
def []=(name, value)
|
704
|
-
set_namevalue_glob(name, value
|
704
|
+
set_namevalue_glob(name, value)
|
705
705
|
end
|
706
706
|
|
707
707
|
# @private
|
@@ -11,29 +11,36 @@ module General
|
|
11
11
|
::RANGES_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
12
12
|
|
13
13
|
@private
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
if drive_letter != default_drive && drive_letter != filename
|
22
|
-
for i in 0 .. drives.Count-1
|
23
|
-
next if i % 2 == 1
|
24
|
-
if drives.Item(i).gsub(':','') == drive_letter
|
25
|
-
hostname_share = drives.Item(i+1) #.gsub('\\','/').gsub('//','')
|
26
|
-
break
|
27
|
-
end
|
14
|
+
NetworkDrive = Struct.new(:drive_letter, :network_name) do
|
15
|
+
|
16
|
+
def self.get_all(drives)
|
17
|
+
ndrives = []
|
18
|
+
count = drives.Count
|
19
|
+
(0..(count - 1)).step(2) do |i|
|
20
|
+
ndrives << NetworkDrive.new( drives.Item(i), drives.Item(i + 1).tr('\\','/'))
|
28
21
|
end
|
29
|
-
|
30
|
-
else
|
31
|
-
return filename
|
22
|
+
ndrives
|
32
23
|
end
|
24
|
+
|
33
25
|
end
|
34
26
|
|
27
|
+
@private
|
28
|
+
def hostnameshare2networkpath(filename)
|
29
|
+
return filename unless filename[0,2] == "//"
|
30
|
+
network = WIN32OLE.new('WScript.Network')
|
31
|
+
drives = network.enumnetworkdrives
|
32
|
+
network_drives = NetworkDrive.get_all(drives)
|
33
|
+
f_c = filename.dup
|
34
|
+
network_drive = network_drives.find do |d|
|
35
|
+
e = f_c.sub!(d.network_name,d.drive_letter)
|
36
|
+
return e if e
|
37
|
+
end
|
38
|
+
filename
|
39
|
+
end
|
40
|
+
|
35
41
|
# @private
|
36
|
-
def absolute_path(file)
|
42
|
+
def absolute_path(file)
|
43
|
+
return file if file[0,2] == "//"
|
37
44
|
file[0,2] = './' if ::EXPANDPATH_JRUBY_BUG && file =~ /[A-Z]:[^\/]/
|
38
45
|
file = File.expand_path(file)
|
39
46
|
file = RobustExcelOle::Cygwin.cygpath('-w', file) if RUBY_PLATFORM =~ /cygwin/
|
@@ -43,12 +50,13 @@ module General
|
|
43
50
|
# @private
|
44
51
|
def canonize(filename)
|
45
52
|
raise TypeREOError, "No string given to canonize, but #{filename.inspect}" unless filename.is_a?(String)
|
46
|
-
filename =
|
47
|
-
normalize(filename)
|
53
|
+
filename = hostnameshare2networkpath(filename)
|
54
|
+
normalize(filename) if filename
|
48
55
|
end
|
49
56
|
|
50
57
|
# @private
|
51
|
-
def normalize(path)
|
58
|
+
def normalize(path)
|
59
|
+
return unless path
|
52
60
|
path = path.gsub('/./', '/') + '/'
|
53
61
|
path = path.gsub(/[\/\\]+/, '/')
|
54
62
|
nil while path.gsub!(/(\/|^)(?!\.\.?)([^\/]+)\/\.\.\//, '\1')
|
@@ -90,9 +98,19 @@ class Array
|
|
90
98
|
end
|
91
99
|
end
|
92
100
|
|
101
|
+
def find_each_index find
|
102
|
+
found, index, q = -1, -1, []
|
103
|
+
while found
|
104
|
+
found = self[index+1..-1].index(find)
|
105
|
+
if found
|
106
|
+
index = index + found + 1
|
107
|
+
q << index
|
108
|
+
end
|
109
|
+
end
|
110
|
+
q
|
111
|
+
end
|
93
112
|
end
|
94
113
|
|
95
|
-
|
96
114
|
# @private
|
97
115
|
class WIN32OLE
|
98
116
|
|
@@ -103,7 +121,7 @@ class WIN32OLE
|
|
103
121
|
class2method = [
|
104
122
|
{Excel => :Hwnd},
|
105
123
|
{Workbook => :FullName},
|
106
|
-
{Worksheet => :
|
124
|
+
{Worksheet => :UsedRange},
|
107
125
|
{RobustExcelOle::Range => :Row},
|
108
126
|
{ListObject => :ListRows}
|
109
127
|
]
|
@@ -113,7 +131,7 @@ class WIN32OLE
|
|
113
131
|
begin
|
114
132
|
self.send(method)
|
115
133
|
if classname == RobustExcelOle::Range && self.Rows.Count == 1 && self.Columns.Count == 1
|
116
|
-
return Cell.new(self)
|
134
|
+
return Cell.new(self, self.Parent)
|
117
135
|
else
|
118
136
|
return classname.new(self)
|
119
137
|
end
|
@@ -164,6 +182,31 @@ class ::String
|
|
164
182
|
word
|
165
183
|
end
|
166
184
|
|
185
|
+
def delete_multiple_underscores
|
186
|
+
word = self
|
187
|
+
while word.index('__') do
|
188
|
+
word.gsub!('__','_')
|
189
|
+
end
|
190
|
+
word
|
191
|
+
end
|
192
|
+
|
193
|
+
def replace_umlauts
|
194
|
+
word = self
|
195
|
+
word.gsub!('ä','ae')
|
196
|
+
word.gsub!('Ä','Ae')
|
197
|
+
word.gsub!('ö','oe')
|
198
|
+
word.gsub!('Ö','Oe')
|
199
|
+
word.gsub!('ü','ue')
|
200
|
+
word.gsub!('Ü','Ue')
|
201
|
+
#word.gsub!(/\x84/,'ae')
|
202
|
+
#word.gsub!(/\x8E/,'Ae')
|
203
|
+
#word.gsub!(/\x94/,'oe')
|
204
|
+
#word.gsub!(/\x99/,'Oe')
|
205
|
+
#word.gsub!(/\x81/,'ue')
|
206
|
+
#word.gsub!(/\x9A/,'Ue')
|
207
|
+
word
|
208
|
+
end
|
209
|
+
|
167
210
|
# taken from http://apidock.com/rails/ActiveSupport/Inflector/constantize
|
168
211
|
# File activesupport/lib/active_support/inflector/methods.rb, line 226
|
169
212
|
def constantize # (camel_cased_word)
|
@@ -14,6 +14,8 @@ module RobustExcelOle
|
|
14
14
|
|
15
15
|
attr_reader :ole_table
|
16
16
|
|
17
|
+
alias ole_object ole_table
|
18
|
+
|
17
19
|
# constructs a list object (or table).
|
18
20
|
# @param [Variable] worksheet_or_ole_listobject a worksheet or a Win32Ole list object
|
19
21
|
# @param [Variable] table_name_or_number a table name or table number
|
@@ -58,31 +60,99 @@ module RobustExcelOle
|
|
58
60
|
def initialize(row_number)
|
59
61
|
@ole_listrow = @@ole_table.ListRows.Item(row_number)
|
60
62
|
end
|
61
|
-
|
63
|
+
|
64
|
+
# returns the value of the cell with given column name or number
|
65
|
+
# @param [Variant] column number or column name
|
66
|
+
# @return [Variant] value of the cell
|
67
|
+
def [] column_number_or_name
|
68
|
+
begin
|
69
|
+
ole_cell = @@ole_table.Application.Intersect(
|
70
|
+
@ole_listrow.Range, @@ole_table.ListColumns.Item(column_number_or_name).Range)
|
71
|
+
ole_cell.Value
|
72
|
+
rescue WIN32OLERuntimeError
|
73
|
+
raise TableRowError, "could not determine the value at column #{column_number_or_name}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def []=(column_number_or_name, value)
|
79
|
+
begin
|
80
|
+
ole_cell = @@ole_table.Application.Intersect(
|
81
|
+
@ole_listrow.Range, @@ole_table.ListColumns.Item(column_number_or_name).Range)
|
82
|
+
ole_cell.Value = value
|
83
|
+
rescue WIN32OLERuntimeError
|
84
|
+
raise TableRowError, "could not assign value #{value.inspect} to cell at column #{column_number_or_name}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# values of the row
|
89
|
+
# @return [Array] values of the row
|
90
|
+
def values
|
91
|
+
begin
|
92
|
+
@ole_listrow.Range.Value.first
|
93
|
+
rescue WIN32OLERuntimeError
|
94
|
+
raise TableError, "could not read values"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# sets the values of the row
|
99
|
+
# @param [Array] values of the row
|
100
|
+
def set_values values
|
101
|
+
begin
|
102
|
+
updated_values = self.values
|
103
|
+
updated_values[0,values.length] = values
|
104
|
+
@ole_listrow.Range.Value = [updated_values]
|
105
|
+
values
|
106
|
+
rescue WIN32OLERuntimeError
|
107
|
+
raise TableError, "could not set values #{values.inspect}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# deletes the values of the row
|
112
|
+
def delete_values
|
113
|
+
begin
|
114
|
+
@ole_listrow.Range.Value = [[].fill(nil,0..(@@ole_table.ListColumns.Count)-1)]
|
115
|
+
nil
|
116
|
+
rescue WIN32OLERuntimeError
|
117
|
+
raise TableError, "could not delete values"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
62
121
|
def method_missing(name, *args)
|
63
|
-
|
122
|
+
name_str = name.to_s
|
123
|
+
core_name = name_str[-1]!='=' ? name_str : name_str[0..-2]
|
64
124
|
column_names = @@ole_table.HeaderRowRange.Value.first
|
65
|
-
|
66
|
-
|
125
|
+
column_name = column_names.find do |c|
|
126
|
+
c == core_name ||
|
127
|
+
c.gsub(/\W/,'') == core_name ||
|
128
|
+
c.replace_umlauts == core_name ||
|
129
|
+
c.gsub(/\W/,'').replace_umlauts == core_name ||
|
130
|
+
c.gsub(/\W/,'').replace_umlauts.underscore.gsub(/[^[\w\d]]/, '_').delete_multiple_underscores == core_name
|
131
|
+
end
|
67
132
|
if column_name
|
68
|
-
|
69
|
-
|
70
|
-
define_getting_setting_method(ole_cell,name.to_s)
|
71
|
-
self.send(name, *args)
|
133
|
+
method_name = core_name.gsub(/\W/,'') + (name_str[-1]!='=' ? "" : "=")
|
134
|
+
define_and_call_method(column_name,method_name,*args)
|
72
135
|
else
|
73
|
-
super
|
136
|
+
super(name, *args)
|
74
137
|
end
|
75
138
|
end
|
76
139
|
|
77
140
|
private
|
78
141
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
142
|
+
def define_and_call_method(column_name,method_name,*args)
|
143
|
+
ole_cell = @@ole_table.Application.Intersect(
|
144
|
+
@ole_listrow.Range, @@ole_table.ListColumns.Item(column_name).Range)
|
145
|
+
define_getting_setting_method(ole_cell,method_name)
|
146
|
+
self.send(method_name, *args)
|
147
|
+
end
|
148
|
+
|
149
|
+
def define_getting_setting_method(ole_cell,name)
|
150
|
+
if name[-1] != '='
|
151
|
+
self.class.define_method(name) do
|
82
152
|
ole_cell.Value
|
83
153
|
end
|
84
154
|
else
|
85
|
-
self.class.define_method(
|
155
|
+
self.class.define_method(name) do |value|
|
86
156
|
ole_cell.Value = value
|
87
157
|
end
|
88
158
|
end
|
@@ -98,34 +168,208 @@ module RobustExcelOle
|
|
98
168
|
|
99
169
|
end
|
100
170
|
|
171
|
+
# @return [Array] a list of column names
|
101
172
|
def column_names
|
102
|
-
|
173
|
+
begin
|
174
|
+
@ole_table.HeaderRowRange.Value.first
|
175
|
+
rescue WIN32OLERuntimeError
|
176
|
+
raise TableError, "could not determine column names"
|
177
|
+
end
|
103
178
|
end
|
104
179
|
|
105
|
-
|
106
|
-
|
107
|
-
|
180
|
+
# adds a row
|
181
|
+
# @param [Integer] position of the new row
|
182
|
+
# @param [Array] values of the column
|
183
|
+
def add_row(position = nil, contents = nil)
|
184
|
+
begin
|
185
|
+
@ole_table.ListRows.Add(position)
|
186
|
+
set_row_values(position, contents) if contents
|
187
|
+
rescue WIN32OLERuntimeError
|
188
|
+
raise TableError, ("could not add row" + (" at position #{position.inspect}" if position))
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
# adds a column
|
193
|
+
# @param [String] name of the column
|
194
|
+
# @param [Integer] position of the new column
|
195
|
+
# @param [Array] values of the column
|
196
|
+
def add_column(column_name = nil, position = nil, contents = nil)
|
197
|
+
begin
|
198
|
+
new_column = @ole_table.ListColumns.Add(position)
|
199
|
+
new_column.Name = column_name if column_name
|
200
|
+
set_column_values(column_name, contents) if contents
|
201
|
+
rescue WIN32OLERuntimeError, TableError
|
202
|
+
raise TableError, ("could not add column"+ ("at position #{position.inspect} with name #{column_name.inspect}" if position))
|
203
|
+
end
|
108
204
|
end
|
109
205
|
|
110
|
-
|
111
|
-
|
206
|
+
# deletes a row
|
207
|
+
# @param [Integer] position of the old row
|
208
|
+
def delete_row(row_number)
|
209
|
+
begin
|
210
|
+
@ole_table.ListRows.Item(row_number).Delete
|
211
|
+
rescue WIN32OLERuntimeError
|
212
|
+
raise TableError, "could not delete row #{row_number.inspect}"
|
213
|
+
end
|
112
214
|
end
|
113
215
|
|
114
|
-
#
|
115
|
-
|
116
|
-
|
216
|
+
# deletes a column
|
217
|
+
# @param [Variant] column number or column name
|
218
|
+
def delete_column(column_number_or_name)
|
219
|
+
begin
|
220
|
+
@ole_table.ListColumns.Item(column_number_or_name).Delete
|
221
|
+
rescue WIN32OLERuntimeError
|
222
|
+
raise TableError, "could not delete column #{column_number_or_name.inspect}"
|
223
|
+
end
|
117
224
|
end
|
118
225
|
|
119
|
-
|
120
|
-
|
226
|
+
# deletes the contents of a row
|
227
|
+
# @param [Integer] row number
|
228
|
+
def delete_row_values(row_number)
|
229
|
+
begin
|
230
|
+
@ole_table.ListRows.Item(row_number).Range.Value = [[].fill(nil,0..(@ole_table.ListColumns.Count-1))]
|
231
|
+
nil
|
232
|
+
rescue WIN32OLERuntimeError
|
233
|
+
raise TableError, "could not delete contents of row #{row_number.inspect}"
|
234
|
+
end
|
121
235
|
end
|
122
236
|
|
237
|
+
# deletes the contents of a column
|
238
|
+
# @param [Variant] column number or column name
|
239
|
+
def delete_column_values(column_number_or_name)
|
240
|
+
begin
|
241
|
+
column_name = @ole_table.ListColumns.Item(column_number_or_name).Range.Value.first
|
242
|
+
@ole_table.ListColumns.Item(column_number_or_name).Range.Value = [column_name] + [].fill([nil],0..(@ole_table.ListRows.Count-1))
|
243
|
+
nil
|
244
|
+
rescue WIN32OLERuntimeError
|
245
|
+
raise TableError, "could not delete contents of column #{column_number_or_name.inspect}"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# renames a row
|
250
|
+
# @param [String] previous name or number of the column
|
251
|
+
# @param [String] new name of the column
|
123
252
|
def rename_column(name_or_number, new_name)
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
253
|
+
begin
|
254
|
+
@ole_table.ListColumns.Item(name_or_number).Name = new_name
|
255
|
+
rescue
|
256
|
+
raise TableError, "could not rename column #{name_or_number.inspect} to #{new_name.inspect}"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# contents of a row
|
261
|
+
# @param [Integer] row number
|
262
|
+
# @return [Array] contents of a row
|
263
|
+
def row_values(row_number)
|
264
|
+
begin
|
265
|
+
@ole_table.ListRows.Item(row_number).Range.Value.first
|
266
|
+
rescue WIN32OLERuntimeError
|
267
|
+
raise TableError, "could not read the values of row #{row_number.inspect}"
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
# sets the contents of a row
|
272
|
+
# @param [Integer] row number
|
273
|
+
# @param [Array] values of the row
|
274
|
+
def set_row_values(row_number, values)
|
275
|
+
begin
|
276
|
+
updated_values = row_values(row_number)
|
277
|
+
updated_values[0,values.length] = values
|
278
|
+
@ole_table.ListRows.Item(row_number).Range.Value = [updated_values]
|
279
|
+
values
|
280
|
+
rescue WIN32OLERuntimeError
|
281
|
+
raise TableError, "could not set the values of row #{row_number.inspect}"
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
# @return [Array] contents of a column
|
286
|
+
def column_values(column_number_or_name)
|
287
|
+
begin
|
288
|
+
@ole_table.ListColumns.Item(column_number_or_name).Range.Value[1,@ole_table.ListRows.Count].flatten
|
289
|
+
rescue WIN32OLERuntimeError
|
290
|
+
raise TableError, "could not read the values of column #{column_number_or_name.inspect}"
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# sets the contents of a column
|
295
|
+
# @param [Integer] column name or column number
|
296
|
+
# @param [Array] contents of the column
|
297
|
+
def set_column_values(column_number_or_name, values)
|
298
|
+
begin
|
299
|
+
updated_values = column_values(column_number_or_name)
|
300
|
+
updated_values[0,values.length] = values
|
301
|
+
column_name = @ole_table.ListColumns.Item(column_number_or_name).Range.Value.first
|
302
|
+
@ole_table.ListColumns.Item(column_number_or_name).Range.Value = column_name + updated_values.map{|v| [v]}
|
303
|
+
values
|
304
|
+
rescue WIN32OLERuntimeError
|
305
|
+
raise TableError, "could not read the values of column #{column_number_or_name.inspect}"
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
# deletes rows that have an empty contents
|
310
|
+
def delete_empty_rows
|
311
|
+
listrows = @ole_table.ListRows
|
312
|
+
nil_array = [[].fill(nil,0..(@ole_table.ListColumns.Count-1))]
|
313
|
+
i = 1
|
314
|
+
while i <= listrows.Count do
|
315
|
+
row = listrows.Item(i)
|
316
|
+
if row.Range.Value == nil_array
|
317
|
+
row.Delete
|
318
|
+
else
|
319
|
+
i = i+1
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
# deletes columns that have an empty contents
|
325
|
+
def delete_empty_columns
|
326
|
+
listcolumns = @ole_table.ListColumns
|
327
|
+
nil_array = [].fill([nil],0..(@ole_table.ListRows.Count-1))
|
328
|
+
i = 1
|
329
|
+
while i <= listcolumns.Count do
|
330
|
+
column = listcolumns.Item(i)
|
331
|
+
if column.Range.Value[1..-1] == nil_array
|
332
|
+
column.Delete
|
333
|
+
else
|
334
|
+
i = i+1
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# finds all cells containing a given value
|
340
|
+
# @param[Variant] value to find
|
341
|
+
# @return [Array] win32ole cells containing the given value
|
342
|
+
def find_cells(value)
|
343
|
+
listrows = @ole_table.ListRows
|
344
|
+
result = []
|
345
|
+
(1..listrows.Count).each do |row_number|
|
346
|
+
row_values(row_number).find_each_index(value).each do |col_number|
|
347
|
+
result << @ole_table.Application.Intersect(listrows.Item(row_number).Range,
|
348
|
+
@ole_table.ListColumns.Item(col_number+1).Range).to_reo
|
349
|
+
end
|
350
|
+
end
|
351
|
+
result
|
352
|
+
end
|
353
|
+
|
354
|
+
# sorts the rows of the list object according to the given column
|
355
|
+
# @param [Variant] column number or name
|
356
|
+
# @option opts [Symbol] sort order
|
357
|
+
def sort(column_number_or_name, sort_order = :ascending)
|
358
|
+
key_range = @ole_table.ListColumns.Item(column_number_or_name).Range
|
359
|
+
@ole_table.Sort.SortFields.Clear
|
360
|
+
sort_order_option = sort_order == :ascending ? XlAscending : XlDescending
|
361
|
+
@ole_table.Sort.SortFields.Add(key_range, XlSortOnValues,sort_order_option,XlSortNormal)
|
362
|
+
@ole_table.Sort.Apply
|
363
|
+
end
|
364
|
+
|
365
|
+
# @private
|
366
|
+
# returns true, if the list object responds to VBA methods, false otherwise
|
367
|
+
def alive?
|
368
|
+
@ole_table.ListRows
|
369
|
+
true
|
370
|
+
rescue
|
371
|
+
# trace $!.message
|
372
|
+
false
|
129
373
|
end
|
130
374
|
|
131
375
|
# @private
|
@@ -136,10 +380,12 @@ module RobustExcelOle
|
|
136
380
|
# @private
|
137
381
|
def inspect
|
138
382
|
"#<ListObject:" + "#{@ole_table.Name}" +
|
139
|
-
"
|
140
|
-
"
|
383
|
+
" #{@ole_table.ListRows.Count}x#{@ole_table.ListColumns.Count}" +
|
384
|
+
" #{@ole_table.Parent.Name}" + " #{@ole_table.Parent.Parent.Name}" + ">"
|
141
385
|
end
|
142
386
|
|
387
|
+
include MethodHelpers
|
388
|
+
|
143
389
|
private
|
144
390
|
|
145
391
|
def method_missing(name, *args)
|
@@ -167,6 +413,10 @@ module RobustExcelOle
|
|
167
413
|
class TableError < WorksheetREOError
|
168
414
|
end
|
169
415
|
|
416
|
+
# @private
|
417
|
+
class TableRowError < WorksheetREOError
|
418
|
+
end
|
419
|
+
|
170
420
|
Table = ListObject
|
171
421
|
TableRow = ListRow
|
172
422
|
|