robust_excel_ole 1.1.1 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e288f5c2c1de7a23b3f3d38bcefa7dc9fb78661b
4
- data.tar.gz: 8c396bc079707bf0602ed3b6e6083d4f04569a0a
3
+ metadata.gz: 9bc4f05390e7e89a7d95a262e280e94dff090063
4
+ data.tar.gz: db6443cf724e5f58acbe8607ab427fc1734afa08
5
5
  SHA512:
6
- metadata.gz: 195f2c061fdffdb4ae22bb19f245b059a5620f894998cb754a14685a25d31f1f8b227dac7c3c8f9e34d9598d3b9a9ead74a333795fe3c7ea49be609aef6111ae
7
- data.tar.gz: e77b113d6b9791e4a3304bbc629f3ba067594c49f20a61d54e5f1d1b6cba12bcfd9322b2ed541ccfddca6914865fd6efb47ce7170db12f388bf9ae4e9a4db5e7
6
+ metadata.gz: f789655b7ae560eecf54132d0470e2441b04d902b95c72c3fb165987e02ef7395235e4f0e3723519928a5df86897b6f6f7340adebb0dde9f66e7aeda493588ad
7
+ data.tar.gz: 7b4110169af5c687a5be28535b8c0359f95f4c30217df5d8d90f26e5a5c54dc28153bf4b8e0bfa9411961a44cc064118cbc681df68b95061a337b61efd247e27
data/Changelog CHANGED
@@ -1,6 +1,13 @@
1
1
  # Change Log
2
2
  All notable changes to this project will be documented in this file.
3
3
 
4
+ ## [1.1.3] - 2018-10-6
5
+
6
+ ## [1.1.2] - 2018-10-5
7
+
8
+ ### Added
9
+ - Excel, Sheet, Book #workbook
10
+
4
11
  ## [1.1.1] - 2018-20-4
5
12
 
6
13
  ### Added
data/README.rdoc CHANGED
@@ -1,15 +1,13 @@
1
1
  = RobustExcelOle
2
2
 
3
- This ruby gem automates reading, modifying, and writing Excel files.
4
- It supports simultaneously running Excel instances and user interactions.
3
+ This ruby gem automates reading, modifying, and writing Excel files. It is designed to support several kinds of concurrency of both simultaneously running Excel instances and simultanously happening user interactions.
5
4
  RobustExcelOle deals with various cases of Excel and user behaviour,
6
5
  and implements workarounds for some Excel bugs.
7
6
  The gem provides convenient methods for common tasks, and facilitates referenced libraries.
8
7
  It supports Excel 2010.
9
8
 
10
9
  RobustExcelOle works by sending VBA methods via Win32OLE.
11
- Moreover, it implements a management system and keeps track of Excel files and Excel instances.
12
- The tool is optimised with help of the rcov tool.
10
+ It implements a management system and keeps track of Excel files and Excel instances.
13
11
 
14
12
  == Requirements
15
13
 
@@ -24,6 +22,10 @@ The tool is optimised with help of the rcov tool.
24
22
  require 'robust_excel_ole'
25
23
  include RobustExcelOle
26
24
 
25
+ or call the console
26
+
27
+ reo.bat
28
+
27
29
  == Description
28
30
 
29
31
  In the following, some features of RobustExcelOle are depicted.
@@ -291,6 +293,10 @@ Hard terminating all Excel processes is done by
291
293
 
292
294
  Excel.kill_all
293
295
 
296
+ === Development
297
+
298
+ The tests of RobustExcelOle are optimised with help of the rcov tool.
299
+
294
300
  === More details
295
301
 
