robust_excel_ole 1.27 → 1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Changelog +36 -2
- data/README.rdoc +121 -19
- data/___dummy_workbook.xls +0 -0
- data/benchmarking/creek_example.rb +1 -1
- data/benchmarking/reo_example.rb +1 -1
- data/benchmarking/reo_example1.rb +1 -1
- data/benchmarking/reo_example2.rb +1 -1
- data/benchmarking/roo_example.rb +1 -1
- data/benchmarking/simple_xlsx_reader_example.rb +1 -1
- data/benchmarking/spreadsheet_example.rb +1 -1
- data/bin/jreo +19 -0
- data/bin/reo +19 -0
- data/docs/README_excel.rdoc +16 -24
- data/docs/README_listobjects.rdoc +176 -0
- data/docs/README_open.rdoc +20 -16
- data/docs/README_ranges.rdoc +72 -55
- data/docs/README_save_close.rdoc +3 -3
- data/docs/README_sheet.rdoc +19 -20
- data/examples/example_ruby_library.rb +2 -2
- data/examples/introductory_examples/example_open.rb +11 -0
- data/examples/introductory_examples/example_range.rb +2 -2
- data/examples/modifying_sheets/example_access_sheets_and_cells.rb +6 -6
- data/examples/modifying_sheets/example_add_names.rb +1 -1
- data/examples/modifying_sheets/example_concating.rb +1 -1
- data/examples/modifying_sheets/example_copying.rb +2 -2
- data/examples/modifying_sheets/example_listobjects.rb +86 -0
- data/examples/modifying_sheets/example_naming.rb +1 -1
- data/examples/modifying_sheets/example_ranges.rb +1 -1
- data/examples/open_save_close/example_control_to_excel.rb +1 -1
- data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +1 -1
- data/examples/open_save_close/example_if_obstructed_save.rb +3 -3
- data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
- data/examples/open_save_close/example_if_unsaved_forget.rb +3 -3
- data/examples/open_save_close/example_if_unsaved_forget_more.rb +4 -4
- data/examples/open_save_close/example_read_only.rb +1 -1
- data/examples/open_save_close/example_simple.rb +1 -1
- data/examples/open_save_close/example_unobtrusively.rb +3 -3
- data/lib/robust_excel_ole.rb +19 -16
- data/lib/robust_excel_ole/address_tool.rb +54 -44
- data/lib/robust_excel_ole/base.rb +9 -6
- data/lib/robust_excel_ole/bookstore.rb +3 -17
- data/lib/robust_excel_ole/cell.rb +17 -22
- data/lib/robust_excel_ole/cygwin.rb +2 -0
- data/lib/robust_excel_ole/excel.rb +136 -201
- data/lib/robust_excel_ole/general.rb +249 -238
- data/lib/robust_excel_ole/list_object.rb +186 -210
- data/lib/robust_excel_ole/list_row.rb +155 -0
- data/lib/robust_excel_ole/range.rb +130 -94
- data/lib/robust_excel_ole/range_owners.rb +54 -135
- data/lib/robust_excel_ole/version.rb +1 -1
- data/lib/robust_excel_ole/workbook.rb +230 -196
- data/lib/robust_excel_ole/worksheet.rb +254 -133
- data/lib/spec_helper.rb +1 -1
- data/robust_excel_ole.gemspec +4 -3
- data/spec/address_tool_spec.rb +2 -2
- data/spec/base_spec.rb +19 -17
- data/spec/bookstore_spec.rb +3 -4
- data/spec/cell_spec.rb +10 -10
- data/spec/cygwin_spec.rb +1 -1
- data/spec/data/more_data/workbook.xls +0 -0
- data/spec/excel_spec.rb +133 -86
- data/spec/general_spec.rb +79 -18
- data/spec/list_object_spec.rb +259 -81
- data/spec/list_row_spec.rb +218 -0
- data/spec/range_spec.rb +75 -41
- data/spec/spec_helper.rb +16 -2
- data/spec/workbook_spec.rb +87 -46
- data/spec/workbook_specs/workbook_all_spec.rb +9 -28
- data/spec/workbook_specs/workbook_close_spec.rb +1 -1
- data/spec/workbook_specs/workbook_misc_spec.rb +52 -45
- data/spec/workbook_specs/workbook_open_spec.rb +103 -50
- data/spec/workbook_specs/workbook_save_spec.rb +22 -23
- data/spec/workbook_specs/workbook_sheet_spec.rb +4 -4
- data/spec/workbook_specs/workbook_subclass_spec.rb +1 -1
- data/spec/workbook_specs/workbook_unobtr_spec.rb +553 -395
- data/spec/worksheet_spec.rb +544 -308
- metadata +38 -3
- data/lib/reo_console.rb +0 -42
@@ -20,7 +20,7 @@ begin
|
|
20
20
|
book.excel.visible = true # make current Excel visible
|
21
21
|
sheet = book.sheet(1) # access a worksheet
|
22
22
|
sleep 1
|
23
|
-
sheet[1,1] = sheet[1,1]
|
23
|
+
sheet[1,1] = sheet[1,1] == "simple" ? "complex" : "simple" # change a cell
|
24
24
|
sleep 1
|
25
25
|
book.save # simple save
|
26
26
|
begin
|
@@ -12,14 +12,14 @@ begin
|
|
12
12
|
simple_file = dir + 'workbook.xls'
|
13
13
|
book = Workbook.open(simple_file, :visible => true) # open a workbook, make Excel visible
|
14
14
|
old_sheet = book.sheet(1)
|
15
|
-
p "1st cell: #{old_sheet[1,1]
|
15
|
+
p "1st cell: #{old_sheet[1,1]}"
|
16
16
|
sleep 2
|
17
17
|
Workbook.unobtrusively(simple_file) do |book| # modify the book and keep its status unchanged
|
18
18
|
sheet = book.sheet(1)
|
19
|
-
sheet[1,1] = sheet[1,1]
|
19
|
+
sheet[1,1] = sheet[1,1] == "simple" ? "complex" : "simple"
|
20
20
|
end
|
21
21
|
new_sheet = book.sheet(1)
|
22
|
-
p "1st cell: #{new_sheet[1,1]
|
22
|
+
p "1st cell: #{new_sheet[1,1]}"
|
23
23
|
p "book saved" if book.Saved
|
24
24
|
book.close # close the workbook
|
25
25
|
ensure
|
data/lib/robust_excel_ole.rb
CHANGED
@@ -1,22 +1,25 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
1
3
|
if RUBY_PLATFORM =~ /java/
|
2
4
|
require 'jruby-win32ole'
|
3
5
|
else
|
4
6
|
require 'win32ole'
|
5
7
|
end
|
6
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/base')
|
7
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/general')
|
8
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/vba_objects')
|
9
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/range_owners')
|
10
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/address_tool')
|
11
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/excel')
|
12
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/bookstore')
|
13
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/workbook')
|
14
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/worksheet')
|
15
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/cell')
|
16
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/range')
|
17
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/list_object')
|
18
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/cygwin') if RUBY_PLATFORM =~ /cygwin/
|
19
|
-
require File.join(File.dirname(__FILE__), 'robust_excel_ole/version')
|
20
8
|
|
21
|
-
|
22
|
-
|
9
|
+
require_relative 'robust_excel_ole/general'
|
10
|
+
require_relative 'robust_excel_ole/base'
|
11
|
+
require_relative 'robust_excel_ole/vba_objects'
|
12
|
+
require_relative 'robust_excel_ole/range_owners'
|
13
|
+
require_relative 'robust_excel_ole/address_tool'
|
14
|
+
require_relative 'robust_excel_ole/excel'
|
15
|
+
require_relative 'robust_excel_ole/bookstore'
|
16
|
+
require_relative 'robust_excel_ole/workbook'
|
17
|
+
require_relative 'robust_excel_ole/worksheet'
|
18
|
+
require_relative 'robust_excel_ole/cell'
|
19
|
+
require_relative 'robust_excel_ole/range'
|
20
|
+
require_relative 'robust_excel_ole/list_row'
|
21
|
+
require_relative 'robust_excel_ole/list_object'
|
22
|
+
require_relative 'robust_excel_ole/cygwin' if RUBY_PLATFORM =~ /cygwin/
|
23
|
+
require_relative 'robust_excel_ole/version'
|
24
|
+
|
25
|
+
General.init_reo_for_win32ole
|
@@ -16,71 +16,80 @@ module RobustExcelOle
|
|
16
16
|
# integer_ranges-fromat: e.g. [3,1], [3,"A"], [3..5,1..2], [3..5, "A".."B"],
|
17
17
|
# [3..4, nil], [nil, 2..4], [2,nil], [nil,4]
|
18
18
|
# a1-format: e.g. "A3", "A3:B5", "A:B", "3:5", "A", "3"
|
19
|
-
|
20
19
|
def as_r1c1(address)
|
21
|
-
transform_address(address
|
20
|
+
transform_address(address, :r1c1)
|
22
21
|
end
|
23
22
|
|
24
23
|
def as_a1(address)
|
25
|
-
transform_address(address
|
24
|
+
transform_address(address, :a1)
|
26
25
|
end
|
27
26
|
|
28
27
|
# valid address formats: e.g. [3,1], [3,"A"], [3..5,1..2], [3..5, "A".."B"],
|
29
28
|
# [3..4, nil], [nil, 2..4], [2,nil], [nil,4]
|
30
29
|
def as_integer_ranges(address)
|
31
|
-
transform_address(address
|
30
|
+
transform_address(address, :int_range)
|
32
31
|
end
|
33
|
-
|
32
|
+
|
34
33
|
private
|
35
34
|
|
36
35
|
def transform_address(address, format)
|
37
36
|
address = address.is_a?(Array) ? address : [address]
|
38
37
|
raise AddressInvalid, "address #{address.inspect} has more than two components" if address.size > 2
|
39
|
-
begin
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
is_r1c1 = comp1 =~ r1c1_expr && (comp2.nil? || comp2 =~ r1c1_expr) && (not is_a1)
|
46
|
-
raise AddressInvalid, "address #{address.inspect} not in A1- or r1c1-format" unless (is_a1 || is_r1c1)
|
47
|
-
return address[0].gsub('[','(').gsub(']',')') if (is_a1 && format==:a1) || (is_r1c1 && format==:r1c1)
|
48
|
-
given_format = (is_a1) ? :a1 : :r1c1
|
49
|
-
row_comp1, col_comp1 = analyze(comp1,given_format)
|
50
|
-
row_comp2, col_comp2 = analyze(comp2,given_format) unless comp2.nil?
|
51
|
-
address_comp1 = comp2 && (not row_comp1.nil?) ? (row_comp1 .. row_comp2) : row_comp1
|
52
|
-
address_comp2 = comp2 && (not col_comp1.nil?) ? (col_comp1 .. col_comp2) : col_comp1
|
53
|
-
else
|
54
|
-
address_comp1, address_comp2 = address
|
55
|
-
end
|
56
|
-
address_comp1 = address_comp1..address_comp1 if (address_comp1.is_a?(Integer) || address_comp1.is_a?(String) || address_comp1.is_a?(Array))
|
57
|
-
address_comp2 = address_comp2..address_comp2 if (address_comp2.is_a?(Integer) || address_comp2.is_a?(String) || address_comp2.is_a?(Array))
|
58
|
-
#raise unless address_comp1.nil? || address_comp1.begin.to_i!=0 || address_comp1.begin.empty?
|
59
|
-
rows = unless address_comp1.nil? || address_comp1.begin == 0 # || address_comp1.begin.to_i==0
|
60
|
-
address_comp1.begin..address_comp1.end
|
61
|
-
end
|
62
|
-
columns = unless address_comp2.nil?
|
63
|
-
if address_comp2.begin.is_a?(String) #address_comp2.begin.to_i == 0
|
64
|
-
col_range = str2num(address_comp2.begin)..str2num(address_comp2.end)
|
65
|
-
col_range==(0..0) ? nil : col_range
|
66
|
-
else
|
67
|
-
address_comp2.begin..address_comp2.end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
rescue
|
71
|
-
raise AddressInvalid, "address (#{address.inspect}) format not correct"
|
38
|
+
rows, columns = begin
|
39
|
+
rows_and_columns(address, format)
|
40
|
+
rescue AddressInvalid
|
41
|
+
raise
|
42
|
+
rescue AddressAlreadyInRightFormat
|
43
|
+
return address[0].gsub('[','(').gsub(']',')')
|
72
44
|
end
|
73
|
-
if format
|
45
|
+
if format == :int_range
|
46
|
+
[rows,columns]
|
47
|
+
elsif format == :r1c1
|
74
48
|
r1c1_string(@row_letter,rows,:min) + r1c1_string(@col_letter,columns,:min) + ":" +
|
75
49
|
r1c1_string(@row_letter,rows,:max) + r1c1_string(@col_letter,columns,:max)
|
76
|
-
elsif format==:int_range
|
77
|
-
[rows,columns]
|
78
50
|
else
|
79
51
|
raise NotImplementedREOError, "not implemented"
|
80
52
|
end
|
81
|
-
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def rows_and_columns(address, format)
|
56
|
+
if address.size != 1
|
57
|
+
address_comp1, address_comp2 = address
|
58
|
+
else
|
59
|
+
comp1, comp2 = address[0].split(':')
|
60
|
+
a1_expr = /^(([A-Z]+[0-9]+)|([A-Z]+$)|([0-9]+))$/
|
61
|
+
is_a1 = comp1 =~ a1_expr && (comp2.nil? || comp2 =~ a1_expr)
|
62
|
+
r1c1_expr = /^(([A-Z]\[?-?[0-9]+\]?[A-Z]\[?-?[0-9]+\]?)|([A-Z]\[?-?[0-9]+\]?)|([A-Z]\[?-?[0-9]+\]?))$/
|
63
|
+
is_r1c1 = comp1 =~ r1c1_expr && (comp2.nil? || comp2 =~ r1c1_expr) && (not is_a1)
|
64
|
+
raise AddressInvalid, "address #{address.inspect} not in A1- or r1c1-format" unless (is_a1 || is_r1c1)
|
65
|
+
raise AddressAlreadyInRightFormat if (is_a1 && format==:a1) || (is_r1c1 && format==:r1c1)
|
66
|
+
given_format = (is_a1) ? :a1 : :r1c1
|
67
|
+
row_comp1, col_comp1 = analyze(comp1,given_format)
|
68
|
+
row_comp2, col_comp2 = analyze(comp2,given_format) unless comp2.nil?
|
69
|
+
address_comp1 = comp2 && (not row_comp1.nil?) ? (row_comp1 .. row_comp2) : row_comp1
|
70
|
+
address_comp2 = comp2 && (not col_comp1.nil?) ? (col_comp1 .. col_comp2) : col_comp1
|
71
|
+
end
|
72
|
+
address_comp1 = address_comp1..address_comp1 if (address_comp1.is_a?(Integer) || address_comp1.is_a?(String) || address_comp1.is_a?(Array))
|
73
|
+
address_comp2 = address_comp2..address_comp2 if (address_comp2.is_a?(Integer) || address_comp2.is_a?(String) || address_comp2.is_a?(Array))
|
74
|
+
raise AddressInvalid, "address contains row 0" if !address_comp1.nil? && address_comp1.begin == 0
|
75
|
+
rows = address_comp1.begin..address_comp1.end unless address_comp1.nil? || address_comp1.begin == 0
|
76
|
+
columns = unless address_comp2.nil?
|
77
|
+
if address_comp2.begin.is_a?(String) #address_comp2.begin.to_i == 0
|
78
|
+
col_range = str2num(address_comp2.begin)..str2num(address_comp2.end)
|
79
|
+
col_range==(0..0) ? nil : col_range
|
80
|
+
else
|
81
|
+
address_comp2.begin..address_comp2.end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
[rows, columns]
|
85
|
+
rescue
|
86
|
+
raise AddressInvalid, "address (#{address.inspect}) format not correct"
|
87
|
+
end
|
82
88
|
|
83
|
-
|
89
|
+
class AddressAlreadyInRightFormat < Exception
|
90
|
+
end
|
91
|
+
|
92
|
+
def r1c1_string(letter, int_range,type)
|
84
93
|
return "" if int_range.nil? || int_range.begin.nil?
|
85
94
|
parameter = type == :min ? int_range.begin : int_range.end
|
86
95
|
is_relative = parameter.is_a?(Array)
|
@@ -88,7 +97,7 @@ module RobustExcelOle
|
|
88
97
|
letter + (is_relative ? "(" : "") + parameter.to_s + (is_relative ? ")" : "")
|
89
98
|
end
|
90
99
|
|
91
|
-
def analyze(comp,format)
|
100
|
+
def analyze(comp, format)
|
92
101
|
row_comp, col_comp = if format==:a1
|
93
102
|
[comp.gsub(/[A-Z]/,''), comp.gsub(/[0-9]/,'')]
|
94
103
|
else
|
@@ -108,6 +117,7 @@ module RobustExcelOle
|
|
108
117
|
|
109
118
|
end
|
110
119
|
|
120
|
+
|
111
121
|
# @private
|
112
122
|
class AddressInvalid < REOError
|
113
123
|
end
|
@@ -65,9 +65,11 @@ module RobustExcelOle
|
|
65
65
|
|
66
66
|
class Base
|
67
67
|
|
68
|
+
include General
|
69
|
+
|
68
70
|
# @private
|
69
71
|
def own_methods
|
70
|
-
(
|
72
|
+
(methods - Object.methods).sort
|
71
73
|
end
|
72
74
|
|
73
75
|
# @private
|
@@ -97,12 +99,10 @@ module RobustExcelOle
|
|
97
99
|
def self.puts_hash(hash)
|
98
100
|
hash.each do |e|
|
99
101
|
if e[1].is_a?(Hash)
|
100
|
-
puts "#{e[0]}
|
101
|
-
e[1].each
|
102
|
-
puts " #{f[0]} => #{f[1]}"
|
103
|
-
end
|
102
|
+
puts "#{e[0]}: "
|
103
|
+
e[1].each{ |f| puts " #{f[0]}: #{f[1]}" }
|
104
104
|
else
|
105
|
-
puts "#{e[0]}
|
105
|
+
puts "#{e[0]}: #{e[1]}"
|
106
106
|
end
|
107
107
|
end
|
108
108
|
end
|
@@ -110,3 +110,6 @@ module RobustExcelOle
|
|
110
110
|
end
|
111
111
|
|
112
112
|
end
|
113
|
+
|
114
|
+
REO = RobustExcelOle
|
115
|
+
|
@@ -4,7 +4,7 @@ module RobustExcelOle
|
|
4
4
|
|
5
5
|
# @private
|
6
6
|
class Bookstore < Base
|
7
|
-
|
7
|
+
|
8
8
|
def initialize
|
9
9
|
@filename2books ||= Hash.new { |hash, key| hash[key] = [] }
|
10
10
|
@hidden_excel_instance = nil
|
@@ -29,19 +29,17 @@ module RobustExcelOle
|
|
29
29
|
# otherwise returns the workbook according to the preference order mentioned above
|
30
30
|
# :prefer_excel returns the workbook in the given Excel instance, if it exists,
|
31
31
|
# otherwise proceeds according to prefer_writable
|
32
|
-
def fetch(filename, options = { :
|
32
|
+
def fetch(filename, options = { prefer_writable: true })
|
33
33
|
return nil unless filename
|
34
34
|
filename = General.absolute_path(filename)
|
35
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
|
-
|
39
38
|
result = open_book = closed_book = nil
|
40
39
|
weakref_books = weakref_books.map { |wr_book| wr_book if wr_book.weakref_alive? }.compact
|
41
40
|
@filename2books[filename_key] = weakref_books
|
42
41
|
weakref_books.each do |wr_book|
|
43
42
|
if !wr_book.weakref_alive?
|
44
|
-
# trace "warn: this should never happen"
|
45
43
|
begin
|
46
44
|
@filename2books[filename_key].delete(wr_book)
|
47
45
|
rescue
|
@@ -50,7 +48,6 @@ module RobustExcelOle
|
|
50
48
|
else
|
51
49
|
book = wr_book.__getobj__
|
52
50
|
next if book.excel == try_hidden_excel
|
53
|
-
|
54
51
|
if options[:prefer_excel] && book.excel == options[:prefer_excel]
|
55
52
|
result = book
|
56
53
|
break
|
@@ -64,7 +61,6 @@ module RobustExcelOle
|
|
64
61
|
end
|
65
62
|
end
|
66
63
|
result ||= (open_book || closed_book)
|
67
|
-
result
|
68
64
|
end
|
69
65
|
|
70
66
|
# stores a workbook
|
@@ -90,17 +86,7 @@ module RobustExcelOle
|
|
90
86
|
|
91
87
|
# returns all stored books
|
92
88
|
def books
|
93
|
-
|
94
|
-
if @filename2books
|
95
|
-
@filename2books.each do |_filename,books|
|
96
|
-
next if books.empty?
|
97
|
-
|
98
|
-
books.each do |wr_book|
|
99
|
-
result << wr_book.__getobj__ if wr_book.weakref_alive?
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
result
|
89
|
+
@filename2books.map{ |_fn,books| books.map{ |wr_bk| wr_bk.__getobj__ if wr_bk.weakref_alive?}.compact}.flatten
|
104
90
|
end
|
105
91
|
|
106
92
|
private
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
-
|
3
|
+
require_relative 'range'
|
4
4
|
|
5
5
|
module RobustExcelOle
|
6
6
|
|
7
7
|
class Cell < Range
|
8
8
|
#attr_reader :ole_cell
|
9
9
|
|
10
|
-
def initialize(win32_cell, worksheet)
|
10
|
+
def initialize(win32_cell, worksheet)
|
11
11
|
super
|
12
12
|
ole_cell
|
13
13
|
end
|
@@ -20,8 +20,8 @@ module RobustExcelOle
|
|
20
20
|
self.Value = value
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
alias v value
|
24
|
+
alias v= value=
|
25
25
|
|
26
26
|
# @private
|
27
27
|
def ole_cell
|
@@ -30,36 +30,31 @@ module RobustExcelOle
|
|
30
30
|
|
31
31
|
# @private
|
32
32
|
def to_s
|
33
|
-
"#<Cell:
|
33
|
+
"#<Cell: (#{@ole_range.Row},#{@ole_range.Column})>"
|
34
34
|
end
|
35
35
|
|
36
36
|
# @private
|
37
37
|
def inspect
|
38
|
-
|
38
|
+
to_s[0..-2] + " #{@ole_range.Parent.Name}>"
|
39
39
|
end
|
40
40
|
|
41
41
|
private
|
42
42
|
|
43
43
|
# @private
|
44
44
|
def method_missing(name, *args)
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
52
|
-
end
|
53
|
-
else
|
54
|
-
begin
|
55
|
-
#@ole_cell.send(name, *args)
|
56
|
-
@ole_range.send(name, *args)
|
57
|
-
rescue NoMethodError
|
58
|
-
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
59
|
-
end
|
45
|
+
super unless name.to_s[0,1] =~ /[A-Z]/
|
46
|
+
if ::ERRORMESSAGE_JRUBY_BUG
|
47
|
+
begin
|
48
|
+
@ole_range.send(name, *args)
|
49
|
+
rescue Java::OrgRacobCom::ComFailException
|
50
|
+
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
60
51
|
end
|
61
52
|
else
|
62
|
-
|
53
|
+
begin
|
54
|
+
@ole_range.send(name, *args)
|
55
|
+
rescue NoMethodError
|
56
|
+
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
57
|
+
end
|
63
58
|
end
|
64
59
|
end
|
65
60
|
end
|
@@ -15,6 +15,9 @@ module RobustExcelOle
|
|
15
15
|
# See https://docs.microsoft.com/en-us/office/vba/api/excel.application(object)#methods
|
16
16
|
|
17
17
|
class Excel < VbaObjects
|
18
|
+
|
19
|
+
include Enumerable
|
20
|
+
|
18
21
|
attr_reader :ole_excel
|
19
22
|
attr_reader :properties
|
20
23
|
attr_reader :address_tool
|
@@ -33,7 +36,7 @@ module RobustExcelOle
|
|
33
36
|
# @option options [Boolean] :screenupdating
|
34
37
|
# @return [Excel] a new Excel instance
|
35
38
|
def self.create(options = {})
|
36
|
-
new(options.merge(:
|
39
|
+
new(options.merge(reuse: false))
|
37
40
|
end
|
38
41
|
|
39
42
|
# connects to the current (first opened) Excel instance, if such a running Excel instance exists
|
@@ -44,7 +47,7 @@ module RobustExcelOle
|
|
44
47
|
# @option options [Boolean] :screenupdating
|
45
48
|
# @return [Excel] an Excel instance
|
46
49
|
def self.current(options = {})
|
47
|
-
new(options.merge(:
|
50
|
+
new(options.merge(reuse: true))
|
48
51
|
end
|
49
52
|
|
50
53
|
# returns an Excel instance
|
@@ -69,10 +72,11 @@ module RobustExcelOle
|
|
69
72
|
options = win32ole_excel
|
70
73
|
win32ole_excel = nil
|
71
74
|
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
75
|
+
options = { reuse: true }.merge(options)
|
76
|
+
ole_xl = if !win32ole_excel.nil?
|
77
|
+
win32ole_excel
|
78
|
+
elsif options[:reuse] == true
|
79
|
+
current_ole_excel
|
76
80
|
end
|
77
81
|
connected = (not ole_xl.nil?) && win32ole_excel.nil?
|
78
82
|
ole_xl ||= WIN32OLE.new('Excel.Application')
|
@@ -86,14 +90,9 @@ module RobustExcelOle
|
|
86
90
|
WIN32OLE.const_load(ole_xl, RobustExcelOle) unless RobustExcelOle.const_defined?(:CONSTANTS)
|
87
91
|
@@hwnd2excel[hwnd] = WeakRef.new(result)
|
88
92
|
end
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
unless reused || connected
|
93
|
-
options = { :displayalerts => :if_visible, :visible => false, :screenupdating => true }.merge(options)
|
94
|
-
end
|
95
|
-
result.set_options(options)
|
96
|
-
end
|
93
|
+
reused = options[:reuse] && stored && stored.alive?
|
94
|
+
options = { displayalerts: :if_visible, visible: false, screenupdating: true }.merge(options) unless reused || connected
|
95
|
+
result.set_options(options)
|
97
96
|
result
|
98
97
|
end
|
99
98
|
|
@@ -110,15 +109,12 @@ module RobustExcelOle
|
|
110
109
|
# @return [Excel] an Excel instance
|
111
110
|
def recreate(opts = {})
|
112
111
|
unless alive?
|
113
|
-
opts = {:
|
114
|
-
{:
|
112
|
+
opts = {visible: false, displayalerts: :if_visible}.merge(
|
113
|
+
{visible: @properties[:visible], displayalerts: @properties[:displayalerts]}).merge(opts)
|
115
114
|
@ole_excel = WIN32OLE.new('Excel.Application')
|
116
115
|
set_options(opts)
|
117
116
|
if opts[:reopen_workbooks]
|
118
|
-
books
|
119
|
-
books.each do |book|
|
120
|
-
book.reopen if !book.alive? && book.excel.alive? && book.excel == self
|
121
|
-
end
|
117
|
+
workbook_class.books.each{ |book| book.reopen if !book.alive? && book.excel.alive? && book.excel == self }
|
122
118
|
end
|
123
119
|
end
|
124
120
|
self
|
@@ -146,34 +142,29 @@ module RobustExcelOle
|
|
146
142
|
end
|
147
143
|
|
148
144
|
def ole_workbooks
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
raise ExcelREOError, 'workbooks could not be determined'
|
156
|
-
end
|
145
|
+
@ole_excel.Workbooks
|
146
|
+
rescue WIN32OLERuntimeError, Java::OrgRacobCom::ComFailException => msg
|
147
|
+
if msg.message =~ /failed to get Dispatch Interface/
|
148
|
+
raise ExcelDamaged, "Excel instance not alive or damaged"
|
149
|
+
else
|
150
|
+
raise ExcelREOError, "workbooks could not be determined\n#{$!.message}"
|
157
151
|
end
|
158
152
|
end
|
159
153
|
|
160
154
|
public
|
161
155
|
|
162
156
|
# @private
|
157
|
+
# returns unsaved workbooks (win32ole objects)
|
163
158
|
def self.contains_unsaved_workbooks?
|
164
159
|
!Excel.current.unsaved_workbooks.empty?
|
165
160
|
end
|
166
161
|
|
167
|
-
# returns unsaved workbooks (win32ole objects)
|
168
162
|
# @private
|
163
|
+
# returns unsaved workbooks (win32ole objects)
|
169
164
|
def unsaved_workbooks
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
rescue RuntimeError => msg
|
174
|
-
raise ExcelDamaged, 'Excel instance not alive or damaged' if msg.message =~ /failed to get Dispatch Interface/
|
175
|
-
end
|
176
|
-
unsaved_workbooks
|
165
|
+
@ole_excel.Workbooks.reject { |w| w.Saved || w.ReadOnly }
|
166
|
+
rescue RuntimeError => msg
|
167
|
+
raise ExcelDamaged, "Excel instance not alive or damaged" if msg.message =~ /failed to get Dispatch Interface/
|
177
168
|
end
|
178
169
|
|
179
170
|
# closes workbooks
|
@@ -184,7 +175,7 @@ module RobustExcelOle
|
|
184
175
|
# :save -> saves the workbooks before closing
|
185
176
|
# :alert -> let Excel do it
|
186
177
|
# @private
|
187
|
-
def close_workbooks(options = { :
|
178
|
+
def close_workbooks(options = { if_unsaved: :raise })
|
188
179
|
return unless alive?
|
189
180
|
|
190
181
|
weak_wkbks = @ole_excel.Workbooks
|
@@ -207,11 +198,12 @@ module RobustExcelOle
|
|
207
198
|
"\nHint: Valid values are :raise, :forget, :save and :alert"
|
208
199
|
end
|
209
200
|
end
|
201
|
+
|
210
202
|
begin
|
211
203
|
@ole_excel.Workbooks.Close
|
212
204
|
rescue
|
213
205
|
if $!.message =~ /kann nicht zugeordnet werden/ or $!.message =~ /800A03EC/
|
214
|
-
raise ExcelREOError,
|
206
|
+
raise ExcelREOError, "user canceled or runtime error"
|
215
207
|
else
|
216
208
|
raise UnexpectedREOError, "unknown WIN32OLERuntimeError: #{msg.message}"
|
217
209
|
end
|
@@ -234,7 +226,7 @@ module RobustExcelOle
|
|
234
226
|
# :forget -> closes the excel instance without saving the workbooks
|
235
227
|
# :alert -> give control to Excel
|
236
228
|
# @option options [Proc] block
|
237
|
-
def self.close_all(options = { :
|
229
|
+
def self.close_all(options = { if_unsaved: :raise }, &blk)
|
238
230
|
options[:if_unsaved] = blk if blk
|
239
231
|
finished_number = error_number = overall_number = 0
|
240
232
|
first_error = nil
|
@@ -242,10 +234,9 @@ module RobustExcelOle
|
|
242
234
|
if excel
|
243
235
|
begin
|
244
236
|
overall_number += 1
|
245
|
-
finished_number += excel.close(:
|
237
|
+
finished_number += excel.close(if_unsaved: options[:if_unsaved])
|
246
238
|
rescue
|
247
239
|
first_error = $!
|
248
|
-
#trace "error when finishing #{$!}"
|
249
240
|
error_number += 1
|
250
241
|
end
|
251
242
|
end
|
@@ -268,19 +259,13 @@ module RobustExcelOle
|
|
268
259
|
old_error_number = error_number
|
269
260
|
9.times do |_index|
|
270
261
|
sleep 0.1
|
271
|
-
excel =
|
272
|
-
new(WIN32OLE.connect('Excel.Application'))
|
273
|
-
rescue
|
274
|
-
nil
|
275
|
-
end
|
262
|
+
excel = new(WIN32OLE.connect('Excel.Application')) rescue nil
|
276
263
|
finishing_action.call(excel) if excel
|
277
264
|
free_all_ole_objects unless (error_number > 0) && (options[:if_unsaved] == :raise)
|
278
265
|
break unless excel
|
279
266
|
break if error_number > old_error_number # + 3
|
280
267
|
end
|
281
|
-
|
282
268
|
raise first_error if ((options[:if_unsaved] == :raise) && first_error) || (first_error.class == OptionInvalid)
|
283
|
-
|
284
269
|
[finished_number, error_number]
|
285
270
|
end
|
286
271
|
|
@@ -293,19 +278,13 @@ module RobustExcelOle
|
|
293
278
|
# :save -> saves the workbooks before closing
|
294
279
|
# :forget -> closes the Excel instance without saving the workbooks
|
295
280
|
# :alert -> Excel takes over
|
296
|
-
def close(options = { :
|
281
|
+
def close(options = { if_unsaved: :raise })
|
297
282
|
finishing_living_excel = alive?
|
298
283
|
if finishing_living_excel
|
299
|
-
hwnd =
|
300
|
-
|
301
|
-
rescue
|
302
|
-
nil
|
303
|
-
end)
|
304
|
-
close_workbooks(:if_unsaved => options[:if_unsaved])
|
284
|
+
hwnd = @ole_excel.Hwnd rescue nil
|
285
|
+
close_workbooks(if_unsaved: options[:if_unsaved])
|
305
286
|
@ole_excel.Quit
|
306
|
-
if false && defined?(weak_wkbks) && weak_wkbks.weakref_alive?
|
307
|
-
weak_wkbks.ole_free
|
308
|
-
end
|
287
|
+
weak_wkbks.ole_free if false && defined?(weak_wkbks) && weak_wkbks.weakref_alive?
|
309
288
|
weak_xl = WeakRef.new(@ole_excel)
|
310
289
|
else
|
311
290
|
weak_xl = nil
|
@@ -319,21 +298,10 @@ module RobustExcelOle
|
|
319
298
|
pid_puffer = ' ' * 32
|
320
299
|
process_id.call(hwnd, pid_puffer)
|
321
300
|
pid = pid_puffer.unpack('L')[0]
|
322
|
-
|
323
|
-
Process.kill('KILL', pid)
|
324
|
-
rescue
|
325
|
-
# trace "kill_error: #{$!}"
|
326
|
-
end
|
301
|
+
Process.kill('KILL', pid) rescue nil
|
327
302
|
end
|
328
303
|
@@hwnd2excel.delete(hwnd)
|
329
|
-
if weak_xl.weakref_alive?
|
330
|
-
# if WIN32OLE.ole_reference_count(weak_xlapp) > 0
|
331
|
-
begin
|
332
|
-
weak_xl.ole_free
|
333
|
-
rescue
|
334
|
-
# trace "weakref_probl_olefree"
|
335
|
-
end
|
336
|
-
end
|
304
|
+
weak_xl.ole_free if weak_xl.weakref_alive?
|
337
305
|
end
|
338
306
|
weak_xl ? 1 : 0
|
339
307
|
end
|
@@ -382,15 +350,42 @@ module RobustExcelOle
|
|
382
350
|
number
|
383
351
|
end
|
384
352
|
|
385
|
-
def self.
|
386
|
-
|
387
|
-
processes.select { |p| p.Name == 'EXCEL.EXE' }.size
|
353
|
+
def self.instance_count
|
354
|
+
WIN32OLE.connect('winmgmts:\\\\.').InstancesOf('win32_process').select { |p| p.Name == 'EXCEL.EXE' }.size
|
388
355
|
end
|
389
356
|
|
390
|
-
def self.
|
357
|
+
def self.known_instance_count
|
391
358
|
@@hwnd2excel.size
|
392
359
|
end
|
393
360
|
|
361
|
+
# returns a running Excel instance opened with RobustExcelOle
|
362
|
+
def self.known_running_instance
|
363
|
+
self.known_running_instances.first
|
364
|
+
end
|
365
|
+
|
366
|
+
# @return [Enumerator] known running Excel instances
|
367
|
+
def self.known_running_instances
|
368
|
+
pid2excel = {}
|
369
|
+
@@hwnd2excel.each do |hwnd,wr_excel|
|
370
|
+
next unless wr_excel.weakref_alive?
|
371
|
+
excel = wr_excel.__getobj__
|
372
|
+
process_id = Win32API.new('user32', 'GetWindowThreadProcessId', %w[I P], 'I')
|
373
|
+
pid_puffer = ' ' * 32
|
374
|
+
process_id.call(hwnd, pid_puffer)
|
375
|
+
pid = pid_puffer.unpack('L')[0]
|
376
|
+
pid2excel[pid] = excel
|
377
|
+
end
|
378
|
+
processes = WIN32OLE.connect('winmgmts:\\\\.').InstancesOf('win32_process')
|
379
|
+
processes.map{ |p| pid2excel[p.ProcessId] if p.Name == 'EXCEL.EXE'}.compact.lazy.each
|
380
|
+
end
|
381
|
+
|
382
|
+
class << self
|
383
|
+
alias excels_number instance_count # :deprecated :#
|
384
|
+
alias known_excels_number known_instance_count # :deprecated :#
|
385
|
+
alias known_excel_instance known_running_instance # :deprecated :#
|
386
|
+
alias known_excel_instances known_running_instances # :deprecated :#
|
387
|
+
end
|
388
|
+
|
394
389
|
private
|
395
390
|
|
396
391
|
# returns a Win32OLE object that represents a Excel instance to which Excel connects
|
@@ -398,7 +393,7 @@ module RobustExcelOle
|
|
398
393
|
# if this Excel instance is being closed, then Excel creates a new Excel instance
|
399
394
|
def self.current_ole_excel
|
400
395
|
if ::CONNECT_EXCEL_JRUBY_BUG
|
401
|
-
result =
|
396
|
+
result = known_running_instance
|
402
397
|
if result.nil?
|
403
398
|
if excels_number > 0
|
404
399
|
dummy_ole_workbook = WIN32OLE.connect(General.absolute_path('___dummy_workbook.xls')) rescue nil
|
@@ -427,17 +422,6 @@ module RobustExcelOle
|
|
427
422
|
result
|
428
423
|
end
|
429
424
|
|
430
|
-
# returns an Excel instance
|
431
|
-
def self.known_excel_instance
|
432
|
-
@@hwnd2excel.each do |hwnd, wr_excel|
|
433
|
-
if wr_excel.weakref_alive?
|
434
|
-
excel = wr_excel.__getobj__
|
435
|
-
return excel if excel.alive?
|
436
|
-
end
|
437
|
-
end
|
438
|
-
nil
|
439
|
-
end
|
440
|
-
|
441
425
|
def self.hwnd2excel(hwnd)
|
442
426
|
excel_weakref = @@hwnd2excel[hwnd]
|
443
427
|
if excel_weakref
|
@@ -457,35 +441,6 @@ module RobustExcelOle
|
|
457
441
|
|
458
442
|
public
|
459
443
|
|
460
|
-
# returns all Excel objects for all Excel instances opened with RobustExcelOle
|
461
|
-
def self.known_excel_instances
|
462
|
-
pid2excel = {}
|
463
|
-
@@hwnd2excel.each do |hwnd,wr_excel|
|
464
|
-
next unless wr_excel.weakref_alive?
|
465
|
-
|
466
|
-
excel = wr_excel.__getobj__
|
467
|
-
process_id = Win32API.new('user32', 'GetWindowThreadProcessId', %w[I P], 'I')
|
468
|
-
pid_puffer = ' ' * 32
|
469
|
-
process_id.call(hwnd, pid_puffer)
|
470
|
-
pid = pid_puffer.unpack('L')[0]
|
471
|
-
pid2excel[pid] = excel
|
472
|
-
end
|
473
|
-
processes = WIN32OLE.connect('winmgmts:\\\\.').InstancesOf('win32_process')
|
474
|
-
processes.select { |p| Excel.new(pid2excel[p.ProcessId]) if p.Name == 'EXCEL.EXE' && pid2excel.include?(p.ProcessId) }
|
475
|
-
result = []
|
476
|
-
processes.each do |p|
|
477
|
-
next unless p.Name == 'EXCEL.EXE'
|
478
|
-
|
479
|
-
if pid2excel.include?(p.ProcessId)
|
480
|
-
excel = pid2excel[p.ProcessId]
|
481
|
-
result << excel
|
482
|
-
end
|
483
|
-
# how to connect to an (interactively opened) Excel instance and get a WIN32OLE object?
|
484
|
-
# after that, lift it to an Excel object
|
485
|
-
end
|
486
|
-
result
|
487
|
-
end
|
488
|
-
|
489
444
|
# @private
|
490
445
|
def excel
|
491
446
|
self
|
@@ -523,15 +478,11 @@ module RobustExcelOle
|
|
523
478
|
|
524
479
|
# returns unsaved workbooks in known (not opened by user) Excel instances
|
525
480
|
# @private
|
526
|
-
def self.unsaved_known_workbooks
|
527
|
-
|
528
|
-
@@hwnd2excel.each do |_hwnd,wr_excel|
|
529
|
-
excel = wr_excel.__getobj__ if wr_excel.weakref_alive?
|
530
|
-
result << excel.unsaved_workbooks
|
531
|
-
end
|
532
|
-
result
|
481
|
+
def self.unsaved_known_workbooks
|
482
|
+
@@hwnd2excel.values.map{ |wk_exl| wk_exl.__getobj__.unsaved_workbooks if wk_exl.weakref_alive? }.compact.flatten
|
533
483
|
end
|
534
484
|
|
485
|
+
|
535
486
|
# @private
|
536
487
|
def print_workbooks
|
537
488
|
self.Workbooks.each { |w| trace "#{w.Name} #{w}" }
|
@@ -539,7 +490,7 @@ module RobustExcelOle
|
|
539
490
|
|
540
491
|
# @private
|
541
492
|
def generate_workbook file_name # :deprecated: #
|
542
|
-
workbook_class.open(file_name, :
|
493
|
+
workbook_class.open(file_name, if_absent: :create, force: {excel: self})
|
543
494
|
end
|
544
495
|
|
545
496
|
# sets DisplayAlerts in a block
|
@@ -579,37 +530,30 @@ module RobustExcelOle
|
|
579
530
|
return if calculation_mode.nil?
|
580
531
|
@properties[:calculation] = calculation_mode
|
581
532
|
calc_mode_changable = @ole_excel.Workbooks.Count > 0 && @ole_excel.Calculation.is_a?(Integer)
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
end
|
604
|
-
saved = []
|
605
|
-
@ole_excel.Workbooks.each { |w| saved << w.Saved }
|
606
|
-
@ole_excel.CalculateBeforeSave = false
|
607
|
-
@ole_excel.Calculation =
|
608
|
-
calculation_mode == :automatic ? XlCalculationAutomatic : XlCalculationManual
|
609
|
-
saved = []
|
610
|
-
@ole_excel.Workbooks.each { |w| saved << w.Saved }
|
533
|
+
return unless calc_mode_changable
|
534
|
+
retain_saved_workbooks do
|
535
|
+
begin
|
536
|
+
best_wb_to_make_visible = @ole_excel.Workbooks.sort_by {|wb|
|
537
|
+
score =
|
538
|
+
(wb.Saved ? 0 : 40) + # an unsaved workbooks is most likely the main workbook
|
539
|
+
(wb.ReadOnly ? 0 : 20) + # the main wb is usually writable
|
540
|
+
case wb.Name.split(".").last.downcase
|
541
|
+
when "xlsm" then 10 # the main workbook is more likely to have macros
|
542
|
+
when "xls" then 8
|
543
|
+
when "xlsx" then 4
|
544
|
+
when "xlam" then -2 # libraries are not normally the main workbook
|
545
|
+
else 0
|
546
|
+
end
|
547
|
+
score
|
548
|
+
}.last
|
549
|
+
best_wb_to_make_visible.Windows(1).Visible = true
|
550
|
+
rescue => e
|
551
|
+
trace "error setting calculation=#{calculation_mode} msg: " + e.message
|
552
|
+
trace e.backtrace
|
553
|
+
# continue on errors here, failing would usually disrupt too much
|
611
554
|
end
|
612
|
-
|
555
|
+
@ole_excel.CalculateBeforeSave = false
|
556
|
+
@ole_excel.Calculation = calculation_mode == :automatic ? XlCalculationAutomatic : XlCalculationManual
|
613
557
|
end
|
614
558
|
end
|
615
559
|
|
@@ -627,7 +571,6 @@ module RobustExcelOle
|
|
627
571
|
# sets calculation mode in a block
|
628
572
|
def with_calculation(calculation_mode)
|
629
573
|
return unless calculation_mode
|
630
|
-
|
631
574
|
old_calculation_mode = @ole_excel.Calculation
|
632
575
|
begin
|
633
576
|
self.calculation = calculation_mode
|
@@ -638,35 +581,39 @@ module RobustExcelOle
|
|
638
581
|
end
|
639
582
|
|
640
583
|
# set options in this Excel instance
|
641
|
-
def for_this_instance(options)
|
642
|
-
set_options(options)
|
643
|
-
end
|
644
|
-
|
645
584
|
def set_options(options)
|
646
585
|
@properties ||= { }
|
647
586
|
PROPERTIES.each do |property|
|
648
587
|
method = (property.to_s + '=').to_sym
|
649
|
-
|
588
|
+
send(method, options[property])
|
650
589
|
end
|
651
590
|
end
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
591
|
+
|
592
|
+
alias for_this_instance set_options # :deprecated: #
|
593
|
+
|
594
|
+
# @return [Enumerator] traversing all workbook objects
|
595
|
+
def each
|
596
|
+
if block_given?
|
597
|
+
ole_workbooks.lazy.each do |ole_workbook|
|
598
|
+
yield workbook_class.new(ole_workbook)
|
599
|
+
end
|
600
|
+
else
|
601
|
+
to_enum(:each).lazy
|
602
|
+
end
|
656
603
|
end
|
657
604
|
|
605
|
+
# @return [Array] all workbook objects
|
658
606
|
def workbooks
|
659
|
-
|
660
|
-
ole_workbooks.map {|ole_workbook| workbook_class.new(ole_workbook) }
|
607
|
+
to_a
|
661
608
|
end
|
662
609
|
|
663
|
-
# traverses
|
610
|
+
# traverses all workbooks and sets options if provided
|
664
611
|
def each_workbook(opts = { })
|
665
|
-
ole_workbooks.each do |ow|
|
612
|
+
ole_workbooks.lazy.each do |ow|
|
666
613
|
wb = workbook_class.new(ow, opts)
|
667
614
|
block_given? ? (yield wb) : wb
|
668
615
|
end
|
669
|
-
end
|
616
|
+
end
|
670
617
|
|
671
618
|
def each_workbook_with_index(opts = { }, offset = 0)
|
672
619
|
i = offset
|
@@ -676,6 +623,8 @@ module RobustExcelOle
|
|
676
623
|
end
|
677
624
|
end
|
678
625
|
|
626
|
+
alias for_all_workbooks each_workbook # :deprecated: #
|
627
|
+
|
679
628
|
def focus
|
680
629
|
self.visible = true
|
681
630
|
# if not Windows10 then
|
@@ -684,32 +633,18 @@ module RobustExcelOle
|
|
684
633
|
# Win32API.new("user32","SetForegroundWindow","","I").call
|
685
634
|
# end
|
686
635
|
end
|
687
|
-
|
688
|
-
# returns the value of a range
|
689
|
-
# @param [String] name the name of a range
|
690
|
-
# @returns [Variant] the value of the range
|
691
|
-
def [] name
|
692
|
-
namevalue_glob(name)
|
693
|
-
end
|
694
|
-
|
695
|
-
# sets the value of a range
|
696
|
-
# @param [String] name the name of the range
|
697
|
-
# @param [Variant] value the contents of the range
|
698
|
-
def []=(name, value)
|
699
|
-
set_namevalue_glob(name, value)
|
700
|
-
end
|
701
|
-
|
636
|
+
|
702
637
|
# @private
|
703
638
|
# returns active workbook
|
704
639
|
def workbook
|
705
640
|
@workbook ||= workbook_class.new(@ole_excel.ActiveWorkbook) if @ole_excel.Workbooks.Count > 0
|
706
641
|
end
|
707
642
|
|
708
|
-
|
643
|
+
alias active_workbook workbook
|
709
644
|
|
710
645
|
# @private
|
711
646
|
def to_s
|
712
|
-
|
647
|
+
"#<Excel: #{hwnd}#{ ("not alive" unless alive?)}>"
|
713
648
|
end
|
714
649
|
|
715
650
|
# @private
|
@@ -717,6 +652,9 @@ module RobustExcelOle
|
|
717
652
|
to_s
|
718
653
|
end
|
719
654
|
|
655
|
+
using ParentRefinement
|
656
|
+
using StringRefinement
|
657
|
+
|
720
658
|
# @private
|
721
659
|
def self.workbook_class
|
722
660
|
@workbook_class ||= begin
|
@@ -753,23 +691,20 @@ module RobustExcelOle
|
|
753
691
|
private
|
754
692
|
|
755
693
|
def method_missing(name, *args)
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
end
|
764
|
-
else
|
765
|
-
begin
|
766
|
-
@ole_excel.send(name, *args)
|
767
|
-
rescue NoMethodError
|
768
|
-
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
769
|
-
end
|
694
|
+
super unless name.to_s[0,1] =~ /[A-Z]/
|
695
|
+
raise ObjectNotAlive, 'method missing: Excel not alive' unless alive?
|
696
|
+
if ::ERRORMESSAGE_JRUBY_BUG
|
697
|
+
begin
|
698
|
+
@ole_excel.send(name, *args)
|
699
|
+
rescue Java::OrgRacobCom::ComFailException
|
700
|
+
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
770
701
|
end
|
771
702
|
else
|
772
|
-
|
703
|
+
begin
|
704
|
+
@ole_excel.send(name, *args)
|
705
|
+
rescue NoMethodError
|
706
|
+
raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
|
707
|
+
end
|
773
708
|
end
|
774
709
|
end
|
775
710
|
end
|