robust_excel_ole 0.3.7 → 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog CHANGED
@@ -1,6 +1,35 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+
5
+ ## [0.3.8] - 2016-02-12
6
+
7
+ ### Added
8
+ - mark down comments
9
+ - trace
10
+ - Excel, Book: respond_to?, methods, special_methods, special_methods
11
+
12
+ ### Changed
13
+
14
+ ## [0.3.7] - 2015-12-04
15
+
16
+ ### Added
17
+ - Book::new: includes lifting Win32Ole objects
18
+ - Book: class synonym: Workbook
19
+ - Book::open: can force_excel can contain an win32ole object
20
+ - Book#excel_of
21
+ - Book: consider Excel version for opening linked workbooks
22
+ - Book#close: with keep_open
23
+ - Excel::new: includes lifting Win32ole objects
24
+ - Excel::close_all: with a little time out
25
+ - Excel: sublassing for Books
26
+
27
+ ### Changed
28
+ - Excel::close_all: bug fix
29
+ - Excel#recreate: reopening closed workbooks, restrict reopening, visible, displayalerts
30
+
31
+
32
+
4
33
  ## [0.3.6] - 2015-10-27
5
34
 
6
35
  ### Added
data/README.rdoc CHANGED
@@ -10,7 +10,7 @@ Goals:
10
10
  - provide convenient methods for frequent (common) tasks
11
11
  - support the use of simultaneously running Excel instances
12
12
  - allow the presence of referenced libraries and provide some support for that
13
- - supports EXCEL 2010, EXCEL 2007
13
+ - support EXCEL 2010, EXCEL 2007
14
14
 
15
15
  This is work in progress.
16
16
 
@@ -43,7 +43,7 @@ Options are
43
43
  +:default_excel+, +:force_excel+, +:if_absent+, +:if_unsaved+, +:if_obstructed+,
44
44
  +:read_only+, +:visible+, +:displayalerts+.
45
45
 
46
- Values for +:default_excel+ are +:reuse+, +:new+ or some Excel instance. Values for +:force_excel+ are +:new+ or some Excel instance. Values for +:if_unsaved+ are +:raise+, +:accept+, +:forget+, +:alert+ and +:new_excel+. Values for +:if_obstructed+ are +:raise+, +:save+, +:close_if_saved+, +:forget+, +:alert+ and +:new_excel+. Values for +:if_absent+ are +:raise+ and +:create+.
46
+ Valid values for +:default_excel+ are +:reuse+, +:new+ or some Excel instance, for +:force_excel+ : +:new+ or some Excel instance, for +:if_unsaved+ : +:raise+, +:accept+, +:forget+, +:alert+ and +:new_excel+, for +:if_obstructed+ : +:raise+, +:save+, +:close_if_saved+, +:forget+, +:alert+ and +:new_excel+ , for +:if_absent+ : +:raise+ and +:create+.
47
47
 
48
48
  Here are a few examples:
49
49
 
@@ -60,7 +60,7 @@ The option +:if_unsaved+ manages this case. For example, +:if_unsaved+ => +:acce
60
60
 
61
61
  book = Book.open('workbook.xls', :if_unsaved => :accept)
62
62
 
63
- If a workbook is open and a workbook with the same name but in different path shall be opened, then the first workbook blocks opening the other workbook. The option +:if_obstructed+ => handles this situation. For example, +:if_obstructed+ => +:forget+ causes the old workbook to close and to open the new workbook.
63
+ If a workbook is open and a workbook with the same name but in different path shall be opened, then the first workbook blocks opening the other workbook. The option +:if_obstructed+ handles this situation. For example, +:if_obstructed+ => +:forget+ causes the old workbook to close and to open the new workbook.
64
64
 
65
65
  book = Book.open('path/workbook.xls', :if_obstructed => :forget)
66
66
 
@@ -70,7 +70,7 @@ Opening linked workbooks for EXCEL 2007 is supported
70
70
 
71
71
  book.close
72
72
 
73
- There is one option: : +:if_unsaved+. Values for this option are +:raise+, +:save+, +:forget+, +:alert+ and +:keep_open+. Example:
73
+ There is one option: : +:if_unsaved+. Valid values for this option are +:raise+, +:save+, +:forget+, +:alert+ and +:keep_open+. Example:
74
74
 
75
75
  Closing the workbook and saving it before if it has unsaved changes.
76
76
 
@@ -93,7 +93,7 @@ An Excel file (or workbook) is represented by a Book object. A Book object is de
93
93
  Identity transparence means that the same Book objects refer to the same Excel files, and vice versa.
94
94
  In other words, a Book objects is a proxy of an Excel file.
95
95
 
96
- === Lifting a workbook to a Book object
96
+ === Promoting a workbook to a Book object
97
97
 
98
98
  A Book object can be created when giving an Excel workbook.
99
99
 
@@ -107,7 +107,7 @@ Saving a workbook with a file name.
107
107
 
108
108
  book.save_as('another_workbook.xls')
109
109
 
110
- The options are +:if_exists+ and +if_obstructed+.
110
+ The options are +:if_exists+ and +if_obstructed+.
111
111
 
112
112
  Saving a workbook and overwriting the file if it exists before.
113
113
 
@@ -123,9 +123,9 @@ If a workbook is blocking the workbook that should be saved, then the former one
123
123
 
