robust_excel_ole 1.21 → 1.24

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.
@@ -32,7 +32,7 @@ module RobustExcelOle
32
32
  def fetch(filename, options = { :prefer_writable => true })
33
33
  return nil unless filename
34
34
  filename = General.absolute_path(filename)
35
- filename_key = General.canonize(filename)
35
+ filename_key = General.canonize(filename).downcase
36
36
  weakref_books = @filename2books[filename_key]
37
37
  return nil if weakref_books.nil? || weakref_books.empty?
38
38
 
@@ -70,9 +70,9 @@ module RobustExcelOle
70
70
  # stores a workbook
71
71
  # @param [Workbook] book a given book
72
72
  def store(book)
73
- filename_key = General.canonize(book.filename)
73
+ filename_key = General.canonize(book.filename).downcase
74
74
  if book.stored_filename
75
- old_filename_key = General.canonize(book.stored_filename)
75
+ old_filename_key = General.canonize(book.stored_filename).downcase
76
76
  # deletes the weak reference to the book
77
77
  @filename2books[old_filename_key].delete(book)
78
78
  end
@@ -12,26 +12,30 @@ module RobustExcelOle
12
12
  ole_cell
13
13
  end
14
14
 
15
- def v
15
+ def value
16
16
  self.Value
17
17
  end
18
18
 
19
- def v=(value)
19
+ def value=(value)
20
20
  self.Value = value
21
21
  end
22
22
 
23
+ alias_method :v, :value
24
+ alias_method :v=, :value=
25
+
26
+ # @private
23
27
  def ole_cell
24
28
  @ole_range = @ole_range.MergeArea.Item(1,1) if @ole_range.MergeCells
25
29
  end
26
30
 
27
31
  # @private
28
32
  def to_s
29
- @ole_range.Name.to_s
33
+ "#<Cell:" + " (#{@ole_range.Row},#{@ole_range.Column})" + ">"
30
34
  end
31
35
 
32
36
  # @private
33
- def inspect
34
- "#<Cell:" + " (#{@ole_range.Row},#{@ole_range.Column})" + ">#"
37
+ def inspect
38
+ self.to_s[0..-2] + " #{@ole_range.Parent.Name}" + ">"
35
39
  end
36
40
 
37
41
  private
@@ -0,0 +1,25 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module RobustExcelOle
4
+
5
+ class Cell < Range
6
+
7
+ def initialize: (win32_cell: WIN32OLE, worksheet: Worksheet) -> void
8
+
9
+ def value -> String
10
+
11
+ def value= (value: Variant) -> Variant
12
+
13
+ def v -> String
14
+
15
+ def v= (value: Variant) -> Variant
16
+
17
+ def ole_cell -> WIN32OLE | void
18
+
19
+ def to_s -> String
20
+
21
+ def inspect -> String
22
+
23
+ end
24
+
25
+ end
@@ -640,13 +640,8 @@ module RobustExcelOle
640
640
  # set options in this Excel instance
641
641
  def for_this_instance(options)
642
642
  set_options(options)
643
- #self.class.new(@ole_excel, options)
644
643
  end
645
644
 
646
- #def set_options(options)
647
- # for_this_instance(options)
648
- #end
649
-
650
645
  def set_options(options)
651
646
  @properties ||= { }
652
647
  PROPERTIES.each do |property|
@@ -701,7 +696,7 @@ module RobustExcelOle
701
696
  # @param [String] name the name of the range
702
697
  # @param [Variant] value the contents of the range
703
698
  def []=(name, value)
704
- set_namevalue_glob(name, value, :color => 42)
699
+ set_namevalue_glob(name, value)
705
700
  end
706
701
 
707
702
  # @private
@@ -10,13 +10,14 @@ module General
10
10
  ::CONNECT_EXCEL_JRUBY_BUG = IS_JRUBY_PLATFORM && true
11
11
  ::RANGES_JRUBY_BUG = IS_JRUBY_PLATFORM && true
12
12
 
13
+ @private
13
14
  NetworkDrive = Struct.new(:drive_letter, :network_name) do
14
15
 
15
16
  def self.get_all(drives)
16
17
  ndrives = []
17
18
  count = drives.Count
18
19
  (0..(count - 1)).step(2) do |i|
19
- ndrives << NetworkDrive.new( drives.Item(i), drives.Item(i + 1))
20
+ ndrives << NetworkDrive.new( drives.Item(i), drives.Item(i + 1).tr('\\','/'))
20
21
  end
