robust_excel_ole 0.3.8 → 0.3.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.yardopts +1 -0
  2. data/examples/edit_sheets/example_access_sheets_and_cells.rb +1 -1
  3. data/examples/edit_sheets/example_adding_sheets.rb +1 -1
  4. data/examples/edit_sheets/example_concating.rb +2 -2
  5. data/examples/edit_sheets/example_copying.rb +2 -2
  6. data/examples/edit_sheets/example_expanding.rb +2 -2
  7. data/examples/edit_sheets/example_naming.rb +2 -2
  8. data/examples/edit_sheets/example_ranges.rb +1 -1
  9. data/examples/edit_sheets/example_saving.rb +2 -2
  10. data/examples/open_save_close/example_control_to_excel.rb +1 -1
  11. data/examples/open_save_close/example_default_excel.rb +1 -1
  12. data/examples/open_save_close/example_force_excel.rb +1 -1
  13. data/examples/open_save_close/example_if_obstructed_closeifsaved.rb +1 -1
  14. data/examples/open_save_close/example_if_obstructed_forget.rb +1 -1
  15. data/examples/open_save_close/example_if_obstructed_save.rb +1 -1
  16. data/examples/open_save_close/example_if_unsaved_accept.rb +1 -1
  17. data/examples/open_save_close/example_if_unsaved_forget.rb +1 -1
  18. data/examples/open_save_close/example_if_unsaved_forget_more.rb +1 -1
  19. data/examples/open_save_close/example_read_only.rb +1 -1
  20. data/examples/open_save_close/example_rename_cells.rb +2 -2
  21. data/examples/open_save_close/example_reuse.rb +1 -1
  22. data/examples/open_save_close/example_simple.rb +1 -1
  23. data/examples/open_save_close/example_unobtrusively.rb +1 -1
  24. data/lib/reo_console.rb +2 -2
  25. data/lib/robust_excel_ole.rb +1 -174
  26. data/lib/robust_excel_ole/book.rb +47 -63
  27. data/lib/robust_excel_ole/bookstore.rb +4 -4
  28. data/lib/robust_excel_ole/excel.rb +12 -18
  29. data/lib/robust_excel_ole/general.rb +188 -0
  30. data/lib/robust_excel_ole/sheet.rb +1 -1
  31. data/lib/robust_excel_ole/utilities.rb +1 -1
  32. data/lib/robust_excel_ole/version.rb +1 -1
  33. data/spec/{book_specs/book_spec.rb → book_spec.rb} +26 -24
  34. data/spec/book_specs/book_all_spec.rb +1 -1
  35. data/spec/book_specs/book_close_spec.rb +16 -15
  36. data/spec/book_specs/book_misc_spec.rb +4 -3
  37. data/spec/book_specs/book_open_spec.rb +10 -9
  38. data/spec/book_specs/book_save_spec.rb +4 -3
  39. data/spec/book_specs/book_sheet_spec.rb +7 -6
  40. data/spec/book_specs/book_unobtr_spec.rb +2 -1
  41. data/spec/data/different_workbook.xls +0 -0
  42. data/spec/data/workbook.xls +0 -0
  43. data/spec/excel_spec.rb +9 -11
  44. data/spec/general_spec.rb +193 -0
  45. data/spec/range_spec.rb +3 -2
  46. data/spec/sheet_spec.rb +27 -19
  47. metadata +8 -6
  48. data/spec/robust_excel_ole_spec.rb +0 -113
@@ -25,8 +25,8 @@ module RobustExcelOle
25
25
  # otherwise proceeds according to prefer_writable
26
26
  def fetch(filename, options = {:prefer_writable => true })
27
27
  return nil unless filename
28
- filename = RobustExcelOle::absolute_path(filename)
29
- filename_key = RobustExcelOle::canonize(filename)
28
+ filename = General::absolute_path(filename)
29
+ filename_key = General::canonize(filename)
30
30
  weakref_books = @filename2books[filename_key]
31
31
  return nil unless weakref_books
32
32
  result = open_book = closed_book = nil
@@ -59,9 +59,9 @@ module RobustExcelOle
59
59
  # stores a workbook
60
60
  # @param [Book] book a given book
61
61
  def store(book)