124
124
  The method +unobtrusively+ enables the user to read or modify a workbook, no matter if it is open in some Excel instance, if it is saved or unsaved, and if it is writable or not. When opening a workbook unobtrusively, its status remains unchanged. This status includes, whether the workbook is opened or closed, saved or unsaved, readonly or writable.
125
125
 
126
- One option chooses the Excel instance in which a closed workbook is opened. The options +:reuse (default) indicates that the closed workbook is opened in the Excel instance of the workbook, if it exists, or that another Excel instance is reused. The option +:hidden+ provokes that the closed workbook is opened in a separate Excel instance that is not visible and has no DisplayAlerts. Any following closed workbook would be opened in this Excel instance as well when using this option. Moreover, an Excel instance can be given directly where to open the closed workbook.
126
+ Some options determine the Excel instance in which a closed workbook is opened. The options +:reuse (default) indicates that the closed workbook is opened in the Excel instance where the workbooks is opened, if such an Excel instance exists, otherwise that another Excel instance is reused. The option +:hidden+ provokes that the closed workbook is opened in a separate Excel instance that is not visible and has no DisplayAlerts. Any following closed workbook would be opened in this Excel instance as well when using this option. Moreover, an Excel instance can be given directly where to open the closed workbook.
127
127
 
128
- Further options are +:read_only+, +:readonly_excel+, and +:keep_open. The option +:readonly_excel+ chooses whether a book that is opened as ReadOnly and that shall be modified shall be opned as writable in the Excel instance where it was open so far, or if it shall be opened as writable in another running Excel instance, if such an Excel exists, or opened in a new Excel instance.
128
+ Further options are +:read_only+, +:readonly_excel+, and +:keep_open. The option +:readonly_excel+ chooses whether a book that is opened in read only mode. If the workbook is opened as read only, then the option +:readonly_excel+ determines whether to close the workbook and open it as writable in the Excel instance where it was open so far, or to open it as writable in another running Excel instance, if such an instance exists, or to open it in a new Excel instance.
129
129
 
130
130
  Book.unobtrusively('workbook.xls', :reuse, :read_only => false, :keep_open => false) do |book|
131
131
  # some modification
@@ -133,7 +133,7 @@ Further options are +:read_only+, +:readonly_excel+, and +:keep_open. The option
133
133
  sheet[1,1] = "c"
134
134
  end
135
135
 
136
- The methods +for_reading+ and +for_modifying+ indicate unobtrusively reading or modifying.
136
+ The methods +for_reading+ and +for_modifying+ are methods for unobtrusively reading or modifying.
137
137
 
138
138
  Book.for_modifying('workbook.xls') do |book|
139
139
  # some modification
@@ -169,7 +169,7 @@ or
169
169
 
170
170
  === Activating a workbook.
171
171
 
172
- Brings the window of a workbook to the foreground . Make it available for keyboard inputs and make the Excel instance visible.
172
+ Bring the window of a workbook to the foreground, make it available for keyboard inputs, and make the Excel instance visible.
173
173
 
174
174
  book.activate
175
175
 
@@ -328,7 +328,7 @@ Reusing a running Excel instance, making it visible and turning on displayalerts
328
328
 
329
329
  excel2 = Excel.new(:reuse => true, :visible => true, :displayalerts => true).
330
330
 
331
- Lifting an Excel instance represented as WIN32OLE object to an Excel object
331
+ Promoting an Excel instance represented as WIN32OLE object to an Excel object
332
332
 
333
333
  excel = Excel.new(:reuse => win32ole_object)
334
334
 
@@ -376,7 +376,7 @@ Closing the Excel instance, saving unsaved wrkbooks and terminating the Excel pr
376
376
 
377
377
  Excel.close_all
378
378
 
379
- The options are +:if_unsaved+ and +:hard+ . Values for :if_unsaved+ are +raise+, +save+, +forget+. Example:
379
+ The options are +:if_unsaved+ and +:hard+ . Values for :if_unsaved+ are +raise+, +save+, and +forget+. Example:
380
380
 
381
381
  Closing all Excel instances, not saving unsaved workbooks and terminating the Excel processes
382
382
 
data/README_detail.rdoc CHANGED
@@ -129,7 +129,7 @@ An Excel file (or workbook) is represented by a Book object. A Book object is de
129
129
  Identity transparence means that the same Book objects refer to the same Excel files, and vice versa.
130
130
  In other words, a Book objects is a proxy of an Excel file.
131
131
 
132
- === Uplifting a workbook to a Book object
132
+ === Promoting a workbook to a Book object
133
133
 
134
134
  A Book object can be created when giving an Excel workbook.
135
135
 
@@ -180,7 +180,7 @@ One option chooses the Excel instance in which a closed workbook is opened. The
180
180
  Options are the following:
181
181
 
182
182
  :reuse (default) : open a closed workbook in the Excel instance of the workbook, if it exists, otherwise reuse another Excel
183
- :hidden : open a closed workbook in one separate Excel instance that is not visible and has no displayaslerts
183
+ :hidden : open a closed workbook in one separate Excel instance that is not visible and has no displayalerts
184
184
  <excel-instance> : open a closed workbooks in the given Excel instance
185
185
 