296
302
  {README_detail.rdoc}[https://github.com/Thomas008/robust_excel_ole/blob/master/README_detail.rdoc]
data/README_detail.rdoc CHANGED
@@ -1,15 +1,13 @@
1
1
  = RobustExcelOle
2
2
 
3
- This ruby gem automates modifying, reading and writing Excel files.
4
- It supports simultaneously running Excel instances and user interactions.
3
+ This ruby gem automates reading, modifying, and writing Excel files. It is designed to support several kinds of concurrency of both simultaneously running Excel instances and simultanously happening user interactions.
5
4
  RobustExcelOle deals with various cases of Excel and user behaviour,
6
5
  and implements workarounds for some Excel bugs.
7
6
  The gem provides convenient methods for common tasks, and facilitates referenced libraries.
8
7
  It supports Excel 2010.
9
8
 
10
9
  RobustExcelOle works by sending VBA methods via Win32OLE.
11
- Moreover, it implements a management system and keeps track of Excel files and Excel instances.
12
- The tool is optimised with help of rcov.
10
+ It implements a management system and keeps track of Excel files and Excel instances.
13
11
 
14
12
  == Requirements
15
13
 
@@ -21,8 +19,13 @@ The tool is optimised with help of rcov.
21
19
 
22
20
  == Usage
23
21
 
22
+ require 'robust_excel_ole'
24
23
  include RobustExcelOle
25
24
 
25
+ or call the console
26
+
27
+ reo.bat
28
+
26
29
  === Opening a workbook.
27
30
 
28
31
  Example:
@@ -4,12 +4,14 @@ require 'weakref'
4
4
 
5
5
  module RobustExcelOle
6
6
 
7
- class Book < REOCommon
7
+ class Book < RangeOwners
8
8
 
9
9
  attr_accessor :excel
10
10
  attr_accessor :ole_workbook
11
11
  attr_accessor :stored_filename
12
12
  attr_accessor :options
13
+ attr_accessor :modified_cells
14
+ attr_reader :workbook
13
15
 
14
16
  alias ole_object ole_workbook
15
17
 
@@ -154,6 +156,8 @@ module RobustExcelOle
154
156
  ensure_workbook(file, options)
155
157
  end
156
158
  bookstore.store(self)
159
+ @modified_cells = []
160
+ @workbook = @excel.workbook = self
157
161
  if block
158
162
  begin
159
163
  yield self
@@ -548,6 +552,7 @@ module RobustExcelOle
548
552
  raise WorkbookReadOnly, "Not opened for writing (opened with :read_only option)" if @ole_workbook.ReadOnly
549
553
  begin
550
554
  discoloring if opts[:discoloring]
555
+ @modified_cells = []
551
556
  @ole_workbook.Save
552
557
  rescue WIN32OLERuntimeError => msg
553
558
  if msg.message =~ /SaveAs/ and msg.message =~ /Workbook/ then
@@ -632,7 +637,8 @@ module RobustExcelOle
632
637
  private
633
638
 
634
639
  def discoloring
635
- self.each{|sheet| sheet.each{|cell| cell.Interior.ColorIndex = XlNone}}
640
+ # self.each{|sheet| sheet.UsedRange.each{|cell| cell.Interior.ColorIndex = XlNone}}
641
+ @modified_cells.each{|cell| cell.Interior.ColorIndex = XlNone}
636
642
  end
637
643
 
638
644
  def save_as_workbook(file, options) # :nodoc: #
@@ -645,6 +651,7 @@ module RobustExcelOle
645
651
  when '.xlsm'; RobustExcelOle::XlOpenXMLWorkbookMacroEnabled
646
652
  end
647
653
  discoloring if options[:discoloring]
654
+ @modified_cells = []
648
655
  @ole_workbook.SaveAs(General::absolute_path(file), file_format)
649
656
  bookstore.store(self)
650
657
  rescue WIN32OLERuntimeError => msg
@@ -661,15 +668,7 @@ module RobustExcelOle
661
668
 
662
669
  # closes a given file if it is open
663
670
  def self.close(file, opts = {:if_unsaved => :raise})
664
- #puts "self.close:"
665
- #puts "file: #{file}"
666
- #begin
667
- # bookstore.fetch(file)
668
- #rescue
669
- # puts "#{$!.message}"
670
- #end
671
671
  book = bookstore.fetch(file) rescue nil
672
- #puts "book after fetch: #{book.inspect}"
673
672
  book.close(opts) if book && book.alive?
674
673
  end
675
674
 
@@ -722,7 +721,7 @@ module RobustExcelOle
722
721
  def copy_sheet(sheet, opts = { })
723
722
  new_sheet_name = opts.delete(:as)
724
723
  after_or_before, base_sheet = opts.to_a.first || [:after, last_sheet]
725
- sheet.Copy({ after_or_before.to_s => base_sheet.worksheet })
724
+ sheet.Copy({ after_or_before.to_s => base_sheet.ole_worksheet })
726
725
  new_sheet = sheet_class.new(@excel.Activesheet)
727
726
  new_sheet.name = new_sheet_name if new_sheet_name
728
727
  new_sheet
@@ -739,7 +738,7 @@ module RobustExcelOle
739
738
  def add_empty_sheet(opts = { })
740
739
  new_sheet_name = opts.delete(:as)
741
740
  after_or_before, base_sheet = opts.to_a.first || [:after, last_sheet]
742
- @ole_workbook.Worksheets.Add({ after_or_before.to_s => base_sheet.worksheet })
741
+ @ole_workbook.Worksheets.Add({ after_or_before.to_s => base_sheet.ole_worksheet })
743
742
  new_sheet = sheet_class.new(@excel.Activesheet)
744
743
  new_sheet.name = new_sheet_name if new_sheet_name
745
744
  new_sheet
@@ -788,66 +787,6 @@ module RobustExcelOle
788
787
  set_nameval(name,value, :color => 42) # 42 - aqua-marin, 4-green
789
788
  end
790
789
 
791
- # returns the contents of a range with given name
792
- # evaluates formula contents of the range is a formula
793
- # if no contents could be returned, then return default value, if provided, raise error otherwise
794
- # Excel Bug: if a local name without a qualifier is given, then by default Excel takes the first worksheet,
795
- # even if a different worksheet is active
796
- # @param [String] name the name of the range
797
- # @param [Hash] opts the options
798
- # @option opts [Symbol] :default the default value that is provided if no contents could be returned
799
- # @return [Variant] the contents of a range with given name
800
- def nameval(name, opts = {:default => nil})
801
- name_obj = name_object(name)
802
- value = begin
803
- name_obj.RefersToRange.Value
804
- rescue WIN32OLERuntimeError
805
- begin
806
- self.sheet(1).Evaluate(name_obj.Name)
807
- rescue WIN32OLERuntimeError
808
- return opts[:default] if opts[:default]
809
- raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
810
- end
811
- end
812
- if value.is_a?(Bignum) #RobustExcelOle::XlErrName
813
- return opts[:default] if opts[:default]
814
- raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
815
- end
816
- return opts[:default] if opts[:default] && value.nil?
817
- value
818
- end
819
-
820
- # sets the contents of a range
821
- # @param [String] name the name of a range
822
- # @param [Variant] value the contents of the range
823
- # @param [FixNum] color the color when setting a value
824
- # @param [Hash] opts :color [FixNum] the color when setting the contents
825
- def set_nameval(name, value, opts = {:color => 0})
826
- begin
827
- cell = name_object(name).RefersToRange
828
- cell.Interior.ColorIndex = opts[:color]
829
- cell.Value = value
830
- rescue WIN32OLERuntimeError
831
- raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{File.basename(self.stored_filename).inspect}"
832
- end
833
- end
834
-
835
- private
836
-
837
- def name_object(name)
838
- begin
839
- self.Parent.Names.Item(name)
840
- rescue WIN32OLERuntimeError
841
- begin
842
- self.Names.Item(name)
843
- rescue WIN32OLERuntimeError
844
- raise NameNotFound, "name #{name.inspect} not in #{File.basename(self.stored_filename).inspect}"
845
- end
846
- end
847
- end
848
-
849
- public
850
-
851
790
  # renames a range
852
791
  # @param [String] name the previous range name
853
792
  # @param [String] new_name the new range name
@@ -10,17 +10,18 @@ end
10
10
 
11
11
  module RobustExcelOle
12
12
 
13
- class Excel < REOCommon
13
+ class Excel < RangeOwners
14
14
 
15
15
  attr_accessor :ole_excel
16
16
  attr_accessor :created
17
-
17
+ attr_accessor :workbook
18
+
18
19
  # setter methods are implemented below
19
20
  attr_reader :visible
20
21
  attr_reader :displayalerts
21
22
  attr_reader :calculation
22
23
  attr_reader :screenupdating
23
-
24
+
24
25
  alias ole_object ole_excel
25
26
 
26
27
  @@hwnd2excel = {}
@@ -96,7 +97,7 @@ module RobustExcelOle
96
97
  result.screenupdating = options[:screenupdating] unless options[:screenupdating].nil?
97
98
  result.created = !reused
98
99
  end
99
- end
100
+ end
100
101
  result
101
102
  end
102
103
 
@@ -603,105 +604,6 @@ module RobustExcelOle
603
604
  set_nameval(name,value, :color => 42) # 42 - aqua-marin, 7-green
604
605
  end
605
606
 
606
- # returns the contents of a range with given name
607
- # evaluates the formula if the contents is a formula
608
- # if no contents could be returned, then return default value, if provided, raise error otherwise
609
- # @param [String] name the range name
610
- # @param [Hash] opts the options
611
- # @option opts [Variant] :default value (default: nil)
612
- def nameval(name, opts = {:default => nil})
613
- name_obj = name_object(name)
614
- value = begin
615
- name_obj.RefersToRange.Value
616
- rescue WIN32OLERuntimeError
617
- begin
618
- self.Evaluate(name_obj.Name)
619
- rescue WIN32OLERuntimeError
620
- return opts[:default] if opts[:default]
621
- raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect}"
622
- end
623
- end
624
- if value.is_a?(Bignum)
625
- return opts[:default] if opts[:default]
626
- raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect}"
627
- end
628
- return opts[:default] if (value.nil? && opts[:default])
629
- value
630
- end
631
-
632
- # assigns a value to a range with given name
633
- # @param [String] name the range name
634
- # @param [Variant] value the assigned value
635
- # @param [Hash] opts :color [FixNum] the color when setting the contents
636
- def set_nameval(name,value, opts = {:color => 0})
637
- begin
638
- cell = name_object(name).RefersToRange
639
- cell.Interior.ColorIndex = opts[:color]
640
- cell.Value = value
641
- rescue WIN32OLERuntimeError
642
- raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect}"
643
- end
644
- end
645
-
646
- private
647
-
648
- def name_object(name)
649
- begin
650
- self.Parent.Names.Item(name)
651
- rescue WIN32OLERuntimeError
652
- begin
653
- self.Names.Item(name)
654
- rescue WIN32OLERuntimeError
655
- raise NameNotFound, "name #{name.inspect}"
656
- end
657
- end
658
- end
659
-
660
- public
661
-
662
- # returns the contents of a range with a locally defined name
663
- # evaluates the formula if the contents is a formula
664
- # if no contents could be returned, then return default value, if provided, raise error otherwise
665
- # @param [String] name the range name
666
- # @param [Hash] opts the options
667
- # @option opts [Symbol] :default the default value that is provided if no contents could be returned
668
- # @return [Variant] the contents of a range with given name
669
- def rangeval(name, opts = {:default => nil})
670
- begin
671
- range = self.Range(name)
672
- rescue WIN32OLERuntimeError
673
- return opts[:default] if opts[:default]
674
- raise NameNotFound, "cannot find name #{name.inspect}"
675
- end
676
- begin
677
- value = range.Value
678
- rescue WIN32OLERuntimeError
679
- return opts[:default] if opts[:default]
680
- raise RangeNotEvaluatable, "cannot determine value of range named #{name.inspect}"
681
- end
682
- return opts[:default] if (value.nil? && opts[:default])
683
- raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect}" if value.is_a?(Bignum)
684
- value
685
- end
686
-
687
- # assigns a value to a range given a locally defined name
688
- # @param [String] name the range name
689
- # @param [Variant] value the assigned value
690
- # @param [Hash] opts :color [FixNum] the color when setting the contents
691
- def set_rangeval(name,value, opts = {:color => 0})
692
- begin
693
- range = self.Range(name)
694
- rescue WIN32OLERuntimeError
695
- raise NameNotFound, "cannot find name #{name.inspect}"
696
- end
697
- begin
698
- range.Interior.ColorIndex = opts[:color]
699
- range.Value = value
700
- rescue WIN32OLERuntimeError
701
- raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{self.name}"
702
- end
703
- end
704
-
705
607
  def to_s # :nodoc: #
