rsxml 0.1.4 → 0.2.0
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.
- data/README.rdoc +47 -6
- data/VERSION +1 -1
- data/lib/rsxml.rb +23 -149
- data/lib/rsxml/namespace.rb +175 -0
- data/lib/rsxml/sexp.rb +90 -0
- data/lib/rsxml/util.rb +25 -0
- data/lib/rsxml/visitor.rb +132 -0
- data/lib/rsxml/xml.rb +99 -0
- data/spec/rsxml/namespace_spec.rb +250 -0
- data/spec/rsxml/sexp_spec.rb +15 -0
- data/spec/rsxml/util_spec.rb +41 -0
- data/spec/rsxml/visitor_spec.rb +82 -0
- data/spec/rsxml/xml_spec.rb +68 -0
- data/spec/rsxml_spec.rb +88 -32
- metadata +20 -5
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Rsxml
|
4
|
+
describe Util do
|
5
|
+
describe "check_opts" do
|
6
|
+
it "should permit a nil opts Hash" do
|
7
|
+
Util.check_opts({}, nil).should == {}
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should return an equals opts Hash" do
|
11
|
+
Util.check_opts({:foo=>nil}, {:foo=>10}).should == {:foo=>10}
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should raise an exception if an opt is given with no matching constraint" do
|
15
|
+
lambda {
|
16
|
+
Util.check_opts({:foo=>nil}, {:bar=>10})
|
17
|
+
}.should raise_error(/not permitted: :bar/)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should raise an exception if the value of an opt with an Array constraint is not in the Array" do
|
21
|
+
lambda {
|
22
|
+
Util.check_opts({:foo=>[1,2,3]}, {:foo=>10})
|
23
|
+
}.should raise_error(/unknown value/)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should permit an opt with an Array constraint to have a nil value" do
|
27
|
+
Util.check_opts({:foo=>[1,2,3]}, {}).should == {}
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should check_opts for opts with Hash constraints" do
|
31
|
+
lambda {
|
32
|
+
Util.check_opts({:foo=>{:bar=>[1,2,3]}}, {:foo=>{:bar=>10}})
|
33
|
+
}.should raise_error(/unknown value/)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should permit sub-hashes to be skipped with a nil value" do
|
37
|
+
Util.check_opts({:foo=>{:bar=>10}}, {}).should == {}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Rsxml
|
4
|
+
describe Visitor::WriteXmlVisitor do
|
5
|
+
it "should write single element xml" do
|
6
|
+
Sexp::traverse(["item"], Visitor::WriteXmlVisitor.new).to_s.should == "<item></item>"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should write single element xml with attributes" do
|
10
|
+
Sexp::traverse([:item, {:foo=>"100"}], Visitor::WriteXmlVisitor.new).to_s.should == '<item foo="100"></item>'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should write nested elements with attributes and text content" do
|
14
|
+
Sexp::traverse([:item, {:foo=>"100"}, [:bar], "foofoo", [:baz]], Visitor::WriteXmlVisitor.new).to_s.should == '<item foo="100"><bar></bar>foofoo<baz></baz></item>'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should permit lazy declaration of namespces" do
|
18
|
+
root = Nokogiri::XML(Sexp::traverse([[:bar, "foo", "http://foo.com/foo"], {"foo:foofoo"=>"fff"}], Visitor::WriteXmlVisitor.new).to_s).children.first
|
19
|
+
root.namespaces.should == {"xmlns:foo"=>"http://foo.com/foo"}
|
20
|
+
|
21
|
+
root.name.should == 'bar'
|
22
|
+
root.namespace.prefix.should == 'foo'
|
23
|
+
root.namespace.href.should == 'http://foo.com/foo'
|
24
|
+
|
25
|
+
root.attributes["foofoo"].value.should == "fff"
|
26
|
+
root.attributes["foofoo"].namespace.prefix.should == 'foo'
|
27
|
+
root.attributes["foofoo"].namespace.href.should == 'http://foo.com/foo'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe Visitor::BuildRsxmlVisitor do
|
32
|
+
describe "strip_namespace_decls" do
|
33
|
+
it "should remove default and prefixed namespace decls from exploded attributes" do
|
34
|
+
Visitor::BuildRsxmlVisitor.new.strip_namespace_decls({"xmlns"=>"http://default.com/default",
|
35
|
+
["foo", "xmlns"]=>"http://foo.com/foo",
|
36
|
+
["bar", "foo", "http://foo.com/foo"]=>"barbar",
|
37
|
+
"baz"=>"bazbaz"}).should ==
|
38
|
+
{["bar", "foo", "http://foo.com/foo"]=>"barbar",
|
39
|
+
"baz"=>"bazbaz"}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "compact_qname" do
|
44
|
+
it "should compact exploded qnames" do
|
45
|
+
Visitor::BuildRsxmlVisitor.new.compact_qname(["foo", "bar", "http://bar.com/bar"]).should ==
|
46
|
+
"bar:foo"
|
47
|
+
Visitor::BuildRsxmlVisitor.new.compact_qname("foo").should ==
|
48
|
+
"foo"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "compact_attr_names" do
|
53
|
+
it "should compact exploded attribute names" do
|
54
|
+
Visitor::BuildRsxmlVisitor.new.compact_attr_names({["foo", "bar", "http://bar.com/bar"]=>"foofoo", "baz"=>"bazbaz", ["foofoo", "bar"]=>"fff"}).should ==
|
55
|
+
{"bar:foo"=>"foofoo", "baz"=>"bazbaz", "bar:foofoo"=>"fff"}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "tag" do
|
60
|
+
it "should append the rsxml tag to the cursor element and yield" do
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "text" do
|
65
|
+
it "should append the text to the cursor element" do
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should read a single element document" do
|
70
|
+
root = Nokogiri::XML('<foo></foo>').children.first
|
71
|
+
rsxml = Rsxml::Xml.traverse(root, Visitor::BuildRsxmlVisitor.new).sexp
|
72
|
+
rsxml.should == ["foo"]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should read a single element document with attributes" do
|
76
|
+
root = Nokogiri::XML('<foo bar="10" baz="20"></foo>').children.first
|
77
|
+
rsxml = Rsxml::Xml.traverse(root, Visitor::BuildRsxmlVisitor.new).sexp
|
78
|
+
rsxml.should == ["foo", {"bar"=>"10", "baz"=>"20"}]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.expand_path("../../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
module Rsxml
|
4
|
+
describe "wrap_fragment" do
|
5
|
+
it "should do nothing if there are no ns_prefixes" do
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should wrap a fragment in a document with namespace declarations if there are ns prefixes" do
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "unwrap_fragment" do
|
13
|
+
it "should do nothing if there is no wrapping element" do
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should remove the outermost element if it is a wrapping element" do
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should throw an exception if it unwraps and there is more than one child" do
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "explode_node" do
|
24
|
+
it "should return the element name String if there is no namespace" do
|
25
|
+
node = Object.new
|
26
|
+
stub(node).name{"foo"}
|
27
|
+
stub(node).namespace{nil}
|
28
|
+
Xml.explode_node(node).should == "foo"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should return the [local_name, prefix, uri] triple if there is a namespace" do
|
32
|
+
node = Object.new
|
33
|
+
stub(node).name{"foo"}
|
34
|
+
namespace = Object.new
|
35
|
+
stub(node).namespace{namespace}
|
36
|
+
stub(namespace).prefix{"bar"}
|
37
|
+
stub(namespace).href{"http://bar.com/bar"}
|
38
|
+
Xml.explode_node(node).should == ["foo", "bar", "http://bar.com/bar"]
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should return a [local_name, "", uri] triple if there is a default namespace" do
|
42
|
+
node = Object.new
|
43
|
+
stub(node).name{"foo"}
|
44
|
+
namespace = Object.new
|
45
|
+
stub(node).namespace{namespace}
|
46
|
+
stub(namespace).prefix{nil}
|
47
|
+
stub(namespace).href{"http://bar.com/bar"}
|
48
|
+
Xml.explode_node(node).should == ["foo", "", "http://bar.com/bar"]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "explode_element" do
|
53
|
+
it "should explode an element and it's attributes" do
|
54
|
+
root = Nokogiri::XML('<foo:bar a="aa" foo:b="bb" xmlns:foo="http://foo.com/foo" xmlns="http://default.com/default"></foo:bar>').children.first
|
55
|
+
|
56
|
+
eelement, eattrs = Rsxml::Xml.explode_element(root)
|
57
|
+
eelement.should == ["bar", "foo", "http://foo.com/foo"]
|
58
|
+
eattrs.should == {"a"=>"aa",
|
59
|
+
["b", "foo", "http://foo.com/foo"]=>"bb",
|
60
|
+
["foo", "xmlns"]=>"http://foo.com/foo",
|
61
|
+
"xmlns"=>"http://default.com/default"}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "traverse" do
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
data/spec/rsxml_spec.rb
CHANGED
@@ -6,6 +6,16 @@ describe Rsxml do
|
|
6
6
|
Rsxml.to_xml([:foo]).should == "<foo></foo>"
|
7
7
|
end
|
8
8
|
|
9
|
+
it "should produce a single-element doc with namespaces" do
|
10
|
+
Rsxml.to_xml([[:bar, :foo, "http://foo.com/foo"]]).should ==
|
11
|
+
'<foo:bar xmlns:foo="http://foo.com/foo"></foo:bar>'
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should produce a fragment without namespace declarations if ns bindings are provided" do
|
15
|
+
Rsxml.to_xml(["foo:bar", {["baz", "foo"]=>"bazbaz"}], :ns=>{"foo"=>"http://foo.com/foo"}).should ==
|
16
|
+
'<foo:bar foo:baz="bazbaz"></foo:bar>'
|
17
|
+
end
|
18
|
+
|
9
19
|
it "should produce a single-element doc with attrs" do
|
10
20
|
xml = Rsxml.to_xml([:foo, {:bar=>1, :baz=>"baz"}])
|
11
21
|
r = Nokogiri::XML(xml).children.first
|
@@ -14,6 +24,60 @@ describe Rsxml do
|
|
14
24
|
r["baz"].should == "baz"
|
15
25
|
end
|
16
26
|
|
27
|
+
it "should produce a single-element doc with element namespace attrs" do
|
28
|
+
xml = Rsxml.to_xml([[:bar, :foo, "http://foo.com/foo"], {:bar=>1, :baz=>"baz"}])
|
29
|
+
r = Nokogiri::XML(xml).children.first
|
30
|
+
r.name.should == "bar"
|
31
|
+
r.namespace.href.should == "http://foo.com/foo"
|
32
|
+
r.namespace.prefix.should == "foo"
|
33
|
+
|
34
|
+
r.attributes["bar"].namespace.should == nil
|
35
|
+
r["bar"].should == "1"
|
36
|
+
|
37
|
+
r.attributes["baz"].namespace.should == nil
|
38
|
+
r["baz"].should == "baz"
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should produce a single-element doc with namespace and attr namespaces" do
|
42
|
+
xml = Rsxml.to_xml([[:bar, :foo, "http://foo.com/foo"],
|
43
|
+
{[:barbar, :bar, "http://bar.com/bar"]=>1,
|
44
|
+
:baz=>"baz"}])
|
45
|
+
r = Nokogiri::XML(xml).children.first
|
46
|
+
|
47
|
+
r.name.should == "bar"
|
48
|
+
r.namespace.prefix.should == "foo"
|
49
|
+
r.namespace.href.should == "http://foo.com/foo"
|
50
|
+
|
51
|
+
barbar = r.attributes["barbar"]
|
52
|
+
barbar.namespace.prefix.should == "bar"
|
53
|
+
barbar.namespace.href.should == "http://bar.com/bar"
|
54
|
+
barbar.value.should == "1"
|
55
|
+
|
56
|
+
baz = r.attributes["baz"]
|
57
|
+
baz.namespace.should == nil
|
58
|
+
baz.value.should == "baz"
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should produce a single-element doc with default namespace and attr namespaces" do
|
62
|
+
xml = Rsxml.to_xml([[:bar, "", "http://foo.com/foo"],
|
63
|
+
{[:barbar, :bar, "http://bar.com/bar"]=>1,
|
64
|
+
:baz=>"baz"}])
|
65
|
+
r = Nokogiri::XML(xml).children.first
|
66
|
+
|
67
|
+
r.name.should == "bar"
|
68
|
+
r.namespace.prefix.should == nil
|
69
|
+
r.namespace.href.should == "http://foo.com/foo"
|
70
|
+
|
71
|
+
barbar = r.attributes["barbar"]
|
72
|
+
barbar.namespace.prefix.should == "bar"
|
73
|
+
barbar.namespace.href.should == "http://bar.com/bar"
|
74
|
+
barbar.value.should == "1"
|
75
|
+
|
76
|
+
baz = r.attributes["baz"]
|
77
|
+
baz.namespace.should == nil
|
78
|
+
baz.value.should == "baz"
|
79
|
+
end
|
80
|
+
|
17
81
|
it "should produce a doc with text content" do
|
18
82
|
xml = Rsxml.to_xml([:foo, "foofoo"])
|
19
83
|
r = Nokogiri::XML(xml).children.first
|
@@ -67,38 +131,13 @@ describe Rsxml do
|
|
67
131
|
r.attributes["baz"].namespace.href.should == "http://foo.com/foo"
|
68
132
|
r.attributes["baz"].namespace.prefix.should == "foo"
|
69
133
|
end
|
70
|
-
|
71
|
-
it "should transform a single tag if a transformer is supplied" do
|
72
|
-
xml = Rsxml.to_xml([:foo]) do |tag,attrs,path|
|
73
|
-
path.should == ""
|
74
|
-
[tag.upcase, attrs]
|
75
|
-
end.should ==
|
76
|
-
"<FOO></FOO>"
|
77
|
-
end
|
78
|
-
|
79
|
-
it "should transform nested tags if a transformer is supplied" do
|
80
|
-
txs = {"/foo"=>"Blub", "/foo[0]/bar"=>"Wub"}
|
81
|
-
xml = Rsxml.to_xml([:foo, [:bar]]) do |tag,attrs,path|
|
82
|
-
$stderr << [tag, attrs, path].inspect
|
83
|
-
[txs[[path, tag].join("/")], attrs]
|
84
|
-
end.should ==
|
85
|
-
"<Blub><Wub></Wub></Blub>"
|
86
|
-
end
|
87
|
-
|
88
|
-
it "should transform a tag with attributes if a transformer is supplied" do
|
89
|
-
xml = Rsxml.to_xml([:foo, {:bar=>"bar"}]) do |tag,attrs,path|
|
90
|
-
path.should == ""
|
91
|
-
[tag.upcase, Hash[*attrs.map{|k,v| [k.to_s.upcase,v]}.flatten]]
|
92
|
-
end.should ==
|
93
|
-
'<FOO BAR="bar"></FOO>'
|
94
|
-
|
95
|
-
end
|
96
134
|
end
|
97
135
|
|
98
136
|
describe "to_rsxml" do
|
137
|
+
|
99
138
|
def test_roundtrip(org)
|
100
139
|
xml = Rsxml.to_xml(org)
|
101
|
-
rsxml = Rsxml.to_rsxml(xml)
|
140
|
+
rsxml = Rsxml.to_rsxml(xml, :style=>:xml)
|
102
141
|
rsxml.should == org
|
103
142
|
end
|
104
143
|
|
@@ -126,14 +165,31 @@ describe Rsxml do
|
|
126
165
|
test_roundtrip(["foo:foofoo", {"xmlns:foo"=>"http://foo.com/foo", "foo:bar"=>"1", "foo:baz"=>"baz"}])
|
127
166
|
end
|
128
167
|
|
168
|
+
it "should parse a doc with namespaces and return exploded names if :style is :exploded" do
|
169
|
+
xml = Rsxml.to_xml(["foo:foofoo", {"xmlns:foo"=>"http://foo.com/foo", "foo:bar"=>"1", "foo:baz"=>"baz"}])
|
170
|
+
rsxml = Rsxml.to_rsxml(xml, :style=>:exploded)
|
171
|
+
rsxml.should == [["foofoo", "foo", "http://foo.com/foo"],
|
172
|
+
{ ["bar", "foo", "http://foo.com/foo"]=>"1",
|
173
|
+
["baz", "foo", "http://foo.com/foo"]=>"baz"}]
|
174
|
+
|
175
|
+
end
|
176
|
+
|
129
177
|
it "should allow namespace prefixes to be specified when parsing a fragment" do
|
130
|
-
|
131
|
-
xml =
|
178
|
+
org_no_ns = ["foofoo", {"foo:bar"=>"1", "foo:baz"=>"baz"}]
|
179
|
+
xml = '<foofoo foo:bar="1" foo:baz="baz"></foofoo>'
|
180
|
+
|
181
|
+
rsxml = Rsxml.to_rsxml(xml, :ns=>{:foo=>"http://foo.com/foo", ""=>"http://baz.com/baz"}, :style=>:xml)
|
182
|
+
|
183
|
+
rsxml.should == org_no_ns
|
184
|
+
end
|
132
185
|
|
133
|
-
|
134
|
-
|
186
|
+
it "should return exploded namespaces if :compact is false when parsing a fragment" do
|
187
|
+
xml = '<foofoo foo:bar="1" foo:baz="baz"></foofoo>'
|
188
|
+
rsxml = Rsxml.to_rsxml(xml, :ns=>{:foo=>"http://foo.com/foo", ""=>"http://baz.com/baz"}, :style=>:exploded)
|
135
189
|
|
136
|
-
rsxml.should ==
|
190
|
+
rsxml.should == [["foofoo", "", "http://baz.com/baz"],
|
191
|
+
{ ["bar", "foo", "http://foo.com/foo"]=>"1",
|
192
|
+
["baz", "foo", "http://foo.com/foo"]=>"baz"}]
|
137
193
|
end
|
138
194
|
|
139
195
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rsxml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Trampoline Systems Ltd
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-05-
|
18
|
+
date: 2011-05-11 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -113,6 +113,16 @@ files:
|
|
113
113
|
- Rakefile
|
114
114
|
- VERSION
|
115
115
|
- lib/rsxml.rb
|
116
|
+
- lib/rsxml/namespace.rb
|
117
|
+
- lib/rsxml/sexp.rb
|
118
|
+
- lib/rsxml/util.rb
|
119
|
+
- lib/rsxml/visitor.rb
|
120
|
+
- lib/rsxml/xml.rb
|
121
|
+
- spec/rsxml/namespace_spec.rb
|
122
|
+
- spec/rsxml/sexp_spec.rb
|
123
|
+
- spec/rsxml/util_spec.rb
|
124
|
+
- spec/rsxml/visitor_spec.rb
|
125
|
+
- spec/rsxml/xml_spec.rb
|
116
126
|
- spec/rsxml_spec.rb
|
117
127
|
- spec/spec_helper.rb
|
118
128
|
has_rdoc: true
|
@@ -150,5 +160,10 @@ signing_key:
|
|
150
160
|
specification_version: 3
|
151
161
|
summary: an s-expression representation of XML documents in Ruby
|
152
162
|
test_files:
|
163
|
+
- spec/rsxml/namespace_spec.rb
|
164
|
+
- spec/rsxml/sexp_spec.rb
|
165
|
+
- spec/rsxml/util_spec.rb
|
166
|
+
- spec/rsxml/visitor_spec.rb
|
167
|
+
- spec/rsxml/xml_spec.rb
|
153
168
|
- spec/rsxml_spec.rb
|
154
169
|
- spec/spec_helper.rb
|