coopy 0.6.4.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +7 -0
- data/LICENSE.md +22 -0
- data/README.md +59 -0
- data/Rakefile +4 -6
- data/coopy.gemspec +26 -0
- data/lib/coopy.rb +32 -175
- data/lib/coopy/alignment.rb +260 -0
- data/lib/coopy/bag.rb +17 -0
- data/lib/coopy/cell_info.rb +24 -0
- data/lib/coopy/change_type.rb +10 -0
- data/lib/coopy/compare_flags.rb +62 -0
- data/lib/coopy/compare_table.rb +327 -0
- data/lib/coopy/coopy.rb +22 -0
- data/lib/coopy/cross_match.rb +10 -0
- data/lib/coopy/csv_table.rb +51 -0
- data/lib/coopy/diff_render.rb +307 -0
- data/lib/coopy/index.rb +73 -0
- data/lib/coopy/index_item.rb +17 -0
- data/lib/coopy/index_pair.rb +72 -0
- data/lib/coopy/mover.rb +123 -0
- data/lib/coopy/ordering.rb +27 -0
- data/lib/coopy/row.rb +9 -0
- data/lib/coopy/simple_cell.rb +15 -0
- data/lib/coopy/simple_table.rb +144 -0
- data/lib/coopy/simple_view.rb +36 -0
- data/lib/coopy/table.rb +44 -0
- data/lib/coopy/table_comparison_state.rb +33 -0
- data/lib/coopy/table_diff.rb +634 -0
- data/lib/coopy/table_text.rb +14 -0
- data/lib/coopy/table_view.rb +31 -0
- data/lib/coopy/unit.rb +53 -0
- data/lib/coopy/version.rb +3 -0
- data/lib/coopy/view.rb +34 -0
- data/spec/fixtures/bridges.html +10 -0
- data/spec/fixtures/bridges_diff.csv +8 -0
- data/spec/fixtures/bridges_new.csv +9 -0
- data/spec/fixtures/bridges_old.csv +9 -0
- data/spec/fixtures/planetary_bodies.html +22 -0
- data/spec/fixtures/planetary_bodies_diff.csv +19 -0
- data/spec/fixtures/planetary_bodies_new.csv +20 -0
- data/spec/fixtures/planetary_bodies_old.csv +19 -0
- data/spec/fixtures/quote_me.csv +10 -0
- data/spec/fixtures/quote_me2.csv +11 -0
- data/spec/integration/table_diff_spec.rb +57 -0
- data/spec/libs/compare_flags_spec.rb +40 -0
- data/spec/libs/coopy_spec.rb +14 -0
- data/spec/libs/ordering_spec.rb +28 -0
- data/spec/libs/unit_spec.rb +31 -0
- data/spec/spec_helper.rb +29 -0
- metadata +153 -46
- data/bin/sqlite_diff +0 -4
- data/bin/sqlite_patch +0 -4
- data/bin/sqlite_rediff +0 -4
- data/lib/coopy/dbi_sql_wrapper.rb +0 -89
- data/lib/coopy/diff_apply_sql.rb +0 -35
- data/lib/coopy/diff_columns.rb +0 -33
- data/lib/coopy/diff_output.rb +0 -21
- data/lib/coopy/diff_output_action.rb +0 -34
- data/lib/coopy/diff_output_group.rb +0 -40
- data/lib/coopy/diff_output_raw.rb +0 -17
- data/lib/coopy/diff_output_stats.rb +0 -45
- data/lib/coopy/diff_output_table.rb +0 -49
- data/lib/coopy/diff_output_tdiff.rb +0 -48
- data/lib/coopy/diff_parser.rb +0 -92
- data/lib/coopy/diff_render_csv.rb +0 -29
- data/lib/coopy/diff_render_html.rb +0 -74
- data/lib/coopy/diff_render_log.rb +0 -52
- data/lib/coopy/row_change.rb +0 -25
- data/lib/coopy/scraperwiki_sql_wrapper.rb +0 -8
- data/lib/coopy/scraperwiki_utils.rb +0 -23
- data/lib/coopy/sequel_sql_wrapper.rb +0 -73
- data/lib/coopy/sql_compare.rb +0 -222
- data/lib/coopy/sql_wrapper.rb +0 -34
- data/lib/coopy/sqlite_sql_wrapper.rb +0 -143
- data/test/test_coopy.rb +0 -126
@@ -0,0 +1,31 @@
|
|
1
|
+
module Coopy
|
2
|
+
class TableView
|
3
|
+
include Coopy::View
|
4
|
+
|
5
|
+
def to_s(d)
|
6
|
+
d.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def get_bag(d)
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_table(d)
|
14
|
+
d
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_structure?(d)
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
def equals(d1, d2)
|
22
|
+
puts("TableView#equals called")
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_datum(str)
|
27
|
+
Coopy::SimpleCell.new(str)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/coopy/unit.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
module Coopy
|
2
|
+
|
3
|
+
class Unit
|
4
|
+
|
5
|
+
attr_accessor :l # integer
|
6
|
+
attr_accessor :r # integer
|
7
|
+
attr_accessor :p # integer
|
8
|
+
|
9
|
+
def initialize(l = -2, r = -2, p = -2)
|
10
|
+
@l = l;
|
11
|
+
@r = r;
|
12
|
+
@p = p;
|
13
|
+
end
|
14
|
+
|
15
|
+
def lp
|
16
|
+
(@p==-2) ? @l : @p
|
17
|
+
end
|
18
|
+
|
19
|
+
def describe(i)
|
20
|
+
(i>=0) ? ("" + i.to_s) : "-"
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_s
|
24
|
+
return describe(@p) + "|" + describe(@l) + ":" + describe(@r) if (@p>=-1)
|
25
|
+
describe(@l) + ":" + describe(@r)
|
26
|
+
end
|
27
|
+
|
28
|
+
def from_string(txt)
|
29
|
+
txt += "]"
|
30
|
+
at = 0
|
31
|
+
txt.each_char do |ch|
|
32
|
+
case ch
|
33
|
+
when /[0-9]/
|
34
|
+
at *= 10;
|
35
|
+
at += ch.to_i
|
36
|
+
when '-'
|
37
|
+
at = -1
|
38
|
+
when '|'
|
39
|
+
@p = at
|
40
|
+
at = 0
|
41
|
+
when ':'
|
42
|
+
@l = at
|
43
|
+
at = 0
|
44
|
+
when ']'
|
45
|
+
@r = at
|
46
|
+
return true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/lib/coopy/view.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Coopy
|
2
|
+
|
3
|
+
# Optimize access to arrays of primitives, avoid needing
|
4
|
+
# each item to be wrapped individually in some kind of access object.
|
5
|
+
# Anticipate future optimization with view pools.
|
6
|
+
|
7
|
+
module View
|
8
|
+
|
9
|
+
def to_s(d)
|
10
|
+
raise NotImplementedError
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_bag(d)
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_table(d)
|
18
|
+
raise NotImplementedError
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_structure?(d)
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
def equals(d1, d2)
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_datum(str)
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<table>
|
2
|
+
<tr><th>@@</th><th>bridge</th><th>designer</th><th>length</th></tr>
|
3
|
+
<tr><td></td><td>Brooklyn</td><td>J. A. Roebling</td><td>1595</td></tr>
|
4
|
+
<tr class="add"><td>+++</td><td>Manhattan</td><td>G. Lindenthal</td><td>1470</td></tr>
|
5
|
+
<tr class="modify"><td class="modify">→</td><td>Williamsburg</td><td class="modify">D. Duck→L. L. Buck</td><td>1600</td></tr>
|
6
|
+
<tr><td></td><td>Queensborough</td><td>Palmer & Hornbostel</td><td>1182</td></tr>
|
7
|
+
<tr><td>...</td><td>...</td><td>...</td><td>...</td></tr>
|
8
|
+
<tr><td></td><td>George Washington</td><td>O. H. Ammann</td><td>3500</td></tr>
|
9
|
+
<tr class="remove"><td>---</td><td>Spamspan</td><td>S. Spamington</td><td>10000</td></tr>
|
10
|
+
</table>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
@@,bridge,designer,length
|
2
|
+
NULL,Brooklyn,"J. A. Roebling",1595
|
3
|
+
+++,Manhattan,"G. Lindenthal",1470
|
4
|
+
->,Williamsburg,"D. Duck->L. L. Buck",1600
|
5
|
+
NULL,Queensborough,"Palmer & Hornbostel",1182
|
6
|
+
...,...,...,...
|
7
|
+
NULL,"George Washington","O. H. Ammann",3500
|
8
|
+
---,Spamspan,"S. Spamington",10000
|
@@ -0,0 +1,9 @@
|
|
1
|
+
bridge,designer,length
|
2
|
+
Brooklyn,J. A. Roebling,1595
|
3
|
+
Manhattan,G. Lindenthal,1470
|
4
|
+
Williamsburg,L. L. Buck,1600
|
5
|
+
Queensborough,Palmer & Hornbostel,1182
|
6
|
+
Triborough,O. H. Ammann,"1380,383"
|
7
|
+
Bronx Whitestone,O. H. Ammann,2300
|
8
|
+
Throgs Neck,O. H. Ammann,1800
|
9
|
+
George Washington,O. H. Ammann,3500
|
@@ -0,0 +1,9 @@
|
|
1
|
+
bridge,designer,length
|
2
|
+
Brooklyn,J. A. Roebling,1595
|
3
|
+
Williamsburg,D. Duck,1600
|
4
|
+
Queensborough,Palmer & Hornbostel,1182
|
5
|
+
Triborough,O. H. Ammann,"1380,383"
|
6
|
+
Bronx Whitestone,O. H. Ammann,2300
|
7
|
+
Throgs Neck,O. H. Ammann,1800
|
8
|
+
George Washington,O. H. Ammann,3500
|
9
|
+
Spamspan,S. Spamington,10000
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<table>
|
2
|
+
<tr class="spec"><td>!</td><td></td><td class="add">+++</td><td></td></tr>
|
3
|
+
<tr><th>@@</th><th>planetary_body</th><th class="add">aphelion</th><th>acceleration</th></tr>
|
4
|
+
<tr><td>+</td><td>Earth</td><td class="add">152098232</td><td>9.80665</td></tr>
|
5
|
+
<tr><td></td><td>Moon</td><td class="add"></td><td>1.625</td></tr>
|
6
|
+
<tr><td>+</td><td>Sun</td><td class="add">0</td><td>274.1</td></tr>
|
7
|
+
<tr class="add"><td>+++</td><td>Mercury</td><td class="add">69816900</td><td>3.7</td></tr>
|
8
|
+
<tr><td>+</td><td>Venus</td><td class="add">108939000</td><td>8.872</td></tr>
|
9
|
+
<tr><td>+</td><td>Mars</td><td class="add">249209300</td><td>3.78</td></tr>
|
10
|
+
<tr><td>+</td><td>Jupiter</td><td class="add">816520800</td><td>25.93</td></tr>
|
11
|
+
<tr><td></td><td>Io</td><td class="add"></td><td>1.789</td></tr>
|
12
|
+
<tr><td>...</td><td>...</td><td class="add">...</td><td>...</td></tr>
|
13
|
+
<tr><td></td><td>Callisto</td><td class="add"></td><td>1.24</td></tr>
|
14
|
+
<tr><td>+</td><td>Saturn</td><td class="add">1513325783</td><td>11.19</td></tr>
|
15
|
+
<tr><td></td><td>Titan</td><td class="add"></td><td>1.3455</td></tr>
|
16
|
+
<tr><td>+</td><td>Uranus</td><td class="add">3004419704</td><td>9.01</td></tr>
|
17
|
+
<tr><td></td><td>Titania</td><td class="add"></td><td>0.379</td></tr>
|
18
|
+
<tr><td></td><td>Oberon</td><td class="add"></td><td>0.347</td></tr>
|
19
|
+
<tr><td>+</td><td>Neptune</td><td class="add">4553946490</td><td>11.28</td></tr>
|
20
|
+
<tr class="modify"><td class="modify">→</td><td>Triton</td><td class="add"></td><td class="modify"> 0.779→0.779</td></tr>
|
21
|
+
<tr class="modify"><td class="modify">→</td><td>Pluto</td><td class="add">7311000000</td><td class="modify"> 0.61→0.61</td></tr>
|
22
|
+
</table>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
!,NULL,+++,NULL
|
2
|
+
@@,planetary_body,aphelion,acceleration
|
3
|
+
+,Earth,152098232,9.80665
|
4
|
+
NULL,Moon,NULL,1.625
|
5
|
+
+,Sun,0,274.1
|
6
|
+
+++,Mercury,69816900,3.7
|
7
|
+
+,Venus,108939000,8.872
|
8
|
+
+,Mars,249209300,3.78
|
9
|
+
+,Jupiter,816520800,25.93
|
10
|
+
NULL,Io,NULL,1.789
|
11
|
+
...,...,...,...
|
12
|
+
NULL,Callisto,NULL,1.24
|
13
|
+
+,Saturn,1513325783,11.19
|
14
|
+
NULL,Titan,NULL,1.3455
|
15
|
+
+,Uranus,3004419704,9.01
|
16
|
+
NULL,Titania,NULL,0.379
|
17
|
+
NULL,Oberon,NULL,0.347
|
18
|
+
+,Neptune,4553946490,11.28
|
19
|
+
->,Triton,NULL," 0.779->0.779"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
planetary_body,aphelion,acceleration
|
2
|
+
"Earth",152098232,9.80665
|
3
|
+
"Moon",,1.625
|
4
|
+
"Sun",0,274.1
|
5
|
+
"Mercury",69816900,3.7
|
6
|
+
"Venus",108939000,8.872
|
7
|
+
"Mars",249209300,3.78
|
8
|
+
"Jupiter",816520800,25.93
|
9
|
+
"Io",,1.789
|
10
|
+
"Europa",,1.314
|
11
|
+
"Ganymede",,1.426
|
12
|
+
"Callisto",,1.24
|
13
|
+
"Saturn",1513325783,11.19
|
14
|
+
"Titan",,1.3455
|
15
|
+
"Uranus",3004419704,9.01
|
16
|
+
"Titania",,0.379
|
17
|
+
"Oberon",,0.347
|
18
|
+
"Neptune",4553946490,11.28
|
19
|
+
"Triton",,0.779
|
20
|
+
"Pluto",7311000000,0.61
|
@@ -0,0 +1,19 @@
|
|
1
|
+
planetary_body,acceleration
|
2
|
+
"Earth",9.80665
|
3
|
+
"Moon",1.625
|
4
|
+
"Sun",274.1
|
5
|
+
"Venus",8.872
|
6
|
+
"Mars",3.78
|
7
|
+
"Jupiter",25.93
|
8
|
+
"Io",1.789
|
9
|
+
"Europa",1.314
|
10
|
+
"Ganymede",1.426
|
11
|
+
"Callisto",1.24
|
12
|
+
"Saturn",11.19
|
13
|
+
"Titan",1.3455
|
14
|
+
"Uranus",9.01
|
15
|
+
"Titania",0.379
|
16
|
+
"Oberon",0.347
|
17
|
+
"Neptune",11.28
|
18
|
+
"Triton", 0.779
|
19
|
+
"Pluto", 0.61
|
@@ -0,0 +1,10 @@
|
|
1
|
+
this,is,a,sheet
|
2
|
+
with,some,odd,values
|
3
|
+
in,cells,"->",":"
|
4
|
+
you,"see?","123""",
|
5
|
+
what,about null,NULL,_NULL
|
6
|
+
and,"new
|
7
|
+
lines","how, really,
|
8
|
+
about","them?"
|
9
|
+
"and 'embedded'","quotes it's","fun","""fun"""
|
10
|
+
"!HELLO!","my!","!friend","the!exclamation!mark"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
this,is,a,sheet
|
2
|
+
with,some,odd,values
|
3
|
+
in,"->",cells,"bob | mcdonald"
|
4
|
+
you,"see?...","Indeed",
|
5
|
+
what,about NULL,_NULL,NULL
|
6
|
+
and,"new
|
7
|
+
so very new
|
8
|
+
lines","how
|
9
|
+
about","them?"
|
10
|
+
"and 'embedded'","'quotes' it's","'fun'","fun"
|
11
|
+
"!!HELLO!!","my","!friend","the!!exclamationmark"
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "diffing tables" do
|
4
|
+
|
5
|
+
[
|
6
|
+
"bridges",
|
7
|
+
"planetary_bodies",
|
8
|
+
].each do |name|
|
9
|
+
|
10
|
+
it "should generate correct diff for #{name}" do
|
11
|
+
|
12
|
+
old_table = Coopy::CsvTable.new(CSV.parse(load_fixture("#{name}_old.csv")))
|
13
|
+
new_table = Coopy::CsvTable.new(CSV.parse(load_fixture("#{name}_new.csv")))
|
14
|
+
|
15
|
+
alignment = Coopy.compare_tables(old_table,new_table).align
|
16
|
+
|
17
|
+
table_diff = Coopy::SimpleTable.new(0,0)
|
18
|
+
|
19
|
+
flags = Coopy::CompareFlags.new
|
20
|
+
highlighter = Coopy::TableDiff.new(alignment,flags)
|
21
|
+
highlighter.hilite table_diff
|
22
|
+
|
23
|
+
expected_diff = CSV.parse(load_fixture("#{name}_diff.csv"))
|
24
|
+
expected_diff.each_with_index do |row, row_index|
|
25
|
+
row.each_with_index do |cell, col_index|
|
26
|
+
expected = table_diff.get_cell(col_index, row_index).to_s
|
27
|
+
got = cell.to_s
|
28
|
+
got = '' if got == "NULL"
|
29
|
+
expected.should eql(got), "row:#{row_index} col:#{col_index} was '#{got}' instead of '#{expected}'"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should generate correct HTML for #{name}" do
|
36
|
+
|
37
|
+
old_table = Coopy::CsvTable.new(CSV.parse(load_fixture("#{name}_old.csv")))
|
38
|
+
new_table = Coopy::CsvTable.new(CSV.parse(load_fixture("#{name}_new.csv")))
|
39
|
+
|
40
|
+
alignment = Coopy.compare_tables(old_table,new_table).align
|
41
|
+
|
42
|
+
table_diff = Coopy::SimpleTable.new(0,0)
|
43
|
+
|
44
|
+
flags = Coopy::CompareFlags.new
|
45
|
+
highlighter = Coopy::TableDiff.new(alignment,flags)
|
46
|
+
highlighter.hilite table_diff
|
47
|
+
|
48
|
+
diff2html = Coopy::DiffRender.new
|
49
|
+
diff2html.render table_diff
|
50
|
+
diff_html = diff2html.html
|
51
|
+
|
52
|
+
diff_html.should == load_fixture("#{name}.html")
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Coopy::CompareFlags do
|
4
|
+
|
5
|
+
context "action settings" do
|
6
|
+
|
7
|
+
it "should allow all by default" do
|
8
|
+
flags = Coopy::CompareFlags.new
|
9
|
+
flags.allow_update.should be_true
|
10
|
+
flags.allow_insert.should be_true
|
11
|
+
flags.allow_delete.should be_true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should allow update if set" do
|
15
|
+
flags = Coopy::CompareFlags.new
|
16
|
+
flags.acts = {"update" => true}
|
17
|
+
flags.allow_update.should be_true
|
18
|
+
flags.allow_insert.should be_false
|
19
|
+
flags.allow_delete.should be_false
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should allow insert if set" do
|
23
|
+
flags = Coopy::CompareFlags.new
|
24
|
+
flags.acts = {"insert" => true}
|
25
|
+
flags.allow_update.should be_false
|
26
|
+
flags.allow_insert.should be_true
|
27
|
+
flags.allow_delete.should be_false
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should allow delete if set" do
|
31
|
+
flags = Coopy::CompareFlags.new
|
32
|
+
flags.acts = {"delete" => true}
|
33
|
+
flags.allow_update.should be_false
|
34
|
+
flags.allow_insert.should be_false
|
35
|
+
flags.allow_delete.should be_true
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Coopy::Ordering do
|
4
|
+
|
5
|
+
it "should convert order to string correctly" do
|
6
|
+
# test default behaviour
|
7
|
+
o = Coopy::Ordering.new
|
8
|
+
o.to_s.should == ''
|
9
|
+
# add a couple of units
|
10
|
+
o.add 1,2,3
|
11
|
+
o.add 3,2,1
|
12
|
+
o.to_s.should == "3|1:2, 1|3:2"
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should not ignore parent if not set" do
|
16
|
+
o = Coopy::Ordering.new
|
17
|
+
o.add 1,2,3
|
18
|
+
o.to_s.should == "3|1:2"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should ignore parent if set" do
|
22
|
+
o = Coopy::Ordering.new
|
23
|
+
o.ignore_parent
|
24
|
+
o.add 1,2,3
|
25
|
+
o.to_s.should == "1:2"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Coopy::Unit do
|
4
|
+
|
5
|
+
context "string conversion" do
|
6
|
+
|
7
|
+
[
|
8
|
+
[3,2,1],
|
9
|
+
[1,2,3],
|
10
|
+
[1,2,-2],
|
11
|
+
[3,2,-1],
|
12
|
+
[0,1,0],
|
13
|
+
].each do |lrp|
|
14
|
+
|
15
|
+
it "should marshall strings in and out correctly (#{lrp.to_s})" do
|
16
|
+
|
17
|
+
u = Coopy::Unit.new lrp[0], lrp[1], lrp[2]
|
18
|
+
str = u.to_s
|
19
|
+
|
20
|
+
nu = Coopy::Unit.new
|
21
|
+
nu.from_string(str).should be_true
|
22
|
+
|
23
|
+
u.l.should == nu.l
|
24
|
+
u.r.should == nu.r
|
25
|
+
u.p.should == nu.p
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|