706
608
  "#<Excel: " + "#{hwnd}" + ("#{"not alive" unless self.alive?}") + ">"
707
609
  end
@@ -6,52 +6,6 @@ REO_LOG_FILE = "reo.log" unless Object.const_defined?(:REO_LOG_FILE)
6
6
 
7
7
  File.delete REO_LOG_FILE rescue nil
8
8
 
9
- class REOCommon
10
-
11
- def excel
12
- raise TypeErrorREO, "receiver instance is neither an Excel nor a Book"
13
- end
14
-
15
- def own_methods
16
- (self.methods - Object.methods).sort
17
- end
18
-
19
- def self.tr1(text)
20
- puts :text
21
- end
22
-
23
- def self.trace(text)
24
- if LOG_TO_STDOUT
25
- puts text
26
- else
27
- if REO_LOG_DIR.empty?
28
- homes = ["HOME", "HOMEPATH"]
29
- home = homes.find {|h| ENV[h] != nil}
30
- reo_log_dir = ENV[home]
31
- else
32
- reo_log_dir = REO_LOG_DIR
33
- end
34
- File.open(reo_log_dir + "/" + REO_LOG_FILE,"a") do | file |
35
- file.puts text
36
- end
37
- end
38
- end
39
-
40
- def self.puts_hash(hash)
41
- hash.each do |e|
42
- if e[1].is_a?(Hash)
43
- puts "#{e[0]} =>"
44
- e[1].each do |f|
45
- puts " #{f[0]} => #{f[1]}"
46
- end
47
- else
48
- puts "#{e[0]} => #{e[1]}"
49
- end
50
- end
51
- end
52
-
53
- end
54
-
55
9
  module RobustExcelOle