186
186
  +:read_only+:: Open the workbook unobtrusively for reading only (default: false)
@@ -392,7 +392,7 @@ Reusing a running Excel instance, making it visible and turning on displayalerts
392
392
 
393
393
  excel2 = Excel.new(:reuse => true, :visible => true, :displayalerts => true).
394
394
 
395
- Uplifting an Excel instance represented as WIN32OLE object to an Excel object
395
+ Promoting an Excel instance represented as WIN32OLE object to an Excel object
396
396
 
397
397
  excel = Excel.new(:reuse => win32ole_object)
398
398
 
@@ -1,14 +1,19 @@
1
1
  # example_simple.rb:
2
2
  # open a book, simple save, save_as, close
3
3
 
4
+ LOG_TO_STDOUT = false
5
+ REO_LOG_FILE = "reo2.log"
6
+ REO_LOG_DIR = "C:/"
7
+
4
8
  require File.join(File.dirname(__FILE__), '../../lib/robust_excel_ole')
5
9
  require File.join(File.dirname(__FILE__), '../../spec/helpers/create_temporary_dir')
6
10
  require "fileutils"
7
11
 
8
12
  include RobustExcelOle
9
13
 
10
- Excel.close_all
14
+ Excel.kill_all
11
15
  begin
16
+ trace "hello"
12
17
  dir = create_tmpdir
13
18
  file_name = dir + 'workbook.xls'
14
19
  other_file_name = dir + 'different_workbook.xls'
@@ -1,4 +1,5 @@
1
1
  require "win32ole"
2
+ require File.join(File.dirname(__FILE__), 'robust_excel_ole/utilities')
2
3
  require File.join(File.dirname(__FILE__), 'robust_excel_ole/excel')
3
4
  require File.join(File.dirname(__FILE__), 'robust_excel_ole/bookstore')
4
5
  require File.join(File.dirname(__FILE__), 'robust_excel_ole/book')
@@ -13,44 +14,75 @@ REO = RobustExcelOle
13
14
 
14
15
  include Enumerable
15
16
 
16
- LOG_TO_STDOUT = true
17
-
18
- REO_LOG_FILE = "reo.log"
19
- REO_LOG_DIR = ""
20
-
21
- File.delete REO_LOG_FILE rescue nil
22
-
23
- module RobustExcelOle
17
+ module RobustExcelOle
18
+
19
+ def test
20
+ memcpy = Win32API.new('crtdll', 'memcpy', 'PPL', 'L')
21
+ def addr(obj); obj.object_id << 1; end
22
+ hallo = "Hallo"
23
+ d = 10 ** 7; 1
24
+ memcpy.call(ziel, addr(hallo) - 900000, 1000000)
25
+
26
+ # d = 10 ** 6
27
+ # memcpy.call(ziel, addr(hallo) - 250000, 1000000)
28
+ 1.step(10,1) {|i|
29
+ puts "i: #{i}"
30
+ memcpy.call(ziel, addr(hallo) - i * d, 300000)
31
+ #memcpy.call(ziel, addr(hallo) - i * d, d-1)
32
+ a = ziel.index("Hal")
33
+ puts "a: #{a}"
34
+ }
35
+ end
24
36
 
25
- def t(text)
26
- if LOG_TO_STDOUT
27
- puts text
28
- else
29
- if REO_LOG_DIR.empty?
30
- homes = ["HOME", "HOMEPATH"]
31
- home = homes.find {|h| ENV[h] != nil}
32
- reo_log_dir = ENV[home]
33
- else
34
- reo_log_dir = REO_LOG_DIR
35
- end
36
- File.open(reo_log_dir + "/" + REO_LOG_FILE,"a") do | file |
37
- file.puts text
38
- end
37
+ def rot # :nodoc: #
38
+ # allocate 4 bytes to store a pointer to the IRunningObjectTable object
39
+ irot_ptr = 0.chr * 4 # or [0].pack(‘L’)
40
+ # creating an instance of a WIN32api method for GetRunningObjectTable
41
+ grot = Win32API.new('ole32', 'GetRunningObjectTable', 'IP', 'I')
42
+ # get a pointer to the IRunningObjectTable interface on the local ROT
43
+ return_val = grot.call(0, irot_ptr)
44
+ # if there is an unexpected error, abort
45
+ if return_val != 0
46
+ puts "unexpected error when calling GetRunningObjectTable"
47
+ return
39
48
  end
49
+ # get a pointer to the irot_ptr
50
+ irot_ptr_ptr = irot_ptr.unpack('L').first
51
+ # allocate 4 bytes to store a pointer to the virtual function table
52
+ irot_vtbl_ptr = 0.chr * 4 # or irot_vtbl_ptr = [0].pack(‘L’)
53
+ # allocate 4 * 7 bytes for the table, since there are 7 functions in the IRunningObjectTable interface
54
+ irot_table = 0.chr * (4 * 7)
55
+ # creating an instance of a WIN32api method for memcpy
56
+ memcpy = Win32API.new('crtdll', 'memcpy', 'PPL', 'L')
57
+ # make a copy of irot_ptr that we can muck about with
58
+ memcpy.call(irot_vtbl_ptr, irot_ptr_ptr, 4)
59
+ # get a pointer to the irot_vtbl
60
+ irot_vtbl_ptr.unpack('L').first
61
+ # Copy the 4*7 bytes at the irot_vtbl_ptr memory address to irot_table
62
+ memcpy.call(irot_table, irot_vtbl_ptr.unpack('L').first, 4 * 7)
63
+ # unpack the contents of the virtual function table into the 'irot_table' array.
64
+ irot_table = irot_table.unpack('L*')
65
+ puts "Number of elements in the vtbl is: " + irot_table.length.to_s
66
+ # EnumRunning is the 1st function in the vtbl.
67
+ enumRunning = Win32::API::Function.new(irot_table[0], 'P', 'I')
68
+ # allocate 4 bytes to store a pointer to the enumerator
69
+ enumMoniker = [0].pack('L') # or 0.chr * 4
70
+ # create a pointer to the enumerator
71
+ return_val_er = enumRunning.call(enumMoniker)
40
72
  end