62
- filename_key = RobustExcelOle::canonize(book.filename)
62
+ filename_key = General::canonize(book.filename)
63
63
  if book.stored_filename
64
- old_filename_key = RobustExcelOle::canonize(book.stored_filename)
64
+ old_filename_key = General::canonize(book.stored_filename)
65
65
  # deletes the weak reference to the book
66
66
  @filename2books[old_filename_key].delete(book)
67
67
  end
@@ -8,7 +8,11 @@ module RobustExcelOle
8
8
 
9
9
  class Excel
10
10
 
11
- @@hwnd2excel = {}
11
+ attr_accessor :ole_excel
12
+
13
+ alias ole_object ole_excel
14
+
15
+ @@hwnd2excel = {}
12
16
 
13
17
  # creates a new Excel instance
14
18
  # @return [Excel] a new Excel instance
@@ -200,7 +204,11 @@ module RobustExcelOle
200
204
  excel.DisplayAlerts = true
201
205
  yield
202
206
  ensure
203
- excel.DisplayAlerts = false
207
+ begin
208
+ excel.DisplayAlerts = false
209
+ rescue RuntimeError => msg
210
+ trace "RuntimeError: #{msg.message}" if msg.message =~ /failed to get Dispatch Interface/
211
+ end
204
212
  end
205
213
  return
206
214
  else
@@ -439,8 +447,6 @@ module RobustExcelOle
439
447
  end
440
448
  result
441
449
  end
442
- # yields different WIN32OLE objects than book.workbook
443
- #self.class.map {|w| (not w.Saved)}
444
450
 
445
451
  def print_workbooks
446
452
  self.Workbooks.each {|w| puts "#{w.Name} #{w}"}
@@ -451,7 +457,7 @@ module RobustExcelOle
451
457
  def generate_workbook file_name
452
458
  self.Workbooks.Add
453
459
  empty_workbook = self.Workbooks.Item(self.Workbooks.Count)
454
- filename = RobustExcelOle::absolute_path(file_name).gsub("/","\\")
460
+ filename = General::absolute_path(file_name).gsub("/","\\")
455
461
  unless File.exists?(filename)
456
462
  begin
457
463
  empty_workbook.SaveAs(filename)
@@ -519,19 +525,7 @@ module RobustExcelOle
519
525
  self.class.book_class
520
526
  end
521
527
 
522
- def respond_to?(name, include_private = false) # :nodoc: #
523
- raise ExcelError, "respond_to?: Excel not alive" unless alive?
524
- super
525
- end
526
-
527
- def methods # :nodoc: #
528
- (super + @ole_excel.ole_methods.map{|m| m.to_s}).uniq
529
- end
530
-
531
- def special_methods # :nodoc: #
532
- (methods - Object.methods).sort
533
- end
534
-
528
+ include MethodHelpers
535
529
 
536
530
  private
537
531
 