56
10
 
57
11
  class REOError < RuntimeError # :nodoc: #
@@ -123,5 +77,163 @@ module RobustExcelOle
123
77
  class UnexpectedError < REOError # :nodoc: #
124
78
  end
125
79
 
126
- end
80
+ class REOCommon
81
+
82
+ def excel
83
+ raise TypeErrorREO, "receiver instance is neither an Excel nor a Book"
84
+ end
85
+
86
+ def own_methods
87
+ (self.methods - Object.methods).sort
88
+ end
89
+
90
+ def self.tr1(text)
91
+ puts :text
92
+ end
93
+
94
+ def self.trace(text)
95
+ if LOG_TO_STDOUT
96
+ puts text
97
+ else
98
+ if REO_LOG_DIR.empty?
99
+ homes = ["HOME", "HOMEPATH"]
100
+ home = homes.find {|h| ENV[h] != nil}
101
+ reo_log_dir = ENV[home]
102
+ else
103
+ reo_log_dir = REO_LOG_DIR
104
+ end
105
+ File.open(reo_log_dir + "/" + REO_LOG_FILE,"a") do | file |
106
+ file.puts text
107
+ end
108
+ end
109
+ end
110
+
111
+ def self.puts_hash(hash)
112
+ hash.each do |e|
113
+ if e[1].is_a?(Hash)
114
+ puts "#{e[0]} =>"
115
+ e[1].each do |f|
116
+ puts " #{f[0]} => #{f[1]}"
117
+ end
118
+ else
119
+ puts "#{e[0]} => #{e[1]}"
120
+ end
121
+ end
122
+ end
123
+
124
+ end
125
+
126
+ class RangeOwners < REOCommon
127
+
128
+ # returns the contents of a range with given name
129
+ # evaluates formula contents of the range is a formula
130
+ # if no contents could be returned, then return default value, if provided, raise error otherwise
131
+ # Excel Bug: if a local name without a qualifier is given, then by default Excel takes the first worksheet,
132
+ # even if a different worksheet is active
133
+ # @param [String] name the name of the range
134
+ # @param [Hash] opts the options
135
+ # @option opts [Symbol] :default the default value that is provided if no contents could be returned
136
+ # @return [Variant] the contents of a range with given name
137
+ def nameval(name, opts = {:default => nil})
138
+ name_obj = name_object(name)
139
+ value = begin
140
+ name_obj.RefersToRange.Value
141
+ rescue WIN32OLERuntimeError
142
+ #begin
143
+ # self.sheet(1).Evaluate(name_obj.Name)
144
+ #rescue WIN32OLERuntimeError
145
+ return opts[:default] if opts[:default]
146
+ raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{self}"
147
+ #end
148
+ end
149
+ if value.is_a?(Bignum) #RobustExcelOle::XlErrName
150
+ return opts[:default] if opts[:default]
151
+ raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{File.basename(workbook.stored_filename).inspect rescue nil}"
152
+ end
153
+ return opts[:default] if opts[:default] && value.nil?
154
+ value
155
+ end
156
+
157
+ # sets the contents of a range
158
+ # @param [String] name the name of a range
159
+ # @param [Variant] value the contents of the range
160
+ # @param [FixNum] color the color when setting a value
161
+ # @param [Hash] opts :color [FixNum] the color when setting the contents
162
+ def set_nameval(name, value, opts = {:color => 0})
163
+ begin
164
+ cell = name_object(name).RefersToRange
165
+ cell.Interior.ColorIndex = opts[:color]
166
+ workbook.modified_cells << cell unless cell_modified?(cell) if workbook
167
+ cell.Value = value
168
+ rescue WIN32OLERuntimeError
169
+ raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{self.inspect}"
170
+ end
171
+ end
172
+
173
+ # returns the contents of a range with a locally defined name
174
+ # evaluates the formula if the contents is a formula
175
+ # if no contents could be returned, then return default value, if provided, raise error otherwise
176
+ # @param [String] name the name of a range
177
+ # @param [Hash] opts the options
178
+ # @option opts [Symbol] :default the default value that is provided if no contents could be returned
179
+ # @return [Variant] the contents of a range with given name
180
+ def rangeval(name, opts = {:default => nil})
181
+ begin
182
+ range = self.Range(name)
183
+ rescue WIN32OLERuntimeError
184
+ return opts[:default] if opts[:default]
185
+ raise NameNotFound, "name #{name.inspect} not in #{self.inspect}"
186
+ end
187
+ begin
188
+ value = range.Value
189
+ rescue WIN32OLERuntimeError
190
+ return opts[:default] if opts[:default]
191
+ raise RangeNotEvaluatable, "cannot determine value of range named #{name.inspect} in #{self.inspect}"
192
+ end
193
+ return opts[:default] if (value.nil? && opts[:default])
194
+ raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect}" if value.is_a?(Bignum)
195
+ value
196
+ end
197
+
198
+ # assigns a value to a range given a locally defined name
199
+ # @param [String] name the name of a range
200
+ # @param [Variant] value the assigned value
201
+ # @param [Hash] opts :color [FixNum] the color when setting the contents
202
+ def set_rangeval(name,value, opts = {:color => 0})
203
+ begin
204
+ return set_nameval(name, value, opts) if self.is_a?(Book)
205
+ range = self.Range(name)
206
+ rescue WIN32OLERuntimeError
207
+ raise NameNotFound, "name #{name.inspect} not in #{self.inspect}"
208
+ end
209
+ begin
210
+ range.Interior.ColorIndex = opts[:color]
211
+ workbook.modified_cells << range unless cell_modified?(range) if workbook
212
+ range.Value = value
213
+ rescue WIN32OLERuntimeError
214
+ raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{self.inspect}"
215
+ end
216
+ end
217
+
218
+ private
219
+
220
+ def name_object(name)
221
+ begin
222
+ self.Parent.Names.Item(name)
223
+ rescue WIN32OLERuntimeError
224
+ begin
225
+ self.Names.Item(name)
226
+ rescue WIN32OLERuntimeError
227
+ raise RobustExcelOle::NameNotFound, "name #{name.inspect} not in #{self.inspect}"
228
+ end
229
+ end
230
+ end
231
+
232
+ def cell_modified?(cell)
233
+ workbook.modified_cells.each{|c| return true if c.Name.Value == cell.Name.Value}
234
+ false
235
+ end
236
+
237
+ end
127
238
 
