rspreadsheet 0.2.15 → 0.3
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.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/.travis.yml +5 -4
- data/DEVEL_BLOG.md +18 -2
- data/GUIDE.md +5 -0
- data/Guardfile +3 -3
- data/README.md +9 -9
- data/lib/helpers/class_extensions.rb +101 -38
- data/lib/rspreadsheet.rb +2 -1
- data/lib/rspreadsheet/cell.rb +110 -19
- data/lib/rspreadsheet/image.rb +118 -0
- data/lib/rspreadsheet/row.rb +14 -369
- data/lib/rspreadsheet/tools.rb +20 -1
- data/lib/rspreadsheet/version.rb +1 -1
- data/lib/rspreadsheet/workbook.rb +81 -20
- data/lib/rspreadsheet/worksheet.rb +31 -10
- data/lib/rspreadsheet/xml_tied_array.rb +179 -0
- data/lib/rspreadsheet/xml_tied_item.rb +111 -0
- data/lib/rspreadsheet/xml_tied_repeatable.rb +151 -0
- data/reinstall_local_gem.sh +2 -2
- data/rspreadsheet.gemspec +15 -3
- data/spec/cell_spec.rb +82 -1
- data/spec/class_extensions_spec.rb +49 -0
- data/spec/image_spec.rb +104 -0
- data/spec/included_image_spec.rb +8 -0
- data/spec/io_spec.rb +39 -27
- data/spec/row_spec.rb +16 -1
- data/spec/rspreadsheet_spec.rb +94 -35
- data/spec/spec_helper.rb +0 -1
- data/spec/test-image-blue.png +0 -0
- data/spec/test-image.png +0 -0
- data/spec/testfile1.ods +0 -0
- data/spec/testfile2-images.ods +0 -0
- data/spec/workbook_spec.rb +27 -0
- data/spec/worksheet_spec.rb +9 -2
- metadata +20 -47
- data/investigate.rb +0 -19
- data/lib/rspreadsheet/xml_tied.rb +0 -253
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'helpers/class_extensions'
|
2
|
+
require 'rspreadsheet/xml_tied_array' # BASTL to je jen kvuli XMLTied class
|
3
|
+
|
4
|
+
module Rspreadsheet
|
5
|
+
|
6
|
+
using ClassExtensions if RUBY_VERSION > '2.1'
|
7
|
+
|
8
|
+
# Note for developers: In case you want to represent a node containing many identical subnodes
|
9
|
+
# (like row contains cells, worksheet contains rows or images part includes images) than
|
10
|
+
# 1. Include module XMLTiedArray into parent class
|
11
|
+
# 2. Subclass XMLTiedItem by object which will represent individual items
|
12
|
+
# 3. Implement methods which are mentioned at both of these and the rest should work itself.
|
13
|
+
# 4. prepare_subitem calls method new of the item and usually sends index and parent + some
|
14
|
+
# more so subitem can implement parent and index methods.
|
15
|
+
|
16
|
+
# @private
|
17
|
+
# abstract class. All successors have some options. MUST implement:
|
18
|
+
# * xml_options
|
19
|
+
#
|
20
|
+
# If you override intializer make sure you call initialize_xml_tied_item(aparent,aindex).
|
21
|
+
#
|
22
|
+
# Optionally you may implement method which makes index accessible under more meaningful name
|
23
|
+
# like column or so. Optionally you may implement method which makes parent accessible under
|
24
|
+
# more meaningful name like worksheet or so.
|
25
|
+
#
|
26
|
+
# By default parent is stored at initialization and never changed. If you do not want to cache
|
27
|
+
# it like this (to prevent inconsistencies) just override parent method to dfind the parent
|
28
|
+
# dynamically (see Cell). If you do so you may want to disable the default parent handling by
|
29
|
+
# calling initialize_xml_tied_item(nil,index) in initializer (or do not call it at all if you
|
30
|
+
# have overridden index as well.
|
31
|
+
#
|
32
|
+
# Note: If there is a object representing parent (presumably using XMLTiedArray) than initialize
|
33
|
+
# signature must be reflected in parent prepare_subitem method
|
34
|
+
#
|
35
|
+
class XMLTiedItem < XMLTied
|
36
|
+
|
37
|
+
def initialize(aparent,aindex)
|
38
|
+
initialize_xml_tied_item(aparent,aindex)
|
39
|
+
end
|
40
|
+
def parent; @xml_tied_parent end
|
41
|
+
def index; @xml_tied_item_index end
|
42
|
+
def set_index(aindex); @xml_tied_item_index=aindex end
|
43
|
+
def index=(aindex); @xml_tied_item_index=aindex end
|
44
|
+
|
45
|
+
# `xml_options[:xml_items_node_name]` gives the name of the tag representing cell
|
46
|
+
# `xml_options[:number-columns-repeated]` gives the name of the previous tag which sais how many times the item is repeated
|
47
|
+
def xml_options; abstract end
|
48
|
+
|
49
|
+
def initialize_xml_tied_item(aparent,aindex)
|
50
|
+
@xml_tied_parent = aparent unless aparent.nil?
|
51
|
+
@xml_tied_item_index = aindex unless aindex.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def mode
|
55
|
+
case
|
56
|
+
when xmlnode.nil? then :outbound
|
57
|
+
when repeated>1 then :repeated
|
58
|
+
else :regular
|
59
|
+
end
|
60
|
+
end
|
61
|
+
def repeated; (Tools.get_ns_attribute_value(xmlnode, 'table', xml_options[:xml_repeated_attribute]) || 1 ).to_i end
|
62
|
+
def repeated?; mode==:repeated || mode==:outbound end
|
63
|
+
alias :is_repeated? :repeated?
|
64
|
+
def xmlnode
|
65
|
+
if parent.xmlnode.nil?
|
66
|
+
nil
|
67
|
+
else
|
68
|
+
parent.my_subnode(index)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
def detach_if_needed
|
72
|
+
detach if repeated? # item did not exist individually yet, detach it within its parent and therefore make it individally editable
|
73
|
+
end
|
74
|
+
def detach
|
75
|
+
parent.detach_if_needed if parent.respond_to?(:detach_if_needed)
|
76
|
+
parent.detach_my_subnode_respect_repeated(index)
|
77
|
+
self
|
78
|
+
end
|
79
|
+
def _shift_by(diff)
|
80
|
+
set_index(index + diff)
|
81
|
+
end
|
82
|
+
def range
|
83
|
+
parent.my_subnode_range(index)
|
84
|
+
end
|
85
|
+
def invalid_reference?; false end
|
86
|
+
# destroys the object so it can not be used, this is necessarry to prevent
|
87
|
+
# accessing cells and rows which has been long time ago deleted and do not represent
|
88
|
+
# any physical object anymore
|
89
|
+
def invalidate_myself
|
90
|
+
raise_destroyed_cell_error = Proc.new {|*params| raise "Calling method of already destroyed Cell."}
|
91
|
+
(self.methods - Object.methods + [:nil?]).each do |method| # "undefine" all methods
|
92
|
+
self.singleton_class.send(:define_method, method, raise_destroyed_cell_error)
|
93
|
+
end
|
94
|
+
self.singleton_class.send(:define_method, :inspect, -> { "#<%s:0x%x destroyed cell>" % [self.class,object_id] }) # define descriptive inspect
|
95
|
+
self.singleton_class.send(:define_method, :invalid_reference?, -> { true }) # define invalid_reference? method
|
96
|
+
# invalidate variables
|
97
|
+
@xml_tied_parent=nil
|
98
|
+
@xml_tied_item_index=nil
|
99
|
+
# self.instance_variables.each do |variable|
|
100
|
+
# instance_variable_set(variable,nil)
|
101
|
+
# end
|
102
|
+
end
|
103
|
+
def delete
|
104
|
+
parent.delete_subitem(index)
|
105
|
+
invalidate_myself
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require 'helpers/class_extensions'
|
2
|
+
require 'rspreadsheet/xml_tied_array'
|
3
|
+
|
4
|
+
module Rspreadsheet
|
5
|
+
|
6
|
+
using ClassExtensions if RUBY_VERSION > '2.1'
|
7
|
+
|
8
|
+
|
9
|
+
# Abstract class similar to XMLTiedArray but with support to "repeatable" items. This is notion specific
|
10
|
+
# to OpenDocument files - whnewer a row repeats more times (or a cell), one can either make many identical
|
11
|
+
# copies of the same xml or only make one xml representing one item and add attribute xml_repeated.
|
12
|
+
#
|
13
|
+
# This class is made to be included, not subclassed - the reason is in delete method which calls super.
|
14
|
+
# This class is also made to handle automatic creation of outbound items.
|
15
|
+
# @private
|
16
|
+
|
17
|
+
module XMLTiedArray_WithRepeatableItems
|
18
|
+
include XMLTiedArray
|
19
|
+
|
20
|
+
def my_subnode_range(aindex)
|
21
|
+
node, range = find_subnode_with_range(aindex)
|
22
|
+
return range
|
23
|
+
end
|
24
|
+
|
25
|
+
# vrátí xmlnode na souřadnici aindex
|
26
|
+
def my_subnode(aindex)
|
27
|
+
result1, result2 = find_subnode_with_range(aindex)
|
28
|
+
return result1
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_subnode_with_range(aindex)
|
32
|
+
options = subitem_xml_options
|
33
|
+
rightindex = 0
|
34
|
+
xmlsubnodes.each do |node|
|
35
|
+
repeated = (node.attributes[options[:xml_repeated_attribute]] || 1).to_i
|
36
|
+
leftindex = rightindex + 1
|
37
|
+
rightindex = rightindex+repeated
|
38
|
+
if rightindex>= aindex
|
39
|
+
return node, leftindex..rightindex
|
40
|
+
end
|
41
|
+
end
|
42
|
+
return nil, rightindex+1..Float::INFINITY
|
43
|
+
end
|
44
|
+
|
45
|
+
# @!group inserting new subnodes
|
46
|
+
|
47
|
+
def insert_new_empty_subnode_before(aindex)
|
48
|
+
insert_new_empty_subnode_before_respect_repeatable(aindex)
|
49
|
+
end
|
50
|
+
|
51
|
+
def insert_new_empty_subnode_before_respect_repeatable(aindex)
|
52
|
+
axmlnode = xmlnode
|
53
|
+
options = subitem_xml_options
|
54
|
+
node,index_range = find_subnode_with_range(aindex)
|
55
|
+
|
56
|
+
if !node.nil? # found the node, now do the insert
|
57
|
+
[index_range.begin..aindex-1,aindex..index_range.end].reject {|range| range.size<1}.each do |range| # split original node by cloning
|
58
|
+
clone_before_and_set_repeated_attribute(node,range.size,options)
|
59
|
+
end
|
60
|
+
node.prev.prev = prepare_repeated_subnode(1, options) # insert new node
|
61
|
+
node.remove! # remove the original node
|
62
|
+
else # insert outbound xmlnode
|
63
|
+
[index+1..aindex-1,aindex..aindex].reject {|range| range.size<1}.each do |range|
|
64
|
+
axmlnode << XMLTiedArray_WithRepeatableItems.prepare_repeated_subnode(range.size, options)
|
65
|
+
end
|
66
|
+
end #TODO: Out of bounds indexes handling
|
67
|
+
return my_subnode(aindex)
|
68
|
+
end
|
69
|
+
|
70
|
+
def prepare_repeated_subnode(times_repeated,options)
|
71
|
+
result = prepare_empty_subnode
|
72
|
+
Tools.set_ns_attribute(result,'table',options[:xml_repeated_attribute],times_repeated, 1)
|
73
|
+
result
|
74
|
+
end
|
75
|
+
|
76
|
+
def clone_before_and_set_repeated_attribute(node,times_repeated,options)
|
77
|
+
newnode = node.copy(true)
|
78
|
+
Tools.set_ns_attribute(newnode,'table',options[:xml_repeated_attribute],times_repeated,1)
|
79
|
+
node.prev = newnode
|
80
|
+
end
|
81
|
+
|
82
|
+
# detaches subnode with aindex
|
83
|
+
def detach_my_subnode_respect_repeated(aindex)
|
84
|
+
axmlnode = xmlnode
|
85
|
+
options = subitem_xml_options
|
86
|
+
node,index_range = find_subnode_with_range(aindex)
|
87
|
+
if index_range.size > 1 # pokud potřebuje vůbec detachovat
|
88
|
+
if !node.nil? # detach subnode
|
89
|
+
[index_range.begin..aindex-1,aindex..aindex,aindex+1..index_range.end].reject {|range| range.size<1}.each do |range| # create new structure by cloning
|
90
|
+
clone_before_and_set_repeated_attribute(node,range.size,options)
|
91
|
+
end
|
92
|
+
node.remove! # remove the original node
|
93
|
+
else # add outbound xmlnode
|
94
|
+
[index_range.begin..aindex-1,aindex..aindex].reject {|range| range.size<1}.each do |range|
|
95
|
+
axmlnode << prepare_repeated_subnode(range.size, options)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
return my_subnode(aindex)
|
100
|
+
end
|
101
|
+
|
102
|
+
def delete_my_subnode_respect_repeated(aindex)
|
103
|
+
detach_my_subnode_respect_repeated(aindex) #TODO: tohle neni uplne spravne, protoze to zanecha skupinu rozdelenou na dve casti
|
104
|
+
subitem(aindex).xmlnode.remove!
|
105
|
+
end
|
106
|
+
|
107
|
+
def how_many_times_node_is_repeated(node) # adding respect to repeated nodes
|
108
|
+
(node.attributes[subitem_xml_options[:xml_repeated_attribute]] || 1).to_i
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
# clean up item from xml (handle possible detachments) and itemcache. leave the object invalidation on the object
|
113
|
+
# this should not be called from nowhere but XMLTiedItem.delete
|
114
|
+
def delete_subitem(aindex)
|
115
|
+
options = subitem_xml_options
|
116
|
+
delete_my_subnode_respect_repeated(aindex) # vymaž node z xml
|
117
|
+
@itemcache.delete(aindex)
|
118
|
+
@itemcache.keys.sort.select{|i| i>=aindex+1 }.each do |i|
|
119
|
+
@itemcache[i-1]=@itemcache.delete(i)
|
120
|
+
@itemcache[i-1]._shift_by(-1)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def delete
|
125
|
+
@itemcache.each do |key,item|
|
126
|
+
item.delete # delete item - this destroys its subitems, xmlnode and invalidates it
|
127
|
+
@itemcache.delete(key) # delete the entry from the hash, normally this would mean this ceases to exist, if user does not have reference stored somewhere. Of he does, the object is invalidated anyways
|
128
|
+
end
|
129
|
+
super # this for example for Row objects calls XMLTiedItem.delete because Row is subclass of XMLTiedItem
|
130
|
+
end
|
131
|
+
|
132
|
+
def find_nonempty_subnode_indexes(axmlnode, options)
|
133
|
+
index = 0
|
134
|
+
result = []
|
135
|
+
axmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |node|
|
136
|
+
repeated = (node.attributes[options[:xml_repeated_attribute]] || 1).to_i
|
137
|
+
index = index + repeated
|
138
|
+
if !(node.content.nil? or node.content.empty? or node.content =='') and (repeated==1)
|
139
|
+
result << index
|
140
|
+
end
|
141
|
+
end
|
142
|
+
return result
|
143
|
+
end
|
144
|
+
|
145
|
+
# truncate the item completely, deleting all its subitems
|
146
|
+
def truncate
|
147
|
+
subitems.reverse.each{ |subitem| subitem.delete } # reverse je tu jen kvuli performanci, aby to mazal zezadu
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
data/reinstall_local_gem.sh
CHANGED
data/rspreadsheet.gemspec
CHANGED
@@ -18,8 +18,14 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
def self.package_installed?(pkgname)
|
22
|
+
system("dpkg-query -l #{pkgname} | grep -q '^i'")
|
23
|
+
end
|
24
|
+
|
21
25
|
# runtime dependencies
|
22
|
-
|
26
|
+
unless package_installed?('ruby-libxml')
|
27
|
+
spec.add_runtime_dependency 'libxml-ruby', '~>2.7' # parsing XML files
|
28
|
+
end
|
23
29
|
spec.add_runtime_dependency 'rubyzip', '~>1.1' # opening zip files
|
24
30
|
spec.add_runtime_dependency 'andand', '~>1.3'
|
25
31
|
|
@@ -32,8 +38,14 @@ Gem::Specification.new do |spec|
|
|
32
38
|
|
33
39
|
# optional and testing
|
34
40
|
spec.add_development_dependency "coveralls", '~>0.7'
|
35
|
-
|
36
|
-
|
41
|
+
|
42
|
+
if RUBY_VERSION.split('.')[0] != "1"
|
43
|
+
# ruby_dep starts to require ruby 2.2.5 which raises errors with ruby 1.9.3
|
44
|
+
# spec.add_development_dependency "guard", '~>2.13'
|
45
|
+
# spec.add_development_dependency "guard-rspec", '~>4.6'
|
46
|
+
end
|
47
|
+
|
37
48
|
# spec.add_development_dependency 'equivalent-xml' # implementing xml diff
|
38
49
|
|
39
50
|
end
|
51
|
+
|
data/spec/cell_spec.rb
CHANGED
@@ -269,6 +269,21 @@ describe Rspreadsheet::Cell do
|
|
269
269
|
@cell.value.month.should eq 1
|
270
270
|
@cell.value.day.should eq 2
|
271
271
|
end
|
272
|
+
it 'stores time correctly' do
|
273
|
+
@cell = @sheet1.cell(1,1)
|
274
|
+
@cell.value= Time.parse('2:42 pm')
|
275
|
+
@cell.value.hour.should eq 14
|
276
|
+
@cell.value.min.should eq 42
|
277
|
+
@cell.value.sec.should eq 0
|
278
|
+
end
|
279
|
+
it 'can read various types of times', :pending => 'see is' do
|
280
|
+
raise @sheet2.cell('D23').xml.inspect
|
281
|
+
expect {@cell = @sheet2.cell('D22'); @cell.value }.not_to raise_error
|
282
|
+
expect {@cell = @sheet2.cell('D23'); @cell.value }.not_to raise_error
|
283
|
+
|
284
|
+
@cell.value.should == Time.new(2005,5,5,3,33,00)
|
285
|
+
end
|
286
|
+
|
272
287
|
it 'can be addressed by even more ways and all are identical' do
|
273
288
|
@cell = @sheet1.cell(2,2)
|
274
289
|
@sheet1.cell('B2').value = 'zaseste'
|
@@ -292,10 +307,14 @@ describe Rspreadsheet::Cell do
|
|
292
307
|
@cell.format.bold = true
|
293
308
|
@cell.format.bold.should be_truthy
|
294
309
|
@cell.mode.should eq :regular
|
310
|
+
|
311
|
+
@cell = @sheet1.cell(2,2)
|
312
|
+
@cell.format.background_color = '#ffeeaa'
|
313
|
+
@cell.format.background_color.should == '#ffeeaa'
|
314
|
+
@cell.mode.should eq :regular
|
295
315
|
end
|
296
316
|
it 'remembers formula when set' do
|
297
317
|
@cell = @sheet1.cell(1,1)
|
298
|
-
# bold
|
299
318
|
@cell.formula.should be_nil
|
300
319
|
@cell.formula='=1+5'
|
301
320
|
@cell.formula.should eq '=1+5'
|
@@ -327,4 +346,66 @@ describe Rspreadsheet::Cell do
|
|
327
346
|
@czkcell.value.should == 344.to_d
|
328
347
|
@czkcell.format.currency.should == 'CZK'
|
329
348
|
end
|
349
|
+
it 'is possible to manipulate borders of cells' do
|
350
|
+
@cell = @sheet1.cell(1,1)
|
351
|
+
|
352
|
+
[@cell.format.top,@cell.format.left,@cell.format.right,@cell.format.bottom].each do |border|
|
353
|
+
border.style = 'dashed'
|
354
|
+
border.style.should == 'dashed'
|
355
|
+
border.width = 0.5
|
356
|
+
border.width.should == 0.5
|
357
|
+
border.color = '#005500'
|
358
|
+
border.color.should == '#005500'
|
359
|
+
end
|
360
|
+
end
|
361
|
+
it 'returns correct border parameters for the cell' do
|
362
|
+
@sheet2.cell('C8').format.top.style.should == 'solid'
|
363
|
+
@sheet2.cell('E8').format.left.color.should == '#ff3333'
|
364
|
+
@sheet2.cell('E8').format.left.style.should == 'solid'
|
365
|
+
@sheet2.cell('F8').format.top.color.should == '#009900'
|
366
|
+
@sheet2.cell('F8').format.top.style.should == 'dotted'
|
367
|
+
end
|
368
|
+
it 'modifies borders correctly' do
|
369
|
+
## initially solid everywhere
|
370
|
+
@sheet2.cell('C8').format.top.style.should == 'solid'
|
371
|
+
@sheet2.cell('C8').format.bottom.style.should == 'solid'
|
372
|
+
@sheet2.cell('C8').format.left.style.should == 'solid'
|
373
|
+
@sheet2.cell('C8').format.right.style.should == 'solid'
|
374
|
+
## change top and right to dotted and observe
|
375
|
+
@sheet2.cell('C8').format.top.style = 'dotted'
|
376
|
+
@sheet2.cell('C8').format.right.style = 'dotted'
|
377
|
+
@sheet2.cell('C8').format.bottom.style.should == 'solid'
|
378
|
+
@sheet2.cell('C8').format.left.style.should == 'solid'
|
379
|
+
@sheet2.cell('C8').format.top.style.should == 'dotted'
|
380
|
+
@sheet2.cell('C8').format.right.style.should == 'dotted'
|
381
|
+
end
|
382
|
+
it 'deletes borders correctly', :pending=> 'consider how to deal with deleted borders' do
|
383
|
+
@cell = @sheet1.cell(1,1)
|
384
|
+
|
385
|
+
[@cell.format.top,@cell.format.left,@cell.format.right,@cell.format.bottom].each do |border|
|
386
|
+
border.style = 'dashed'
|
387
|
+
border.should_not be_nil
|
388
|
+
border.delete
|
389
|
+
border.should be_nil
|
390
|
+
end
|
391
|
+
|
392
|
+
# delete right border in existing file and observe
|
393
|
+
@sheet2.cell('C8').format.right.delete
|
394
|
+
@sheet2.cell('C8').format.right.should == nil
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'can delete borders in many ways', :pending => 'consider what syntax to support' do
|
398
|
+
@cell=@sheet2.cell('C8')
|
399
|
+
@cell.border_right.should_not be_nil
|
400
|
+
@cell.border_right.delete
|
401
|
+
@cell.border_right.should be_nil
|
402
|
+
|
403
|
+
@cell.border_left.should_not be_nil
|
404
|
+
@cell.border_left = nil
|
405
|
+
@cell.border_left.should be_nil
|
406
|
+
|
407
|
+
@cell.format.top.should_not_be_nil
|
408
|
+
@cell.format.top.style = 'none'
|
409
|
+
@cell.border_top.should_not be_nil ## ?????
|
410
|
+
end
|
330
411
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
if RUBY_VERSION > '2.1'
|
4
|
+
# testing ClassExtensionsForSpec
|
5
|
+
describe LibXML::XML::Node do
|
6
|
+
before do
|
7
|
+
@n = LibXML::XML::Node.new('a')
|
8
|
+
@n << LibXML::XML::Node.new('i','italic')
|
9
|
+
b = LibXML::XML::Node.new('p','paragraph')
|
10
|
+
b << LibXML::XML::Node.new('b','boldtext')
|
11
|
+
@n << b
|
12
|
+
@n << LibXML::XML::Node.new_text('textnode')
|
13
|
+
|
14
|
+
@m = LibXML::XML::Node.new('a')
|
15
|
+
@m << LibXML::XML::Node.new('i','italic')
|
16
|
+
c = LibXML::XML::Node.new('p','paragraph')
|
17
|
+
c << LibXML::XML::Node.new('b','boldtext')
|
18
|
+
@m << c
|
19
|
+
@m << LibXML::XML::Node.new_text('textnode')
|
20
|
+
|
21
|
+
@m2 = LibXML::XML::Node.new('a')
|
22
|
+
end
|
23
|
+
it 'can compare nodes' do
|
24
|
+
@n.should == @m
|
25
|
+
@n.should_not == @m2
|
26
|
+
end
|
27
|
+
it 'has correct elements' do
|
28
|
+
# raise @n.first_diff(@m).inspect
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# testing ClassExtensions
|
33
|
+
begin
|
34
|
+
using ClassExtensions
|
35
|
+
|
36
|
+
describe Array do
|
37
|
+
it 'can sum simple array' do
|
38
|
+
a = [1,2,3,4]
|
39
|
+
a.sum.should == 10
|
40
|
+
end
|
41
|
+
it 'ignores text and nils while summing' do
|
42
|
+
a = [1,nil, nil,2,3,'foo',5.0]
|
43
|
+
a.sum.should == 11
|
44
|
+
[nil, 'nic'].sum.should == 0
|
45
|
+
[].sum.should == 0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|