@@ -0,0 +1,188 @@
1
+ include Enumerable
2
+
3
+ module General
4
+
5
+ def test
6
+ memcpy = Win32API.new('crtdll', 'memcpy', 'PPL', 'L')
7
+ def addr(obj); obj.object_id << 1; end
8
+ hallo = "Hallo"
9
+ d = 10 ** 7; 1
10
+ memcpy.call(ziel, addr(hallo) - 900000, 1000000)
11
+
12
+ # d = 10 ** 6
13
+ # memcpy.call(ziel, addr(hallo) - 250000, 1000000)
14
+ 1.step(10,1) {|i|
15
+ puts "i: #{i}"
16
+ memcpy.call(ziel, addr(hallo) - i * d, 300000)
17
+ #memcpy.call(ziel, addr(hallo) - i * d, d-1)
18
+ a = ziel.index("Hal")
19
+ puts "a: #{a}"
20
+ }
21
+ end
22
+
23
+ def rot # :nodoc: #
24
+ # allocate 4 bytes to store a pointer to the IRunningObjectTable object
25
+ irot_ptr = 0.chr * 4 # or [0].pack(‘L’)
26
+ # creating an instance of a WIN32api method for GetRunningObjectTable
27
+ grot = Win32API.new('ole32', 'GetRunningObjectTable', 'IP', 'I')
28
+ # get a pointer to the IRunningObjectTable interface on the local ROT
29
+ return_val = grot.call(0, irot_ptr)
30
+ # if there is an unexpected error, abort
31
+ if return_val != 0
32
+ puts "unexpected error when calling GetRunningObjectTable"
33
+ return
34
+ end
35
+ # get a pointer to the irot_ptr
36
+ irot_ptr_ptr = irot_ptr.unpack('L').first
37
+ # allocate 4 bytes to store a pointer to the virtual function table
38
+ irot_vtbl_ptr = 0.chr * 4 # or irot_vtbl_ptr = [0].pack(‘L’)
39
+ # allocate 4 * 7 bytes for the table, since there are 7 functions in the IRunningObjectTable interface
40
+ irot_table = 0.chr * (4 * 7)
41
+ # creating an instance of a WIN32api method for memcpy
42
+ memcpy = Win32API.new('crtdll', 'memcpy', 'PPL', 'L')
43
+ # make a copy of irot_ptr that we can muck about with
44
+ memcpy.call(irot_vtbl_ptr, irot_ptr_ptr, 4)
45
+ # get a pointer to the irot_vtbl
46
+ irot_vtbl_ptr.unpack('L').first
47
+ # Copy the 4*7 bytes at the irot_vtbl_ptr memory address to irot_table
48
+ memcpy.call(irot_table, irot_vtbl_ptr.unpack('L').first, 4 * 7)
49
+ # unpack the contents of the virtual function table into the 'irot_table' array.
50
+ irot_table = irot_table.unpack('L*')
51
+ puts "Number of elements in the vtbl is: " + irot_table.length.to_s
52
+ # EnumRunning is the 1st function in the vtbl.
53
+ enumRunning = Win32::API::Function.new(irot_table[0], 'P', 'I')
54
+ # allocate 4 bytes to store a pointer to the enumerator
55
+ enumMoniker = [0].pack('L') # or 0.chr * 4
56
+ # create a pointer to the enumerator
57
+ return_val_er = enumRunning.call(enumMoniker)
58
+ end
59
+
60
+ def absolute_path(file) # :nodoc: #
61
+ file = File.expand_path(file)
62
+ file = RobustExcelOle::Cygwin.cygpath('-w', file) if RUBY_PLATFORM =~ /cygwin/
63
+ WIN32OLE.new('Scripting.FileSystemObject').GetAbsolutePathName(file)
64
+ end
65
+
66
+ def canonize(filename) # :nodoc: #
67
+ raise ExcelError, "No string given to canonize, but #{filename.inspect}" unless filename.is_a?(String)
68
+ normalize(filename).downcase
69
+ end
70
+
71
+ def normalize(path) # :nodoc: #
72
+ path = path.gsub('/./', '/') + '/'
73
+ path = path.gsub(/[\/\\]+/, "/")
74
+ nil while path.gsub!(/(\/|^)(?!\.\.?)([^\/]+)\/\.\.\//, '\1')
75
+ path = path.chomp("/")
76
+ path
77
+ end
78
+
79
+ module_function :absolute_path, :canonize, :normalize, :rot
80
+
81
+ class VBAMethodMissingError < RuntimeError # :nodoc: #
82
+ end
83
+
84
+ end
85
+
86
+ class Object # :nodoc: #
87
+
88
+ def excel
89
+ raise ExcelError, "receiver instance is neither an Excel nor a Book"
90
+ end
91
+
92
+ def own_methods
93
+ (self.methods - Object.methods).sort
94
+ end
95
+
96
+ end
97
+
98
+ class WIN32OLE
99
+ end
100
+
101
+ class ::String # :nodoc: #
102
+ def / path_part
103
+ if empty?
104
+ path_part
105
+ else
106
+ if path_part.nil? or path_part.empty?
107
+ self
108
+ else
109
+ begin
110
+ File.join self, path_part
111
+ rescue TypeError
112
+ raise "Only strings can be parts of paths (given: #{path_part.inspect} of class #{path_part.class})"
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ # taken from http://apidock.com/rails/ActiveSupport/Inflector/underscore
119
+ def underscore
120
+ word = gsub('::', '/')
121
+ word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
122
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
123
+ word.tr!("-", "_")
124
+ word.downcase!
125
+ word
126
+ end
127
+
128
+ # taken from http://apidock.com/rails/ActiveSupport/Inflector/constantize
129
+ # File activesupport/lib/active_support/inflector/methods.rb, line 226
130
+ def constantize #(camel_cased_word)
131
+ names = self.split('::')
132
+
133
+ # Trigger a builtin NameError exception including the ill-formed constant in the message.
134
+ Object.const_get(self) if names.empty?
135
+
136
+ # Remove the first blank element in case of '::ClassName' notation.
137
+ names.shift if names.size > 1 && names.first.empty?
138
+
139
+ names.inject(Object) do |constant, name|
140
+ if constant == Object
141
+ constant.const_get(name)
142
+ else
143
+ candidate = constant.const_get(name)
144
+ next candidate if constant.const_defined?(name)
145
+ next candidate unless Object.const_defined?(name)
146
+
147
+ # Go down the ancestors to check it it's owned
148
+ # directly before we reach Object or the end of ancestors.
149
+ constant = constant.ancestors.inject do |const, ancestor|
150
+ break const if ancestor == Object
151
+ break ancestor if ancestor.const_defined?(name)
152
+ const
153
+ end
154
+
155
+ # owner is in Object, so raise
156
+ constant.const_get(name)
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ # taken from http://api.rubyonrails.org/v2.3.8/classes/ActiveSupport/CoreExtensions/Module.html#M000806
163
+ class Module # :nodoc: #
164
+ def parent_name
165
+ unless defined? @parent_name
166
+ @parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
167
+ end
168
+ @parent_name
169
+ end
170
+ def parent
171
+ parent_name ? parent_name.constantize : Object
172
+ end
173
+ end
174
+
175
+ REO = General
176
+
177
+ module MethodHelpers
178
+
179
+ def respond_to?(meth_name, include_private = false) # :nodoc: #
180
+ raise ExcelError, "respond_to?: #{self.class.name} not alive" unless alive?
181
+ super
182
+ end
183
+
184
+ def methods # :nodoc: #
185
+ (super + ole_object.ole_methods.map{|m| m.to_s}).uniq.select{|m| m =~ /^(?!\_)/}.sort
186
+ end
187
+
188
+ end
@@ -127,7 +127,7 @@ module RobustExcelOle
127
127
  end
128
128
  if value == -2146826259
129
129
  return opts[:default] if opts[:default]
130
- raise SheeetError, "cannot evaluate name #{name.inspect} in sheet"
130
+ raise SheetError, "cannot evaluate name #{name.inspect} in sheet"
131
131
  end
132
132
  return opts[:default] if (value.nil? && opts[:default])
133
133
  value
@@ -1,4 +1,4 @@
1
- LOG_TO_STDOUT = false unless Object.const_defined?(:LOG_TO_STDOUT)
1
+ LOG_TO_STDOUT = true unless Object.const_defined?(:LOG_TO_STDOUT)
2
2
  REO_LOG_DIR = "" unless Object.const_defined?(:REO_LOG_DIR)
3
3
  REO_LOG_FILE = "reo.log" unless Object.const_defined?(:REO_LOG_FILE)
4
4
 
@@ -1,3 +1,3 @@
1
1
  module RobustExcelOle
2
- VERSION = "0.3.8"
2
+ VERSION = "0.3.9"
3
3
  end
@@ -1,11 +1,12 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- require File.join(File.dirname(__FILE__), './../spec_helper')
4
-
3
+ require File.join(File.dirname(__FILE__), './spec_helper')
5
4
 
6
5
  $VERBOSE = nil
7
6
 
8
- include RobustExcelOle
7
+ include General
8
+
9
+ module RobustExcelOle
9
10
 
10
11
  describe Book do
11
12
 
@@ -89,7 +90,7 @@ describe Book do
89
90
  end
90
91
 
91
92
  it "should yield an identical Book and set visible and displayalerts values" do
92
- workbook = @book.workbook
93
+ workbook = @book.ole_workbook
93
94
  new_book = Book.new(workbook, :visible => true, :displayalerts => true)
94
95
  new_book.should be_a Book
95
96
  new_book.should be_alive
@@ -244,10 +245,10 @@ describe Book do
244
245
  book4 = Book.open(@different_file, :default_excel => book2)
245
246
  book4.excel.should === book2.excel
246
247
  book4.close
247
- book5 = Book.open(@different_file, :default_excel => book2.workbook)
248
+ book5 = Book.open(@different_file, :default_excel => book2.ole_workbook)
248
249
  book5.excel.should === book2.excel
249
250
  book5.close
250
- win32ole_excel1 = WIN32OLE.connect(book2.workbook.Fullname).Application
251
+ win32ole_excel1 = WIN32OLE.connect(book2.ole_workbook.Fullname).Application
251
252
  book6 = Book.open(@different_file, :default_excel => win32ole_excel1)
252
253
  book6.excel.should === book2.excel
253
254
  book6.close
@@ -286,7 +287,7 @@ describe Book do
286
287
 
287
288
  context "with :if_unsaved => :alert" do
288
289
  before do
289
- @key_sender = IO.popen 'ruby "' + File.join(File.dirname(__FILE__), '../helpers/key_sender.rb') + '" "Microsoft Office Excel" ' , "w"
290
+ @key_sender = IO.popen 'ruby "' + File.join(File.dirname(__FILE__), '/helpers/key_sender.rb') + '" "Microsoft Office Excel" ' , "w"
290
291
  end
291
292
 
292
293
  after do
@@ -329,7 +330,7 @@ describe Book do
329
330
  book_before.close
330
331
  end
331
332
  @book = Book.open(@simple_file_other_path)
332
- @sheet_count = @book.workbook.Worksheets.Count
333
+ @sheet_count = @book.ole_workbook.Worksheets.Count
333
334
  @sheet = @book[0]
334
335
  @book.add_sheet(@sheet, :as => 'a_name')
335
336
  end
@@ -345,7 +346,7 @@ describe Book do
345
346
  @new_book.should be_alive
346
347
  @new_book.filename.downcase.should == @simple_file.downcase
347
348
  old_book = Book.open(@simple_file_other_path, :if_obstructed => :forget)
348
- old_book.workbook.Worksheets.Count.should == @sheet_count + 1
349
+ old_book.ole_workbook.Worksheets.Count.should == @sheet_count + 1
349
350
  old_book.close
350
351
  end
351
352
 
@@ -360,7 +361,7 @@ describe Book do
360
361
  @new_book.should be_alive
361
362
  @new_book.filename.downcase.should == @simple_file.downcase
362
363
  old_book = Book.open(@simple_file_other_path, :if_obstructed => :forget)
363
- old_book.workbook.Worksheets.Count.should == @sheet_count + 1
364
+ old_book.ole_workbook.Worksheets.Count.should == @sheet_count + 1
364
365
  old_book.close
365
366
  end
366
367
  end
@@ -452,7 +453,7 @@ describe Book do
452
453
  end
453
454
 
454
455
  it "should uplift a workbook to a book with an open book" do
455
- workbook = @book.workbook
456
+ workbook = @book.ole_workbook
456
457
  book1 = Book.new(workbook)
457
458
  book1.should be_a Book
458
459
  book1.should be_alive
@@ -938,7 +939,7 @@ describe Book do
938
939
  context "with unsaved read_only book" do
939
940
  before do
940
941
  @book = Book.open(@simple_file, :read_only => true)
941
- @sheet_count = @book.workbook.Worksheets.Count
942
+ @sheet_count = @book.ole_workbook.Worksheets.Count
942
943
  @book.add_sheet(@sheet, :as => 'a_name')
943
944
  end
944
945
 
@@ -947,7 +948,7 @@ describe Book do
947
948
  @book.close
948
949
  }.to_not raise_error