41
73
 
42
- def absolute_path(file)
74
+ def absolute_path(file) # :nodoc: #
43
75
  file = File.expand_path(file)
44
76
  file = RobustExcelOle::Cygwin.cygpath('-w', file) if RUBY_PLATFORM =~ /cygwin/
45
77
  WIN32OLE.new('Scripting.FileSystemObject').GetAbsolutePathName(file)
46
78
  end
47
79
 
48
- def canonize(filename)
80
+ def canonize(filename) # :nodoc: #
49
81
  raise ExcelError, "No string given to canonize, but #{filename.inspect}" unless filename.is_a?(String)
50
82
  normalize(filename).downcase rescue nil
51
83
  end
52
84
 
53
- def normalize(path)
85
+ def normalize(path) # :nodoc: #
54
86
  path = path.gsub('/./', '/') + '/'
55
87
  path = path.gsub(/[\/\\]+/, "/")
56
88
  nil while path.gsub!(/(\/|^)(?!\.\.?)([^\/]+)\/\.\.\//, '\1')
@@ -58,11 +90,14 @@ module RobustExcelOle
58
90
  path
59
91
  end
60
92
 
61
- module_function :t, :absolute_path, :canonize
93
+ module_function :absolute_path, :canonize, :rot
62
94
 
63
95
  class VBAMethodMissingError < RuntimeError # :nodoc: #
64
96
  end
65
97
 
98
+ #module RobustExcelOle::Utilites # :nodoc: #
99
+
100
+ #end
66
101
  end
67
102
 
68
103
  class Object # :nodoc: #
@@ -79,10 +114,14 @@ class ::String # :nodoc: #
79
114
  if empty?
80
115
  path_part
81
116
  else
82
- begin
83
- File.join self, path_part
84
- rescue TypeError
85
- raise "Only strings can be parts of paths (given: #{path_part.inspect} of class #{path_part.class})"
117
+ if path_part.nil? or path_part.empty?
118
+ self
119
+ else
120
+ begin
121
+ File.join self, path_part
122
+ rescue TypeError
123
+ raise "Only strings can be parts of paths (given: #{path_part.inspect} of class #{path_part.class})"
124
+ end
86
125
  end
87
126
  end
88
127
  end
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'weakref'
4
4
 
5
+ include Utilities
6
+
5
7
  module RobustExcelOle
6
8
 
7
9
  class Book
@@ -25,42 +27,48 @@ module RobustExcelOle
25
27
  class << self
26
28
 
27
29
  # opens a workbook.
28
- #
29
- # when reopening a workbook that was opened and closed before, transparency identity is ensured:
30
- # same Book objects refer to the same Excel files, and vice versa
31
- #
30
+ # @param [String] file the file name
31
+ # @param [Hash] opts the options
32
+ # @option opts [Variant] :default_excel :reuse (default), :new, or <excel-instance>
33
+ # @option opts [Variant] :force_excel :new (default), or <excel-instance>
34
+ # @option opts [Symbol] :if_unsaved :raise (default), :forget, :accept, :alert, or :new_excel
35
+ # @option opts [Symbol] :if_obstructed :raise (default), :forget, :save, :close_if_saved, or _new_excel
36
+ # @option opts [Symbol] :if_absent :raise (default), or :create
37
+ # @option opts [Boolean] :read_only true (default), or false
38
+ # @option opts [Boolean] :displayalerts true, or false (default)
39
+ # @option opts [Boolean] :visible true, or false (default)
32
40
  # options:
33
41
  # :default_excel if the workbook was already open in an Excel instance, then open it there.
34
42
  # Otherwise, i.e. if the workbook was not open before or the Excel instance is not alive
35
- # :reuse (default) -> connects to a (the first opened) running Excel instance,
43
+ # :reuse -> connects to a (the first opened) running Excel instance,
36
44
  # excluding the hidden Excel instance, if it exists,
37
45
  # otherwise opens in a new Excel instance.
38
46
  # :new -> opens in a new Excel instance
39
47
  # <excel-instance> -> opens in the given Excel instance
40
48
  # :force_excel no matter whether the workbook was already open
41
- # :new (default) -> opens in a new Excel instance
49
+ # :new -> opens in a new Excel instance
42
50
  # <excel-instance> -> opens in the given Excel instance
43
51
  # :if_unsaved if an unsaved workbook with the same name is open, then
44
- # :raise (default) -> raises an exception
52
+ # :raise -> raises an exception
45
53
  # :forget -> close the unsaved workbook, open the new workbook
46
54
  # :accept -> lets the unsaved workbook open
47
55
  # :alert -> gives control to Excel
48
56
  # :new_excel -> opens the new workbook in a new Excel instance
49
57
  # :if_obstructed if a workbook with the same name in a different path is open, then
50
- # :raise (default) -> raises an exception
58
+ # :raise -> raises an exception
51
59
  # :forget -> closes the old workbook, open the new workbook
52
60
  # :save -> saves the old workbook, close it, open the new workbook
53
61
  # :close_if_saved -> closes the old workbook and open the new workbook, if the old workbook is saved,
54
62
  # otherwise raises an exception.
55
63
  # :new_excel -> opens the new workbook in a new Excel instance
56
- # :if_absent :raise (default) -> raises an exception , if the file does not exists
64
+ # :if_absent :raise -> raises an exception , if the file does not exists
57
65
  # :create -> creates a new Excel file, if it does not exists
58
66
  #
59
- # :read_only opens in read-only mode (default: false)
60
- # :displayalerts enables DisplayAlerts in Excel (default: false)
61
- # :visible makes visible in Excel (default: false)
67
+ # :read_only opens in read-only mode
68
+ # :displayalerts enables DisplayAlerts in Excel
69
+ # :visible makes visible in Excel
62
70
  # if :default_excel is set, then DisplayAlerts and Visible are set only if these parameters are given
63
-
71
+ # @return [Book] a workbook
64
72
  def open(file, opts={ }, &block)
65
73
  options = DEFAULT_OPEN_OPTS.merge(opts)
66
74
  book = nil
@@ -88,8 +96,9 @@ module RobustExcelOle
88
96
 
89
97
  # creates a Book object for a given workbook or file name
90
98
  # @param [WIN32OLE] workbook a workbook
91
- # @options opts [Symbol] see above
92
- # @return [Book] a Book object
99
+ # @param [Hash] opts the options
100
+ # @option opts [Symbol] see above
101
+ # @return [Book] a workbook
93
102
  def self.new(workbook, opts={ }, &block)
94
103
  if workbook && (workbook.is_a? WIN32OLE)
95
104
  filename = workbook.Fullname.tr('\\','/') rescue nil
@@ -106,6 +115,10 @@ module RobustExcelOle
106
115
 
107
116
  # creates a new Book object, if a file name is given
108
117
  # lifts the workbook to a Book object, if a workbook is given
118
+ # @param [Variant] file_or_workbook file name or workbook
119
+ # @param [Hash] opts the options
120
+ # @option opts [Symbol] see above
121
+ # @return [Book] a workbook
109
122
  def initialize(file_or_workbook, opts={ }, &block)
110
123
  options = DEFAULT_OPEN_OPTS.merge(opts)
111
124
  options[:excel] = options[:force_excel] ? options[:force_excel] : options[:default_excel]
@@ -116,7 +129,7 @@ module RobustExcelOle
116
129
  win32ole_excel = WIN32OLE.connect(workbook.Fullname).Application rescue nil
117
130
  @excel = excel_class.new(win32ole_excel)
118
131
  self.apply_options(options)
119
- # if the Excel could not be lifted up, then create it
132
+ # if the Excel could not be promoted, then create it
120
133
  ensure_excel(options)
121
134
  else
122
135
  file = file_or_workbook
@@ -141,7 +154,7 @@ module RobustExcelOle
141
154
  private
142
155
 
143
156
  # returns an Excel object when given Excel, Book or Win32ole object representing a Workbook or an Excel
144
- def self.excel_of(object)
157
+ def self.excel_of(object) # :nodoc: #
145
158
  if object.is_a? WIN32OLE
146
159
  case object.ole_obj_help.name
147
160
  when /Workbook/i
@@ -155,12 +168,12 @@ module RobustExcelOle
155
168
  object.excel
156
169
  end
157
170
  #rescue
158
- # t "no Excel, Book, or WIN32OLE object representing a Workbook or an Excel instance"
171
+ # trace "no Excel, Book, or WIN32OLE object representing a Workbook or an Excel instance"
159
172
  end
160
173
 
161
174
  public
162
175
 
163
- def ensure_excel(options)
176
+ def ensure_excel(options) # :nodoc: #
164
177
  return if @excel && @excel.alive?
165
178
  if options[:excel] == :reuse
166
179
  @excel = excel_class.new(:reuse => true)
@@ -190,7 +203,7 @@ module RobustExcelOle
190
203
  end
191
204
  end
192
205
 
193
- def ensure_workbook(file, options)
206
+ def ensure_workbook(file, options) # :nodoc: #
194
207
  file = @stored_filename ? @stored_filename : file
195
208
  unless File.exist?(file)
196
209
  if options[:if_absent] == :create
@@ -267,21 +280,21 @@ module RobustExcelOle
267
280
 
268
281
  private
269
282
 
270
- def open_or_create_workbook(file, options)
283
+ def open_or_create_workbook(file, options) # :nodoc: #
271
284
  if ((not @workbook) || (options[:if_unsaved] == :alert) || options[:if_obstructed]) then
272
285
  begin
273
286
  filename = RobustExcelOle::absolute_path(file)
274
287
  begin
275
288
  workbooks = @excel.Workbooks
276
289
  rescue RuntimeError => msg
277
- t "RuntimeError: #{msg.message}"
290
+ trace "RuntimeError: #{msg.message}"
278
291
  if msg.message =~ /method missing: Excel not alive/
279
292
  raise ExcelErrorOpen, "Excel instance not alive or damaged"
280
293
  else
281
294
  raise ExcelErrorOpen, "unknown RuntimeError"
282
295
  end
283
296
  rescue WeakRef::RefError => msg
284
- t "WeakRefError: #{msg.message}"
297
+ trace "WeakRefError: #{msg.message}"
285
298
  raise ExcelErrorOpen, "#{msg.message}"
286
299
  end
287
300
  # workaround for linked workbooks for Excel 2007:
@@ -292,7 +305,7 @@ module RobustExcelOle
292
305
  workbooks.Open(filename,{ 'ReadOnly' => options[:read_only] })
293
306
  workbooks.Item(1).Close if @excel.Version == "12.0" && count == 0
294
307
  rescue WIN32OLERuntimeError => msg
295
- t "WIN32OLERuntimeError: #{msg.message}"
308
+ trace "WIN32OLERuntimeError: #{msg.message}"
296
309
  if msg.message =~ /800A03EC/
297
310
  raise ExcelErrorOpen, "open: user canceled or open error"
298
311
  else
@@ -312,14 +325,17 @@ module RobustExcelOle
312
325
  public
313
326
 
314
327
  # closes the workbook, if it is alive
315
- #
328
+ # @param [Hash] opts the options
329
+ # @option opts [Symbol] :if_unsaved :raise (default), :save, :forget, :keep_open, or :alert
316
330
  # options:
317
331
  # :if_unsaved if the workbook is unsaved
318
- # :raise (default) -> raises an exception
332
+ # :raise -> raises an exception
319
333
  # :save -> saves the workbook before it is closed
320
334
  # :forget -> closes the workbook
321
335
  # :keep_open -> keep the workbook open
322
336
  # :alert -> gives control to excel
337
+ # @raise ExcelErrorClose if the option :if_unsaved is :raise and the workbook is unsaved, or option is invalid
338
+ # @raise ExcelErrorCanceled if the user has canceled
323
339
  def close(opts = {:if_unsaved => :raise})
324
340
  if (alive? && (not @workbook.Saved) && writable) then
325
341
  case opts[:if_unsaved]
@@ -370,17 +386,27 @@ module RobustExcelOle
370
386
  unobtrusively(*args, &block)
371
387
  end
372
388
 
373
- # modifies a workbook such that its state (open/close, saved/unsaved, readonly/writable) remains unchanged.
374
- # options:
375
- # :reuse (default) : opens closed workbooks in the Excel instance of the workbook, if it exists, reuse another Excel, otherwise
376
- # :hidden : opens closed workbooks in one separate Excel instance that is not visible and has no displayaslerts
377
- # <excel-instance> : opens closed workbooks in the given Excel instance
389
+ # modifies a workbook such that its state (open/close, saved/unsaved, readonly/writable) remains unchanged
390
+ # @param [String] file the file name
391
+ # @param [Hash] if_closed an option
392
+ # @param [Hash] opts the options
393
+ # @option opts [Variant] :if_closed :reuse (default), :hidden or a Excel instance
394
+ # @option opts [Boolean] :read_only whether the file is opened for read-only
395
+ # @option opts [Boolean] :readonly_excel behaviour when workbook is opened read-only and shall be modified
396
+ # @option opts [Boolean] :keep_open whether the workbook shall be kept open after unobtrusively opening
397
+ # options:
398
+ # :if_closed : if the workbook is closed, then open it in
399
+ # :reuse -> the Excel instance of the workbook, if it exists,
400
+ # reuse another Excel, otherwise
401
+ # :hidden -> a separate Excel instance that is not visible and has no displayaslerts
402
+ # <excel-instance> -> the given Excel instance
378
403
  # :read_only : opens the workbook unobtrusively for reading only (default: false)
379
404
  # :readonly_excel: if the workbook is opened only as ReadOnly and shall be modified, then
380
405
  # true: closes it and open it as writable in the Excel instance where it was open so far
381
406
  # false (default) opens it as writable in another running excel instance, if it exists,
382
407
  # otherwise open in a new Excel instance.
383
408
  # :keep_open: lets the workbook open after unobtrusively opening (default: false)
409
+ # @return [Book] a workbook
384
410
  def self.unobtrusively(file, if_closed = nil, opts = { }, &block)
385
411
  if if_closed.is_a? Hash
386
412
  opts = if_closed
@@ -440,6 +466,9 @@ module RobustExcelOle
440
466
  end
441
467
 
442
468
  # renames a range
469
+ # @param [String] name the previous range name
470
+ # @param [String] new_name the new range name
471
+ # @raise ExcelError if name is not in the file, or if new_name cannot be set
443
472
  def rename_range(name, new_name)
444
473
  begin
445
474
  item = self.Names.Item(name)
@@ -454,8 +483,14 @@ module RobustExcelOle
454
483
  end
455
484
 
456
485
  # returns the contents of a range with given name
457
- # if no contents could returned, then return default value, if a default value was provided
458
- # raise an error, otherwise
486
+ # @param [String] name the range name
487
+ # @param [Hash] opts the options
488
+ # @option opts [Symbol] :default the default value that is provided if no contents could be returned
489
+ # @raise ExcelError if range name is not in the workbook
490
+ # @raise SheetError if range value could not be evaluated
491
+ # @return [Variant] the contents of a range with given name
492
+ # if no contents could be returned, then return default value, if a default value was provided
493
+ # raise an error, otherwise
459
494
  def nvalue(name, opts = {:default => nil})
460
495
  begin
461
496
  item = self.Names.Item(name)
@@ -483,8 +518,9 @@ module RobustExcelOle
483
518
  end
484
519
 
485
520
  # sets the contents of a range with given name
486
- # @param [String] name the range name
521
+ # @param [String] name the range name
487
522
  # @param [Variant] value the contents of the range
523
+ # @raise ExcelError if range name is not in the workbook or if a RefersToRange error occurs
488
524
  def set_nvalue(name, value)
489
525
  begin
490
526
  item = self.Names.Item(name)
@@ -498,7 +534,8 @@ module RobustExcelOle
498
534
  end
499
535
  end
500
536
 
501
- # brings the workbook to the foreground and available for heyboard inputs, and makes the Excel instance visible
537
+ # brings workbook to foreground, makes it available for heyboard inputs, makes the Excel instance visible
538
+ # @raise ExcelError if workbook cannot be activated
502
539
  def activate
503
540
  @excel.visible = true
504
541
  begin
@@ -509,12 +546,13 @@ module RobustExcelOle
509
546
  end
510
547
  end
511
548
 
512
- # returns whether the workbook is visible or invisible
549
+ # returns true, if the workbook is visible, false otherwise
513
550
  def visible
514
551
  @excel.Windows(@workbook.Name).Visible
515
552
  end
516
553
 
517
554
  # makes a workbook visible or invisible
555
+ # @param [Boolean] visible_value value that determines whether the workbook shall be visible
518
556
  def visible= visible_value
519
557
  saved = @workbook.Saved
520
558
  @excel.Windows(@workbook.Name).Visible = visible_value
@@ -538,15 +576,15 @@ module RobustExcelOle
538
576
  @workbook.Fullname.tr('\\','/') rescue nil
539
577
  end
540
578
 
541
- def writable
579
+ def writable # :nodoc: #
542
580
  (not @workbook.ReadOnly) if @workbook
543
581
  end
544
582
 
545
- def saved
583
+ def saved # :nodoc: #
546
584
  @workbook.Saved if @workbook
547
585
  end
548
586
 
549
- # returns true, if the full book names and excel Instances are identical, false otherwise
587
+ # @return [Boolean] true, if the full book names and excel Instances are identical, false otherwise
550
588
  def == other_book
551
589
  other_book.is_a?(Book) &&
552
590
  @excel == other_book.excel &&
@@ -558,7 +596,8 @@ module RobustExcelOle
558
596
  end
559
597
 
560
598
  # simple save of a workbook.
561
- # @return [Boolean] true, if successfully saved, nil or error otherwise
599
+ # @raise ExcelErrorSave if workbook is not alive or opened for read-only, or another error occurs
600
+ # @return [Boolean] true, if successfully saved, nil otherwise
562
601
  def save
563
602
  raise ExcelErrorSave, "Workbook is not alive" if (not alive?)
564
603
  raise ExcelErrorSave, "Not opened for writing (opened with :read_only option)" if @workbook.ReadOnly
@@ -575,21 +614,25 @@ module RobustExcelOle
575
614
  end
576
615
 
577
616
  # saves a workbook with a given file name.
578
- # @param [String] file the file name
579
- # @option opts [Symbol] :if_exists if a file with the same name exists, then
580
- #
581
- # options:
582
- # :if_exists if a file with the same name exists, then
617
+ # @param [String] file file name
618
+ # @param [Hash] opts the options
619
+ # @option opts [Symbol] :if_exists :raise (default), :overwrite, or :alert
620
+ # @option opts [Symbol] :if_obstructed :raise (default), :forget, :save, or :close_if_saved
621
+ # options:
622
+ # :if_exists if a file with the same name exists, then
583
623
  # :raise -> raises an exception, dont't write the file (default)
584
624
  # :overwrite -> writes the file, delete the old file
585
625
  # :alert -> gives control to Excel
586
626
  # :if_obstructed if a workbook with the same name and different path is already open and blocks the saving, then
587
- # :raise (default) -> raises an exception
627
+ # :raise -> raises an exception
588
628
  # :forget -> closes the blocking workbook
589
629
  # :save -> saves the blocking workbook and closes it
590
630
  # :close_if_saved -> closes the blocking workbook, if it is saved,
591
631
  # otherwise raises an exception
592
- # returns true, if successfully saved, nil or error otherwise
632
+ # @raise ExcelErrorSave if workbook is not alive, opened in read-only mode, invalid options,
633
+ # the file already exists (with option :if_exists :raise),
634
+ # the workbook is blocked by another one (with option :if_obstructed :raise)
635
+ # @return [Boolean] true, if successfully saved, nil otherwise
593
636
  def save_as(file = nil, opts = { } )
594
637
  raise ExcelErrorSave, "Workbook is not alive" if (not alive?)
595
638
  raise ExcelErrorSave, "Not opened for writing (opened with :read_only option)" if @workbook.ReadOnly
@@ -649,7 +692,7 @@ module RobustExcelOle
649
692
 
650
693
  private
651
694
 
652
- def save_as_workbook(file, options)
695
+ def save_as_workbook(file, options) # :nodoc: #
653
696
  begin
654
697
  dirname, basename = File.split(file)
655
698
  file_format =
@@ -692,7 +735,7 @@ module RobustExcelOle
692
735
  end
693
736
 
694
737
  # sets the value of a range given its name
695
- # @param [String] name the name of the range
738
+ # @param [String] name the name of the range
696
739
  # @param [Variant] value the contents of the range
697
740
  def []= (name, value)
698
741
  set_nvalue(name,value)
@@ -706,9 +749,12 @@ module RobustExcelOle
706
749
 
707
750
  # adds a sheet to the workbook
708
751
  # @param [Sheet] sheet a sheet
709
- # @option opts [Symbol] :as new name of the copyed sheet
752
+ # @param [Hash] opts the options
753
+ # @option opts [Symbol] :as new name of the copyed sheet
710
754
  # @option opts [Symbol] :before a sheet before which the sheet shall be inserted
711
- # @option opts [Symbol] :after a sheet after which the sheet shall be inserted
755
+ # @option opts [Symbol] :after a sheet after which the sheet shall be inserted
756
+ # @raise ExcelErrorSheet if the sheet name already exists
757
+ # @return [Sheet] the added sheet
712
758
  def add_sheet(sheet = nil, opts = { })
713
759
  if sheet.is_a? Hash
714
760
  opts = sheet
@@ -726,38 +772,38 @@ module RobustExcelOle
726
772
  if msg.message =~ /800A03EC/
727
773
  raise ExcelErrorSheet, "sheet name already exists"
728
774
  else
729
- t "#{msg.message}"
775
+ trace "#{msg.message}"
730
776
  raise ExcelErrorSheetUnknown
731
777
  end
732
778
  end
733
779
  new_sheet
734
780
  end
735
781
 
736
- def self.bookstore
782
+ def self.bookstore # :nodoc: #
737
783
  @@bookstore ||= Bookstore.new
738
784
  end
739
785
 
740
- def bookstore
786
+ def bookstore # :nodoc: #
741
787
  self.class.bookstore
742
788
  end
743
789
 
744
- def self.show_books
790
+ def self.show_books # :nodoc: #
745
791
  bookstore.books
746
792
  end
747
793
 
748
- def to_s
794
+ def to_s # :nodoc: #
749
795
  "#{self.filename}"
750
796
  end
751
797
 
752
- def inspect
753
- "<#Book: " + "#{"not alive " unless alive?}" + "#{File.basename(self.filename) if alive?}" + " #{@workbook} #{@excel}" + ">"
798
+ def inspect # :nodoc: #
799
+ "#<Book: " + "#{"not alive " unless alive?}" + "#{File.basename(self.filename) if alive?}" + " #{@workbook} #{@excel}" + ">"
754
800
  end
755
801
 
756
- def self.in_context(klass)
802
+ def self.in_context(klass) # :nodoc: #
757
803
 
758
804
  end
759
805
 
760
- def self.excel_class
806
+ def self.excel_class # :nodoc: #
761
807
  @excel_class ||= begin
762
808
  module_name = self.parent_name
763
809
  "#{module_name}::Excel".constantize
@@ -766,7 +812,7 @@ module RobustExcelOle
766
812
  end
767
813
  end
768
814
 
769
- def self.sheet_class
815
+ def self.sheet_class # :nodoc: #
770
816
  @sheet_class ||= begin
771
817
  module_name = self.parent_name
772
818
  "#{module_name}::Sheet".constantize
@@ -775,17 +821,33 @@ module RobustExcelOle
775
821
  end
776
822
  end
777
823
 
778
- def excel_class
824
+ def excel_class # :nodoc: #
779
825
  self.class.excel_class
780
826
  end
781
827
 
782
- def sheet_class
828
+ def sheet_class # :nodoc: #
783
829
  self.class.sheet_class
784
830
  end
785
831
 
832
+ def respond_to?(name, include_private = false) # :nodoc: #
833
+ raise ExcelError, "respond_to?: workbook not alive" unless alive?
834
+ super
835
+ end
836
+
837
+ #alias old_book_methods methods
838
+
839
+ def methods # :nodoc: #
840
+ #(old_book_methods + @workbook.ole_methods.map{|m| m.to_s}).uniq
841
+ (super + @workbook.ole_methods.map{|m| m.to_s}).uniq
842
+ end
843
+
844
+ def special_methods # :nodoc: #
845
+ (methods - Object.methods).sort
846
+ end
847
+
786
848
  private
787
849
 
788
- def method_missing(name, *args)
850
+ def method_missing(name, *args) # :nodoc: #
789
851
  if name.to_s[0,1] =~ /[A-Z]/
790
852
  begin
791
853
  raise ExcelError, "method missing: workbook not alive" unless alive?
@@ -802,6 +864,8 @@ module RobustExcelOle
802
864
  end
803
865
  end
804
866
 
867
+
868
+
805
869
  end
806
870
 
807
871
  public