robust_excel_ole 1.19.9 → 1.20

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7148da566c7571df574a54fe8f1fe027f93bcf216e9060951e1ab9318aa68f2b
4
- data.tar.gz: 3c859955ee4ef1a6b3bc71159173c9074388f6bba7a11f071fa253dd520d4521
3
+ metadata.gz: 1cbad43d74758e37eb8e8d17e0297ead9f7cda838f5a157832145d41bacb743a
4
+ data.tar.gz: 80a112947a96132e8f8bb5ccccdccace4b7c1227418475aac51d6aa771b2e876
5
5
  SHA512:
6
- metadata.gz: 7030d95eb00cdc12f2b9d762fbf924422b7a6ffe2f098bbd9c03b8e7acad560c9828756e0cc09ca384af8bb625cf3efacb9ec51b56aa1479d7f383eade83baa8
7
- data.tar.gz: c4c61ae7e2122e8ab98d77f32b188b28f7c230f60fd3be4287e55d35cb9966b30f7492aaa0c8af87e89c048280fbca3de44966e52c83ccc83a9884429e1eb40d
6
+ metadata.gz: 4983b1d7e31e09873bf70e9903e3bdcd7a438e238283c5f2bae9198b5ed53c83fd5726f55b7e9ad4559b820dca65f2c82cb82f85091b199f4b58adfa98064c6b
7
+ data.tar.gz: 6c1c920de4c68699a10e87241121a01e66884317f06ad8ce9962b049c024658b797e014ef0aaaa297287065e80d85514d384925f24412bf1175aa8d97c252865
data/Changelog CHANGED
@@ -2,7 +2,7 @@
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
4
 
5
- ## [1.20] 2020-12-07
5
+ ## [1.20] 2020-14-07
6
6
 
7
7
  ### Changed
8
8
  - using pry in console
@@ -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 Win32OlE.
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, you can send any WIN32OLE (VBA) method to it. See
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, you can determine the name of the workbook.
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
- You can also create a new, empty workbook.
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, you can open the workbook using a block, similar to, e.g., +File.open+.
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,7 +318,9 @@ 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
- === Reading and writing list objects
321
+ === List Objects
322
+
323
+ === Creating list objects
322
324
 
323
325
  We can define a list object (or table) from scratch.
324
326
 
@@ -326,25 +328,115 @@ We can define a list object (or table) from scratch.
326
328
 
327
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 "Amount".
328
330
 
329
- A row in this table can be accessed with help of [], e.g.
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)
335
+
336
+ or
337
+
338
+ table = ole_listobject.to_reo
330
339
 
331
- table[1]
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.
332
342
 
333
- Now we can set and get the value of a cell of the table, e.g.
343
+ A row in this table can be accessed with help of #[], e.g.
334
344
 
335
- table[1].person = "John"
336
- table[1].person
345
+ row1 = table[1]
346
+
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 underscored versions of the column names, e.g.
350
+
351
+ row1.person = "John"
352
+ row1.person
337
353
  # => "John"
338
354
 
339
- Likewise we can get a table with help of an existing Win32OlE table.
355
+ We can also read and set values in a whole row, e.g.
340
356
 
341
- ole_listobject = worksheet.ListObjects.Item("Table 1")
342
- table = ListObject.new(ole_listobject)
357
+ table.row_values(1)
358
+ # => ["John", 40]
359
+
360
+ or
361
+
362
+ table[1].values
363
+ # => ["John", 40]
364
+
365
+ and
366
+
367
+ table.set_row_values(1, ["Herbert", 80])
368
+ # => ["Herbert", 80]
369
+
370
+ or
371
+
372
+ table[1].set_values(["Herbert", 80])
373
+
374
+ 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.
375
+
376
+ Similarly, we can read and set the values in a whole column, e.g.
377
+
378
+ table.column_values("Person")
379
+ # => ["John", "Peter"]
380
+
381
+ and
382
+
383
+ table.set_column_values(1, ["Herbert","Paul"])
384
+
385
+ The column names we can get with help of
386
+
387
+ table.column_names
388
+
389
+ A column can be renamed.
390
+
391
+ table.rename_column("Person", "Enterprise")
392
+
393
+ or
394
+
395
+ table.rename_column(1, "Enterprise")
396
+
397
+ === Adding and Deleting rows and columns
398
+
399
+ We can add rows and columns, supplying optionally their name, the position and contents.
400
+
401
+ table.add_column("column_name")
402
+ table.add_column("column_name", 3)
403
+ table.add_column("column_name", 3, ["John", "Paul"])
404
+
405
+ table.add_row(3)
406
+ table.add_row(3, ["John", 40, 2, 2004])
407
+
408
+ Deleting columns and rows is done by
409
+
410
+ table.delete_column("column_name")
411
+ table.delete_row(3)
412
+
413
+ We can delete only the contents of a column
414
+
415
+ table.delete_column_values("column_name")
416
+
417
+ Similarly can delete only the contents of a row.
418
+
419
+ table.delete_row_values(2)
420
+
421
+ or
422
+
423
+ table[2].delete_values
424
+
425
+ Finally we can delete empty rows and columns.
426
+
427
+ table.delete_empty_rows
428
+ table.delete_empty_columns
429
+
430
+ === Finding values and sorting
431
+
432
+ You can find all cells containing a given value, e.g.
433
+
434
+ table.find_value(value)
435
+ #=> [#<Cell: (5,8)>#, #<Cell: (9,6)>#]
436
+
437
+ You can sort a table according to a given column and sort order, e.g.
343
438
 