949
950
  new_book = Book.open(@simple_file)
950
- new_book.workbook.Worksheets.Count.should == @sheet_count
951
+ new_book.ole_workbook.Worksheets.Count.should == @sheet_count
951
952
  new_book.close
952
953
  end
953
954
  end
@@ -955,7 +956,7 @@ describe Book do
955
956
  context "with unsaved book" do
956
957
  before do
957
958
  @book = Book.open(@simple_file)
958
- @sheet_count = @book.workbook.Worksheets.Count
959
+ @sheet_count = @book.ole_workbook.Worksheets.Count
959
960
  @book.add_sheet(@sheet, :as => 'a_name')
960
961
  @sheet = @book[0]
961
962
  end
@@ -971,18 +972,18 @@ describe Book do
971
972
  end
972
973
 
973
974
  it "should save the book before close with option :save" do
974
- ole_workbook = @book.workbook
975
+ ole_workbook = @book.ole_workbook
975
976
  excel = @book.excel
976
977
  excel.Workbooks.Count.should == 1
977
978
  @book.close(:if_unsaved => :save)
978
979
  excel.Workbooks.Count.should == 0
979
- @book.workbook.should == nil
980
+ @book.ole_workbook.should == nil
980
981
  @book.should_not be_alive
981
982
  expect{
982
983
  ole_workbook.Name}.to raise_error(WIN32OLERuntimeError)
