robust_excel_ole 1.19.13 → 1.20

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69409f50b60be33d067f1e3ab2e53af4c467d0cf9a685f2ea6d37ce0edc92da0
4
- data.tar.gz: efd36f474dfde3e684d65addd41bc02c2b4582ad48caccb28d4013ee59baec1e
3
+ metadata.gz: 1cbad43d74758e37eb8e8d17e0297ead9f7cda838f5a157832145d41bacb743a
4
+ data.tar.gz: 80a112947a96132e8f8bb5ccccdccace4b7c1227418475aac51d6aa771b2e876
5
5
  SHA512:
6
- metadata.gz: bc7549286d189d53ba13e2c5c90bc94fe137777828665d8380c32508344f03a500cacecd10d6ec9218523202676214432a6f18f77abfb485a53eb3376ff4133e
7
- data.tar.gz: 507f721508cfbe119637f6f8fc49f13ec4e02cd020b4409a2162674062cc6aedc9301e20ab821733c05fd858c34c15019281a302b2e78d2c3d80dcb664787926
6
+ metadata.gz: 4983b1d7e31e09873bf70e9903e3bdcd7a438e238283c5f2bae9198b5ed53c83fd5726f55b7e9ad4559b820dca65f2c82cb82f85091b199f4b58adfa98064c6b
7
+ data.tar.gz: 6c1c920de4c68699a10e87241121a01e66884317f06ad8ce9962b049c024658b797e014ef0aaaa297287065e80d85514d384925f24412bf1175aa8d97c252865
@@ -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
 
@@ -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,34 +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
103
165
  end
104
166
 
105
- def insert_column(position = 1, column_name = "")
106
- @ole_table.ListColumns.Add
107
- rename_column(position,column_name)
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
108
177
  end
109
178
 
110
- def delete_column(column_name_or_number)
111
- @ole_table.ListColumns.Item(row_number).Delete
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
112
191
  end
113
192
 
114
- # insert row below row_number
115
- def insert_row(position = 1)
116
- @ole_table.ListRows.Add(position)
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
117
201
  end
118
202
 
119
- def delete_row(row_number)
120
- @ole_table.ListRows.Item(row_number).Delete
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
121
234
  end
122
235
 
236
+ # renames a row
237
+ # @param [String] previous name or number of the column
238
+ # @param [String] new name of the column
123
239
  def rename_column(name_or_number, new_name)
124
- column_names = @ole_table.HeaderRowRange.Value.first
125
- position = name_or_number.respond_to?(:abs) ? name_or_number : (column_names.index(name_or_number) + 1)
126
- column_names[position-1] = new_name
127
- @ole_table.HeaderRowRange.Value = [column_names]
128
- 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
129
350
  end
130
351
 
131
352
  # @private
@@ -136,8 +357,8 @@ module RobustExcelOle
136
357
  # @private
137
358
  def inspect
138
359
  "#<ListObject:" + "#{@ole_table.Name}" +
139
- " size:#{@ole_table.ListRows.Count}x#{@ole_table.ListColumns.Count}" +
140
- " 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}" + ">"
141
362
  end
142
363
 
143
364
  private
@@ -167,6 +388,10 @@ module RobustExcelOle
167
388
  class TableError < WorksheetREOError
168
389
  end
169
390
 
391
+ # @private
392
+ class TableRowError < WorksheetREOError
393
+ end
394
+
170
395
  Table = ListObject
171
396
  TableRow = ListRow
172
397
 
@@ -1,3 +1,3 @@
1
1
  module RobustExcelOle
2
- VERSION = "1.19.13"
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.13
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-13 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