robust_excel_ole 1.14 → 1.18.1

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog +34 -1
  3. data/README.rdoc +20 -6
  4. data/___dummy_workbook.xls +0 -0
  5. data/docs/README_excel.rdoc +7 -1
  6. data/docs/README_open.rdoc +45 -20
  7. data/docs/README_ranges.rdoc +11 -2
  8. data/examples/example_ruby_library.rb +27 -0
  9. data/extconf.rb +13 -0
  10. data/lib/robust_excel_ole.rb +4 -3
  11. data/lib/robust_excel_ole/{address.rb → address_tool.rb} +23 -22
  12. data/lib/robust_excel_ole/{reo_common.rb → base.rb} +2 -90
  13. data/lib/robust_excel_ole/bookstore.rb +14 -77
  14. data/lib/robust_excel_ole/cell.rb +30 -18
  15. data/lib/robust_excel_ole/excel.rb +105 -64
  16. data/lib/robust_excel_ole/general.rb +40 -15
  17. data/lib/robust_excel_ole/range.rb +42 -19
  18. data/lib/robust_excel_ole/range_owners.rb +40 -25
  19. data/lib/robust_excel_ole/vba_objects.rb +30 -0
  20. data/lib/robust_excel_ole/version.rb +1 -1
  21. data/lib/robust_excel_ole/workbook.rb +310 -336
  22. data/lib/robust_excel_ole/worksheet.rb +51 -25
  23. data/robust_excel_ole.gemspec +1 -0
  24. data/spec/address_tool_spec.rb +175 -0
  25. data/spec/{reo_common_spec.rb → base_spec.rb} +19 -34
  26. data/spec/bookstore_spec.rb +3 -3
  27. data/spec/cell_spec.rb +67 -25
  28. data/spec/data/more_data/workbook.xls +0 -0
  29. data/spec/excel_spec.rb +137 -369
  30. data/spec/general_spec.rb +21 -27
  31. data/spec/range_spec.rb +57 -3
  32. data/spec/workbook_spec.rb +11 -79
  33. data/spec/workbook_specs/workbook_misc_spec.rb +29 -40
  34. data/spec/workbook_specs/workbook_open_spec.rb +570 -30
  35. data/spec/workbook_specs/workbook_unobtr_spec.rb +440 -136
  36. data/spec/worksheet_spec.rb +36 -4
  37. metadata +11 -7
  38. data/spec/address_spec.rb +0 -174
@@ -50,94 +50,10 @@ module RobustExcelOle
50
50
  class MiscREOError < REOError
51
51
  end
52
52
 
53
- # @private
54
- class ExcelDamaged < ExcelREOError
55
- end
56
-
57
- # @private
58
- class UnsavedWorkbooks < ExcelREOError
59
- end
60
-
61
- # @private
62
- class WorkbookBlocked < WorkbookREOError
63
- end
64
-
65
- # @private
66
- class WorkbookNotSaved < WorkbookREOError
67
- end
68
-
69
- # @private
70
- class WorkbookReadOnly < WorkbookREOError
71
- end
72
-
73
- # @private
74
- class WorkbookBeingUsed < WorkbookREOError
75
- end
76
-
77
- # @private
78
- class WorkbookConnectingUnsavedError < WorkbookREOError
79
- end
80
-
81
- # @private
82
- class WorkbookConnectingBlockingError < WorkbookREOError
83
- end
84
-
85
- # @private
86
- class WorkbookConnectingUnknownError < WorkbookREOError
87
- end
88
-
89
- # @private
90
- class FileNotFound < FileREOError
91
- end
92
-
93
- # @private
94
- class FileNameNotGiven < FileREOError
95
- end
96
-
97
- # @private
98
- class FileAlreadyExists < FileREOError
99
- end
100
-
101
- # @private
102
- class NameNotFound < NamesREOError
103
- end
104
-
105
- # @private
106
- class NameAlreadyExists < NamesREOError
107
- end
108
-
109
- # @private
110
- class RangeNotEvaluatable < MiscREOError
111
- end
112
-
113
- # @private
114
- class RangeNotCreated < MiscREOError
115
- end
116
-
117
- # @private
118
- class RangeNotCopied < MiscREOError
119
- end
120
-
121
- # @private
122
- class OptionInvalid < MiscREOError
123
- end
124
-
125
- # @private
126
- class ObjectNotAlive < MiscREOError
127
- end
128
-
129
53
  # @private