21
22
  ndrives
22
23
  end
@@ -24,23 +25,22 @@ module General
24
25
  end
25
26
 
26
27
  @private
27
- def network2hostnamesharepath(filename)
28
+ def hostnameshare2networkpath(filename)
29
+ return filename unless filename[0,2] == "//"
28
30
  network = WIN32OLE.new('WScript.Network')
29
31
  drives = network.enumnetworkdrives
30
- drive_letter, filename_after_drive_letter = filename.split(':')
31
- drive_letter = normalize_drive_letter(drive_letter)
32
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
33
+ f_c = filename.dup
34
+ network_drive = network_drives.find do |d|
35
+ e = f_c.sub!(d.network_name,d.drive_letter)
36
+ return e if e
37
+ end
38
+ filename
39
+ end
37
40
 
38
- def self.normalize_drive_letter(drive)
39
- drive.upcase.end_with?(':') ? drive : "#{drive}:"
40
- end
41
-
42
41
  # @private
43
- def absolute_path(file)
42
+ def absolute_path(file)
43
+ return file if file[0,2] == "//"
44
44
  file[0,2] = './' if ::EXPANDPATH_JRUBY_BUG && file =~ /[A-Z]:[^\/]/
45
45
  file = File.expand_path(file)
46
46
  file = RobustExcelOle::Cygwin.cygpath('-w', file) if RUBY_PLATFORM =~ /cygwin/
@@ -50,8 +50,8 @@ module General
50
50
  # @private
51
51
  def canonize(filename)
52
52
  raise TypeREOError, "No string given to canonize, but #{filename.inspect}" unless filename.is_a?(String)
53
- filename = network2hostnamesharepath(filename)
54
- normalize(filename).downcase if filename
53
+ filename = hostnameshare2networkpath(filename)
54
+ normalize(filename) if filename
55
55
  end
56
56
 
57
57
  # @private
@@ -142,16 +142,33 @@ class WIN32OLE
142
142
  raise TypeREOError, "given object cannot be type-lifted to a RobustExcelOle object"
143
143
  end
144
144
 
145
- alias method_missing_before_implicit_typelift method_missing
146
- def xx_method_missing(name, *args, &blk)
147
- begin
148
- reo_obj = self.to_reo
149
- rescue
150
- puts "$!.message: #{$!.message}"
151
- method_missing_before_implicit_typelift(name, *args, &blk)
152
- end
153
- reo_obj.send(name, *args, &blk)
154
- end
145
+
146
+ # def method_missing(name, *args, &blk)
147
+ # puts "method_missing:"
148
+ # puts "name: #{name.inspect}"
149
+ # puts "self: #{self}"
150
+ # puts "self.ole_type: #{self.ole_type}"
151
+ # puts "self.to_reo: #{self.to_reo}"
152
+ # begin
153
+ # reo_obj = self.to_reo
154
+ # rescue
155
+ # puts "error: #{$!.message}"
156
+ # raise # NoMethodError, "undefined method #{name.inspect} for #{self.inspect}"
157
+ # end
158
+ # reo_obj.send(name, *args, &blk)
159
+ # end
160
+
161
+ #alias method_missing_before_implicit_typelift method_missing
162
+ #def method_missing(name, *args, &blk)
163
+ # begin
164
+ # reo_obj = self.to_reo
165
+ # rescue
166
+ # puts "$!.message: #{$!.message}"
167
+ # method_missing_before_implicit_typelift(name, *args, &blk)
168
+ # end
169
+ # reo_obj.send(name, *args, &blk)
170
+ #end
171
+
155
172
  end
156
173
 
157
174
  # @private
@@ -17,23 +17,30 @@ module RobustExcelOle
17
17
  alias ole_object ole_table
18
18
 
19
19
  # constructs a list object (or table).
20
- # @param [Variable] worksheet_or_ole_listobject a worksheet or a Win32Ole list object
20
+ # @param [Variable] worksheet_or_listobject a worksheet or a list object
21
21
  # @param [Variable] table_name_or_number a table name or table number
22
22
  # @param [Array] position a position of the upper left corner
23
23
  # @param [Integer] rows_count number of rows
24
24
  # @param [Variable] columns_count_or_names number of columns or array of column names
25
25
  # @return [ListObject] a ListObject object