239
+ end
@@ -2,36 +2,35 @@
2
2
 
3
3
  module RobustExcelOle
4
4
 
5
- class Sheet < REOCommon
6
- attr_reader :worksheet
5
+ class Sheet < RangeOwners
6
+
7
+ attr_reader :ole_worksheet
8
+ attr_reader :workbook
7
9
 
8
10
  def initialize(win32_worksheet)
9
- @worksheet = win32_worksheet
10
- if @worksheet.ProtectContents
11
- @worksheet.Unprotect
11
+ @ole_worksheet = win32_worksheet
12
+ if @ole_worksheet.ProtectContents
13
+ @ole_worksheet.Unprotect
12
14
  @end_row = last_row
13
15
  @end_column = last_column
14
- @worksheet.Protect
16
+ @ole_worksheet.Protect
15
17
  else
16
18
  @end_row = last_row
17
19
  @end_column = last_column
18
20
  end
19
- end
20
-
21
- def workbook
22
- book_class.new(self.Parent)
21
+ @workbook = book_class.new(self.Parent)
23
22
  end
24
23
 
25
24
  # returns name of the sheet
26
25
  def name
27
- @worksheet.Name
26
+ @ole_worksheet.Name
28
27
  end
29
28
 
30
29
  # name the sheet
31
30
  # @param [String] new_name the new name of the sheet
32
31
  def name= (new_name)
33
32
  begin
34
- @worksheet.Name = new_name
33
+ @ole_worksheet.Name = new_name
35
34
  rescue WIN32OLERuntimeError => msg
36
35
  if msg.message =~ /800A03EC/
37
36
  raise NameAlreadyExists, "sheet name #{new_name.inspect} already exists"
@@ -49,7 +48,7 @@ module RobustExcelOle
49
48
  yx = "#{y}_#{x}"
50
49
  @cells = { }
51
50
  begin
52
- @cells[yx] = RobustExcelOle::Cell.new(@worksheet.Cells.Item(y, x))
51
+ @cells[yx] = RobustExcelOle::Cell.new(@ole_worksheet.Cells.Item(y, x))
53
52
  rescue
54
53
  raise RangeNotEvaluatable, "cannot read cell (#{p1.inspect},#{p2.inspect})"
55
54
  end
@@ -73,7 +72,7 @@ module RobustExcelOle
73
72
  if p3 != :__not_provided
74
73
  y, x, value = p1, p2, p3
75
74
  begin
76
- cell = @worksheet.Cells.Item(y, x)
75
+ cell = @ole_worksheet.Cells.Item(y, x)
77
76
  cell.Value = value
78
77
  cell.Interior.ColorIndex = 42 # aqua-marin, 4-green
79
78
  rescue WIN32OLERuntimeError
@@ -92,104 +91,6 @@ module RobustExcelOle
92
91
  end
93
92
  end
94
93
  end
95
-
96
- # returns the contents of a range
97
- # evaluates the formula if the contents is a formula
98
- # if no contents could be returned, then return default value, if provided, raise error otherwise
99
- # @param [String] name the name of a range
100
- # @param [Hash] opts the options
101
- # @option opts [Variant] :default default value (default: nil)
102
- def nameval(name, opts = {:default => nil})
103
- name_obj = name_object(name)
104
- value = begin
105
- name_obj.RefersToRange.Value
106
- rescue WIN32OLERuntimeError
107
- begin
108
- self.Evaluate(name_obj.Name)
109
- rescue WIN32OLERuntimeError
110
- return opts[:default] if opts[:default]
111
- raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{self.Name}"
112
- end
113
- end
114
- if value.is_a?(Bignum) # RobustExcelOle::XlErrName
115
- return opts[:default] if opts[:default]
116
- raise RangeNotEvaluatable, "cannot evaluate range named #{name.inspect} in #{self.Name}"
117
- end
118
- return opts[:default] if (value.nil? && opts[:default])
119
- value
120
- end
121
-
122
- # assigns a value to a range
123
- # @param [String] name the name of a range
124
- # @param [Variant] value the assigned value
125
- # @param [Hash] opts :color [FixNum] the color when setting the contents
126
- def set_nameval(name,value, opts = {:color => 0})
127
- begin
128
- cell = name_object(name).RefersToRange
129
- cell.Interior.ColorIndex = opts[:color]
130
- cell.Value = value
131
- rescue WIN32OLERuntimeError
132
- raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{self.name}"
133
- end
134
- end
135
-
136
- private
137
-
138
- def name_object(name)
139
- begin
140
- self.Parent.Names.Item(name)
141
- rescue WIN32OLERuntimeError
142
- begin
143
- self.Names.Item(name)
144
- rescue WIN32OLERuntimeError
145
- raise NameNotFound, "name #{name.inspect} not in #{self.name}"
146
- end
147
- end
148
- end
149
-
150
- public
151
-
152
- # returns the contents of a range with a locally defined name
153
- # evaluates the formula if the contents is a formula
154
- # if no contents could be returned, then return default value, if provided, raise error otherwise
155
- # @param [String] name the name of a range
156
- # @param [Hash] opts the options
157
- # @option opts [Symbol] :default the default value that is provided if no contents could be returned
158
- # @return [Variant] the contents of a range with given name
159
- def rangeval(name, opts = {:default => nil})
160
- begin
161
- range = self.Range(name)
162
- rescue WIN32OLERuntimeError
163
- return opts[:default] if opts[:default]
164
- raise NameNotFound, "name #{name.inspect} not in #{self.name}"
165
- end
166
- begin
167
- value = range.Value
168
- rescue WIN32OLERuntimeError
169
- return opts[:default] if opts[:default]
170
- raise RangeNotEvaluatable, "cannot determine value of range named #{name.inspect} in #{self.name}"
171
- end
172
- return opts[:default] if (value.nil? && opts[:default])
173
- value
174
- end
175
-
176
- # assigns a value to a range given a locally defined name
177
- # @param [String] name the name of a range
178
- # @param [Variant] value the assigned value
179
- # @param [Hash] opts :color [FixNum] the color when setting the contents
180
- def set_rangeval(name,value, opts = {:color => 0})
181
- begin
182
- range = self.Range(name)
183
- rescue WIN32OLERuntimeError
184
- raise NameNotFound, "name #{name.inspect} not in #{self.name}"
185
- end
186
- begin
187
- range.Interior.ColorIndex = opts[:color]
188
- range.Value = value
189
- rescue WIN32OLERuntimeError
190
- raise RangeNotEvaluatable, "cannot assign value to range named #{name.inspect} in #{self.name}"
191
- end
192
- end
193
94
 