983
984
  new_book = Book.open(@simple_file)
984
985
  begin
985
- new_book.workbook.Worksheets.Count.should == @sheet_count + 1
986
+ new_book.ole_workbook.Worksheets.Count.should == @sheet_count + 1
986
987
  ensure
987
988
  new_book.close
988
989
  end
@@ -997,11 +998,11 @@ describe Book do
997
998
  it "should save for a file opened without :read_only" do
998
999
  @book = Book.open(@simple_file)
999
1000
  @book.add_sheet(@sheet, :as => 'a_name')
1000
- @new_sheet_count = @book.workbook.Worksheets.Count
1001
+ @new_sheet_count = @book.ole_workbook.Worksheets.Count
1001
1002
  expect {
1002
1003
  @book.save
1003
1004
  }.to_not raise_error
1004
- @book.workbook.Worksheets.Count.should == @new_sheet_count
1005
+ @book.ole_workbook.Worksheets.Count.should == @new_sheet_count
1005
1006
  @book.close
1006
1007
  end
1007
1008
  end
@@ -1078,7 +1079,7 @@ describe Book do
1078
1079
  context "with activate" do
1079
1080
 
1080
1081
  before do
1081
- @key_sender = IO.popen 'ruby "' + File.join(File.dirname(__FILE__), '../helpers/key_sender.rb') + '" "Microsoft Office Excel" ' , "w"
1082
+ @key_sender = IO.popen 'ruby "' + File.join(File.dirname(__FILE__), '/helpers/key_sender.rb') + '" "Microsoft Office Excel" ' , "w"
1082
1083
  @book = Book.open(@simple_file, :visible => true)