130
54
  class TypeREOError < REOError
131
55
  end
132
56
 
133
- # @private
134
- class TimeOut < REOError
135
- end
136
-
137
- # @private
138
- class AddressInvalid < REOError
139
- end
140
-
141
57
  # @private
142
58
  class UnexpectedREOError < REOError
143
59
  end
@@ -145,13 +61,9 @@ module RobustExcelOle
145
61
  # @private
146
62
  class NotImplementedREOError < REOError
147
63
  end
64
+
148
65
 
149
- class REOCommon
150
-
151
- # @private
152
- def excel
153
- raise TypeREOError, 'receiver instance is neither an Excel nor a Workbook'
154
- end
66
+ class Base
155
67
 
156
68
  # @private
157
69
  def own_methods
@@ -2,7 +2,8 @@
2
2
 
3
3
  module RobustExcelOle
4
4
 
5
- class Bookstore < REOCommon
5
+ class Bookstore < Base
6
+
6
7
  def initialize
7
8
  @filename2books ||= Hash.new { |hash, key| hash[key] = [] }
8
9
  @hidden_excel_instance = nil
@@ -29,11 +30,9 @@ module RobustExcelOle
29
30
  # otherwise proceeds according to prefer_writable
30
31
  def fetch(filename, options = { :prefer_writable => true })
31
32
  return nil unless filename
32
-
33
33
  filename = General.absolute_path(filename)
34
34
  filename_key = General.canonize(filename)
35
- weakref_books = @filename2books[filename_key]
36
- weakref_books = consider_networkpaths(filename_key) if weakref_books.empty? || weakref_books.nil?
35
+ weakref_books = @filename2books[filename_key]
37
36
  return nil if weakref_books.nil? || weakref_books.empty?
38
37
 
39
38
  result = open_book = closed_book = nil
@@ -67,68 +66,6 @@ module RobustExcelOle
67
66
  result
68
67
  end
69
68
 
70
- # @private
71
- def consider_networkpaths(filename)
72
- network = WIN32OLE.new('WScript.Network')
73
- drives = network.enumnetworkdrives
74
- drive_letter, filename_after_drive_letter = filename.split(':')
75
- found_filename = nil
76
- # if filename starts with a drive letter not c and this drive exists,
77
- # then if there is the corresponding host_share_path in the bookstore,
78
- # then take the corresponding workbooks
79
- if drive_letter != 'c' && drive_letter != filename
80
- for i in 0 .. drives.Count-1
81
- next if i % 2 == 1
82
- if drives.Item(i).gsub(':','').downcase == drive_letter
83
- hostname_share = drives.Item(i+1).gsub('\\','/').gsub('//','').downcase
84
- break
85
- end
86
- end
87
- @filename2books.each do |stored_filename,_|
88
- if hostname_share && stored_filename
89
- if stored_filename[0] == '/'
90
- index_hostname = stored_filename[1,stored_filename.length].index('/')+2
91
- index_hostname_share = stored_filename[index_hostname,stored_filename.length].index('/')
92
- hostname_share_in_stored_filename = stored_filename[1,index_hostname+index_hostname_share-1]
93
- if hostname_share_in_stored_filename == hostname_share
94
- found_filename = stored_filename
95
- break
96
- end
97
- end
98
- end
99
- end
100
- elsif filename[0] == '/'
101
- # if filename starts with a host name and share, and this is an existing host name share path,
102
- # then if there are workbooks with the corresponding drive letter,
103
- # then take these workbooks,
104
- index_hostname = filename[1,filename.length].index('/')+2
105
- index_hostname_share = filename[index_hostname,filename.length].index('/')
106
- hostname_share_in_filename = filename[1,index_hostname+index_hostname_share-1]
107
- filename_after_hostname_share = filename[index_hostname+index_hostname_share+1, filename.length]
108
- require 'socket'
109
- hostname = Socket.gethostname
110
- if hostname_share_in_filename[0,hostname_share_in_filename.index('/')] == hostname.downcase
111
- for i in 0 .. drives.Count-1
112
- next if i % 2 == 1
113
- hostname_share = drives.Item(i+1).gsub('\\','/').gsub('//','').downcase
114
- if hostname_share == hostname_share_in_filename
115
- drive_letter = drives.Item(i).gsub(':','').downcase
116
- break
117
- end
118
- end
119
- @filename2books.each do |stored_filename,_|
120
- if stored_filename
121
- if drive_letter && stored_filename.start_with?(drive_letter.downcase) && stored_filename.end_with?(filename_after_hostname_share)
122
- found_filename = stored_filename
123
- break
124
- end
125
- end
126
- end
127
- end
128
- end
129
- @filename2books[found_filename]
130
- end
131
-
132
69
  # stores a workbook