194
95
  # assigns a name to a range (a cell) given by an address
195
96
  # @param [String] name the range name
@@ -233,7 +134,7 @@ module RobustExcelOle
233
134
  offset += 1
234
135
  1.upto(@end_row) do |row|
235
136
  next if row < offset
236
- yield RobustExcelOle::Range.new(@worksheet.Range(@worksheet.Cells(row, 1), @worksheet.Cells(row, @end_column)))
137
+ yield RobustExcelOle::Range.new(@ole_worksheet.Range(@ole_worksheet.Cells(row, 1), @ole_worksheet.Cells(row, @end_column)))
237
138
  end
238
139
  end
239
140
 
@@ -247,7 +148,7 @@ module RobustExcelOle
247
148
  offset += 1
248
149
  1.upto(@end_column) do |column|
249
150
  next if column < offset
250
- yield RobustExcelOle::Range.new(@worksheet.Range(@worksheet.Cells(1, column), @worksheet.Cells(@end_row, column)))
151
+ yield RobustExcelOle::Range.new(@ole_worksheet.Range(@ole_worksheet.Cells(1, column), @ole_worksheet.Cells(@end_row, column)))
251
152
  end
252
153
  end
253
154
 
@@ -259,12 +160,12 @@ module RobustExcelOle
259
160
 
260
161
  def row_range(row, range = nil)
261
162
  range ||= 1..@end_column
262
- RobustExcelOle::Range.new(@worksheet.Range(@worksheet.Cells(row , range.min ), @worksheet.Cells(row , range.max )))
163
+ RobustExcelOle::Range.new(@ole_worksheet.Range(@ole_worksheet.Cells(row , range.min ), @ole_worksheet.Cells(row , range.max )))
263
164
  end
264
165
 
265
166
  def col_range(col, range = nil)
266
167
  range ||= 1..@end_row
267
- RobustExcelOle::Range.new(@worksheet.Range(@worksheet.Cells(range.min , col ), @worksheet.Cells(range.max , col )))
168
+ RobustExcelOle::Range.new(@ole_worksheet.Range(@ole_worksheet.Cells(range.min , col ), @ole_worksheet.Cells(range.max , col )))
268
169
  end
269
170
 
270
171
 
@@ -281,12 +182,20 @@ module RobustExcelOle
281
182
  self.class.book_class
282
183
  end
283
184
 
284
- private
185
+ def to_s # :nodoc: #
186
+ "#<Sheet: " + "#{"not alive " unless @workbook.alive?}" + "#{name}" + " #{File.basename(@workbook.stored_filename)} >"
187
+ end
188
+
189
+ def inspect # :nodoc: #
190
+ self.to_s
191
+ end
192
+
193
+ private
285
194
 
286
195
  def method_missing(name, *args) # :nodoc: #
287
196
  if name.to_s[0,1] =~ /[A-Z]/
288
197
  begin
289
- @worksheet.send(name, *args)
198
+ @ole_worksheet.send(name, *args)
290
199
  rescue WIN32OLERuntimeError => msg
291
200
  if msg.message =~ /unknown property or method/
292
201
  raise VBAMethodMissingError, "unknown VBA property or method #{name.inspect}"
@@ -299,22 +208,19 @@ module RobustExcelOle
299
208
  end
300
209
  end
301
210
 
302
-
303
211
  def last_row
304
- special_last_row = @worksheet.UsedRange.SpecialCells(RobustExcelOle::XlLastCell).Row
305
- used_last_row = @worksheet.UsedRange.Rows.Count
212
+ special_last_row = @ole_worksheet.UsedRange.SpecialCells(RobustExcelOle::XlLastCell).Row
213
+ used_last_row = @ole_worksheet.UsedRange.Rows.Count
306
214
 
307
215
  special_last_row >= used_last_row ? special_last_row : used_last_row
308
216
  end
309
217
 
310
218
  def last_column
311
- special_last_column = @worksheet.UsedRange.SpecialCells(RobustExcelOle::XlLastCell).Column
312
- used_last_column = @worksheet.UsedRange.Columns.Count
219
+ special_last_column = @ole_worksheet.UsedRange.SpecialCells(RobustExcelOle::XlLastCell).Column
220
+ used_last_column = @ole_worksheet.UsedRange.Columns.Count
313
221
 
314
222
  special_last_column >= used_last_column ? special_last_column : used_last_column
315
223
  end
316
224
  end
317
-
318
- public
319
225
 
320
226
  end
@@ -1,3 +1,3 @@
1
1
  module RobustExcelOle
2
- VERSION = "1.1.1"
2
+ VERSION = "1.1.3"
3
3
  end
@@ -11,7 +11,8 @@ Gem::Specification.new do |s|
11
11
 
12
12
  s.summary = "RobustExcelOle automates processing Excel files in Windows by using the win32ole library."
13
13
  s.description = "RobustExcelOle automates modifying, reading and writing Excel files in Windows by using the win32ole library.
14
- It supports simultaneously running Excel instances and user interactions.
14
+ It is disigned to cope with several kinds of concurrency of both simultaneously running
15
+ Excel instances and simultanously happening user interactions.
15
16
  RobustExcelOle deals with various cases of Excel (and user) behaviour,