344
- r4 = t4[1]
345
- r4.person
346
- # =>
347
- r.person = "John"
439
+ table.sort("Person", :ascending)
348
440
 
349
441
  === More things
350
442
 
data/bin/jreo CHANGED
@@ -1,3 +1,24 @@
1
- @echo off
1
+ #!/usr/bin/env jruby
2
+ # -*- jruby -*-
2
3
 
3
- jruby ../lib/reo_console.rb
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
@@ -1,5 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby -*-
3
+
1
4
  require 'pry'
2
- require '../lib/robust_excel_ole'
5
+ require 'robust_excel_ole'
3
6
 
4
7
  include REO
5
8
  include General
@@ -1,5 +1,5 @@
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
@@ -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_table.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,77 @@ 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
- # if filename starts with a drive letter not c and this drive exists,
19
- # then determine the corresponding host_share_path
20
- default_drive = File.absolute_path(".")[0]
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
28
- end
29
- hostname_share + filename_after_drive_letter if hostname_share
30
- else
31
- return filename
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
36
+ end
37
+
38
+ def self.normalize_drive_letter(drive)
39
+ drive.upcase.end_with?(':') ? drive : "#{drive}:"
40
+ end
41
+
42
+
43
+ =begin
44
+ NetworkDrive = Struct.new(:drive_letter, :network_name)
45
+
46
+ @private
47
+ def network2hostnamesharepath(filename)
48
+ puts "network2hostnamesharepath:"
49
+ puts "filename: #{filename}"
50
+ network = WIN32OLE.new('WScript.Network')
51
+ drives = network.enumnetworkdrives
52
+ puts "drives: #{drives.inspect}"
53
+ drive_letter, filename_after_drive_letter = filename.split(':')
54
+ puts "drive_letter: #{drive_letter.inspect}"
55
+ puts "filename_after_drive_letter: #{filename_after_drive_letter.inspect}"
56
+ drive_letter = normalize_drive_letter(drive_letter)
57
+ puts "drive_letter: #{drive_letter.inspect}"
58
+ network_drives = get_network_drives
59
+ puts "network_drives: #{network_drives.inspect}"
60
+ network_drive = network_drives.find{ |d| d.drive_letter == drive_letter }
61
+ puts "network_drive: #{network_drive.inspect}"
62
+ return filename unless network_drive
63
+ #return (File.exists?(filename) ? filename : nil) unless network_drive
64
+ return network_drive.network_name + filename_after_drive_letter
65
+ end
66
+
67
+ def get_network_drives
68
+ network = WIN32OLE.new('WScript.Network')
69
+ drives = network.enumnetworkdrives
70
+ ndrives = []
71
+ count = drives.Count
72
+ (0..(count - 1)).step(2) do |i|
73
+ ndrives << NetworkDrive.new( drives.Item(i), drives.Item(i + 1))
32
74
  end
75
+ ndrives
33
76
  end
34
77
 
78
+ def normalize_drive_letter(drive)
79
+ drive.upcase.end_with?(':') ? drive : "#{drive}:"
80
+ end
81
+
82
+ =end
83
+
35
84
  # @private
36
85
  def absolute_path(file)
37
86
  file[0,2] = './' if ::EXPANDPATH_JRUBY_BUG && file =~ /[A-Z]:[^\/]/
@@ -44,11 +93,12 @@ module General
44
93
  def canonize(filename)
45
94
  raise TypeREOError, "No string given to canonize, but #{filename.inspect}" unless filename.is_a?(String)
46
95
  filename = network2hostnamesharepath(filename)
47
- normalize(filename).downcase
96
+ normalize(filename).downcase if filename
48
97
  end
49
98
 
50
99
  # @private
51
- def normalize(path)
100
+ def normalize(path)
101
+ return unless path
52
102
  path = path.gsub('/./', '/') + '/'
53
103
  path = path.gsub(/[\/\\]+/, '/')