133
70
  # @param [Workbook] book a given book
134
71
  def store(book)
@@ -138,8 +75,7 @@ module RobustExcelOle
138
75
  # deletes the weak reference to the book
139
76
  @filename2books[old_filename_key].delete(book)
140
77
  end
141
- @filename2books[filename_key] |= [WeakRef.new(book)]
142
- book.stored_filename = book.filename
78
+ @filename2books[filename_key] |= [WeakRef.new(book)]
143
79
  end
144
80
 
145
81
  # creates and returns a separate Excel instance with Visible and DisplayAlerts equal false
@@ -168,7 +104,6 @@ module RobustExcelOle
168
104
 
169
105
  private
170
106
 
171
- # @private
172
107
  def try_hidden_excel
173
108
  @hidden_excel_instance.__getobj__ if @hidden_excel_instance && @hidden_excel_instance.weakref_alive? && @hidden_excel_instance.__getobj__.alive?
174
109
  end
@@ -177,24 +112,26 @@ module RobustExcelOle
177
112
 
178
113
  # prints the book store
179
114
  # @private
180
- def print
181
- # trace "@filename2books:"
115
+ def print_filename2books
116
+ #puts "@filename2books:"
182
117
  if @filename2books
183
- @filename2books.each do |_filename,books|
184
- # trace " filename: #{filename}"
185
- # trace " books:"
118
+ @filename2books.each do |filename,books|
119
+ #puts " filename: #{filename}"
120
+ #puts " books:"
186
121
  if books.empty?
187
- # trace " []"
122
+ #puts " []"
188
123
  else
189
124
  books.each do |book|
190
125
  if book.weakref_alive?
191
- # trace "#{book}"
126
+ #puts "book.filename: #{book.filename}"
192
127
  else # this should never happen
193
- # trace "weakref not alive"
128
+ #puts "weakref not alive"
194
129
  end
195
130
  end
196
131
  end
197
132
  end
133
+ else
134
+ #puts "nil"
198
135
  end
199
136
  end
200
137
  end
@@ -1,11 +1,15 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
+ require File.join(File.dirname(__FILE__), './range')
4
+
3
5
  module RobustExcelOle
4
- class Cell < REOCommon
5
- attr_reader :cell
6
6
 
7
- def initialize(win32_cell)
8
- @cell = win32_cell.MergeCells ? win32_cell.MergeArea.Item(1,1) : win32_cell
7
+ class Cell < Range
8
+ #attr_reader :ole_cell
9
+
10
+ def initialize(win32_cell, worksheet)
11
+ super
12
+ ole_cell
9
13
  end
10
14
 
11
15
  def v
@@ -16,25 +20,33 @@ module RobustExcelOle
16
20
  self.Value = value
17
21
  end
18
22
 
23
+ def ole_cell
24
+ @ole_range = @ole_range.MergeArea.Item(1,1) if @ole_range.MergeCells
25
+ end
26
+
27
+ private
28
+
19
29
  # @private
20
30
  def method_missing(name, *args)
21
- #if name.to_s[0,1] =~ /[A-Z]/
22
- if JRUBY_BUG_ERRORMESSAGE
23
- begin
24
- @cell.send(name, *args)
25
- rescue Java::OrgRacobCom::ComFailException
26
- raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
31
+ if name.to_s[0,1] =~ /[A-Z]/
32
+ if ::ERRORMESSAGE_JRUBY_BUG
33
+ begin
34
+ #@ole_cell.send(name, *args)
35
+ @ole_range.send(name, *args)
36
+ rescue Java::OrgRacobCom::ComFailException
37
+ raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
38
+ end
39
+ else
40
+ begin
41
+ #@ole_cell.send(name, *args)
42
+ @ole_range.send(name, *args)
43
+ rescue NoMethodError
44
+ raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
45
+ end
27
46
  end
28
47
  else
29
- begin
30
- @cell.send(name, *args)
31
- rescue NoMethodError
32
- raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
33
- end
48
+ super
34
49
  end
35
- # else
36
- # super
37
- # end
38
50
  end
39
51
  end
40
52
  end