16
17
  supplies workarounds for some Excel bugs, and supports referenced libraries."
17
18
 
data/spec/book_spec.rb CHANGED
@@ -1064,17 +1064,17 @@ describe Book do
1064
1064
  @book1.nameval("new").should == "bar"
1065
1065
  end
1066
1066
 
1067
- it "should evaluate a formula" do
1068
- @book1.nameval("named_formula").should == 4
1069
- end
1067
+ #it "should evaluate a formula" do
1068
+ # @book1.nameval("named_formula").should == 4
1069
+ #end
1070
1070
 
1071
- it "should evaluate a formula via []" do
1072
- @book1["named_formula"].should == 4
1073
- end
1071
+ #it "should evaluate a formula via []" do
1072
+ # @book1["named_formula"].should == 4
1073
+ #end
1074
1074
 
1075
- it "should return default value if name not defined" do
1076
- @book1.nameval("foo", :default => 2).should == 2
1077
- end
1075
+ #it "should return default value if name not defined" do
1076
+ # @book1.nameval("foo", :default => 2).should == 2
1077
+ #end
1078
1078
 
1079
1079
  end
1080
1080
 
@@ -646,33 +646,33 @@ describe Book do
646
646
  @book1.nameval("new").should == "bar"
647
647
  end
648
648
 
649
- it "should evaluate a formula" do
650
- @book1.nameval("named_formula").should == 4
651
- end
649
+ #it "should evaluate a formula" do
650
+ # @book1.nameval("named_formula").should == 4
651
+ #end
652
652
 
653
- it "should evaluate a formula via []" do
654
- @book1["named_formula"].should == 4
655
- end
653
+ #it "should evaluate a formula via []" do
654
+ # @book1["named_formula"].should == 4
655
+ #end
656
656
 
657
657
  it "should raise an error if name not defined" do
658
658
  expect {
659
659
  @book1.nameval("foo")
660
- }.to raise_error(NameNotFound, /name "foo" not in "another_workbook.xls"/)
660
+ }.to raise_error(NameNotFound, /name "foo" not in #<Book: another_workbook/)
661
661
  expect {
662
662
  @book1.set_nameval("foo","bar")
663
- }.to raise_error(NameNotFound, /name "foo" not in "another_workbook.xls"/)
663
+ }.to raise_error(NameNotFound, /name "foo" not in #<Book: another_workbook/)
664
664
  expect {
665
665
  @book1["foo"] = "bar"
666
- }.to raise_error(NameNotFound, /name "foo" not in "another_workbook.xls"/)
666
+ }.to raise_error(NameNotFound, /name "foo" not in #<Book: another_workbook/)
667
667
  end
668
668
 
669
669
  it "should raise an error if name was defined but contents is calcuated" do
670
670
  expect {
671
671
  @book1.set_nameval("named_formula","bar")
672
- }.to raise_error(RangeNotEvaluatable, /cannot assign value to range named "named_formula" in "another_workbook.xls"/)
672
+ }.to raise_error(RangeNotEvaluatable, /cannot assign value to range named "named_formula" in #<Book: another_workbook/)
673
673
  expect {
674
674
  @book1["named_formula"] = "bar"
675
- }.to raise_error(RangeNotEvaluatable, /cannot assign value to range named "named_formula" in "another_workbook.xls"/)
675
+ }.to raise_error(RangeNotEvaluatable, /cannot assign value to range named "named_formula" in #<Book: another_workbook/)
676
676
  end
677
677
 
678
678
  # Excel Bug: for local names without uqifier: takes the first sheet as default even if another sheet is activated
Binary file
data/spec/excel_spec.rb CHANGED
@@ -1722,10 +1722,10 @@ module RobustExcelOle
1722
1722
  @excel1["firstcell"].should == "foo"
1723
1723
  end
1724
1724
 
1725
- it "should evaluate a formula" do
1726
- @excel1.nameval("named_formula").should == 4
1727
- @excel1["named_formula"].should == 4
1728
- end
1725
+ #it "should evaluate a formula" do
1726
+ # @excel1.nameval("named_formula").should == 4
1727
+ # @excel1["named_formula"].should == 4
1728
+ #end
1729
1729
 
1730
1730
  it "should raise an error if name not defined" do
1731
1731
  expect {
@@ -1791,14 +1791,14 @@ module RobustExcelOle
1791
1791
  it "should raise an error if name not defined for the sheet" do
1792
1792
  expect {
1793
1793
  @excel1.rangeval("foo")
1794
- }.to raise_error(NameNotFound, /cannot find name "foo"/)
1794
+ }.to raise_error(NameNotFound, /name "foo" not in/)
1795
1795
  expect {
1796
1796
  @excel1.rangeval("named_formula")
1797
- }.to raise_error(NameNotFound, /cannot find name "named_formula"/)
1797
+ }.to raise_error(NameNotFound, /name "named_formula" not in/)
1798
1798
  expect {
1799
1799
  excel2 = Excel.create
1800
1800
  excel2.rangeval("one")
1801
- }.to raise_error(NameNotFound, /cannot find name "one"/)
1801
+ }.to raise_error(NameNotFound, /name "one" not in/)
1802
1802
  end
1803
1803
 
1804
1804
  it "should set a range to a value" do
@@ -1810,7 +1810,7 @@ module RobustExcelOle
1810
1810
  it "should raise an error if name cannot be evaluated" do
1811
1811
  expect{
1812
1812
  @excel1.set_nameval("foo", 1)
1813
- }.to raise_error(NameNotFound, /cannot find name "foo"/)
1813
+ }.to raise_error(NameNotFound, /name "foo" not in/)
1814
1814
  end
1815
1815
 
1816
1816
  end
data/spec/range_spec.rb CHANGED
@@ -16,7 +16,7 @@ describe RobustExcelOle::Range do
16
16
  @dir = create_tmpdir
17
17
  @book = Book.open(@dir + '/workbook.xls', :force_excel => :new)