26
- def initialize(worksheet_or_ole_listobject,
27
- table_name_or_number = "",
26
+ def initialize(worksheet_or_listobject,
27
+ table_name_or_number = "_table_name",
28
28
  position = [1,1],
29
29
  rows_count = 1,
30
30
  columns_count_or_names = 1)
31
-
32
- if (worksheet_or_ole_listobject.ListRows rescue nil)
33
- @ole_table = worksheet_or_ole_listobject
31
+
32
+ # ole_table is being assigned to the first parameter, if this parameter is a ListObject
33
+ # otherwise the first parameter could be a worksheet, and get the ole_table via the ListObject name or number
34
+ @ole_table = if worksheet_or_listobject.respond_to?(:ListRows)
35
+ worksheet_or_listobject.ole_table
34
36
  else
35
- @worksheet = worksheet_or_ole_listobject.to_reo
36
- @ole_table = @worksheet.ListObjects.Item(table_name_or_number) rescue nil
37
+ begin
38
+ worksheet_or_listobject.send(:ListRows)
39
+ worksheet_or_listobject
40
+ rescue
41
+ @worksheet = worksheet_or_listobject.to_reo
42
+ @worksheet.ListObjects.Item(table_name_or_number) rescue nil
43
+ end
37
44
  end
38
45
  unless @ole_table
39
46
  columns_count =
@@ -52,6 +59,7 @@ module RobustExcelOle
52
59
  end
53
60
  end
54
61
 
62
+
55
63
  ole_table = @ole_table
56
64
  @row_class = Class.new(ListRow) do
57
65
 
@@ -5,7 +5,7 @@ module RobustExcelOle
5
5
  # This class essentially wraps a Win32Ole Range object.
6
6
  # You can apply all VBA methods (starting with a capital letter)
7
7
  # that you would apply for a Range object.
8
- # See https://docs.microsoft.com/en-us/office/vba/api/excel.worksheet#methods
8
+ # See https://docs.microsoft.com/en-us/office/vba/api/excel.range#methods
9
9
 
10
10
  class Range < VbaObjects
11
11
 
@@ -20,8 +20,14 @@ module RobustExcelOle
20
20
  def initialize(win32_range, worksheet = nil)
21
21
  @ole_range = win32_range
22
22
  @worksheet = worksheet ? worksheet.to_reo : worksheet_class.new(self.Parent)
23
- address_r1c1 = @ole_range.AddressLocal(true,true,XlR1C1)
24
- @rows, @columns = address_tool.as_integer_ranges(address_r1c1)
23
+ end
24
+
25
+ def rows
26
+ @rows ||= (1..@ole_range.Rows.Count)
27
+ end
28
+
29
+ def columns
30
+ @columns ||= (1..@ole_range.Columns.Count)
25
31
  end
26
32
 
27
33
  def each
@@ -49,7 +55,6 @@ module RobustExcelOle
49
55
  # @params [Range] a range
50
56
  # @returns [Array] the values
51
57
  def values(range = nil)
52
- #result = map { |x| x.Value }.flatten
53
58
  result_unflatten = if !::RANGES_JRUBY_BUG
54
59
  map { |x| x.v }
55
60
  else
@@ -65,15 +70,17 @@ module RobustExcelOle
65
70
  end
66
71
  end
67
72
 
68
- def v
73
+ # returns flat array of the values of a given range
74
+ # @returns [Array] values of the range (as a nested array)
75
+ def value
69
76
  begin
70
77
  if !::RANGES_JRUBY_BUG
71
78
  self.Value
72
79
  else
73
80
  values = []
74
- @rows.each do |r|
81
+ rows.each do |r|
75
82
  values_col = []
76
- @columns.each{ |c| values_col << worksheet.Cells(r,c).Value}
83
+ columns.each{ |c| values_col << worksheet.Cells(r,c).Value}
77
84
  values << values_col
78
85
  end
79
86
  values
@@ -84,144 +91,101 @@ module RobustExcelOle
84
91
 
85
92
  end
86
93
 
87
- def v=(value)
94
+ # sets the values if the range
95
+ # @param [Variant] value
96
+ def value=(value)
88
97
  begin
89
98
  if !::RANGES_JRUBY_BUG
90
99
  ole_range.Value = value
91
100
  else
92
- @rows.each_with_index do |r,i|
93
- @columns.each_with_index do |c,j|
101
+ rows.each_with_index do |r,i|
102
+ columns.each_with_index do |c,j|
94
103
  ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value)