54
104
  nil while path.gsub!(/(\/|^)(?!\.\.?)([^\/]+)\/\.\.\//, '\1')
@@ -90,9 +140,19 @@ class Array
90
140
  end
91
141
  end
92
142
 
143
+ def find_each_index find
144
+ found, index, q = -1, -1, []
145
+ while found
146
+ found = self[index+1..-1].index(find)
147
+ if found
148
+ index = index + found + 1
149
+ q << index
150
+ end
151
+ end
152
+ q
153
+ end
93
154
  end
94
155
 
95
-
96
156
  # @private
97
157
  class WIN32OLE
98
158
 
@@ -113,7 +173,7 @@ class WIN32OLE
113
173
  begin
114
174
  self.send(method)
115
175
  if classname == RobustExcelOle::Range && self.Rows.Count == 1 && self.Columns.Count == 1
116
- return Cell.new(self)
176
+ return Cell.new(self, self.Parent)
117
177
  else
118
178
  return classname.new(self)
119
179
  end
@@ -58,6 +58,63 @@ module RobustExcelOle
58
58
  def initialize(row_number)
59
59
  @ole_listrow = @@ole_table.ListRows.Item(row_number)
60
60
  end
61
+
62
+ # returns the value of the cell with given column name or number
63
+ # @param [Variant] column number or column name
64
+ # @return [Variant] value of the cell
65
+ def [] column_number_or_name
66
+ begin
67
+ ole_cell = @@ole_table.Application.Intersect(
68
+ @ole_listrow.Range, @@ole_table.ListColumns.Item(column_number_or_name).Range)
69
+ ole_cell.Value
70
+ rescue WIN32OLERuntimeError
71
+ raise TableRowError, "could not determine the value at column #{column_number_or_name}"
72
+ end
73
+ end
74
+
75
+
76
+ def []=(column_number_or_name, value)
77
+ begin
78
+ ole_cell = @@ole_table.Application.Intersect(
79
+ @ole_listrow.Range, @@ole_table.ListColumns.Item(column_number_or_name).Range)
80
+ ole_cell.Value = value
81
+ rescue WIN32OLERuntimeError
82
+ raise TableRowError, "could not assign value #{value.inspect} to cell at column #{column_number_or_name}"
83
+ end
84
+ end
85
+
86
+ # values of the row
87
+ # @return [Array] values of the row
88
+ def values
89
+ begin
90
+ @ole_listrow.Range.Value.first
91
+ rescue WIN32OLERuntimeError
92
+ raise TableError, "could not read values"
93
+ end
94
+ end
95
+
96
+ # sets the values of the row
97
+ # @param [Array] values of the row
98
+ def set_values values
99
+ begin
100
+ updated_values = self.values
101
+ updated_values[0,values.length] = values
102
+ @ole_listrow.Range.Value = [updated_values]
103
+ values
104
+ rescue WIN32OLERuntimeError
105
+ raise TableError, "could not set values #{values.inspect}"
106
+ end
107
+ end
108
+
109
+ # deletes the values of the row
110
+ def delete_values
111
+ begin
112
+ @ole_listrow.Range.Value = [[].fill(nil,0..(@@ole_table.ListColumns.Count)-1)]
113
+ nil
114
+ rescue WIN32OLERuntimeError
115
+ raise TableError, "could not delete values"
116
+ end
117
+ end
61
118
 
62
119
  def method_missing(name, *args)
63
120
  name_before_last_equal = name.to_s.split('=').first
@@ -66,7 +123,7 @@ module RobustExcelOle
66
123
  column_name = column_names[method_names.index(name_before_last_equal)]
67
124
  if column_name
68
125
  ole_cell = @@ole_table.Application.Intersect(
69
- @ole_listrow.Range, @@ole_table.ListColumns(column_name).Range)
126
+ @ole_listrow.Range, @@ole_table.ListColumns.Item(column_name).Range)
70
127
  define_getting_setting_method(ole_cell,name.to_s)
71
128
  self.send(name, *args)
72
129
  else
@@ -98,8 +155,198 @@ module RobustExcelOle
98
155
 
99
156
  end
100
157
 
158
+ # @return [Array] a list of column names
101
159
  def column_names