@@ -14,21 +14,17 @@ module RobustExcelOle
14
14
  # that you would apply for an Application object.
15
15
  # See https://docs.microsoft.com/en-us/office/vba/api/excel.application(object)#methods
16
16
 
17
- class Excel < RangeOwners
18
- attr_accessor :ole_excel
19
- #attr_accessor :created
20
- attr_accessor :workbook
21
-
22
- # setter methods are implemented below
23
- attr_reader :visible
24
- attr_reader :displayalerts
25
- attr_reader :calculation
26
- attr_reader :screenupdating
17
+ class Excel < VbaObjects
18
+ attr_reader :ole_excel
19
+ attr_reader :properties
20
+ attr_reader :address_tool
27
21
 
28
22
  alias ole_object ole_excel
29
23
 
30
24
  @@hwnd2excel = {}
31
25
 
26
+ PROPERTIES = [:visible, :displayalerts, :calculation, :screenupdating]
27
+
32
28
  # creates a new Excel instance
33
29
  # @param [Hash] options the options
34
30
  # @option options [Variant] :displayalerts
@@ -96,10 +92,7 @@ module RobustExcelOle
96
92
  unless reused || connected
97
93
  options = { :displayalerts => :if_visible, :visible => false, :screenupdating => true }.merge(options)
98
94
  end
99
- result.visible = options[:visible] unless options[:visible].nil?
100
- result.displayalerts = options[:displayalerts] unless options[:displayalerts].nil?
101
- result.calculation = options[:calculation] unless options[:calculation].nil?
102
- result.screenupdating = options[:screenupdating] unless options[:screenupdating].nil?
95
+ result.set_options(options)
103
96
  end
104
97
  result
105
98
  end
@@ -117,14 +110,10 @@ module RobustExcelOle
117
110
  # @return [Excel] an Excel instance
118
111
  def recreate(opts = {})
119
112
  unless alive?
120
- opts = {
121
- :visible => @visible || false,
122
- :displayalerts => @displayalerts || :if_visible
123
- }.merge(opts)
113
+ opts = {:visible => false, :displayalerts => :if_visible}.merge(
114
+ {:visible => @properties[:visible], :displayalerts => @properties[:displayalerts]}).merge(opts)
124
115
  @ole_excel = WIN32OLE.new('Excel.Application')
125
- self.visible = opts[:visible]
126
- self.displayalerts = opts[:displayalerts]
127
- self.calculation = opts[:calculation]
116
+ set_options(opts)
128
117
  if opts[:reopen_workbooks]
129
118
  books = workbook_class.books
130
119
  books.each do |book|
@@ -135,10 +124,18 @@ module RobustExcelOle
135
124
  self
136
125
  end
137
126
 
127
+ # @private
128
+ def address_tool
129
+ raise(ExcelREOError, "Excel contains no workbook") unless @ole_excel.Workbooks.Count > 0
130
+ @address_tool ||= begin
131
+ address_string = @ole_excel.Workbooks.Item(1).Worksheets.Item(1).Cells.Item(1,1).Address(true,true,XlR1C1)
132
+ address_tool_class.new(address_string)
133
+ end
134
+ end
135
+
138
136
  private
139
137
 
140
138
  # retain the saved status of all workbooks
141
- # @private
142
139
  def retain_saved_workbooks
143
140
  saved_stati = @ole_excel.Workbooks.map { |w| w.Saved }
144
141
  begin
@@ -148,7 +145,6 @@ module RobustExcelOle
148
145
  end
149
146
  end
150
147
 
151
- # @private
152
148
  def ole_workbooks
153
149
  ole_workbooks = begin
154
150
  @ole_excel.Workbooks
@@ -163,11 +159,13 @@ module RobustExcelOle
163
159
 
164
160
  public
165
161
 
162
+ # @private
166
163
  def self.contains_unsaved_workbooks?
167
164
  !Excel.current.unsaved_workbooks.empty?
168
165
  end
169
166
 
170
167
  # returns unsaved workbooks (win32ole objects)
168
+ # @private
171
169
  def unsaved_workbooks
172
170
  unsaved_workbooks = []
173
171
  begin
@@ -185,6 +183,7 @@ module RobustExcelOle
185
183
  # :forget -> closes the Excel instance without saving the workbooks
186
184
  # :save -> saves the workbooks before closing
187
185
  # :alert -> let Excel do it
186
+ # @private
188
187
  def close_workbooks(options = { :if_unsaved => :raise })
