winexcel 0.0.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.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +156 -0
- data/Rakefile +7 -0
- data/examples/basic.rb +49 -0
- data/examples/extended.rb +73 -0
- data/examples/fixtures/a.xls +0 -0
- data/examples/fixtures/b.xlsx +0 -0
- data/examples/fixtures/template.xls +0 -0
- data/examples/my_basic_file.xls +0 -0
- data/examples/my_extended_file.xls +0 -0
- data/features/connect_to_open_excel_file.feature +32 -0
- data/features/create_excel_file_from_template_and_open.feature +35 -0
- data/features/fixtures/a.xls +0 -0
- data/features/fixtures/b.xlsx +0 -0
- data/features/open_excel_file.feature +41 -0
- data/features/step_definitions/excel_file_steps.rb +71 -0
- data/features/support/common.rb +37 -0
- data/features/support/env.rb +14 -0
- data/features/support/matchers.rb +9 -0
- data/lib/winexcel.rb +12 -0
- data/lib/winexcel/core_ext/object.rb +34 -0
- data/lib/winexcel/core_ext/ordered_hash.rb +100 -0
- data/lib/winexcel/excel/xl_file_format.rb +74 -0
- data/lib/winexcel/excel_file.rb +255 -0
- data/lib/winexcel/excel_file/common_methods.rb +422 -0
- data/lib/winexcel/excel_file/other_methods.rb +315 -0
- data/lib/winexcel/excel_file/write_2D_array.rb +169 -0
- data/lib/winexcel/fileutils_ext/backup_file.rb +25 -0
- data/lib/winexcel/fileutils_ext/create_dir_if_missing.rb +18 -0
- data/lib/winexcel/version.rb +3 -0
- data/lib/winexcel/win32olerot_ext/win32olerot.so +0 -0
- data/tasks/cucumber.rake +23 -0
- data/tasks/rspec.rake +9 -0
- data/winexcel.gemspec +26 -0
- metadata +163 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module CommonHelpers
|
2
|
+
def get_command_output
|
3
|
+
strip_color_codes(File.read(@stdout)).chomp
|
4
|
+
end
|
5
|
+
|
6
|
+
def strip_color_codes(text)
|
7
|
+
text.gsub(/\e\[\d+m/, '')
|
8
|
+
end
|
9
|
+
|
10
|
+
def in_tmp_folder(&block)
|
11
|
+
FileUtils.chdir(@tmp_root, &block)
|
12
|
+
end
|
13
|
+
|
14
|
+
def in_project_folder(&block)
|
15
|
+
project_folder = @active_project_folder || @tmp_root
|
16
|
+
FileUtils.chdir(project_folder, &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def in_home_folder(&block)
|
20
|
+
FileUtils.chdir(@home_path, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def force_local_lib_override(project_name = @project_name)
|
24
|
+
rakefile = File.read(File.join(project_name, 'Rakefile'))
|
25
|
+
File.open(File.join(project_name, 'Rakefile'), "w+") do |f|
|
26
|
+
f << "$:.unshift('#{@lib_path}')\n"
|
27
|
+
f << rakefile
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_active_project_folder project_name
|
32
|
+
@active_project_folder = File.join(@tmp_root, project_name)
|
33
|
+
@project_name = project_name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
World(CommonHelpers)
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__) + "/../../lib"))
|
2
|
+
require 'winexcel.rb'
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
Before do
|
6
|
+
@tmp_root = File.dirname(__FILE__) + "/../../tmp"
|
7
|
+
@home_path = File.expand_path(File.join(@tmp_root, "home"))
|
8
|
+
@lib_path = File.expand_path(File.dirname(__FILE__) + "/../../lib")
|
9
|
+
FileUtils.rm_rf @tmp_root
|
10
|
+
FileUtils.mkdir_p @home_path
|
11
|
+
ENV['HOME'] = @home_path
|
12
|
+
ENV['CUCUMBER_RUNNING'] = 'yes'
|
13
|
+
end
|
14
|
+
|
data/lib/winexcel.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module WinExcel
|
2
|
+
|
3
|
+
require 'winexcel/core_ext/object'
|
4
|
+
require 'winexcel/core_ext/ordered_hash'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'winexcel/fileutils_ext/create_dir_if_missing'
|
7
|
+
require 'winexcel/fileutils_ext/backup_file'
|
8
|
+
|
9
|
+
require 'winexcel/excel/xl_file_format'
|
10
|
+
require 'winexcel/version'
|
11
|
+
require 'winexcel/excel_file'
|
12
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class Object
|
2
|
+
# Returns true if the object is nil or empty. It works on most popular objects
|
3
|
+
# like hashes, arrays and strings. Main purpose is to avoid double checking statements
|
4
|
+
# (and to eliminate bugs caused by single checking) like in code below:
|
5
|
+
# if some_obj == nil or some_obj.empty?
|
6
|
+
# # do something
|
7
|
+
# end
|
8
|
+
# Remarks: When this funcion is applied to a String, false is returned when
|
9
|
+
# the string contains white space characters only.
|
10
|
+
def unempty?
|
11
|
+
if [nil, [], {}].include?(self) or (self.kind_of?(String) and self.strip == '')
|
12
|
+
return false
|
13
|
+
else
|
14
|
+
return true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def in?(arr)
|
19
|
+
return true if arr.unempty? and arr.include?(self)
|
20
|
+
end
|
21
|
+
|
22
|
+
def has?(obj)
|
23
|
+
if [nil].include?(self)
|
24
|
+
return false
|
25
|
+
else
|
26
|
+
return self.include?(obj)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def eq?(obj)
|
31
|
+
return self.to_s.upcase == obj.to_s.upcase
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module WinExcel
|
2
|
+
module CoreExt #:nodoc:
|
3
|
+
|
4
|
+
if RUBY_VERSION >= '1.9'
|
5
|
+
class OrderedHash < ::Hash
|
6
|
+
end
|
7
|
+
else
|
8
|
+
# This class is based on the Ruby 1.9 ordered hashes.
|
9
|
+
#
|
10
|
+
# It keeps the semantics and most of the efficiency of normal hashes
|
11
|
+
# while also keeping track of the order in which elements were set.
|
12
|
+
#
|
13
|
+
class OrderedHash #:nodoc:
|
14
|
+
include Enumerable
|
15
|
+
|
16
|
+
Node = Struct.new(:key, :value, :next, :prev)
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@hash = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](key)
|
23
|
+
@hash[key] && @hash[key].value
|
24
|
+
end
|
25
|
+
|
26
|
+
def []=(key, value)
|
27
|
+
if node = @hash[key]
|
28
|
+
node.value = value
|
29
|
+
else
|
30
|
+
node = Node.new(key, value)
|
31
|
+
|
32
|
+
if @first.nil?
|
33
|
+
@first = @last = node
|
34
|
+
else
|
35
|
+
node.prev = @last
|
36
|
+
@last.next = node
|
37
|
+
@last = node
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
@hash[key] = node
|
42
|
+
value
|
43
|
+
end
|
44
|
+
|
45
|
+
def delete(key)
|
46
|
+
if node = @hash[key]
|
47
|
+
prev_node = node.prev
|
48
|
+
next_node = node.next
|
49
|
+
|
50
|
+
next_node.prev = prev_node if next_node
|
51
|
+
prev_node.next = next_node if prev_node
|
52
|
+
|
53
|
+
@first = next_node if @first == node
|
54
|
+
@last = prev_node if @last == node
|
55
|
+
|
56
|
+
value = node.value
|
57
|
+
end
|
58
|
+
|
59
|
+
@hash.delete(key)
|
60
|
+
value
|
61
|
+
end
|
62
|
+
|
63
|
+
def keys
|
64
|
+
self.map { |k, v| k }
|
65
|
+
end
|
66
|
+
|
67
|
+
def values
|
68
|
+
self.map { |k, v| v }
|
69
|
+
end
|
70
|
+
|
71
|
+
def each
|
72
|
+
return unless @first
|
73
|
+
yield [@first.key, @first.value]
|
74
|
+
node = @first
|
75
|
+
yield [node.key, node.value] while node = node.next
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def merge(other)
|
80
|
+
hash = self.class.new
|
81
|
+
|
82
|
+
self.each do |key, value|
|
83
|
+
hash[key] = value
|
84
|
+
end
|
85
|
+
|
86
|
+
other.each do |key, value|
|
87
|
+
hash[key] = value
|
88
|
+
end
|
89
|
+
|
90
|
+
hash
|
91
|
+
end
|
92
|
+
|
93
|
+
def empty?
|
94
|
+
@hash.empty?
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module WinExcel
|
2
|
+
module Excel
|
3
|
+
APPLICATION_NAME = 'Excel.Application'
|
4
|
+
LOAD_ALL_CONSTANTS = false # for performance reasons it's been disabled
|
5
|
+
|
6
|
+
#
|
7
|
+
# XlFileFormat is much more faster replacement for LOAD_ALL_CONSTANTS
|
8
|
+
#
|
9
|
+
module XlFileFormat
|
10
|
+
# Excel::XlFileFormat::
|
11
|
+
|
12
|
+
# Name = Value # Description
|
13
|
+
XlAddIn = 18 # Microsoft Excel 97-2003 Add-In
|
14
|
+
XlAddIn8 = 18 # Microsoft Excel 97-2003 Add-In
|
15
|
+
XlCSV = 6 # CSV
|
16
|
+
XlCSVMac = 22 # Macintosh CSV
|
17
|
+
XlCSVMSDOS = 24 # MSDOS CSV
|
18
|
+
XlCSVWindows = 23 # Windows CSV
|
19
|
+
XlCurrentPlatformText = -4158 # Current Platform Text
|
20
|
+
XlDBF2 = 7 # DBF2
|
21
|
+
XlDBF3 = 8 # DBF3
|
22
|
+
XlDBF4 = 11 # DBF4
|
23
|
+
XlDIF = 9 # DIF
|
24
|
+
XlExcel12 = 50 # Excel12
|
25
|
+
XlExcel2 = 16 # Excel2
|
26
|
+
XlExcel2FarEast = 27 # Excel2 FarEast
|
27
|
+
XlExcel3 = 29 # Excel3
|
28
|
+
XlExcel4 = 33 # Excel4
|
29
|
+
XlExcel4Workbook = 35 # Excel4 Workbook
|
30
|
+
XlExcel5 = 39 # Excel5
|
31
|
+
XlExcel7 = 39 # Excel7
|
32
|
+
XlExcel8 = 56 # Excel8
|
33
|
+
XlExcel9795 = 43 # Excel9795
|
34
|
+
XlHtml = 44 # HTML format
|
35
|
+
XlIntlAddIn = 26 # International Add-In
|
36
|
+
XlIntlMacro = 25 # International Macro
|
37
|
+
XlOpenDocumentSpreadsheet = 60 # OpenDocument Spreadsheet
|
38
|
+
XlOpenXMLAddIn = 55 # Open XML Add-In
|
39
|
+
XlOpenXMLTemplate = 54 # Open XML Template
|
40
|
+
XlOpenXMLTemplateMacroEnabled = 53 # Open XML Template Macro Enabled
|
41
|
+
XlOpenXMLWorkbook = 51 # Open XML Workbook
|
42
|
+
XlOpenXMLWorkbookMacroEnabled = 52 # Open XML Workbook Macro Enabled
|
43
|
+
XlSYLK = 2 # SYLK
|
44
|
+
XlTemplate = 17 # Template
|
45
|
+
XlTemplate8 = 17 # Template 8
|
46
|
+
XlTextMac = 19 # Macintosh Text
|
47
|
+
XlTextMSDOS = 21 # MSDOS Text
|
48
|
+
XlTextPrinter = 36 # Printer Text
|
49
|
+
XlTextWindows = 20 # Windows Text
|
50
|
+
XlUnicodeText = 42 # Unicode Text
|
51
|
+
XlWebArchive = 45 # Web Archive
|
52
|
+
XlWJ2WD1 = 14 # WJ2WD1
|
53
|
+
XlWJ3 = 40 # WJ3
|
54
|
+
XlWJ3FJ3 = 41 # WJ3FJ3
|
55
|
+
XlWK1 = 5 # WK1
|
56
|
+
XlWK1ALL = 31 # WK1ALL
|
57
|
+
XlWK1FMT = 30 # WK1FMT
|
58
|
+
XlWK3 = 15 # WK3
|
59
|
+
XlWK3FM3 = 32 # WK3FM3
|
60
|
+
XlWK4 = 38 # WK4
|
61
|
+
XlWKS = 4 # Worksheet
|
62
|
+
XlWorkbookDefault = 51 # Workbook default
|
63
|
+
XlWorkbookNormal = -4143 # Workbook normal
|
64
|
+
XlWorks2FarEast = 28 # Works2 FarEast
|
65
|
+
XlWQ1 = 34 # WQ1
|
66
|
+
XlXMLSpreadsheet = 46 # XML Spreadsheet
|
67
|
+
end
|
68
|
+
|
69
|
+
# not yet implemented
|
70
|
+
RunModes = {}
|
71
|
+
RunModes[:open_new_in_isolated_excel] = :open_new_in_isolated_excel
|
72
|
+
RunModes[:find_in_existing_not_isolated_workbooks] = :find_in_existing_not_isolated_workbooks
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,255 @@
|
|
1
|
+
# excel_file.rb
|
2
|
+
#
|
3
|
+
# File based on Xls.rb being part of 'wwatf' project
|
4
|
+
# Copyright (C) 2010-2011 Sobieraj Kamil <ksob@dslowl.com>.
|
5
|
+
#
|
6
|
+
# This file is published under New BSD License
|
7
|
+
# You can redistribute and/or
|
8
|
+
# modify it under the terms of the New BSD License.
|
9
|
+
#
|
10
|
+
# New BSD License claims:
|
11
|
+
# Redistribution and use in source and binary forms, with or without
|
12
|
+
# modification, are permitted provided that the following conditions
|
13
|
+
# are met:
|
14
|
+
#
|
15
|
+
# 1. Redistributions of source code must retain the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer.
|
17
|
+
#
|
18
|
+
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
19
|
+
# this list of conditions and the following disclaimer in the documentation
|
20
|
+
# and/or other materials provided with the distribution.
|
21
|
+
#
|
22
|
+
# 3. Neither the name of Zend Technologies USA, Inc. nor the names of its
|
23
|
+
# contributors may be used to endorse or promote products derived from this
|
24
|
+
# software without specific prior written permission.
|
25
|
+
#
|
26
|
+
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
27
|
+
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
28
|
+
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
29
|
+
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
30
|
+
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
31
|
+
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
32
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
33
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
34
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
35
|
+
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
36
|
+
|
37
|
+
|
38
|
+
require 'logger'
|
39
|
+
require 'win32ole'
|
40
|
+
|
41
|
+
require 'rubygems'
|
42
|
+
if RUBY_VERSION >= '1.9'
|
43
|
+
require 'win32olerot'
|
44
|
+
else
|
45
|
+
require 'winexcel/win32olerot_ext/win32olerot'
|
46
|
+
end
|
47
|
+
|
48
|
+
require 'winexcel/excel_file/write_2D_array'
|
49
|
+
require 'winexcel/excel_file/common_methods'
|
50
|
+
require 'winexcel/excel_file/other_methods'
|
51
|
+
|
52
|
+
# Excel interface class.
|
53
|
+
# This class provides many simple methods for using Excel spreadsheets.
|
54
|
+
#
|
55
|
+
# Inner working:
|
56
|
+
# If the File is already open in excel, data is read from the open file
|
57
|
+
# and left open after the call to the close/finalize method.
|
58
|
+
# If the file is not open, It will be opened in the background
|
59
|
+
# and closed when the close/finalize method is called.
|
60
|
+
#
|
61
|
+
# For examples look at the examples folder as well as Cucumber/RSpec
|
62
|
+
# files in features and spec directories
|
63
|
+
#
|
64
|
+
# Information for developers:
|
65
|
+
# It is helpful to use COM/Win32OLE tracking tool like "oakland ActiveX Inspector"
|
66
|
+
# to clearly see what Excel instances are beeing created
|
67
|
+
#
|
68
|
+
module WinExcel
|
69
|
+
|
70
|
+
class ExcelFile
|
71
|
+
# Singleton Class to store Excel Constant Variables
|
72
|
+
class ExcelConst;
|
73
|
+
end
|
74
|
+
|
75
|
+
attr_accessor :excel
|
76
|
+
attr_accessor :workbook
|
77
|
+
attr_accessor :records
|
78
|
+
attr_accessor :fileName
|
79
|
+
|
80
|
+
@@automationInstance = nil
|
81
|
+
|
82
|
+
XlsAutomationSecurity = 3 # msoAutomationSecurityForceDisable
|
83
|
+
XlsDisplayAlerts = false
|
84
|
+
XlsVisible = false
|
85
|
+
XlsScreenUpdating = false
|
86
|
+
XlsInteractive = false
|
87
|
+
|
88
|
+
def setSettings excel
|
89
|
+
excel.Application.AutomationSecurity = XlsAutomationSecurity
|
90
|
+
excel.DisplayAlerts = XlsDisplayAlerts
|
91
|
+
excel.Visible = XlsVisible
|
92
|
+
excel.ScreenUpdating = XlsScreenUpdating
|
93
|
+
excel.Interactive = XlsInteractive
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# initilize creates an ExcelFile instance for a given .xls file.
|
98
|
+
# If the File is already open in excel, data is read from the open file and left open after the call to the close/finalize method.
|
99
|
+
# If the file is not open, It will be opened in the background and closed when the close/finalize method is called.
|
100
|
+
#
|
101
|
+
# For examples look at the end of the file as well as Cucumber/RSpec files
|
102
|
+
#
|
103
|
+
# Information for developers:
|
104
|
+
# It is helpful to use Win32OLE tracking tool like "oakland ActiveX Inspector"
|
105
|
+
# to clearly see what Excel instances are beeing created
|
106
|
+
#
|
107
|
+
def initialize(file, debug = false, template = nil)
|
108
|
+
@excelOpen=false
|
109
|
+
@connectedToOpenWorkBook=false
|
110
|
+
@log = Logger.new(STDERR)
|
111
|
+
@log.level = Logger::WARN
|
112
|
+
@log.level = Logger::DEBUG if debug
|
113
|
+
|
114
|
+
if not @@automationInstance
|
115
|
+
ExcelFile.killExcelAutomationProcesses
|
116
|
+
end
|
117
|
+
|
118
|
+
connectToOpenWorkbook = lambda {
|
119
|
+
# open existing file in a traditional way connecting to running Excel instance
|
120
|
+
workbookObj = WIN32OLE.connect(file)
|
121
|
+
@excel = workbookObj.Application
|
122
|
+
@excelOpen = true
|
123
|
+
basename = File.basename(file)
|
124
|
+
@workbook = @excel.Workbooks(basename)
|
125
|
+
@connectedToOpenWorkBook=true
|
126
|
+
@log.info(self.class) { "Attached to open Workbook: #{basename}" }
|
127
|
+
}
|
128
|
+
|
129
|
+
openAutomationInstance = lambda {
|
130
|
+
if not @@automationInstance
|
131
|
+
@@automationInstance = WIN32OLE::new(Excel::APPLICATION_NAME)
|
132
|
+
setSettings @@automationInstance
|
133
|
+
@log.info(self.class) { "Excel Automation Instance Created" }
|
134
|
+
end
|
135
|
+
@excel = @@automationInstance
|
136
|
+
}
|
137
|
+
|
138
|
+
makeFileFromTemplateAndOpen = lambda {
|
139
|
+
# copy the template on place of the file (that's been just moved)
|
140
|
+
openAutomationInstance.call
|
141
|
+
@workbook = @@automationInstance.Workbooks.Add(template)
|
142
|
+
@workbook.SaveAs(file.gsub("/", "\\"), Excel::XlFileFormat::XlWorkbookNormal)
|
143
|
+
@log.info(self.class) { "File: '#{file}' created from template '#{template}'." }
|
144
|
+
}
|
145
|
+
|
146
|
+
openFileInAutomationInstance = lambda {
|
147
|
+
# create isolated Excel and open that workbook/file inside of it
|
148
|
+
openAutomationInstance.call
|
149
|
+
@excelOpen = true
|
150
|
+
begin
|
151
|
+
basename = File.basename(file)
|
152
|
+
@workbook = @excel.Workbooks(basename)
|
153
|
+
@log.info(self.class) { "Attached to open Workbook: '#{basename}'." }
|
154
|
+
rescue
|
155
|
+
if File.exists?(file)
|
156
|
+
@workbook = @excel.Workbooks.Open(file)
|
157
|
+
@log.info(self.class) { "File: '#{file}' opened." }
|
158
|
+
else
|
159
|
+
raise "File: '#{file}' does not exist."
|
160
|
+
end
|
161
|
+
end
|
162
|
+
}
|
163
|
+
|
164
|
+
# check in ROT if workbook is open if so use WIN32OLE::connect(file) otherwise open in isolation
|
165
|
+
rot = WIN32OLE::RunningObjectTable.new
|
166
|
+
if rot.nil? then
|
167
|
+
throw 'Cannot access WIN32OLE::RunningObjectTable'
|
168
|
+
end
|
169
|
+
begin
|
170
|
+
isFileRunning = rot.is_running?(file)
|
171
|
+
if isFileRunning and template
|
172
|
+
connectToOpenWorkbook.call
|
173
|
+
|
174
|
+
# save file, close it and move to backup
|
175
|
+
save
|
176
|
+
sleep 1
|
177
|
+
@workbook.close
|
178
|
+
while rot.is_running?(file) do
|
179
|
+
sleep 1
|
180
|
+
end
|
181
|
+
@excel.quit
|
182
|
+
@excel = nil
|
183
|
+
GC.start
|
184
|
+
FileUtils.moveFileToBackupDir file
|
185
|
+
@log.info(self.class) { "File: #{file} successfully saved, closed and moved to BACKUP folder." }
|
186
|
+
|
187
|
+
makeFileFromTemplateAndOpen.call
|
188
|
+
elsif isFileRunning and not template
|
189
|
+
connectToOpenWorkbook.call
|
190
|
+
elsif not isFileRunning and template
|
191
|
+
makeFileFromTemplateAndOpen.call
|
192
|
+
elsif not isFileRunning and not template
|
193
|
+
openFileInAutomationInstance.call
|
194
|
+
end
|
195
|
+
rescue
|
196
|
+
@log.error(self.class) { "Error attaching: wasFileOpenedByUser: #{@connectedToOpenWorkBook}, file: #{file}, error: #{$!}" }
|
197
|
+
raise
|
198
|
+
end
|
199
|
+
|
200
|
+
@records = {}
|
201
|
+
|
202
|
+
if Excel::LOAD_ALL_CONSTANTS
|
203
|
+
# Get the standard set of Excel constants
|
204
|
+
WIN32OLE.const_load(@excel, ExcelConst) if ExcelConst.constants == []
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.killExcelAutomationProcesses
|
209
|
+
begin
|
210
|
+
wmi = WIN32OLE.connect("winmgmts://")
|
211
|
+
processes = wmi.ExecQuery("select * from win32_process where commandline like '%excel.exe\"% /automation %'")
|
212
|
+
processes.each do |process|
|
213
|
+
Process.kill('KILL', process.ProcessID)
|
214
|
+
end
|
215
|
+
rescue
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# not used
|
220
|
+
# do not work yet
|
221
|
+
def self.killInvisibleExcelProcesses
|
222
|
+
2.times do
|
223
|
+
excelObj = WIN32OLE::connect(Excel::APPLICATION_NAME)
|
224
|
+
if not excelObj.Visible
|
225
|
+
finalize(excelObj)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.finalize()
|
231
|
+
if not @@automationInstance.nil?
|
232
|
+
begin
|
233
|
+
@@automationInstance.Workbooks.each do |wb|
|
234
|
+
begin
|
235
|
+
wb.Close(false)
|
236
|
+
rescue
|
237
|
+
end
|
238
|
+
wb = nil
|
239
|
+
end
|
240
|
+
GC.start
|
241
|
+
sleep(3)
|
242
|
+
rescue
|
243
|
+
end
|
244
|
+
@@automationInstance.quit
|
245
|
+
sleep 1
|
246
|
+
@@automationInstance = nil
|
247
|
+
GC.start
|
248
|
+
sleep(3)
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|