95
104
  end
96
105
  end
97
106
  end
98
107
  value
99
108
  rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
100
- raise RangeNotEvaluatable, "cannot assign value to range #{address_r1c1.inspect}"
109
+ raise RangeNotEvaluatable, "cannot assign value to range #{self.inspect}"
101
110
  end
102
111
  end
103
112
 
104
- alias_method :value, :v
105
- alias_method :value=, :v=
113
+ alias_method :v, :value
114
+ alias_method :v=, :value=
106
115
 
107
- # copies a range
108
- # @params [Address or Address-Array] address or upper left position of the destination range
109
- # @options [Worksheet] the destination worksheet
110
- # @options [Hash] options: :transpose, :values_only
111
- def copy(dest_address1, sheet_or_dest_address2 = :__not_provided, options_or_sheet = :__not_provided, not_provided_or_options = :__not_provided)
116
+ # sets the values if the range with a given color
117
+ # @param [Variant] value
118
+ # @option opts [Symbol] :color the color of the cell when set
119
+ def set_value(value, opts = { })
112
120
  begin
113
- dest_address = if sheet_or_dest_address2.is_a?(Object::Range) or sheet_or_dest_address2.is_a?(Integer)
114
- [dest_address1,sheet_or_dest_address2]
115
- else
116
- dest_address1
117
- end
118
- dest_sheet = if sheet_or_dest_address2.is_a?(Worksheet) or sheet_or_dest_address2.is_a?(WIN32OLE)
119
- sheet_or_dest_address2.to_reo
120
- else
121
- if options_or_sheet.is_a?(Worksheet) or options_or_sheet.is_a?(WIN32OLE)
122
- options_or_sheet.to_reo
123
- else
124
- @worksheet
125
- end
126
- end
127
- options = if options_or_sheet.is_a?(Hash)
128
- options_or_sheet
129
- else
130
- if not_provided_or_options.is_a?(Hash)
131
- not_provided_or_options
132
- else
133
- { }
134
- end
135
- end
136
- rows, columns = address_tool.as_integer_ranges(dest_address)
137
- dest_address_is_position = (rows.min == rows.max && columns.min == columns.max)
138
- dest_range_address = if (not dest_address_is_position)
139
- [rows.min..rows.max,columns.min..columns.max]
140
- else
141
- if (not options[:transpose])
142
- [rows.min..rows.min+self.Rows.Count-1,
143
- columns.min..columns.min+self.Columns.Count-1]
144
- else
145
- [rows.min..rows.min+self.Columns.Count-1,
146
- columns.min..columns.min+self.Rows.Count-1]
147
- end
148
- end
149
- dest_range = dest_sheet.range(dest_range_address)
150
- if options[:values_only]
151
- dest_range.v = options[:transpose] ? self.v.transpose : self.v
121
+ if !::RANGES_JRUBY_BUG
122
+ ole_range.Value = value
152
123
  else
153
- if dest_range.worksheet.workbook.excel == @worksheet.workbook.excel
154
- if options[:transpose]
155
- self.Copy
156
- dest_range.PasteSpecial(XlPasteAll,XlPasteSpecialOperationNone,false,true)
157
- else
158
- self.Copy(dest_range.ole_range)
159
- end
160
- else
161
- if options[:transpose]
162
- added_sheet = @worksheet.workbook.add_sheet
163
- self.copy_special(dest_address, added_sheet, :transpose => true)
164
- added_sheet.range(dest_range_address).copy_special(dest_address,dest_sheet)
165
- @worksheet.workbook.excel.with_displayalerts(false) {added_sheet.Delete}
166
- else
167
- self.Copy
168
- dest_sheet.Paste(dest_range.ole_range)
124
+ rows.each_with_index do |r,i|
125
+ columns.each_with_index do |c,j|
126
+ ole_range.Cells(i+1,j+1).Value = (value.respond_to?(:first) ? value[i][j] : value)
169
127
  end
170
128
  end
171
129
  end
172
- rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
173
- raise RangeNotCopied, 'cannot copy range'
130
+ ole_range.Interior.ColorIndex = opts[:color] unless opts[:color].nil?
131
+ value
132
+ rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
133
+ raise RangeNotEvaluatable, "cannot assign value to range #{self.inspect}"
174
134
  end
175
135
  end
176
136
 
177
- # becomes copy
178
137
  # copies a range
179
138
  # @params [Address or Address-Array] address or upper left position of the destination range