189
188
  return unless alive?
190
189
 
@@ -392,14 +391,13 @@ module RobustExcelOle
392
391
  @@hwnd2excel.size
393
392
  end
394
393
 
395
- #private
394
+ private
396
395
 
397
396
  # returns a Win32OLE object that represents a Excel instance to which Excel connects
398
397
  # connects to the first opened Excel instance
399
398
  # if this Excel instance is being closed, then Excel creates a new Excel instance
400
- # @private
401
399
  def self.current_ole_excel
402
- if JRUBY_BUG_CONNECT
400
+ if ::CONNECT_EXCEL_JRUBY_BUG
403
401
  result = known_excel_instance
404
402
  if result.nil?
405
403
  if excels_number > 0
@@ -440,6 +438,25 @@ module RobustExcelOle
440
438
  nil
441
439
  end
442
440
 
441
+ def self.hwnd2excel(hwnd)
442
+ excel_weakref = @@hwnd2excel[hwnd]
443
+ if excel_weakref
444
+ if excel_weakref.weakref_alive?
445
+ excel_weakref.__getobj__
446
+ else
447
+ trace 'dead reference to an Excel'
448
+ begin
449
+ @@hwnd2excel.delete(hwnd)
450
+ nil
451
+ rescue
452
+ trace "Warning: deleting dead reference failed! (hwnd: #{hwnd.inspect})"
453
+ end
454
+ end
455
+ end
456
+ end
457
+
458
+ public
459
+
443
460
  # returns all Excel objects for all Excel instances opened with RobustExcelOle
444
461
  def self.known_excel_instances
445
462
  pid2excel = {}
@@ -474,24 +491,6 @@ module RobustExcelOle
474
491
  self
475
492
  end
476
493
 
477
- # @private
478
- def self.hwnd2excel(hwnd)
479
- excel_weakref = @@hwnd2excel[hwnd]
480
- if excel_weakref
481
- if excel_weakref.weakref_alive?
482
- excel_weakref.__getobj__
483
- else
484
- trace 'dead reference to an Excel'
485
- begin
486
- @@hwnd2excel.delete(hwnd)
487
- nil
488
- rescue
489
- trace "Warning: deleting dead reference failed! (hwnd: #{hwnd.inspect})"
490
- end
491
- end
492
- end
493
- end
494
-
495
494
  # @private
496
495
  def hwnd
497
496
  self.Hwnd
@@ -545,7 +544,7 @@ module RobustExcelOle
545
544
 
546
545
  # sets DisplayAlerts in a block
547
546
  def with_displayalerts displayalerts_value
548
- old_displayalerts = displayalerts
547
+ old_displayalerts = @properties[:displayalerts]
549
548
  self.displayalerts = displayalerts_value
550
549
  begin
551
550
  yield self
@@ -556,26 +555,29 @@ module RobustExcelOle
556
555
 
557
556
  # makes the current Excel instance visible or invisible
558
557
  def visible= visible_value
559
- @ole_excel.Visible = @visible = visible_value
560
- @ole_excel.DisplayAlerts = @visible if @displayalerts == :if_visible
558
+ return if visible_value.nil?
559
+ @ole_excel.Visible = @properties[:visible] = visible_value
560
+ @ole_excel.DisplayAlerts = @properties[:visible] if @properties[:displayalerts] == :if_visible
561
561
  end
562
562
 
563
563
  # enables DisplayAlerts in the current Excel instance
564
564
  def displayalerts= displayalerts_value
565
- @displayalerts = displayalerts_value
566
- @ole_excel.DisplayAlerts = @displayalerts == :if_visible ? @ole_excel.Visible : displayalerts_value
565
+ return if displayalerts_value.nil?
566
+ @properties[:displayalerts] = displayalerts_value
567
+ @ole_excel.DisplayAlerts = @properties[:displayalerts] == :if_visible ? @ole_excel.Visible : displayalerts_value
567
568
  end
568
569
 
569
570
  # sets ScreenUpdating
570
571
  def screenupdating= screenupdating_value
571
- @ole_excel.ScreenUpdating = @screenupdating = screenupdating_value
572
+ return if screenupdating_value.nil?
573
+ @ole_excel.ScreenUpdating = @properties[:screenupdating] = screenupdating_value
572
574
  end
573
575
 
574
576
  # sets calculation mode
575
577
  # retains the saved-status of the workbooks when set to manual
