robust_excel_ole 1.19.10 → 1.21
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 +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)
|