180
139
  # @options [Worksheet] the destination worksheet
181
140
  # @options [Hash] options: :transpose, :values_only
182
- def copy_special(dest_address, dest_sheet = :__not_provided, options = { })
183
- rows, columns = address_tool.as_integer_ranges(dest_address)
184
- dest_sheet = @worksheet if dest_sheet == :__not_provided
185
- dest_address_is_position = (rows.min == rows.max && @columns.min == @columns.max)
186
- dest_range_address = if (not dest_address_is_position)
141
+ def copy(dest_address, *remaining_args)
142
+ dest_sheet = @worksheet
143
+ options = { }
144
+ remaining_args.each do |arg|
145
+ case arg
146
+ when Object::Range, Integer then dest_address = [dest_address,arg]
147
+ when Worksheet, WIN32OLE then dest_sheet = arg.to_reo
148
+ when Hash then options = arg
149
+ else raise RangeNotCopied, "cannot copy range: argument error: #{remaining_args.inspect}"
150
+ end
151
+ end
152
+ begin
153
+ rows, columns = address_tool.as_integer_ranges(dest_address)
154
+ dest_address_is_position = (rows.min == rows.max && columns.min == columns.max)
155
+ dest_range_address = if (not dest_address_is_position)
187
156
  [rows.min..rows.max,columns.min..columns.max]
188
157
  else
189
158
  if (not options[:transpose])
190
- [rows.min..rows.min+self.Rows.Count-1,
191
- columns.min..columns.min+self.Columns.Count-1]
159
+ [rows.min..rows.min+self.Rows.Count-1, columns.min..columns.min+self.Columns.Count-1]
192
160
  else
193
- [rows.min..rows.min+self.Columns.Count-1,
194
- columns.min..columns.min+self.Rows.Count-1]
161
+ [rows.min..rows.min+self.Columns.Count-1, columns.min..columns.min+self.Rows.Count-1]
195
162
  end
196
163
  end
197
- dest_range = dest_sheet.range(dest_range_address)
198
- begin
164
+ dest_range = dest_sheet.range(dest_range_address)
199
165
  if options[:values_only]
200
- dest_range.Value = options[:transpose] ? self.Value.transpose : self.Value
166
+ dest_range.v = options[:transpose] ? self.v.transpose : self.v
201
167
  else
202
- if dest_range.worksheet.workbook.excel == @worksheet.workbook.excel
168
+ if dest_range.worksheet.workbook.excel == @worksheet.workbook.excel
203
169
  if options[:transpose]
204
- self.Copy
205
- #dest_range.PasteSpecial('transpose' => true)
170
+ self.Copy
206
171
  dest_range.PasteSpecial(XlPasteAll,XlPasteSpecialOperationNone,false,true)
207
172
  else
208
- #self.Copy('destination' => dest_range.ole_range)
209
173
  self.Copy(dest_range.ole_range)
210
174
  end
211
175
  else
212
176
  if options[:transpose]
213
177
  added_sheet = @worksheet.workbook.add_sheet
214
- self.copy_special(dest_address, added_sheet, :transpose => true)
215
- added_sheet.range(dest_range_address).copy_special(dest_address,dest_sheet)
178
+ self.copy(dest_address, added_sheet, :transpose => true)
179
+ added_sheet.range(dest_range_address).copy(dest_address,dest_sheet)
216
180
  @worksheet.workbook.excel.with_displayalerts(false) {added_sheet.Delete}
217
181
  else
218
182
  self.Copy
219
- #dest_sheet.Paste('destination' => dest_range.ole_range)
220
183
  dest_sheet.Paste(dest_range.ole_range)
221
184
  end
222
185
  end
223
186
  end
224
- rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
187
+ dest_range
188
+ rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
225
189
  raise RangeNotCopied, 'cannot copy range'
226
190
  end
227
191
  end
@@ -249,12 +213,12 @@ module RobustExcelOle
249
213
 
250
214
  # @private
251
215
  def to_s
252
- "#<REO::Range: " + "[#{@rows},#{@columns}] " + "#{worksheet.Name} " + ">"
216
+ "#<REO::Range: " + "#{@ole_range.Address('External' => true).gsub(/\$/,'')} " + ">"
253
217
  end
254
218
 
255
219
  # @private
256
220
  def inspect
257
- self.to_s
221
+ to_s
258
222
  end
259
223
 
260
224
  # @private