102
- @ole_table.HeaderRowRange.Value.first
160
+ begin
161
+ @ole_table.HeaderRowRange.Value.first
162
+ rescue WIN32OLERuntimeError
163
+ raise TableError, "could not determine column names"
164
+ end
165
+ end
166
+
167
+ # adds a row
168
+ # @param [Integer] position of the new row
169
+ # @param [Array] values of the column
170
+ def add_row(position = nil, contents = nil)
171
+ begin
172
+ @ole_table.ListRows.Add(position)
173
+ set_row_values(position, contents) if contents
174
+ rescue WIN32OLERuntimeError
175
+ raise TableError, ("could not add row" + (" at position #{position.inspect}" if position))
176
+ end
177
+ end
178
+
179
+ # adds a column
180
+ # @param [String] name of the column
181
+ # @param [Integer] position of the new column
182
+ # @param [Array] values of the column
183
+ def add_column(column_name = nil, position = nil, contents = nil)
184
+ begin
185
+ new_column = @ole_table.ListColumns.Add(position)
186
+ new_column.Name = column_name if column_name
187
+ set_column_values(column_name, contents) if contents
188
+ rescue WIN32OLERuntimeError, TableError
189
+ raise TableError, ("could not add column"+ ("at position #{position.inspect} with name #{column_name.inspect}" if position))
190
+ end
191
+ end
192
+
193
+ # deletes a row
194
+ # @param [Integer] position of the old row
195
+ def delete_row(row_number)
196
+ begin
197
+ @ole_table.ListRows.Item(row_number).Delete
198
+ rescue WIN32OLERuntimeError
199
+ raise TableError, "could not delete row #{row_number.inspect}"
200
+ end
201
+ end
202
+
203
+ # deletes a column
204
+ # @param [Variant] column number or column name
205
+ def delete_column(column_number_or_name)
206
+ begin
207
+ @ole_table.ListColumns.Item(column_number_or_name).Delete
208
+ rescue WIN32OLERuntimeError
209
+ raise TableError, "could not delete column #{column_number_or_name.inspect}"
210
+ end
211
+ end
212
+
213
+ # deletes the contents of a row
214
+ # @param [Integer] row number
215
+ def delete_row_values(row_number)
216
+ begin
217
+ @ole_table.ListRows.Item(row_number).Range.Value = [[].fill(nil,0..(@ole_table.ListColumns.Count-1))]
218
+ nil
219
+ rescue WIN32OLERuntimeError
220
+ raise TableError, "could not delete contents of row #{row_number.inspect}"
221
+ end
222
+ end
223
+
224
+ # deletes the contents of a column
225
+ # @param [Variant] column number or column name
226
+ def delete_column_values(column_number_or_name)
227
+ begin
228
+ column_name = @ole_table.ListColumns.Item(column_number_or_name).Range.Value.first
229
+ @ole_table.ListColumns.Item(column_number_or_name).Range.Value = [column_name] + [].fill([nil],0..(@ole_table.ListRows.Count-1))
230
+ nil
231
+ rescue WIN32OLERuntimeError
232
+ raise TableError, "could not delete contents of column #{column_number_or_name.inspect}"
233
+ end
234
+ end
235
+
236
+ # renames a row
237
+ # @param [String] previous name or number of the column
238
+ # @param [String] new name of the column
239
+ def rename_column(name_or_number, new_name)
240
+ begin
241
+ @ole_table.ListColumns.Item(name_or_number).Name = new_name
242
+ rescue
243
+ raise TableError, "could not rename column #{name_or_number.inspect} to #{new_name.inspect}"
244
+ end
245
+ end
246
+
247
+ # contents of a row
248
+ # @param [Integer] row number
249
+ # @return [Array] contents of a row
250
+ def row_values(row_number)
251
+ begin
252
+ @ole_table.ListRows.Item(row_number).Range.Value.first
253
+ rescue WIN32OLERuntimeError
254
+ raise TableError, "could not read the values of row #{row_number.inspect}"
255
+ end
256
+ end
257
+
258
+ # sets the contents of a row
259
+ # @param [Integer] row number
260
+ # @param [Array] values of the row
261
+ def set_row_values(row_number, values)
262
+ begin
263
+ updated_values = row_values(row_number)
264
+ updated_values[0,values.length] = values
265
+ @ole_table.ListRows.Item(row_number).Range.Value = [updated_values]
266
+ values
267
+ rescue WIN32OLERuntimeError
268
+ raise TableError, "could not set the values of row #{row_number.inspect}"
269
+ end
270
+ end
271
+
272
+ # @return [Array] contents of a column
273
+ def column_values(column_number_or_name)
274
+ begin
275
+ @ole_table.ListColumns.Item(column_number_or_name).Range.Value[1,@ole_table.ListRows.Count].flatten
276
+ rescue WIN32OLERuntimeError
277
+ raise TableError, "could not read the values of column #{column_number_or_name.inspect}"
278
+ end
279
+ end
280
+
281
+ # sets the contents of a column
282
+ # @param [Integer] column name or column number
283
+ # @param [Array] contents of the column
284
+ def set_column_values(column_number_or_name, values)
285
+ begin
286
+ updated_values = column_values(column_number_or_name)
287
+ updated_values[0,values.length] = values
288
+ column_name = @ole_table.ListColumns.Item(column_number_or_name).Range.Value.first
289
+ @ole_table.ListColumns.Item(column_number_or_name).Range.Value = column_name + updated_values.map{|v| [v]}
290
+ values
291
+ rescue WIN32OLERuntimeError
292
+ raise TableError, "could not read the values of column #{column_number_or_name.inspect}"
293
+ end
294
+ end
295
+
296
+ # deletes rows that have an empty contents
297
+ def delete_empty_rows
298
+ listrows = @ole_table.ListRows
299
+ nil_array = [[].fill(nil,0..(@ole_table.ListColumns.Count-1))]
300
+ i = 1
301
+ while i <= listrows.Count do
302
+ row = listrows.Item(i)
303
+ if row.Range.Value == nil_array
304
+ row.Delete
305
+ else
306
+ i = i+1
307
+ end
308
+ end
309
+ end
310
+
311
+ # deletes columns that have an empty contents
312
+ def delete_empty_columns
313
+ listcolumns = @ole_table.ListColumns
314
+ nil_array = [].fill([nil],0..(@ole_table.ListRows.Count-1))
315
+ i = 1
316
+ while i <= listcolumns.Count do
317
+ column = listcolumns.Item(i)
318
+ if column.Range.Value[1..-1] == nil_array
319
+ column.Delete
320
+ else
321
+ i = i+1
322
+ end
323
+ end
324
+ end
325
+
326
+ # finds all cells containing a given value
327
+ # @param[Variant] value to find
328
+ # @return [Array] win32ole cells containing the given value
329
+ def find_cells(value)
330
+ listrows = @ole_table.ListRows
331
+ result = []
332
+ (1..listrows.Count).each do |row_number|
333
+ row_values(row_number).find_each_index(value).each do |col_number|
334
+ result << @ole_table.Application.Intersect(listrows.Item(row_number).Range,
335
+ @ole_table.ListColumns.Item(col_number+1).Range).to_reo
336
+ end
337
+ end
338
+ result
339
+ end
340
+
341
+ # sorts the rows of the list object according to the given column
342
+ # @param [Variant] column number or name
343
+ # @option opts [Symbol] sort order
344
+ def sort(column_number_or_name, sort_order = :ascending)
345
+ key_range = @ole_table.ListColumns.Item(column_number_or_name).Range
346
+ @ole_table.Sort.SortFields.Clear
347
+ sort_order_option = sort_order == :ascending ? XlAscending : XlDescending
348
+ @ole_table.Sort.SortFields.Add(key_range, XlSortOnValues,sort_order_option,XlSortNormal)
349
+ @ole_table.Sort.Apply
103
350
  end