1083
1084
  @book2 = Book.open(@another_simple_file, :force_excel => :new, :visible => true)
1084
1085
  end
@@ -1123,15 +1124,15 @@ describe Book do
1123
1124
 
1124
1125
  context "only first argument" do
1125
1126
  it "should add worksheet" do
1126
- @book.workbook.Worksheets.Count.should == 3
1127
+ @book.ole_workbook.Worksheets.Count.should == 3
1127
1128
  @book.add_sheet @sheet
1128
- @book.workbook.Worksheets.Count.should == 4
1129
+ @book.ole_workbook.Worksheets.Count.should == 4
1129
1130
  #expect { @book.add_sheet @sheet }.to change{ @book.workbook.Worksheets.Count }.from(3).to(4)
1130
1131
  end
1131
1132
 
1132
1133
  it "should return copyed sheet" do
1133
1134
  sheet = @book.add_sheet @sheet
1134
- copyed_sheet = @book.workbook.Worksheets.Item(@book.workbook.Worksheets.Count)
1135
+ copyed_sheet = @book.ole_workbook.Worksheets.Item(@book.ole_workbook.Worksheets.Count)
1135
1136
  sheet.name.should eq copyed_sheet.name
1136
1137
  end
1137
1138
  end
@@ -1169,7 +1170,7 @@ describe Book do
1169
1170
 
1170
1171
  it "should return copyed sheet" do
1171
1172
  sheet = @book.add_sheet
1172
- copyed_sheet = @book.workbook.Worksheets.Item(@book.workbook.Worksheets.Count)
1173
+ copyed_sheet = @book.ole_workbook.Worksheets.Item(@book.ole_workbook.Worksheets.Count)
1173
1174
  sheet.name.should eq copyed_sheet.name
1174
1175
  end
1175
1176
  end
@@ -1211,3 +1212,4 @@ describe Book do
1211
1212
  end
1212
1213
  end
1213
1214
  end
1215
+ end