18
18
  @sheet = @book.sheet(2)
19
- @range = RobustExcelOle::Range.new(@sheet.worksheet.UsedRange.Rows(1))
19
+ @range = RobustExcelOle::Range.new(@sheet.ole_worksheet.UsedRange.Rows(1))
20
20
  end
21
21
 
22
22
  after do
@@ -53,7 +53,7 @@ describe RobustExcelOle::Range do
53
53
  context "when instance is column range" do
54
54
  before do
55
55
  @sheet = @book.sheet(1)
56
- @range = RobustExcelOle::Range.new(@sheet.worksheet.UsedRange.Columns(1))
56
+ @range = RobustExcelOle::Range.new(@sheet.ole_worksheet.UsedRange.Columns(1))
57
57
  end
58
58
  it { @range.values.should eq ['foo', 'foo', 'matz'] }
59
59
  end
data/spec/sheet_spec.rb CHANGED
@@ -443,18 +443,18 @@ describe Sheet do
443
443
  @sheet1["another"].should == nil
444
444
  end
445
445
 
446
- it "should evaluate named formula" do
447
- @sheet1["named_formula"].should == 4
448
- end
446
+ #it "should evaluate named formula" do
447
+ # @sheet1["named_formula"].should == 4
448
+ #end
449
449
 
450
- it "should evaluate a formula" do
451
- @sheet1["another_formula"].should == 5
452
- end
450
+ #it "should evaluate a formula" do
451
+ # @sheet1["another_formula"].should == 5
452
+ #end
453
453
 
454
454
  it "should raise an error if name not defined" do
455
455
  expect {
456
456
  @sheet1["foo"]
457
- }.to raise_error(NameNotFound, /name "foo" not in Sheet1/)
457
+ }.to raise_error(NameNotFound, /name "foo" not in #<Sheet: Sheet1/)
458
458
  end
459
459
 
460
460
  it "should set a range to a value" do
@@ -468,7 +468,7 @@ describe Sheet do
468
468
  it "should raise an error if name cannot be evaluated" do
469
469
  expect{
470
470
  @sheet1["foo"] = 1
471
- }.to raise_error(NameNotFound, /name "foo" not in Sheet1/)
471
+ }.to raise_error(NameNotFound, /name "foo" not in #<Sheet: Sheet1/)
472
472
  end
473
473
  end
474
474
 
@@ -487,20 +487,20 @@ describe Sheet do
487
487
  @sheet1.nameval("firstcell").should == "foo"
488
488
  end
489
489
 
490
- it "should evaluate a formula" do
491
- @sheet1.nameval("another_formula").should == 5
492
- end
490
+ #it "should evaluate a formula" do
491
+ # @sheet1.nameval("another_formula").should == 5
492
+ #end
493
493
 
494
494
  it "should raise an error if name not defined" do
495
495
  expect {
496
496
  @sheet1.nameval("foo")
497
- }.to raise_error(NameNotFound, /name "foo" not in Sheet1/)
497
+ }.to raise_error(NameNotFound, /name "foo" not in/)
498
498
  end
499
499
 
500
500
  it "should raise an error of coordinates are given instead of a defined name" do
501
501
  expect {
502
502
  @sheet1.nameval("A1")
503
- }.to raise_error(NameNotFound, /name "A1" not in Sheet1/)
503
+ }.to raise_error(NameNotFound, /name "A1" not in #<Sheet: Sheet1/)
504
504
  end
505
505
 
506
506
  it "should return default value for a range with empty contents" do
@@ -518,7 +518,7 @@ describe Sheet do
518
518
  it "should raise an error if name cannot be evaluated" do
519
519
  expect{
520
520
  @sheet1.set_nameval("foo", 1)
521
- }.to raise_error(NameNotFound, /name "foo" not in Sheet1/)
521
+ }.to raise_error(NameNotFound, /name "foo" not in #<Sheet: Sheet1/)
522
522
  end
523
523
  end
524
524
 
@@ -560,13 +560,13 @@ describe Sheet do
560
560
  it "should raise an error if name not defined for the sheet" do
561
561
  expect {
562
562
  @sheet1.rangeval("foo")
563
- }.to raise_error(NameNotFound, /name "foo" not in Sheet1/)
563
+ }.to raise_error(NameNotFound, /name "foo" not in #<Sheet: Sheet1/)
564
564
  expect {
565
565
  @sheet1.rangeval("named_formula")
566
- }.to raise_error(NameNotFound, /name "named_formula" not in Sheet1/)
566
+ }.to raise_error(NameNotFound, /name "named_formula" not in #<Sheet: Sheet1/)
567
567
  expect {
568
568
  @sheet2.rangeval("firstcell")
569
- }.to raise_error(NameNotFound, /name "firstcell" not in Sheet2/)
569
+ }.to raise_error(NameNotFound, /name "firstcell" not in #<Sheet: Sheet2/)
570
570
  end
571
571
 
572
572
  it "should set a range to a value" do
@@ -580,7 +580,7 @@ describe Sheet do
580
580
  it "should raise an error if name cannot be evaluated" do
581
581
  expect{
582
582
  @sheet1.set_nameval("foo", 1)
583
- }.to raise_error(NameNotFound, /name "foo" not in Sheet1/)
583
+ }.to raise_error(NameNotFound, /name "foo" not in #<Sheet: Sheet1/)
584
584
  end
585
585
 
586
586
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: robust_excel_ole
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - traths
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-20 00:00:00.000000000 Z
11
+ date: 2018-05-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -26,7 +26,8 @@ dependencies:
26
26
  version: 2.6.0
27
27
  description: |-
28
28
  RobustExcelOle automates modifying, reading and writing Excel files in Windows by using the win32ole library.
29
- It supports simultaneously running Excel instances and user interactions.
29
+ It is disigned to cope with several kinds of concurrency of both simultaneously running
30
+ Excel instances and simultanously happening user interactions.
30
31
  RobustExcelOle deals with various cases of Excel (and user) behaviour,
31
32
  supplies workarounds for some Excel bugs, and supports referenced libraries.
32
33
  email: