rspreadsheet 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,296 @@
1
1
  require('rspreadsheet/cell')
2
+ include Forwardable
2
3
 
3
4
  # Currently this is only syntax sugar for cells and contains no functionality
4
5
 
5
6
  module Rspreadsheet
6
7
 
8
+ class RowArray
9
+ def initialize(aworksheet_node)
10
+ @worksheet_node = aworksheet_node
11
+
12
+ # initialize @rowgroups from @worksheet_node
13
+ @rowgroups = []
14
+ unless @worksheet_node.nil?
15
+ @worksheet_node.elements.select{|node| node.name == 'table-row'}.each do |row_source_node|
16
+ @rowgroups << prepare_row_group(row_source_node) # it is in @worksheet_node so suffices to add object to @rowgroups
17
+ end
18
+ end
19
+ end
20
+ def prepare_row_group(size_or_xmlnode) # appends new RowGroup at the end
21
+ # reading params
22
+ if size_or_xmlnode.kind_of? LibXML::XML::Node
23
+ size = (size_or_xmlnode['number-rows-repeated'] || 1).to_i
24
+ node = size_or_xmlnode
25
+ elsif size_or_xmlnode.to_i>0
26
+ size = size_or_xmlnode.to_i
27
+ node = nil
28
+ else
29
+ return nil
30
+ end
31
+ index = first_unused_row_index
32
+
33
+ # construct result
34
+ RowGroup.new(self,index..index+size-1,node).normalize
35
+ end
36
+ def add_row_group(size_or_xmlnode)
37
+ result = prepare_row_group(size_or_xmlnode)
38
+ @rowgroups << result
39
+ @worksheet_node << result.xmlnode
40
+ result
41
+ end
42
+ def get_row_group(rowi)
43
+ @rowgroups.find{ |rowgroup| rowgroup.range.cover?(rowi) }
44
+ end
45
+ def get_row(rowi)
46
+ rg = get_row_group(rowi).andand.normalize
47
+ case rg
48
+ when SingleRow then rg
49
+ when RowGroup then MemberOfRowGroup.new(rowi, rg)
50
+ when nil
51
+ if rowi>0 then UninitializedEmptyRow.new(self,rowi) else nil end
52
+ else raise
53
+ end
54
+ end
55
+ # prolonges the RowArray to cantain rowi and returns it
56
+ def detach_of_bound_row_group(rowi)
57
+ fill_row_group_size = rowi-first_unused_row_index
58
+ if fill_row_group_size>0
59
+ add_row_group(fill_row_group_size)
60
+ end
61
+ add_row_group(1)
62
+ return get_row(rowi)
63
+ end
64
+ def first_unused_row_index
65
+ if @rowgroups.empty?
66
+ 1
67
+ else
68
+ @rowgroups.last.range.end+1
69
+ end
70
+ end
71
+ # This detaches row rowi from the group and perhaps splits the RowGroup
72
+ # into two pieces. This makes the row individually editable.
73
+ def detach(rowi)
74
+ index = get_row_group_index(rowi)
75
+ row_group = @rowgroups[index]
76
+ range = row_group.range
77
+
78
+ # prepare new components
79
+ replaceby = []
80
+ replaceby << RowGroup.new(self,range.begin..rowi-1)
81
+ replaceby << (result = SingleRow.new(self,rowi))
82
+ replaceby << RowGroup.new(self,rowi+1..range.end)
83
+
84
+ # put original range somewhere in replaceby and shorten it
85
+ if rowi>range.begin
86
+ replaceby[0] = row_group
87
+ row_group.range = range.begin..rowi-1
88
+ else
89
+ replaceby[2] = row_group
90
+ row_group.range = rowi+1..range.end
91
+ end
92
+
93
+ # normalize and delete empty parts
94
+ replaceby = replaceby.map(&:normalize).compact
95
+
96
+ # do the replacement in xml
97
+ marker = LibXML::XML::Node.new('temporarymarker')
98
+ row_group.xmlnode.next = marker
99
+ row_group.xmlnode.remove!
100
+ replaceby.each{ |rg|
101
+ marker.prev = rg.xmlnode
102
+ }
103
+ marker.remove!
104
+
105
+ # do the replacement in array
106
+ @rowgroups[index..index]=replaceby
107
+ result
108
+ end
109
+
110
+ private
111
+ def get_row_group_index(rowi)
112
+ @rowgroups.find_index{ |rowgroup| rowgroup.range.cover?(rowi) }
113
+ end
114
+ end
115
+
7
116
  class Row
8
- def initialize(workbook,rowi)
9
- @rowi = rowi
10
- @workbook = workbook
117
+ @readonly = :unknown
118
+ # ? @rowindex
119
+ def self.empty_row_node
120
+ LibXML::XML::Node.new('table-row',nil, Tools.get_namespace('table'))
11
121
  end
122
+ end
123
+
124
+ class RowWithXMLNode < Row
125
+ attr_accessor :xmlnode
126
+ def style_name=(value); Tools.set_ns_attribute(@xmlnode,'table','style-name',value) end
12
127
  def cells(coli)
13
- @workbook.cells(@rowi,coli)
128
+ coli = coli.to_i
129
+ return nil if coli.to_i<=0
130
+ Cell.new(self,coli,cellnodes(coli))
131
+ end
132
+ def nonemptycells
133
+ nonemptycellsindexes.collect{ |index| cells(index) }
134
+ end
135
+ def nonemptycellsindexes
136
+ used_col_range.to_a.select do |coli|
137
+ cellnode = cellnodes(coli)
138
+ !(cellnode.content.nil? or cellnode.content.empty? or cellnode.content =='') or
139
+ !cellnode.attributes.to_a.reject{ |attr| attr.name == 'number-columns-repeated'}.empty?
140
+ end
141
+ end
142
+ def used_col_range
143
+ 1..first_unused_column_index-1
144
+ end
145
+ def cellnodes(coli)
146
+ cellnode = nil
147
+ while true
148
+ curr_coli=1
149
+ cellnode = @xmlnode.elements.select{|n| n.name=='table-cell'}.find do |el|
150
+ curr_coli += (Tools.get_ns_attribute_value(el, 'table', 'number-columns-repeated') || 1).to_i
151
+ curr_coli > coli
152
+ end
153
+ unless cellnode.nil?
154
+ return cellnode
155
+ else
156
+ add_cell
157
+ end
158
+ end
159
+ end
160
+ def add_cell(repeated=1)
161
+ cell = Cell.new(self,first_unused_column_index)
162
+ Tools.set_ns_attribute(cell.xmlnode,'table','number-columns-repeated',repeated) if repeated>1
163
+ @xmlnode << cell.xmlnode
164
+ cell
165
+ end
166
+ def used_range
167
+ fu = first_unused_column_index
168
+ (fu>1) ? 1..fu : nil
169
+ end
170
+ def first_unused_column_index
171
+ 1 + @xmlnode.elements.select{|n| n.name=='table-cell'}.reduce(0) do |sum, el|
172
+ sum + (Tools.get_ns_attribute_value(el, 'table', 'number-columns-repeated') || 1).to_i
173
+ end
14
174
  end
15
175
  end
16
176
 
177
+ class RowGroup < RowWithXMLNode
178
+ @readonly = :yes_always
179
+ attr_reader :range
180
+ attr_accessor :parent_array, :xmlnode
181
+ def initialize(aparent_array,arange,axmlnode=nil)
182
+ @parent_array = aparent_array
183
+ @range = arange
184
+ if axmlnode.nil?
185
+ axmlnode = Row.empty_row_node
186
+ Tools.set_ns_attribute(axmlnode,'table','number-rows-repeated',range.size) if range.size>1
187
+ end
188
+ @xmlnode = axmlnode
189
+ end
190
+ # returns SingleRow if size of range is 1 and nil if it is 0 or less
191
+ def normalize
192
+ case range.size
193
+ when 2..Float::INFINITY then self
194
+ when 1 then SingleRow.new_from_rowgroup(self)
195
+ else nil
196
+ end
197
+ end
198
+ def repeated; range.size end
199
+ def repeated?; range.size>1 end
200
+ def range=(arange)
201
+ @range=arange
202
+ Tools.set_ns_attribute(@xmlnode,'table','number-rows-repeated',range.size, 1)
203
+ end
204
+ end
205
+
206
+ class SingleRow < RowWithXMLNode
207
+ @readonly = :no
208
+ attr_accessor :xmlnode
209
+ # index Integer
210
+ def initialize(aparent_array,aindex,axmlnode=nil)
211
+ @parent_array = aparent_array
212
+ @index = aindex
213
+ if axmlnode.nil?
214
+ axmlnode = Row.empty_row_node
215
+ end
216
+ @xmlnode = axmlnode
217
+ end
218
+ def self.new_from_rowgroup(rg)
219
+ anode = rg.xmlnode
220
+ Tools.remove_ns_attribute(anode,'table','number-rows-repeated')
221
+
222
+ SingleRow.new(rg.parent_array,rg.range.begin,anode)
223
+ end
224
+ def normalize; self end
225
+ def repeated?; false end
226
+ def repeated; 1 end
227
+ def range; (@index..@index) end
228
+ def detach; true end
229
+ def row; @index end
230
+
231
+ end
232
+
233
+ class LazyDetachableRow < Row
234
+ @readonly = :yes_but_detachable
235
+ def initialize(rowi)
236
+ @index = rowi.to_i
237
+ end
238
+ def add_cell; detach.add_cell end
239
+ def style_name=(value); detach.style_name=value end
240
+ def row; @index end
17
241
  end
242
+
243
+ ## there are not data in this object, they are taken from RowGroup, but this is only readonly
244
+ class MemberOfRowGroup < LazyDetachableRow
245
+ @readonly = :yes_but_detachable
246
+ extend Forwardable
247
+ delegate [:repeated?, :repeated, :xmlnode, :parent_array] => :@row_group
248
+ attr_accessor :row_group # for dubugging
249
+
250
+ # @index Integer
251
+ # @row_group RepeatedRow
252
+ def initialize(arowi,arow_group)
253
+ super(arowi)
254
+ @row_group = arow_group
255
+ raise 'Wrong parameter given' unless @row_group.is_a? RowGroup
256
+ end
257
+ def detach # detaches MemberOfRowGroup from its RowGroup perhaps splitting RowGroup
258
+ @row_group.parent_array.detach(@index)
259
+ end
260
+ def cells(coli)
261
+ Cell.new(self,coli,@row_group.cellnodes(coli)).tap{|n| n.mode = :repeated}
262
+ end
263
+ def nonemptycells
264
+ @row_group.nonemptycellsindexes.collect{ |coli| cells(coli) }
265
+ end
266
+ end
267
+
268
+ ## this is a row outside the used bounds. the main purpose of this object is to magically synchronize to existing data, once they are created
269
+ class UninitializedEmptyRow < LazyDetachableRow
270
+ @readonly = :yes_but_detachable
271
+ attr_reader :parent_array # debug only
272
+ def initialize(aparent_array,arowi)
273
+ super(arowi)
274
+ @parent_array = aparent_array
275
+ end
276
+ def cells(coli)
277
+ if still_out_of_used_range?
278
+ Cell.new(self,coli,Cell.empty_cell_node).tap{|n| n.mode = :outbound}
279
+ else
280
+ @parent_array.get_row(@index).cells(coli)
281
+ end
282
+ end
283
+ def normalize
284
+ if still_out_of_used_range?
285
+ self
286
+ else
287
+ @parent_array.get_row(@index)
288
+ end
289
+ end
290
+ def detach; @parent_array.detach_of_bound_row_group(@index) end
291
+ def still_out_of_used_range?; @index >= @parent_array.first_unused_row_index end
292
+ def xmlnode; Row.empty_row_node end
293
+ def nonemptycells; [] end
294
+ end
295
+
296
+ end
@@ -20,13 +20,87 @@ module Tools
20
20
  row = rowname.to_i
21
21
  return [row,col]
22
22
  end
23
-
24
- # this object represents array which can contain repeated values
25
- # inspired valuely by http://www-users.cs.umn.edu/~saad/software/SPARSKIT/paper.ps
26
- class SparseRepeatedArray < Array
23
+ def self.get_namespace(prefix)
24
+ ns_array = {
25
+ 'office'=>"urn:oasis:names:tc:opendocument:xmlns:office:1.0",
26
+ 'style'=>"urn:oasis:names:tc:opendocument:xmlns:style:1.0",
27
+ 'text'=>"urn:oasis:names:tc:opendocument:xmlns:text:1.0",
28
+ 'table'=>"urn:oasis:names:tc:opendocument:xmlns:table:1.0",
29
+ 'draw'=>"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
30
+ 'fo'=>"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
31
+ 'xlink'=>"http://www.w3.org/1999/xlink",
32
+ 'dc'=>"http://purl.org/dc/elements/1.1/",
33
+ 'meta'=>"urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
34
+ 'number'=>"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
35
+ 'presentation'=>"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",
36
+ 'svg'=>"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
37
+ 'chart'=>"urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
38
+ 'dr3d'=>"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
39
+ 'math'=>"http://www.w3.org/1998/Math/MathML",
40
+ 'form'=>"urn:oasis:names:tc:opendocument:xmlns:form:1.0",
41
+ 'script'=>"urn:oasis:names:tc:opendocument:xmlns:script:1.0",
42
+ 'ooo'=>"http://openoffice.org/2004/office",
43
+ 'ooow'=>"http://openoffice.org/2004/writer",
44
+ 'oooc'=>"http://openoffice.org/2004/calc",
45
+ 'dom'=>"http://www.w3.org/2001/xml-events",
46
+ 'xforms'=>"http://www.w3.org/2002/xforms",
47
+ 'xsd'=>"http://www.w3.org/2001/XMLSchema",
48
+ 'xsi'=>"http://www.w3.org/2001/XMLSchema-instance",
49
+ 'rpt'=>"http://openoffice.org/2005/report",
50
+ 'of'=>"urn:oasis:names:tc:opendocument:xmlns:of:1.2",
51
+ 'xhtml'=>"http://www.w3.org/1999/xhtml",
52
+ 'grddl'=>"http://www.w3.org/2003/g/data-view#",
53
+ 'tableooo'=>"http://openoffice.org/2009/table",
54
+ 'drawooo'=>"http://openoffice.org/2010/draw",
55
+ 'calcext'=>"urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0",
56
+ 'loext'=>"urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
57
+ 'field'=>"urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0",
58
+ 'formx'=>"urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0",
59
+ 'css3t'=>"http://www.w3.org/TR/css3-text/"
60
+ }
61
+ if @pomnode.nil?
62
+ @pomnode = LibXML::XML::Node.new('xxx')
63
+ end
64
+ if @ns.nil? then @ns={} end
65
+ if @ns[prefix].nil?
66
+ @ns[prefix] = LibXML::XML::Namespace.new(@pomnode, prefix, ns_array[prefix])
67
+ end
68
+ return @ns[prefix]
69
+ end
70
+ # sets namespaced attribute "ns_prefix:key" in node to value. if value == delete_value then remove the attribute
71
+ def self.set_ns_attribute(node,ns_prefix,key,value,delete_value=nil)
72
+ ns = Tools.get_namespace(ns_prefix)
73
+ attr = node.attributes.get_attribute_ns(ns.href, key)
27
74
 
28
-
75
+ unless value==delete_value # set attribute
76
+ if attr.nil? # create attribute if needed
77
+ attr = LibXML::XML::Attr.new(node, key,'temporarilyempty')
78
+ attr.namespaces.namespace = ns
79
+ end
80
+ attr.value = value.to_s
81
+ attr
82
+ else # remove attribute
83
+ attr.remove! unless attr.nil?
84
+ nil
85
+ end
86
+ end
87
+ def self.get_ns_attribute(node,ns_prefix,key)
88
+ node.attributes.get_attribute_ns(Tools.get_namespace(ns_prefix).href,key)
89
+ end
90
+ def self.get_ns_attribute_value(node,ns_prefix,key)
91
+ Tools.get_ns_attribute(node,ns_prefix,key).andand.value
92
+ end
93
+ def self.remove_ns_attribute(node,ns_prefix,key)
94
+ node.attributes.get_attribute_ns(Tools.get_namespace(ns_prefix).href,key)
95
+ attr.remove! unless attr.nil?
29
96
  end
30
97
  end
31
98
 
99
+ end
100
+
101
+ class Range
102
+ def size
103
+ res = self.end-self.begin+1
104
+ res>0 ? res : 0
105
+ end
32
106
  end
@@ -1,3 +1,3 @@
1
1
  module Rspreadsheet
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -4,22 +4,16 @@ require 'libxml'
4
4
  module Rspreadsheet
5
5
  class Workbook
6
6
  attr_reader :worksheets, :filename
7
+ attr_reader :xmlnode # debug
7
8
  def initialize(afilename=nil)
8
9
  @worksheets={}
9
10
  @filename = afilename
10
- if filename.nil?
11
- else
12
- @content_xml = Zip::File.open(filename) do |zip|
13
- LibXML::XML::Document.io zip.get_input_stream('content.xml')
14
- end
15
-
16
- ndx = 0
17
- @content_xml.find_first('//office:spreadsheet').each_element { |node|
18
- sheet = Worksheet.new(node)
19
- @worksheets[ndx]=sheet
20
- @worksheets[node.name]=sheet
21
- ndx+=1
22
- }
11
+ @content_xml = Zip::File.open(@filename || './lib/rspreadsheet/empty_file_template.ods') do |zip|
12
+ LibXML::XML::Document.io zip.get_input_stream('content.xml')
13
+ end
14
+ @xmlnode = @content_xml.find_first('//office:spreadsheet')
15
+ @xmlnode.find('./table:table').each do |node|
16
+ create_worksheet_from_node(node)
23
17
  end
24
18
  end
25
19
  def save(new_filename=nil)
@@ -30,20 +24,31 @@ class Workbook
30
24
  @filename = new_filename
31
25
  end
32
26
  Zip::File.open(@filename) do |zip|
33
- # it is easy, because @content_xml in in sync with contents all the time
27
+ # it is easy, because @xmlnode in in sync with contents all the time
34
28
  zip.get_output_stream('content.xml') do |f|
35
29
  f.write @content_xml
36
30
  end
37
31
  end
38
32
  end
39
- def create_worksheet(node=nil)
40
- sheet = Worksheet.new(node)
41
- @worksheets[worksheets_count]=sheet
42
- @worksheets[node.name]=sheet unless node.nil?
33
+ def create_worksheet_from_node(source_node)
34
+ sheet = Worksheet.new(source_node)
35
+ register_worksheet(sheet)
43
36
  return sheet
44
37
  end
45
- def worksheets
46
- @worksheets
38
+ def create_worksheet_with_name(name)
39
+ sheet = Worksheet.new(name)
40
+ register_worksheet(sheet)
41
+ return sheet
42
+ end
43
+ def create_worksheet
44
+ index = worksheets_count
45
+ create_worksheet_with_name("Strana #{index}")
46
+ end
47
+ def register_worksheet(worksheet)
48
+ index = worksheets_count+1
49
+ @worksheets[index]=worksheet
50
+ @worksheets[worksheet.name]=worksheet unless worksheet.name.nil?
51
+ @xmlnode << worksheet.xmlnode if worksheet.xmlnode.doc != @xmlnode.doc
47
52
  end
48
53
  def worksheets_count
49
54
  @worksheets.keys.select{ |k| k.kind_of? Numeric }.size #TODO: ?? max
@@ -51,5 +56,8 @@ class Workbook
51
56
  def worksheet_names
52
57
  @worksheets.keys.reject{ |k| k.kind_of? Numeric }
53
58
  end
59
+ def xmldoc
60
+ @xmlnode.doc
61
+ end
54
62
  end
55
63
  end
@@ -1,47 +1,38 @@
1
1
  require 'rspreadsheet/row'
2
2
  require 'rspreadsheet/tools'
3
- require 'forwardable'
3
+ # require 'forwardable'
4
4
 
5
5
  module Rspreadsheet
6
6
 
7
7
  class Worksheet
8
- attr_accessor :name
9
- extend Forwardable
10
- def_delegators :nonemptycells
8
+ attr_accessor :name, :xmlnode
9
+ # extend Forwardable
10
+ # def_delegators :nonemptycells
11
11
 
12
- def initialize(source_node=nil)
13
- @source_node = source_node
14
- ## initialize cells
15
- @cells = Hash.new do |hash, coords|
16
- # we create empty cell and place it to hash, we do not have to check whether there is a cell in XML already, because it would be in hash as well
17
- hash[coords]=Cell.new(coords[0],coords[1])
18
- # TODO: create XML empty node here or upon save?
19
- end
20
- rowi = 1
21
- unless @source_node.nil?
22
- @source_node.elements.select{ |node| node.name == 'table-row'}.each do |row_source_node|
23
- coli = 1
24
- row_source_node.elements.select{ |node| node.name == 'table-cell'}.each do |cell_source_node|
25
- initialize_cell(rowi,coli,cell_source_node)
26
- coli += 1
27
- end
28
- rowi += 1
29
- end
12
+ def initialize(xmlnode_or_sheet_name)
13
+ # set up the @xmlnode according to parameter
14
+ case xmlnode_or_sheet_name
15
+ when LibXML::XML::Node
16
+ @xmlnode = xmlnode_or_sheet_name
17
+ when String
18
+ @xmlnode = LibXML::XML::Node.new('table')
19
+ ns = LibXML::XML::Namespace.new(@xmlnode, 'table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0')
20
+ @xmlnode .namespaces.namespace = ns
21
+ @xmlnode['table:name'] = xmlnode_or_sheet_name
22
+ else raise 'Provide name or xml node to create a Worksheet object'
30
23
  end
24
+
31
25
  ## initialize rows
32
- @spredsheetrows=Array.new()
33
- end
34
- def initialize_cell(r,c,source_node)
35
- @cells[[r,c]]=Cell.new(r,c,source_node)
26
+ @spredsheetrows=RowArray.new(@xmlnode)
36
27
  end
37
28
  def cells(r,c)
38
- @cells[[r,c]]
29
+ rows(r).andand.cells(c)
39
30
  end
40
31
  def nonemptycells
41
- @cells.values
32
+ used_rows_range.collect{ |rowi| rows(rowi) }.collect { |row| row.nonemptycells }.flatten
42
33
  end
43
34
  def rows(rowi)
44
- @spredsheetrows[rowi] ||= Row.new(self,rowi)
35
+ @spredsheetrows.get_row(rowi)
45
36
  end
46
37
  ## syntactic sugar follows
47
38
  def [](r,c)
@@ -64,6 +55,9 @@ class Worksheet
64
55
  super
65
56
  end
66
57
  end
58
+ def used_rows_range
59
+ 1..@spredsheetrows.first_unused_row_index-1
60
+ end
67
61
  end
68
62
 
69
63
  end
data/rspreadsheet.gemspec CHANGED
@@ -28,12 +28,13 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "bundler", "~> 1.5"
29
29
  spec.add_development_dependency "rake", '~>0.9'
30
30
  # testig - see http://bit.ly/1n5yM51
31
- spec.add_development_dependency "rspec", '~>2'
31
+ spec.add_development_dependency "rspec", '~>2' # testing
32
+ spec.add_development_dependency 'pry-nav' # enables pry 'next', 'step' commands
32
33
 
33
34
  # optional and testing
34
35
  spec.add_development_dependency "coveralls", '~>0.7'
35
- spec.add_development_dependency "test_notifier", '~>2.0' # test notifier for kde and other platforms
36
36
  spec.add_development_dependency "guard", '~>2.6'
37
37
  spec.add_development_dependency "guard-rspec", '~>2.6'
38
+ # spec.add_development_dependency 'equivalent-xml' # implementing xml diff
38
39
 
39
40
  end
data/spec/cell_spec.rb ADDED
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rspreadsheet::Cell do
4
+ before do
5
+ book1 = Rspreadsheet.new
6
+ @sheet1 = book1.create_worksheet
7
+ book2 = Rspreadsheet.new($test_filename)
8
+ @sheet2 = book2.worksheets[1]
9
+ end
10
+ it 'contains good row and col coordinates' do
11
+ @cell = @sheet1.cells(1,3)
12
+ @cell.row.should == 1
13
+ @cell.col.should == 3
14
+ @cell.coordinates.should == [1,3]
15
+
16
+ @cell = @sheet2.cells(7,2)
17
+ @cell.row.should == 7
18
+ @cell.col.should == 2
19
+ @cell.coordinates.should == [7,2]
20
+ end
21
+ it 'can be referenced by more vars and both are synchronized' do
22
+ @cell = @sheet1.cells(1,1)
23
+ @sheet1[1,1] = 'novinka'
24
+ @cell.value.should == 'novinka'
25
+ end
26
+ it 'can be modified by more ways and all are identical' do
27
+ @cell = @sheet1.cells(2,2)
28
+ @sheet1[2,2] = 'zaprve'
29
+ @cell.value.should == 'zaprve'
30
+ @sheet1.cells(2,2).value = 'zadruhe'
31
+ @cell.value.should == 'zadruhe'
32
+ @sheet1.B2 = 'zatreti'
33
+ @cell.value.should == 'zatreti'
34
+ end
35
+ it 'can include links' do
36
+ @sheet2.A12.should == '[http://example.org/]'
37
+ end
38
+ it 'contains good row and col coordinates even after table:number-columns-repeated cells' do
39
+ @cell = @sheet2.cells(13,5)
40
+ @cell.value.should == 'afterrepeated'
41
+ @cell.row.should == 13
42
+ @cell.col.should == 5
43
+ end
44
+ it 'does not accept negative and zero coordinates' do
45
+ @sheet2.cells(0,5).should be(nil)
46
+ @sheet2.cells(2,-5).should be(nil)
47
+ @sheet2.cells(-2,-5).should be(nil)
48
+ end
49
+ end