robust_excel_ole 0.3.7 → 0.3.8

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.
@@ -1,6 +1,8 @@
1
1
 
2
2
  # -*- coding: utf-8 -*-
3
3
 
4
+ include Utilities
5
+
4
6
  module RobustExcelOle
5
7
 
6
8
  class Bookstore
@@ -11,6 +13,10 @@ module RobustExcelOle
11
13
  end
12
14
 
13
15
  # returns a book with the given filename, if it was open once
16
+ # @param [String] filename the file name
17
+ # @param [Hash] options the options
18
+ # @option option [Boolean] :prefer_writable
19
+ # @option option [Boolean] :prefer_excel
14
20
  # prefers open books to closed books, and among them, prefers more recently opened books
15
21
  # excludes hidden Excel instance
16
22
  # options: :prefer_writable returns the writable book, if it is open (default: true)
@@ -29,7 +35,7 @@ module RobustExcelOle
29
35
  begin
30
36
  @filename2books[filename_key].delete(wr_book)
31
37
  rescue
32
- t "Warning: deleting dead reference failed: file: #{filename.inspect}"
38
+ trace "Warning: deleting dead reference failed: file: #{filename.inspect}"
33
39
  end
34
40
  else
35
41
  book = wr_book.__getobj__
@@ -51,6 +57,7 @@ module RobustExcelOle
51
57
  end
52
58
 
53
59
  # stores a workbook
60
+ # @param [Book] book a given book
54
61
  def store(book)
55
62
  filename_key = RobustExcelOle::canonize(book.filename)
56
63
  if book.stored_filename
@@ -63,7 +70,7 @@ module RobustExcelOle
63
70
  end
64
71
 
65
72
  # creates and returns a separate Excel instance with Visible and DisplayAlerts equal false
66
- def hidden_excel
73
+ def hidden_excel # :nodoc: #
67
74
  unless (@hidden_excel_instance && @hidden_excel_instance.weakref_alive? && @hidden_excel_instance.__getobj__.alive?)
68
75
  @hidden_excel_instance = WeakRef.new(Excel.create)
69
76
  end
@@ -87,25 +94,25 @@ module RobustExcelOle
87
94
 
88
95
  private
89
96
 
90
- def try_hidden_excel
97
+ def try_hidden_excel # :nodoc: #
91
98
  @hidden_excel_instance.__getobj__ if (@hidden_excel_instance && @hidden_excel_instance.weakref_alive? && @hidden_excel_instance.__getobj__.alive?)
92
99
  end
93
100
 
94
101
  # prints the book store
95
- def print
96
- t "@filename2books:"
102
+ def print # :nodoc: #
103
+ trace "@filename2books:"
97
104
  if @filename2books
98
105
  @filename2books.each do |filename,books|
99
- t " filename: #{filename}"
100
- t " books:"
106
+ trace " filename: #{filename}"
107
+ trace " books:"
101
108
  if books.empty?
102
- t " []"
109
+ trace " []"
103
110
  else
104
111
  books.each do |book|
105
112
  if book.weakref_alive?
106
- t "#{book}"
113
+ trace "#{book}"
107
114
  else
108
- t "weakref not alive"
115
+ trace "weakref not alive"
109
116
  end
110
117
  end
111
118
  end
@@ -11,7 +11,7 @@ module RobustExcelOle
11
11
  @conv_to_win32_path =
12
12
  Win32API.new('cygwin1.dll', 'cygwin_conv_to_win32_path', 'PP', 'I')
13
13
 
14
- def cygpath(options, path)
14
+ def cygpath(options, path) # :nodoc: #
15
15
  absolute = shortname = false
16
16
  func = nil
