robust_excel_ole 1.19.10 → 1.21
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +1 -1
- data/README.rdoc +127 -21
- data/bin/jreo +23 -2
- data/bin/reo +27 -0
- data/lib/reo_console.rb +13 -10
- data/lib/robust_excel_ole/bookstore.rb +1 -0
- data/lib/robust_excel_ole/cell.rb +10 -0
- data/lib/robust_excel_ole/general.rb +64 -21
- data/lib/robust_excel_ole/list_object.rb +292 -16
- data/lib/robust_excel_ole/range.rb +65 -45
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +4 -1
- data/lib/robust_excel_ole/worksheet.rb +14 -0
- data/spec/bookstore_spec.rb +1 -1
- data/spec/general_spec.rb +13 -1
- data/spec/list_object_spec.rb +226 -13
- data/spec/workbook_spec.rb +12 -0
- metadata +4 -4
- data/bin/reo_old +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7598173082d025a168f3c4e8021eb41c97fb1af36943e35cf2a812fcc0f39672
|
4
|
+
data.tar.gz: 2e1e0585da1b1369d323b218b0817f23679b71f99f637a269a6abf14673df615
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09581d754af617dcbe58149087d78c0281e7aa1e6d5feb27f4b58a0b08a0cc5967d15398d85952174143a2e867133b2d1dbf352fd0656bc7488183c7edca94ab'
|
7
|
+
data.tar.gz: bc6c1bed4f9b3370a376b875fa5a4f64b690ef6df6da70efde30a5caa49447b32b28ba09864adcb4c0ca9ea861ddeb28b5af851e30db826e749c6c97cc0153de
|
data/Changelog
CHANGED
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
|
@@ -77,10 +77,10 @@ Let's open a workbook.
|
|
77
77
|
|
78
78
|
workbook = Workbook.open 'spec/data/workbook.xls'
|
79
79
|
|
80
|
-
Now we have a Workbook object that wraps a WIN32OLE object. That is,
|
80
|
+
Now we have a Workbook object that wraps a WIN32OLE object. That is, we can send any WIN32OLE (VBA) method to it. See
|
81
81
|
https://docs.microsoft.com/en-us/office/vba/api/excel.workbook#methods.
|
82
82
|
|
83
|
-
For example,
|
83
|
+
For example, we can determine the name of the workbook.
|
84
84
|
|
85
85
|
workbook.Name
|
86
86
|
# => "workbook.xls"
|
@@ -122,11 +122,11 @@ RobustExcelOle allows unobtrusively reading and modifying workbooks, i.e. access
|
|
122
122
|
# do something
|
123
123
|
end
|
124
124
|
|
125
|
-
|
125
|
+
We can also create a new, empty workbook.
|
126
126
|
|
127
127
|
Workbook.create('spec/data/new_workbook.xls', :visible => true)
|
128
128
|
|
129
|
-
Moreover,
|
129
|
+
Moreover, we can open the workbook using a block, similar to, e.g., +File.open+.
|
130
130
|
|
131
131
|
Workbook.open('spec/data/workbook.xls') do |workbook|
|
132
132
|
# do something
|
@@ -318,33 +318,139 @@ and set another value to that range.
|
|
318
318
|
|
319
319
|
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
320
|
|
321
|
-
===
|
321
|
+
=== List Objects
|
322
|
+
|
323
|
+
=== Creating List Objects
|
322
324
|
|
323
325
|
We can define a list object (or table) from scratch.
|
324
326
|
|
325
|
-
table = ListObject.new(worksheet, "table 1", [1,1], 3,["Person","
|
327
|
+
table = ListObject.new(worksheet, "table 1", [1,1], 3,["Person","AmountSales"])
|
328
|
+
|
329
|
+
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 "Amoun%tSales".
|
326
330
|
|
327
|
-
|
331
|
+
Likewise we can get a RobustExcelOle list object with help of an existing WIN32OlE list object.
|
332
|
+
|
333
|
+
ole_listobject = worksheet.ListObjects.Item("Table 1")
|
334
|
+
table = ListObject.new(ole_listobject)
|
328
335
|
|
329
|
-
|
336
|
+
or
|
330
337
|
|
331
|
-
table
|
338
|
+
table = ole_listobject.to_reo
|
332
339
|
|
333
|
-
Now we
|
340
|
+
Now we have a RobustExcelOle ListObject that wraps a WIN32OLE ListObject. So we can send any WIN32OLE (VBA) method to it. See
|
341
|
+
https://docs.microsoft.com/en-us/office/vba/api/excel.listobject#methods.
|
334
342
|
|
335
|
-
|
336
|
-
table[1].person
|
337
|
-
# => "John"
|
343
|
+
A row in this table can be accessed with help of #[], e.g.
|
338
344
|
|
339
|
-
|
345
|
+
row1 = table[1]
|
340
346
|
|
341
|
-
|
342
|
-
|
347
|
+
=== Reading and setting values
|
348
|
+
|
349
|
+
Now we can set and get the value of a cell of the table with help of methods that are equal to or are underscored variants of the column names, e.g.
|
350
|
+
|
351
|
+
row1.AmountSales = 40
|
352
|
+
|
353
|
+
or
|
354
|
+
|
355
|
+
row1.amount_sales = 40
|
356
|
+
|
357
|
+
and
|
358
|
+
|
359
|
+
row1.AmountSales
|
360
|
+
# => 40
|
361
|
+
|
362
|
+
or
|
363
|
+
|
364
|
+
row1.amount_sales
|
365
|
+
# => 40
|
366
|
+
|
367
|
+
Special characters in the colare being ignored.
|
368
|
+
|
369
|
+
We can also read and set values in a whole row, e.g.
|
370
|
+
|
371
|
+
table.row_values(1)
|
372
|
+
# => ["John", 40]
|
373
|
+
|
374
|
+
or
|
375
|
+
|
376
|
+
table[1].values
|
377
|
+
# => ["John", 40]
|
378
|
+
|
379
|
+
and
|
380
|
+
|
381
|
+
table.set_row_values(1, ["Herbert", 80])
|
382
|
+
# => ["Herbert", 80]
|
383
|
+
|
384
|
+
or
|
385
|
+
|
386
|
+
table[1].set_values(["Herbert", 80])
|
387
|
+
|
388
|
+
If the number of given values is less than the number of cells in the row, only the first values are written. The remaining values keep their value.
|
389
|
+
|
390
|
+
Similarly, we can read and set the values in a whole column, e.g.
|
391
|
+
|
392
|
+
table.column_values("Person")
|
393
|
+
# => ["John", "Peter"]
|
394
|
+
|
395
|
+
and
|
396
|
+
|
397
|
+
table.set_column_values(1, ["Herbert","Paul"])
|
398
|
+
|
399
|
+
The column names we can get with help of
|
400
|
+
|
401
|
+
table.column_names
|
402
|
+
|
403
|
+
A column can be renamed.
|
404
|
+
|
405
|
+
table.rename_column("Person", "Enterprise")
|
406
|
+
|
407
|
+
or
|
408
|
+
|
409
|
+
table.rename_column(1, "Enterprise")
|
410
|
+
|
411
|
+
=== Adding and Deleting rows and columns
|
412
|
+
|
413
|
+
We can add rows and columns, supplying optionally their name, the position and contents.
|
414
|
+
|
415
|
+
table.add_column("column_name")
|
416
|
+
table.add_column("column_name", 3)
|
417
|
+
table.add_column("column_name", 3, ["John", "Paul"])
|
418
|
+
|
419
|
+
table.add_row(3)
|
420
|
+
table.add_row(3, ["John", 40, 2, 2004])
|
421
|
+
|
422
|
+
Deleting columns and rows is done by
|
423
|
+
|
424
|
+
table.delete_column("column_name")
|
425
|
+
table.delete_row(3)
|
426
|
+
|
427
|
+
We can delete only the contents of a column
|
428
|
+
|
429
|
+
table.delete_column_values("column_name")
|
430
|
+
|
431
|
+
Similarly can delete only the contents of a row.
|
432
|
+
|
433
|
+
table.delete_row_values(2)
|
434
|
+
|
435
|
+
or
|
436
|
+
|
437
|
+
table[2].delete_values
|
438
|
+
|
439
|
+
Finally we can delete empty rows and columns.
|
440
|
+
|
441
|
+
table.delete_empty_rows
|
442
|
+
table.delete_empty_columns
|
443
|
+
|
444
|
+
=== Finding values and sorting
|
445
|
+
|
446
|
+
You can find all cells containing a given value, e.g.
|
447
|
+
|
448
|
+
table.find_value(value)
|
449
|
+
#=> [#<Cell: (5,8)>#, #<Cell: (9,6)>#]
|
450
|
+
|
451
|
+
You can sort a table according to a given column and sort order, e.g.
|
343
452
|
|
344
|
-
|
345
|
-
r4.person
|
346
|
-
# =>
|
347
|
-
r.person = "John"
|
453
|
+
table.sort("Person", :ascending)
|
348
454
|
|
349
455
|
=== More things
|
350
456
|
|
data/bin/jreo
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
-
|
1
|
+
#!/usr/bin/env jruby
|
2
|
+
# -*- jruby -*-
|
2
3
|
|
3
|
-
|
4
|
+
require 'pry'
|
5
|
+
require 'robust_excel_ole'
|
6
|
+
|
7
|
+
include REO
|
8
|
+
include General
|
9
|
+
|
10
|
+
puts 'REO console started'
|
11
|
+
puts
|
12
|
+
|
13
|
+
# some pry configuration
|
14
|
+
Pry.config.windows_console_warning = false
|
15
|
+
Pry.config.history.should_save = true
|
16
|
+
Pry.config.color = false
|
17
|
+
#Pry.editor = 'notepad' # 'subl', 'vi'
|
18
|
+
#Pry.config.prompt =
|
19
|
+
# [
|
20
|
+
# ->(_obj, _nest_level, _) { ">> " },
|
21
|
+
# ->(*) { " " }
|
22
|
+
# ]
|
23
|
+
|
24
|
+
pry
|
data/bin/reo
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- ruby -*-
|
3
|
+
|
4
|
+
require 'pry'
|
5
|
+
require '../robust_excel_ole/lib/robust_excel_ole'
|
6
|
+
|
7
|
+
include REO
|
8
|
+
include General
|
9
|
+
|
10
|
+
# some pry configuration
|
11
|
+
Pry.config.windows_console_warning = false
|
12
|
+
#Pry.config.history_save = true
|
13
|
+
Pry.config.color = false
|
14
|
+
#Pry.editor = 'notepad' # 'subl', 'vi'
|
15
|
+
#Pry.config.prompt =
|
16
|
+
#[
|
17
|
+
#->(_obj, _nest_level, _) { ">> " },
|
18
|
+
#->(*) { " " }
|
19
|
+
#]
|
20
|
+
|
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/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)
|
@@ -24,6 +24,16 @@ module RobustExcelOle
|
|
24
24
|
@ole_range = @ole_range.MergeArea.Item(1,1) if @ole_range.MergeCells
|
25
25
|
end
|
26
26
|
|
27
|
+
# @private
|
28
|
+
def to_s
|
29
|
+
@ole_range.Name.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
# @private
|
33
|
+
def inspect
|
34
|
+
"#<Cell:" + " (#{@ole_range.Row},#{@ole_range.Column})" + ">#"
|
35
|
+
end
|
36
|
+
|
27
37
|
private
|
28
38
|
|
29
39
|
# @private
|
@@ -10,28 +10,35 @@ module General
|
|
10
10
|
::CONNECT_EXCEL_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
11
11
|
::RANGES_JRUBY_BUG = IS_JRUBY_PLATFORM && true
|
12
12
|
|
13
|
+
NetworkDrive = Struct.new(:drive_letter, :network_name) do
|
14
|
+
|
15
|
+
def self.get_all(drives)
|
16
|
+
ndrives = []
|
17
|
+
count = drives.Count
|
18
|
+
(0..(count - 1)).step(2) do |i|
|
19
|
+
ndrives << NetworkDrive.new( drives.Item(i), drives.Item(i + 1))
|
20
|
+
end
|
21
|
+
ndrives
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
13
26
|
@private
|
14
27
|
def network2hostnamesharepath(filename)
|
15
28
|
network = WIN32OLE.new('WScript.Network')
|
16
29
|
drives = network.enumnetworkdrives
|
17
|
-
drive_letter, filename_after_drive_letter = filename.split(':')
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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
|
28
|
-
end
|
29
|
-
hostname_share + filename_after_drive_letter if hostname_share
|
30
|
-
else
|
31
|
-
return filename
|
32
|
-
end
|
30
|
+
drive_letter, filename_after_drive_letter = filename.split(':')
|
31
|
+
drive_letter = normalize_drive_letter(drive_letter)
|
32
|
+
network_drives = NetworkDrive.get_all(drives)
|
33
|
+
network_drive = network_drives.find{ |d| d.drive_letter == drive_letter }
|
34
|
+
return filename unless network_drive
|
35
|
+
return network_drive.network_name + filename_after_drive_letter
|
33
36
|
end
|
34
37
|
|
38
|
+
def self.normalize_drive_letter(drive)
|
39
|
+
drive.upcase.end_with?(':') ? drive : "#{drive}:"
|
40
|
+
end
|
41
|
+
|
35
42
|
# @private
|
36
43
|
def absolute_path(file)
|
37
44
|
file[0,2] = './' if ::EXPANDPATH_JRUBY_BUG && file =~ /[A-Z]:[^\/]/
|
@@ -44,11 +51,12 @@ module General
|
|
44
51
|
def canonize(filename)
|
45
52
|
raise TypeREOError, "No string given to canonize, but #{filename.inspect}" unless filename.is_a?(String)
|
46
53
|
filename = network2hostnamesharepath(filename)
|
47
|
-
normalize(filename).downcase
|
54
|
+
normalize(filename).downcase 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)
|