104
351
 
105
352
  # @private
@@ -110,8 +357,8 @@ module RobustExcelOle
110
357
  # @private
111
358
  def inspect
112
359
  "#<ListObject:" + "#{@ole_table.Name}" +
113
- " size:#{@ole_table.ListRows.Count}x#{@ole_table.ListColumns.Count}" +
114
- " worksheet:#{@ole_table.Parent.Name}" + " workbook:#{@ole_table.Parent.Parent.Name}" + ">"
360
+ " #{@ole_table.ListRows.Count}x#{@ole_table.ListColumns.Count}" +
361
+ " #{@ole_table.Parent.Name}" + " #{@ole_table.Parent.Parent.Name}" + ">"
115
362
  end
116
363
 
117
364
  private
@@ -141,6 +388,10 @@ module RobustExcelOle
141
388
  class TableError < WorksheetREOError
142
389
  end
143
390
 
391
+ # @private
392
+ class TableRowError < WorksheetREOError
393
+ end
394
+
144
395
  Table = ListObject
145
396
  TableRow = ListRow
146
397
 
@@ -1,3 +1,3 @@
1
1
  module RobustExcelOle
2
- VERSION = "1.19.9"
2
+ VERSION = "1.20"
3
3
  end
@@ -97,6 +97,9 @@ module RobustExcelOle
97
97
  when String
98
98
  file = file_or_workbook
99
99
  raise FileNotFound, "file #{General.absolute_path(file).inspect} is a directory" if File.directory?(file)
100
+ when ->(n){ n.respond_to? :to_path }
101
+ file = file_or_workbook.to_path
102
+ raise FileNotFound, "file #{General.absolute_path(file).inspect} is a directory" if File.directory?(file)
100
103
  else
101
104
  raise TypeREOError, 'given object is neither a filename, a Win32ole, nor a Workbook object'
102
105
  end
@@ -59,7 +59,7 @@ describe Bookstore do
59
59
  @file_path = "spec/data/workbook.xls"
60
60
  @absolute_file_path = "C:/gim/ats/aSrc/gems/robust_excel_ole/spec/data/workbook.xls"
61
61
  @network_path = "N:/data/workbook.xls"
62
- @hostname_share_path = "DESKTOP-A3C5CJ6/spec/workbook.xls"
62
+ @hostname_share_path = "DESKTOP-A3C5CJ6/spec/data/workbook.xls"
63
63
  end
64
64
 
65
65
  after do
@@ -29,6 +29,10 @@ module RobustExcelOle
29
29
  @linked_file = @dir + '/workbook_linked.xlsm'
30
30
  @simple_file_xlsm = @dir + '/workbook.xls'
31
31
  @simple_file_xlsx = @dir + '/workbook.xlsx'
32
+ @network_path = "N:/data/workbook.xls"
33
+ @hostname_share_path = "//DESKTOP-A3C5CJ6/spec/data/workbook.xls"
34
+ @simple_file_extern = "D:/data/workbook.xls"
35
+ @hostname_share_path = "//DESKTOP-A3C5CJ6/spec/data/workbook.xls"
32
36
  end
33
37
 
34
38
  after do
@@ -186,7 +190,7 @@ module RobustExcelOle
186
190
  filename = 'C:/Dokumente und Einstellungen/Zauberthomas/Eigene Dateien/robust_excel_ole/spec/book_spec.rb'
187
191
  absolute_path(filename).gsub("\\","/").should == filename
188
192
  end
189
- end
193
+ end
190
194
  end
191
195
 
192
196
  describe "canonize" do
@@ -230,6 +234,14 @@ module RobustExcelOle
230
234
  }.to raise_error(TypeREOError, "No string given to canonize, but 1")
231
235
  end
232
236
 
237
+ it "should yield the hostname share path" do
238
+ General.canonize(@network_path).should == normalize(@hostname_share_path).downcase
239
+ General.canonize(@hostname_share_path).should == normalize(@hostname_share_path).downcase
240
+ General.canonize(@simple_file).should == normalize(@simple_file).downcase
241
+ General.canonize(@simple_file_extern).should == normalize(@simple_file_extern).downcase
242
+ end
243
+
244
+
233
245
  end
234
246
  end
235
247
 