17
17
  options.delete(" \t-").chars {|opt|
@@ -2,30 +2,40 @@
2
2
 
3
3
  require 'timeout'
4
4
 
5
- module RobustExcelOle
5
+ include Utilities
6
+
7
+ module RobustExcelOle
6
8
 
7
9
  class Excel
8
10
 
9
11
  @@hwnd2excel = {}
10
12
 
11
13
  # creates a new Excel instance
14
+ # @return [Excel] a new Excel instance
12
15
  def self.create
13
16
  new(:reuse => false)
14
17
  end
15
18
 
16
19
  # uses the current Excel instance (connects), if such a running Excel instance exists
17
20
  # creates a new one, otherwise
21
+ # @return [Excel] an Excel instance
18
22
  def self.current
19
23
  new(:reuse => true)
20
24
  end
21
25
 
22
26
  # returns an Excel instance
23
- # given: a WIN32OLE object representing an Excel instance, or a Hash representing options:
27
+ # given a WIN32OLE object representing an Excel instance, or a Hash representing options:
28
+ # @param [Hash] options the options
29
+ # @option options [Boolean] :reuse
30
+ # @option options [Boolean] :displayalerts
31
+ # @option options [Boolean] :visible
32
+ # options:
24
33
  # :reuse connects to an already running Excel instance (true) or
25
34
  # creates a new Excel instance (false) (default: true)
26
35
  # :displayalerts allows display alerts in Excel (default: false)
27
36
  # :visible makes the Excel visible (default: false)
28
37
  # if :reuse => true, then DisplayAlerts and Visible are set only if they are given
38
+ # @return [Excel] an Excel instance
29
39
  def self.new(options = {})
30
40
  if options.is_a? WIN32OLE
31
41
  excel = options
@@ -66,8 +76,13 @@ module RobustExcelOle
66
76
  end
67
77
 
68
78
  # reopens a closed Excel instance
79
+ # @param [Hash] opts the options
80
+ # @option opts [Boolean] :reopen_workbooks
81
+ # @option opts [Boolean] :displayalerts
82
+ # @option opts [Boolean] :visible
69
83
  # options: reopen_workbooks (default: false): reopen the workbooks in the Excel instances
70
84
  # :visible (default: false), :displayalerts (default: false)
85
+ # @return [Excel] an Excel instance
71
86
  def recreate(opts = {})
72
87
  unless self.alive?
73
88
  opts = {
@@ -99,7 +114,7 @@ module RobustExcelOle
99
114
  begin
100
115
  result.Visible # send any method, just to see if it responds
101
116
  rescue
102
- t "dead excel " + ("Window-handle = #{result.HWnd}" rescue "without window handle")
117
+ trace "dead excel " + ("Window-handle = #{result.HWnd}" rescue "without window handle")
103
118
  return nil
104
119
  end
105
120
  end
@@ -110,14 +125,21 @@ module RobustExcelOle
110
125
  public
111
126
 
112
127
  # closes all Excel instances
128
+ # @param [Hash] options the options
129
+ # @option options [Symbol] :if_unsaved :raise, :save, :forget, :alert, or :keep_open
130
+ # @option options [Boolean] :hard
131
+ # @option options [Boolean] :kill_if_timeout
113
132
  # options:
114
133
  # :if_unsaved if unsaved workbooks are open in an Excel instance
115
134
  # :raise (default) -> raises an exception
116
135
  # :save -> saves the workbooks before closing
117
136
  # :forget -> closes the excel instance without saving the workbooks
137
+ # :keep_open -> let the workbooks open
118
138
  # :alert -> give control to Excel
119
139
  # :hard closes Excel instances soft (default: false), or, additionally kills the Excel processes hard (true)
120
140
  # :kill_if_timeout: kills Excel instances hard if the closing process exceeds a certain time limit (default: true)
141
+ # @raise ExcelError if time limit has exceeded, some Excel instance cannot be closed, or
142
+ # unsaved workbooks exist and option :if_unsaved is :raise
121
143
  def self.close_all(options={})
122
144
  options = {
123
145
  :if_unsaved => :raise,
@@ -153,12 +175,12 @@ module RobustExcelOle
153
175
 
154
176
  private
155
177
 
156
- def self.manage_unsaved_workbooks(excel, options)
178
+ def self.manage_unsaved_workbooks(excel, options) # :nodoc: #
157
179
  unsaved_workbooks = []
158
180
  begin
159
181
  excel.Workbooks.each {|w| unsaved_workbooks << w unless (w.Saved || w.ReadOnly)}
160
182
  rescue RuntimeError => msg
161
- t "RuntimeError: #{msg.message}"
183
+ trace "RuntimeError: #{msg.message}"
162
184
  raise ExcelErrorOpen, "Excel instance not alive or damaged" if msg.message =~ /failed to get Dispatch Interface/
163
185
  end
164
186
  unless unsaved_workbooks.empty?
@@ -199,7 +221,7 @@ module RobustExcelOle
199
221
  end
200
222
  end
201
223
 
202
- def self.close_excel_ole_instance(ole_excel)
224
+ def self.close_excel_ole_instance(ole_excel) # :nodoc: #
203
225
  @@hwnd2excel.delete(ole_excel.Hwnd)
204
226
  excel = ole_excel
205
227
  ole_excel = nil
@@ -214,21 +236,21 @@ module RobustExcelOle
214
236
  if weak_excel_ref.weakref_alive? then
215
237
  begin
216
238
  weak_excel_ref.ole_free
217
- t "successfully ole_freed #{weak_excel_ref}"
239
+ trace "successfully ole_freed #{weak_excel_ref}"
218
240
  rescue
219
- t "could not do ole_free on #{weak_excel_ref}"
241
+ trace "could not do ole_free on #{weak_excel_ref}"
220
242
  end
221
243
  end
222
244
  @@hwnd2excel.delete(excel_hwnd)
223
245
  rescue => e
224
- t "Error when closing Excel: #{e.message}"
246
+ trace "Error when closing Excel: #{e.message}"
225
247
  #t e.backtrace
226
248
  end
227
249
  free_all_ole_objects
228
250
  end
229
251
 
230
252
  # frees all OLE objects in the object space
231
- def self.free_all_ole_objects
253
+ def self.free_all_ole_objects # :nodoc: #
232
254
  anz_objekte = 0
233
255
  ObjectSpace.each_object(WIN32OLE) do |o|
234
256
  anz_objekte += 1
@@ -238,18 +260,21 @@ module RobustExcelOle
238
260
  #t o.ole_type rescue nil
239
261
  begin
240
262
  o.ole_free
241
- #t "olefree OK"
263
+ #trace "olefree OK"
242
264
  rescue
243
- #t "olefree_error: #{$!}"
244
- #t $!.backtrace.first(9).join "\n"
265
+ #trace "olefree_error: #{$!}"
266
+ #trace $!.backtrace.first(9).join "\n"
245
267
  end
246
268
  end
247
- t "went through #{anz_objekte} OLE objects"
269
+ trace "went through #{anz_objekte} OLE objects"
248
270
  end
249
271
 
250
272
  public
251
273
 
252
274
  # closes the Excel
275
+ # @param [Hash] options the options
276
+ # @option options [Symbol] :if_unsaved :raise, :save, :forget, or :keep_open
277
+ # @option options [Boolean] :hard
253
278
  # :if_unsaved if unsaved workbooks are open in an Excel instance
254
279
  # :raise (default) -> raises an exception
255
280
  # :save -> saves the workbooks before closing
@@ -285,10 +310,10 @@ module RobustExcelOle
285
310
  if weak_excel_ref.weakref_alive? then
286
311
  begin
287
312
  weak_excel_ref.ole_free
288
- t "successfully ole_freed #{weak_excel_ref}"
313
+ trace "successfully ole_freed #{weak_excel_ref}"
289
314
  rescue => msg
290
- t "#{msg.message}"
291
- t "could not do ole_free on #{weak_excel_ref}"
315
+ trace "#{msg.message}"
316
+ trace "could not do ole_free on #{weak_excel_ref}"
292
317
  end
293
318
  end
294
319
  @@hwnd2excel.delete(excel_hwnd)
@@ -305,6 +330,7 @@ module RobustExcelOle
305
330
  public
306
331
 
307
332
  # kill all Excel instances
333
+ # @return [Fixnum] number of killed Excel processes
308
334
  def self.kill_all
309
335
  procs = WIN32OLE.connect("winmgmts:\\\\.")
310
336
  processes = procs.InstancesOf("win32_process")
@@ -345,31 +371,31 @@ module RobustExcelOle
345
371
  result
346
372
  end
347
373
 
348
- def excel
374
+ def excel # :nodoc: #
349
375
  self
350
376
  end
351
377
 
352
- def self.hwnd2excel(hwnd)
378
+ def self.hwnd2excel(hwnd) # :nodoc: #
353
379
  excel_weakref = @@hwnd2excel[hwnd]
354
380
  if excel_weakref
355
381
  if excel_weakref.weakref_alive?
356
382
  excel_weakref.__getobj__
357
383
  else
358
- t "dead reference to an Excel"
384
+ trace "dead reference to an Excel"
359
385
  begin
360
386
  @@hwnd2excel.delete(hwnd)
361
387
  rescue
362
- t "Warning: deleting dead reference failed! (hwnd: #{hwnd.inspect})"
388
+ trace "Warning: deleting dead reference failed! (hwnd: #{hwnd.inspect})"
363
389
  end
364
390
  end
365
391
  end
366
392
  end
367
393
 
368
- def hwnd
394
+ def hwnd # :nodoc: #
369
395
  self.Hwnd rescue nil
370
396
  end
371
397
 
372
- def self.print_hwnd2excel
398
+ def self.print_hwnd2excel # :nodoc: #
373
399
  @@hwnd2excel.each do |hwnd,wr_excel|
374
400
  excel_string = (wr_excel.weakref_alive? ? wr_excel.__getobj__.to_s : "weakref not alive")
375
401
  printf("hwnd: %8i => excel: %s\n", hwnd, excel_string)
@@ -393,7 +419,7 @@ module RobustExcelOle
393
419
 
394
420
 
395
421
  # returns all unsaved workbooks in Excel instances
396
- def self.unsaved_workbooks_all
422
+ def self.unsaved_workbooks_all # :nodoc: #
397
423
  result = []
398
424
  @@hwnd2excel.each do |hwnd,wr_excel|
399
425
  excel = wr_excel.__getobj__
@@ -408,7 +434,7 @@ module RobustExcelOle
408
434
  begin
409
435
  self.Workbooks.each {|w| result << w unless (w.Saved || w.ReadOnly)}
410
436
  rescue RuntimeError => msg
411
- t "RuntimeError: #{msg.message}"
437
+ trace "RuntimeError: #{msg.message}"
412
438
  raise ExcelErrorOpen, "Excel instance not alive or damaged" if msg.message =~ /failed to get Dispatch Interface/
413
439
  end
414
440
  result
@@ -417,11 +443,11 @@ module RobustExcelOle
417
443
  #self.class.map {|w| (not w.Saved)}
418
444
 
419
445
  def print_workbooks
420
- self.Workbooks.each {|w| t "#{w.Name} #{w}"}
446
+ self.Workbooks.each {|w| puts "#{w.Name} #{w}"}
421
447
  end
422
448
 
423
449
 
424
- # empty workbook is generated, saved and closed
450
+ # generates, saves, and closes empty workbook
425
451
  def generate_workbook file_name
426
452
  self.Workbooks.Add
427
453
  empty_workbook = self.Workbooks.Item(self.Workbooks.Count)
@@ -457,7 +483,7 @@ module RobustExcelOle
457
483
  @displayalerts = @ole_excel.DisplayAlerts = displayalerts_value
458
484
  end
459
485
 
460
- # return if in the current Excel instance DisplayAlerts is enabled
486
+ # return whether DisplayAlerts is enabled in the current Excel instance
461
487
  def displayalerts
462
488
  @displayalerts = @ole_excel.DisplayAlerts
463
489
  end
@@ -472,15 +498,15 @@ module RobustExcelOle
472
498
  @visible = @ole_excel.Visible
473
499
  end
474
500
 
475
- def to_s
501
+ def to_s # :nodoc: #
476
502
  "#<Excel: " + "#{hwnd}" + ("#{"not alive" unless self.alive?}") + ">"
477
503
  end
478
504
 
479
- def inspect
505
+ def inspect # :nodoc: #
480
506
  self.to_s
481
507
  end
482
508
 
483
- def self.book_class
509
+ def self.book_class # :nodoc: #
484
510
  @book_class ||= begin
485
511
  module_name = self.parent_name
486
512
  "#{module_name}::Book".constantize
@@ -489,13 +515,27 @@ module RobustExcelOle
489
515
  end
490
516
  end
491
517
 
492
- def book_class
518
+ def book_class # :nodoc: #
493
519
  self.class.book_class
494
520
  end
495
521
 
522
+ def respond_to?(name, include_private = false) # :nodoc: #
523
+ raise ExcelError, "respond_to?: Excel not alive" unless alive?
524
+ super
525
+ end
526
+
527
+ def methods # :nodoc: #
528
+ (super + @ole_excel.ole_methods.map{|m| m.to_s}).uniq
529
+ end
530
+
531
+ def special_methods # :nodoc: #
532
+ (methods - Object.methods).sort
533
+ end
534
+
535
+
496
536
  private
497
537
 
498
- def method_missing(name, *args)
538
+ def method_missing(name, *args) # :nodoc: #
499
539
  if name.to_s[0,1] =~ /[A-Z]/
500
540
  begin
501
541
  raise ExcelError, "method missing: Excel not alive" unless alive?
@@ -1,5 +1,9 @@
1
1
  # -*- coding: utf-8 -*-
2
+
3
+ include Utilities
4
+
2
5
  module RobustExcelOle
6
+
3
7
  class Sheet
4
8
  attr_reader :worksheet
5
9
 
@@ -16,10 +20,13 @@ module RobustExcelOle
16
20
  end
17
21
  end
18
22
 
23
+ # returns name of the workbook
19
24
  def name
20
25
  @worksheet.Name
21
26
  end
22
27
 
28
+ # name the sheet
29
+ # @param [String] new_name the new name of the sheet
23
30
  def name= (new_name)
24
31
  begin
25
32
  @worksheet.Name = new_name
@@ -27,7 +34,7 @@ module RobustExcelOle
27
34
  if msg.message =~ /800A03EC/
28
35
  raise ExcelErrorSheet, "sheet name #{new_name.inspect} already exists"
29
36
  else
30
- t "#{msg.message}"
37
+ trace "#{msg.message}"
31
38
  raise ExcelErrorSheetUnknown
32
39
  end
33
40
  end
@@ -104,8 +111,12 @@ module RobustExcelOle
104
111
  end
105
112
 
106
113
  # returns the contents of a range with given name
114
+ # @param [String] name the range name
115
+ # @param [Hash] opts the options
116
+ # @option opts [Variant] :default default value (default: nil)
107
117
  # if no contents could returned, then return default value, if a default value was provided
108
118
  # raise an error, otherwise
119
+ # @raise SheetError if value of the range cannot be evaluated
109
120
  def nvalue(name, opts = {:default => nil})
110
121
  begin
111
122
  value = self.Evaluate(name)
@@ -116,12 +127,16 @@ module RobustExcelOle
116
127
  end
117
128
  if value == -2146826259
118
129
  return opts[:default] if opts[:default]
119
- raise SheetError, "cannot evaluate name #{name.inspect} in sheet"
130
+ raise SheeetError, "cannot evaluate name #{name.inspect} in sheet"
120
131
  end
121
132
  return opts[:default] if (value.nil? && opts[:default])
122
133
  value
123
134
  end
124
135
 
136
+ # assigns a value to a range with given name
137
+ # @param [String] name the range name
138
+ # @param [Variant] value the assigned value
139
+ # @raise SheetError if name is not in the sheet or the value cannot be assigned
125
140
  def set_nvalue(name,value)
126
141
  begin
127
142
  item = self.Names.Item(name)
@@ -136,6 +151,9 @@ module RobustExcelOle
136
151
  end
137
152
 
138
153
  # assigns a name to a range (a cell) given by an address
154
+ # @param [String] name the range name
155
+ # @param [Fixnum] row the row
156
+ # @param [Fixnum] column the column
139
157
  def set_name(name,row,column)
140
158
  begin
141
159
  old_name = self[row,column].Name.Name rescue nil
@@ -146,28 +164,36 @@ module RobustExcelOle
146
164
  self.Names.Add("Name" => name, "RefersToR1C1" => "=" + address)
147
165
  end
148
166
  rescue WIN32OLERuntimeError => msg
149
- t "WIN32OLERuntimeError: #{msg.message}"
167
+ trace "WIN32OLERuntimeError: #{msg.message}"
150
168
  raise SheetError, "cannot add name #{name.inspect} to cell with row #{row.inspect} and column #{column.inspect}"
151
169
  end
152
170
  end
153
171
 
172
+ def respond_to?(name, include_private = false) # :nodoc: #
173
+ super
174
+ end
175
+
176
+ def methods # :nodoc: #
177
+ super
178
+ end
179
+
154
180
  private
155
181
 
156
- def method_missing(name, *args)
157
- if name.to_s[0,1] =~ /[A-Z]/
158
- begin
159
- @worksheet.send(name, *args)
160
- rescue WIN32OLERuntimeError => msg
161
- if msg.message =~ /unknown property or method/
162
- raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
163
- else
164
- raise msg
182
+ def method_missing(name, *args) # :nodoc: #
183
+ if name.to_s[0,1] =~ /[A-Z]/
184
+ begin
185
+ @worksheet.send(name, *args)
186
+ rescue WIN32OLERuntimeError => msg
187
+ if msg.message =~ /unknown property or method/
188
+ raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
189
+ else
190
+ raise msg
191
+ end
165
192
  end
193
+ else
194
+ super
166
195
  end
167
- else
168
- super
169
196
  end
170
- end
171
197
 
172
198
 
173
199
  def last_row