576
578
  def calculation= calculation_mode
577
579
  return if calculation_mode.nil?
578
- @calculation = calculation_mode
580
+ @properties[:calculation] = calculation_mode
579
581
  calc_mode_changable = @ole_excel.Workbooks.Count > 0 && @ole_excel.Calculation.is_a?(Integer)
580
582
  if calc_mode_changable
581
583
  retain_saved_workbooks do
@@ -615,9 +617,9 @@ module RobustExcelOle
615
617
  def Calculation= calculation_vba_mode
616
618
  case calculation_vba_mode
617
619
  when XlCalculationManual
618
- @calculation = :manual
620
+ @properties[:calculation] = :manual
619
621
  when XlCalculationAutomatic
620
- @calculation = :automatic
622
+ @properties[:calculation] = :automatic
621
623
  end
622
624
  @ole_excel.Calculation = calculation_vba_mode
623
625
  end
@@ -637,13 +639,22 @@ module RobustExcelOle
637
639
 
638
640
  # set options in this Excel instance
639
641
  def for_this_instance(options)
640
- self.class.new(@ole_excel, options)
642
+ set_options(options)
643
+ #self.class.new(@ole_excel, options)
641
644
  end
642
645
 
643
- def set_options(options)
644
- for_this_instance(options)
645
- end
646
+ #def set_options(options)
647
+ # for_this_instance(options)
648
+ #end
646
649
 
650
+ def set_options(options)
651
+ @properties ||= { }
652
+ PROPERTIES.each do |property|
653
+ method = (property.to_s + '=').to_sym
654
+ self.send(method, options[property])
655
+ end
656
+ end
657
+
647
658
  # set options in all workbooks
648
659
  def for_all_workbooks(options)
649
660
  each_workbook(options)
@@ -690,12 +701,17 @@ module RobustExcelOle
690
701
  # @param [String] name the name of the range
691
702
  # @param [Variant] value the contents of the range
692
703
  def []=(name, value)
693
- old_color_if_modified = workbook.color_if_modified
694
- workbook.color_if_modified = 42 unless workbook.nil? # aqua-marin
695
- set_namevalue_glob(name,value)
696
- workbook.color_if_modified = old_color_if_modified
704
+ set_namevalue_glob(name, value, :color => 42)
697
705
  end
698
706
 
707
+ # @private
708
+ # returns active workbook
709
+ def workbook
710
+ @workbook ||= workbook_class.new(@ole_excel.ActiveWorkbook) if @ole_excel.Workbooks.Count > 0
711
+ end
712
+
713
+ alias_method :active_workbook, :workbook
714
+
699
715
  # @private
700
716
  def to_s
701
717
  '#<Excel: ' + hwnd.to_s + ('not alive' unless alive?).to_s + '>'
@@ -721,15 +737,30 @@ module RobustExcelOle
721
737
  self.class.workbook_class
722
738
  end
723
739
 
740
+ # @private
741
+ def self.address_tool_class
742
+ @address_tool_class ||= begin
743
+ module_name = parent_name
744
+ "#{module_name}::AddressTool".constantize
745
+ rescue NameError => e
746
+ AddressTool
747
+ end
748
+ end
749
+
750
+ # @private
751
+ def address_tool_class
752
+ self.class.address_tool_class
753
+ end
754
+
755
+
724
756
  include MethodHelpers
725
757
 
726
758
  private
727
759
 
728
- # @private
729
760
  def method_missing(name, *args)
730
761
  if name.to_s[0,1] =~ /[A-Z]/
731
762
  raise ObjectNotAlive, 'method missing: Excel not alive' unless alive?
732
- if JRUBY_BUG_ERRORMESSAGE
763
+ if ::ERRORMESSAGE_JRUBY_BUG
733
764
  begin
734
765
  @ole_excel.send(name, *args)
735
766
  rescue Java::OrgRacobCom::ComFailException => msg
@@ -748,7 +779,16 @@ module RobustExcelOle
748
779
  end
749
780
  end
750
781
 
751
- public
782
+ public
783
+
784
+ # @private
785
+ class ExcelDamaged < ExcelREOError
786
+ end
787
+
788
+ # @private
789
+ class UnsavedWorkbooks < ExcelREOError
790
+ end
791
+
752
792
 
753
793
  Application = Excel
754
794
 
@@ -757,3 +797,4 @@ end
757
797
  class WIN32OLE
758
798
  include Enumerable
759
799
  end
800
+