@@ -45,7 +45,7 @@ describe ListObject do
45
45
  ole_table = @sheet.ListObjects.Item(1)
46
46
  table = Table.new(ole_table)
47
47
  table.Name.should == "table3"
48
- table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Date"]
48
+ table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Price"]
49
49
  table.ListRows.Count.should == 6
50
50
  @sheet[3,4].Value.should == "Number"
51
51
  end
@@ -54,7 +54,7 @@ describe ListObject do
54
54
  ole_table = @sheet.ListObjects.Item(1)
55
55
  table = Table.new(@sheet, "table3")
56
56
  table.Name.should == "table3"
57
- table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Date"]
57
+ table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Price"]
58
58
  table.ListRows.Count.should == 6
59
59
  @sheet[3,4].Value.should == "Number"
60
60
  end
@@ -63,7 +63,7 @@ describe ListObject do
63
63
  ole_table = @sheet.ListObjects.Item(1)
64
64
  table = Table.new(@sheet, 1)
65
65
  table.Name.should == "table3"
66
- table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Date"]
66
+ table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Price"]
67
67
  table.ListRows.Count.should == 6
68
68
  @sheet[3,4].Value.should == "Number"
69
69
  end
@@ -80,7 +80,7 @@ describe ListObject do
80
80
  ole_table = @sheet.ListObjects.Item(1)
81
81
  table = Table.new(@sheet.ole_worksheet, "table3")
82
82
  table.Name.should == "table3"
83
- table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Date"]
83
+ table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Price"]
84
84
  table.ListRows.Count.should == 6
85
85
  @sheet[3,4].Value.should == "Number"
86
86
  end
@@ -89,7 +89,7 @@ describe ListObject do
89
89
  ole_table = @sheet.ListObjects.Item(1)
90
90
  table = Table.new(@sheet.ole_worksheet, 1)
91
91
  table.Name.should == "table3"
92
- table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Date"]
92
+ table.HeaderRowRange.Value.first.should == ["Number","Person","Amount","Time","Price"]
93
93
  table.ListRows.Count.should == 6
94
94
  @sheet[3,4].Value.should == "Number"
95
95
  end
@@ -117,6 +117,7 @@ describe ListObject do
117
117
  @table_row1.amount.should == 42
118
118
  @sheet[2,2].Value.should == 42
119
119
  end
120
+
120
121
  end
121
122
 
122
123
  context "with type-lifted ole list object" do
@@ -132,12 +133,216 @@ describe ListObject do
132
133
  @table_row1.number = 1
133
134
  @table_row1.number.should == 1
134
135
  @sheet[4,4].Value.should == 1
135
- @table_row1.person.should == "Herbert"
136
- @table_row1.person = "John"
137
136
  @table_row1.person.should == "John"
138
- @sheet[4,5].Value.should == "John"
137
+ @table_row1.person = "Herbert"
138
+ @table_row1.person.should == "Herbert"
139
+ @sheet[4,5].Value.should == "Herbert"
139
140
  end
140
141
  end
141
142
 
142
143
  end
144
+
145
+ describe "reading and setting contents of rows and columns" do
146
+
147
+ before do
148
+ ole_table = @sheet.ListObjects.Item(1)
149
+ @table = Table.new(ole_table)
150
+ end
151
+
152
+ it "should read contents of a column" do
153
+ @table.column_values("Person").should == ["John","Fred",nil,"Angel",nil,"Werner"]
154
+ expect{
155
+ @table.column_values("P")
156
+ }.to raise_error(TableError)
157
+ end
158
+
159
+ it "should set contents of a column" do
160
+ @table.set_column_values("Person",["H",nil,nil,nil,"G","W"])
161
+ @table.ListColumns.Item(2).Range.Value.should == [["Person"],["H"],[nil],[nil],[nil],["G"],["W"]]
162
+ @table.set_column_values("Person",["T","Z"])
163
+ @table.ListColumns.Item(2).Range.Value.should == [["Person"],["T"],["Z"],[nil],[nil],["G"],["W"]]
164
+ expect{
165
+ @table.set_column_values("P",["H",nil,nil,nil,"G","W"])
166
+ }.to raise_error(TableError)
167
+ end
168
+
169
+ it "should read contents of a row" do
170
+ @table.row_values(1).should == [3.0, "John", 50.0, 0.5, 30]
171
+ @table[1].values.should == [3.0, "John", 50.0, 0.5, 30]
172
+ expect{
173
+ @table.row_values(9)
174
+ }.to raise_error(TableError)
175
+ end
176
+
177
+ it "should set contents of a row" do
178
+ @table.set_row_values(1, [5, "George", 30.0, 0.2, 50])
179
+ @table.ListRows.Item(1).Range.Value.first.should == [5, "George", 30.0, 0.2, 50]
180
+ @table.set_row_values(1, [6, "Martin"])
181
+ @table.ListRows.Item(1).Range.Value.first.should == [6, "Martin", 30.0, 0.2, 50]
182
+ @table[1].set_values([2, "Merlin", 20.0, 0.1, 40])
183
+ @table[1].set_values([4, "John"])
184
+ @table.ListRows.Item(1).Range.Value.first.should == [4, "John", 20.0, 0.1, 40]
185
+ expect{
186
+ @table.set_row_values(9, [5, "George", 30.0, 0.2, 50])
187
+ }.to raise_error(TableError)
188
+ end
189
+
190
+ end
191
+
192
+ describe "renaming, adding and deleting columns and rows" do
193
+
194
+ before do
195
+ ole_table = @sheet.ListObjects.Item(1)
196
+ @table = Table.new(ole_table)
197
+ end
198
+
199
+ it "should list column names" do
200
+ @table.column_names.should == @table.HeaderRowRange.Value.first
201
+ end
202
+
203
+ it "should rename a column name" do
204
+ @table.rename_column("Person", "P")
205
+ @table.HeaderRowRange.Value.first.should == ["Number","P","Amount","Time","Price"]
206
+ end
207
+
208
+ it "should append a column" do
209
+ @table.add_column("column_name")
210
+ column_names = @table.HeaderRowRange.Value.first.should == ["Number","Person", "Amount","Time","Price", "column_name"]
211
+ end
212
+
213
+ it "should add a column" do
214
+ @table.add_column("column_name", 3)
215
+ column_names = @table.HeaderRowRange.Value.first.should == ["Number","Person","column_name","Amount","Time","Price"]
216
+ expect{
217
+ @table.add_column(8, "column_name")
218
+ }.to raise_error(TableError)
219
+ end
220
+
221
+ it "should add a column with contents" do
222
+ @table.add_column("column_name", 3, ["a","b","c","d","e","f"])
223
+ column_names = @table.HeaderRowRange.Value.first.should == ["Number","Person","column_name","Amount","Time","Price"]
224
+ @table.ListColumns.Item(3).Range.Value.should == [["column_name"],["a"],["b"],["c"],["d"],["e"],["f"]]
225
+ end
226
+
227
+ it "should delete a column" do
228
+ @table.delete_column(4)
229
+ @table.HeaderRowRange.Value.first.should == ["Number","Person", "Amount","Price"]
230
+ expect{
231
+ @table.delete_column(6)
232
+ }.to raise_error(TableError)
233
+ end
234
+
235
+ it "should append a row" do
236
+ @table.add_row
237
+ listrows = @table.ListRows
238
+ listrows.Item(listrows.Count).Range.Value.first.should == [nil,nil,nil,nil,nil]
239
+ end
240
+
241
+ it "should add a row" do
242
+ @table.add_row(2)
243
+ listrows = @table.ListRows
244
+ listrows.Item(1).Range.Value.first.should == [3.0, "John", 50.0, 0.5, 30]
245
+ listrows.Item(2).Range.Value.first.should == [nil,nil,nil,nil,nil]
246
+ listrows.Item(3).Range.Value.first.should == [2.0, "Fred", nil, 0.5416666666666666, 40]
247
+ expect{
248
+ @table.add_row(9)
249
+ }.to raise_error(TableError)
250
+ end
251
+
252
+ it "should add a row with contents" do
253
+ @table.add_row(2, [2.0, "Herbert", 30.0, 0.25, 40])
254
+ listrows = @table.ListRows
255
+ listrows.Item(1).Range.Value.first.should == [3.0, "John", 50.0, 0.5, 30]
256
+ listrows.Item(2).Range.Value.first.should == [2.0, "Herbert", 30.0, 0.25, 40]
257
+ listrows.Item(3).Range.Value.first.should == [2.0, "Fred", nil, 0.5416666666666666, 40]
258
+ end
259
+
260
+ it "should delete a row" do
261
+ @table.delete_row(4)
262
+ listrows = @table.ListRows
263
+ listrows.Item(5).Range.Value.first.should == [1,"Werner",40,0.5, 80]
264
+ listrows.Item(4).Range.Value.first.should == [nil,nil,nil,nil,nil]
265
+ expect{
266
+ @table.delete_row(8)
267
+ }.to raise_error(TableError)
268
+ end
269
+
270
+ it "should delete the contents of a column" do
271
+ @table.ListColumns.Item(3).Range.Value.should == [["Amount"],[50],[nil],[nil],[100],[nil],[40]]
272
+ @table.delete_column_values(3)
273
+ @table.HeaderRowRange.Value.first.should == ["Number","Person", "Amount", "Time","Price"]
274
+ @table.ListColumns.Item(3).Range.Value.should == [["Amount"],[nil],[nil],[nil],[nil],[nil],[nil]]
275
+ @table.ListColumns.Item(1).Range.Value.should == [["Number"],[3],[2],[nil],[3],[nil],[1]]
276
+ @table.delete_column_values("Number")
277
+ @table.ListColumns.Item(1).Range.Value.should == [["Number"],[nil],[nil],[nil],[nil],[nil],[nil]]
278
+ expect{
279
+ @table.delete_column_values("N")
280
+ }.to raise_error(TableError)
281
+ end
282
+
283
+ it "should delete the contents of a row" do
284
+ @table.ListRows.Item(2).Range.Value.first.should == [2.0, "Fred", nil, 0.5416666666666666, 40]
285
+ @table.delete_row_values(2)
286
+ @table.ListRows.Item(2).Range.Value.first.should == [nil,nil,nil,nil,nil]
287
+ @table.ListRows.Item(1).Range.Value.first.should == [3.0, "John", 50.0, 0.5, 30]
288
+ @table[1].delete_values
289
+ @table.ListRows.Item(1).Range.Value.first.should == [nil,nil,nil,nil,nil]
290
+ expect{
291
+ @table.delete_row_values(9)
292
+ }.to raise_error(TableError)
293
+ end
294
+
295
+ it "should delete empty rows" do
296
+ @table.delete_empty_rows
297
+ @table.ListRows.Count.should == 4
298
+ @table.ListRows.Item(1).Range.Value.first.should == [3.0, "John", 50.0, 0.5, 30]
299
+ @table.ListRows.Item(2).Range.Value.first.should == [2.0, "Fred", nil, 0.5416666666666666, 40]
300
+ @table.ListRows.Item(3).Range.Value.first.should == [3, "Angel", 100, 0.6666666666666666, 60]
301
+ @table.ListRows.Item(4).Range.Value.first.should == [1,"Werner",40,0.5, 80]
302
+ end
303
+
304
+ it "should delete empty columns" do
305
+ @table.delete_column_values(4)
306
+ @table.ListColumns.Count.should == 5
307
+ @table.HeaderRowRange.Value.first.should == ["Number","Person", "Amount", "Time","Price"]
308
+ @table.delete_empty_columns
309
+ @table.ListColumns.Count.should == 4
310
+ @table.HeaderRowRange.Value.first.should == ["Number","Person", "Amount","Price"]
311
+ end
312
+ end
313
+
314
+ describe "find all cells of a given value" do
315
+
316
+ before do
317
+ ole_table = @sheet.ListObjects.Item(1)
318
+ @table = Table.new(ole_table)
319
+ end
320
+
321
+ it "should find all cells" do
322
+ cells = @table.find_cells(40)
323
+ cells[0].Row.should == 5
324
+ cells[0].Column.should == 8
325
+ cells[1].Row.should == 9
326
+ cells[1].Column.should == 6
327
+ end
328
+
329
+ end
330
+
331
+ describe "sort the table" do
332
+
333
+ before do
334
+ ole_table = @sheet.ListObjects.Item(1)
335
+ @table = Table.new(ole_table)
336
+ end
337
+
338
+ it "should sort the table according to first table" do
339
+ @table.sort("Number")
340
+ @table.ListRows.Item(1).Range.Value.first.should == [1,"Werner",40,0.5, 80]
341
+ @table.ListRows.Item(2).Range.Value.first.should == [2, "Fred", nil, 0.5416666666666666, 40]
342
+ @table.ListRows.Item(3).Range.Value.first.should == [3, "John", 50.0, 0.5, 30]
343
+ @table.ListRows.Item(4).Range.Value.first.should == [3, "Angel", 100, 0.6666666666666666, 60]
344
+ end
345
+
346
+ end
347
+
143
348
  end
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  require File.join(File.dirname(__FILE__), './spec_helper')
4
+ require 'pathname'
4
5
 
5
6
  $VERBOSE = nil
6
7
 
@@ -20,6 +21,7 @@ describe Workbook do
20
21
  before do
21
22
  @dir = create_tmpdir
22
23
  @simple_file = @dir + '/workbook.xls'
24
+ @pathname_file = Pathname(@dir) + 'workbook.xls'
23
25
  @simple_save_file = @dir + '/workbook_save.xls'
24
26
  @different_file = @dir + '/different_workbook.xls'
25
27
  @simple_file_other_path = @dir + '/more_data/workbook.xls'
@@ -47,6 +49,16 @@ describe Workbook do
47
49
  @book.close
48
50
  end
49
51
  end
52
+
53
+ context "with pathname" do
54
+ it "open an existing file" do
55
+ expect {
56
+ @book = Workbook.open(@pathname_file)
57
+ }.to_not raise_error
58
+ @book.should be_a Workbook
59
+ @book.close
60
+ end
61
+ end
50
62
  end
51
63
 
52
64
  describe "Book" do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: robust_excel_ole
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.9
4
+ version: '1.20'
5
5
  platform: ruby
6
6
  authors:
7
7
  - traths
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-12 00:00:00.000000000 Z
11
+ date: 2020-07-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -49,8 +49,7 @@ email:
49
49
  - Thomas.Raths@gmx.net
50
50
  executables:
51
51
  - jreo
52
- - reo.rb
53
- - reo_old
52
+ - reo
54
53
  extensions: []
55
54
  extra_rdoc_files:
56
55
  - README.rdoc
@@ -80,8 +79,7 @@ files:
80
79
  - benchmarking/simple_xlsx_reader_example.rb
81
80
  - benchmarking/spreadsheet_example.rb
82
81
  - bin/jreo
83
- - bin/reo.rb
84
- - bin/reo_old
82
+ - bin/reo
85
83
  - docs/README_excel.rdoc
86
84
  - docs/README_open.rdoc
87
85
  - docs/README_ranges.rdoc
@@ -1,3 +0,0 @@
1
- @echo off
2
-
3
- ruby ../lib/reo_console.rb