nori 2.4.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.travis.yml +3 -1
- data/CHANGELOG.md +4 -0
- data/lib/nori/core_ext/hash.rb +0 -15
- data/lib/nori/parser/nokogiri.rb +13 -1
- data/lib/nori/version.rb +1 -1
- data/lib/nori/xml_utility_node.rb +5 -3
- data/nori.gemspec +1 -0
- data/spec/nori/api_spec.rb +17 -17
- data/spec/nori/core_ext/hash_spec.rb +5 -35
- data/spec/nori/core_ext/object_spec.rb +2 -2
- data/spec/nori/core_ext/string_spec.rb +8 -8
- data/spec/nori/nori_spec.rb +82 -77
- metadata +17 -25
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5734d4c7a672d830ea4199339b869da468bc2eab
|
4
|
+
data.tar.gz: d590616887899c0c17739e95b4f46e64ba12a367
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ce4642320270373612e945d7912269e45541954ca9b1f163c81e9527333994aa6f1c2f289d11fc61c3768aea76dffcd3d64923f830e2439e995c2d305a6140e5
|
7
|
+
data.tar.gz: 0f3b03f4ffda5f874fd5a5780de08bbb891167351ea67c69d2f8b86f49e0a65f8b11582e0070343731398641afda5ae9b881f6ea308556f9ff1bdb98af3576b6
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/lib/nori/core_ext/hash.rb
CHANGED
@@ -4,21 +4,6 @@ class Nori
|
|
4
4
|
module CoreExt
|
5
5
|
module Hash
|
6
6
|
|
7
|
-
# @return <String> This hash as a query string
|
8
|
-
#
|
9
|
-
# @example
|
10
|
-
# { :name => "Bob",
|
11
|
-
# :address => {
|
12
|
-
# :street => '111 Ruby Ave.',
|
13
|
-
# :city => 'Ruby Central',
|
14
|
-
# :phones => ['111-111-1111', '222-222-2222']
|
15
|
-
# }
|
16
|
-
# }.to_params
|
17
|
-
# #=> "name=Bob&address[city]=Ruby Central&address[phones][]=111-111-1111&address[phones][]=222-222-2222&address[street]=111 Ruby Ave."
|
18
|
-
def to_params
|
19
|
-
map { |k, v| normalize_param(k,v) }.flatten.join('&')
|
20
|
-
end
|
21
|
-
|
22
7
|
# @param key<Object> The key for the param.
|
23
8
|
# @param value<Object> The value for the param.
|
24
9
|
#
|
data/lib/nori/parser/nokogiri.rb
CHANGED
@@ -19,15 +19,27 @@ class Nori
|
|
19
19
|
stack.push Nori::XMLUtilityNode.new(options, name, Hash[*attrs.flatten])
|
20
20
|
end
|
21
21
|
|
22
|
+
# To keep backward behaviour compatibility
|
23
|
+
# delete last child if it is a space-only text node
|
22
24
|
def end_element(name)
|
23
25
|
if stack.size > 1
|
24
26
|
last = stack.pop
|
27
|
+
maybe_string = last.children.last
|
28
|
+
if maybe_string.is_a?(String) and maybe_string.strip.empty?
|
29
|
+
last.children.pop
|
30
|
+
end
|
25
31
|
stack.last.add_node last
|
26
32
|
end
|
27
33
|
end
|
28
34
|
|
35
|
+
# If this node is a successive character then add it as is.
|
36
|
+
# First child being a space-only text node will not be added
|
37
|
+
# because there is no previous characters.
|
29
38
|
def characters(string)
|
30
|
-
|
39
|
+
last = stack.last
|
40
|
+
if last and last.children.last.is_a?(String) or string.strip.size > 0
|
41
|
+
last.add_node(string)
|
42
|
+
end
|
31
43
|
end
|
32
44
|
|
33
45
|
alias cdata_block characters
|
data/lib/nori/version.rb
CHANGED
@@ -24,10 +24,11 @@ class Nori
|
|
24
24
|
# 13:20:00-05:00 1:20 PM, US Eastern Standard Time
|
25
25
|
# 13:20:00+02:00 1:20 PM, Central European Standard Time
|
26
26
|
# 13:20:00Z 1:20 PM, Coordinated Universal Time (UTC)
|
27
|
+
# 13:20:30.5555Z 1:20 PM and 30.5555 seconds, Coordinated Universal Time (UTC)
|
27
28
|
# 00:00:00 midnight
|
28
29
|
# 24:00:00 midnight
|
29
30
|
|
30
|
-
XS_TIME = /^\d{2}:\d{2}:\d{2}[
|
31
|
+
XS_TIME = /^\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/
|
31
32
|
|
32
33
|
# Simple xs:date Regexp.
|
33
34
|
# Valid xs:date formats
|
@@ -38,7 +39,7 @@ class Nori
|
|
38
39
|
# 2004-04-12+02:00 April 12, 2004, Central European Summer Time, which is 2 hours ahead of Coordinated Universal Time (UTC)
|
39
40
|
# 2004-04-12Z April 12, 2004, Coordinated Universal Time (UTC)
|
40
41
|
|
41
|
-
XS_DATE =
|
42
|
+
XS_DATE = /^-?\d{4}-\d{2}-\d{2}(?:Z|[+-]\d{2}:?\d{2})?$/
|
42
43
|
|
43
44
|
# Simple xs:dateTime Regexp.
|
44
45
|
# Valid xs:dateTime formats
|
@@ -48,8 +49,9 @@ class Nori
|
|
48
49
|
# 2004-04-12T13:20:00+02:00 1:20 pm on April 12, 2004, Central European Summer Time
|
49
50
|
# 2004-04-12T13:20:15.5-05:00 1:20 pm and 15.5 seconds on April 12, 2004, US Eastern Standard Time
|
50
51
|
# 2004-04-12T13:20:00Z 1:20 pm on April 12, 2004, Coordinated Universal Time (UTC)
|
52
|
+
# 2004-04-12T13:20:15.5Z 1:20 pm and 15.5 seconds on April 12, 2004, Coordinated Universal Time (UTC)
|
51
53
|
|
52
|
-
XS_DATE_TIME =
|
54
|
+
XS_DATE_TIME = /^-?\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})?$/
|
53
55
|
|
54
56
|
def self.typecasts
|
55
57
|
@@typecasts
|
data/nori.gemspec
CHANGED
data/spec/nori/api_spec.rb
CHANGED
@@ -4,7 +4,7 @@ describe Nori do
|
|
4
4
|
|
5
5
|
describe "PARSERS" do
|
6
6
|
it "should return a Hash of parser details" do
|
7
|
-
Nori::PARSERS.
|
7
|
+
expect(Nori::PARSERS).to eq({ :rexml => "REXML", :nokogiri => "Nokogiri" })
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -16,12 +16,12 @@ describe Nori do
|
|
16
16
|
</history>
|
17
17
|
XML
|
18
18
|
|
19
|
-
nori.parse(xml)["history"]["ns10:case"].
|
19
|
+
expect(nori.parse(xml)["history"]["ns10:case"]).to eq("a_case")
|
20
20
|
end
|
21
21
|
|
22
22
|
it "defaults to not change XML tags" do
|
23
23
|
xml = '<userResponse id="1"><accountStatus>active</accountStatus></userResponse>'
|
24
|
-
nori.parse(xml).
|
24
|
+
expect(nori.parse(xml)).to eq({ "userResponse" => { "@id" => "1", "accountStatus" => "active" } })
|
25
25
|
end
|
26
26
|
|
27
27
|
it "raises when passed unknown global options" do
|
@@ -33,7 +33,7 @@ describe Nori do
|
|
33
33
|
context ".new with :strip_namespaces" do
|
34
34
|
it "strips the namespace identifiers when set to true" do
|
35
35
|
xml = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"></soap:Envelope>'
|
36
|
-
nori(:strip_namespaces => true).parse(xml).
|
36
|
+
expect(nori(:strip_namespaces => true).parse(xml)).to have_key("Envelope")
|
37
37
|
end
|
38
38
|
|
39
39
|
it "still converts namespaced entries to array elements" do
|
@@ -47,7 +47,7 @@ describe Nori do
|
|
47
47
|
XML
|
48
48
|
|
49
49
|
expected = [{ "name" => "a_name" }, { "name" => "another_name" }]
|
50
|
-
nori(:strip_namespaces => true).parse(xml)["history"]["case"].
|
50
|
+
expect(nori(:strip_namespaces => true).parse(xml)["history"]["case"]).to eq(expected)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
@@ -58,7 +58,7 @@ describe Nori do
|
|
58
58
|
snakecase_symbols = lambda { |tag| tag.snakecase.to_sym }
|
59
59
|
nori = nori(:convert_tags_to => snakecase_symbols)
|
60
60
|
|
61
|
-
nori.parse(xml).
|
61
|
+
expect(nori.parse(xml)).to eq({ :user_response => { :@id => "1", :account_status => "active" } })
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -98,29 +98,29 @@ describe Nori do
|
|
98
98
|
context "#parse" do
|
99
99
|
it "defaults to use advanced typecasting" do
|
100
100
|
hash = nori.parse("<value>true</value>")
|
101
|
-
hash["value"].
|
101
|
+
expect(hash["value"]).to eq(true)
|
102
102
|
end
|
103
103
|
|
104
104
|
it "defaults to use the Nokogiri parser" do
|
105
105
|
# parsers are loaded lazily by default
|
106
106
|
require "nori/parser/nokogiri"
|
107
107
|
|
108
|
-
Nori::Parser::Nokogiri.
|
108
|
+
expect(Nori::Parser::Nokogiri).to receive(:parse).and_return({})
|
109
109
|
nori.parse("<any>thing</any>")
|
110
110
|
end
|
111
111
|
|
112
112
|
it "strips the XML" do
|
113
113
|
xml = double("xml")
|
114
|
-
xml.
|
114
|
+
expect(xml).to receive(:strip).and_return("<any>thing</any>")
|
115
115
|
|
116
|
-
nori.parse(xml).
|
116
|
+
expect(nori.parse(xml)).to eq({ "any" => "thing" })
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
120
|
context "#parse without :advanced_typecasting" do
|
121
121
|
it "can be changed to not typecast too much" do
|
122
122
|
hash = nori(:advanced_typecasting => false).parse("<value>true</value>")
|
123
|
-
hash["value"].
|
123
|
+
expect(hash["value"]).to eq("true")
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
@@ -129,7 +129,7 @@ describe Nori do
|
|
129
129
|
# parsers are loaded lazily by default
|
130
130
|
require "nori/parser/rexml"
|
131
131
|
|
132
|
-
Nori::Parser::REXML.
|
132
|
+
expect(Nori::Parser::REXML).to receive(:parse).and_return({})
|
133
133
|
nori(:parser => :rexml).parse("<any>thing</any>")
|
134
134
|
end
|
135
135
|
end
|
@@ -138,13 +138,13 @@ describe Nori do
|
|
138
138
|
it "can be changed to not delete xmlns attributes" do
|
139
139
|
xml = '<userResponse xmlns="http://schema.company.com/some/path/to/namespace/v1"><accountStatus>active</accountStatus></userResponse>'
|
140
140
|
hash = nori(:delete_namespace_attributes => false).parse(xml)
|
141
|
-
hash.
|
141
|
+
expect(hash).to eq({"userResponse" => {"@xmlns" => "http://schema.company.com/some/path/to/namespace/v1", "accountStatus" => "active"}})
|
142
142
|
end
|
143
143
|
|
144
144
|
it "can be changed to not delete xsi attributes" do
|
145
145
|
xml = '<userResponse xsi="abc:myType"><accountStatus>active</accountStatus></userResponse>'
|
146
146
|
hash = nori(:delete_namespace_attributes => false).parse(xml)
|
147
|
-
hash.
|
147
|
+
expect(hash).to eq({"userResponse" => {"@xsi" => "abc:myType", "accountStatus" => "active"}})
|
148
148
|
end
|
149
149
|
end
|
150
150
|
|
@@ -152,13 +152,13 @@ describe Nori do
|
|
152
152
|
it "can be changed to delete xmlns attributes" do
|
153
153
|
xml = '<userResponse xmlns="http://schema.company.com/some/path/to/namespace/v1"><accountStatus>active</accountStatus></userResponse>'
|
154
154
|
hash = nori(:delete_namespace_attributes => true).parse(xml)
|
155
|
-
hash.
|
155
|
+
expect(hash).to eq({"userResponse" => {"accountStatus" => "active"}})
|
156
156
|
end
|
157
157
|
|
158
158
|
it "can be changed to delete xsi attributes" do
|
159
159
|
xml = '<userResponse xsi="abc:myType"><accountStatus>active</accountStatus></userResponse>'
|
160
160
|
hash = nori(:delete_namespace_attributes => true).parse(xml)
|
161
|
-
hash.
|
161
|
+
expect(hash).to eq({"userResponse" => {"accountStatus" => "active"}})
|
162
162
|
end
|
163
163
|
end
|
164
164
|
|
@@ -166,7 +166,7 @@ describe Nori do
|
|
166
166
|
it "can be configured to skip dash to underscope conversion" do
|
167
167
|
xml = '<any-tag>foo bar</any-tag'
|
168
168
|
hash = nori(:convert_dashes_to_underscores => false).parse(xml)
|
169
|
-
hash.
|
169
|
+
expect(hash).to eq({'any-tag' => 'foo bar'})
|
170
170
|
end
|
171
171
|
end
|
172
172
|
|
@@ -2,36 +2,6 @@ require "spec_helper"
|
|
2
2
|
|
3
3
|
describe Hash do
|
4
4
|
|
5
|
-
describe "#to_params" do
|
6
|
-
|
7
|
-
{
|
8
|
-
{ "foo" => "bar", "baz" => "bat" } => "foo=bar&baz=bat",
|
9
|
-
{ "foo" => [ "bar", "baz" ] } => "foo[]=bar&foo[]=baz",
|
10
|
-
{ "foo" => [ {"bar" => "1"}, {"bar" => 2} ] } => "foo[][bar]=1&foo[][bar]=2",
|
11
|
-
{ "foo" => { "bar" => [ {"baz" => 1}, {"baz" => "2"} ] } } => "foo[bar][][baz]=1&foo[bar][][baz]=2",
|
12
|
-
{ "foo" => {"1" => "bar", "2" => "baz"} } => "foo[1]=bar&foo[2]=baz"
|
13
|
-
}.each do |hash, params|
|
14
|
-
it "should covert hash: #{hash.inspect} to params: #{params.inspect}" do
|
15
|
-
hash.to_params.split('&').sort.should == params.split('&').sort
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should not leave a trailing &" do
|
20
|
-
{
|
21
|
-
:name => 'Bob',
|
22
|
-
:address => {
|
23
|
-
:street => '111 Ruby Ave.',
|
24
|
-
:city => 'Ruby Central',
|
25
|
-
:phones => ['111-111-1111', '222-222-2222']
|
26
|
-
}
|
27
|
-
}.to_params.should_not =~ /&$/
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should URL encode unsafe characters" do
|
31
|
-
{:q => "?&\" +"}.to_params.should == "q=%3F%26%22%20%2B"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
5
|
describe "#normalize_param" do
|
36
6
|
it "should have specs"
|
37
7
|
end
|
@@ -40,8 +10,8 @@ describe Hash do
|
|
40
10
|
|
41
11
|
it "should turn the hash into xml attributes" do
|
42
12
|
attrs = { :one => "ONE", "two" => "TWO" }.to_xml_attributes
|
43
|
-
attrs.
|
44
|
-
attrs.
|
13
|
+
expect(attrs).to match(/one="ONE"/m)
|
14
|
+
expect(attrs).to match(/two="TWO"/m)
|
45
15
|
end
|
46
16
|
|
47
17
|
it "should preserve _ in hash keys" do
|
@@ -51,9 +21,9 @@ describe Hash do
|
|
51
21
|
:merb => "uses extlib"
|
52
22
|
}.to_xml_attributes
|
53
23
|
|
54
|
-
attrs.
|
55
|
-
attrs.
|
56
|
-
attrs.
|
24
|
+
expect(attrs).to match(/some_long_attribute="with short value"/)
|
25
|
+
expect(attrs).to match(/merb="uses extlib"/)
|
26
|
+
expect(attrs).to match(/crash="burn"/)
|
57
27
|
end
|
58
28
|
end
|
59
29
|
|
@@ -5,13 +5,13 @@ describe Object do
|
|
5
5
|
describe "#blank?" do
|
6
6
|
[nil, false, [], {}].each do |object|
|
7
7
|
it "should return true for: #{object.inspect}" do
|
8
|
-
object.blank
|
8
|
+
expect(object.blank?).to be_true
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
[true, [nil], 1, "string", { :key => "value" }].each do |object|
|
13
13
|
it "should return false for: #{object.inspect}" do
|
14
|
-
object.blank
|
14
|
+
expect(object.blank?).to be_false
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
@@ -4,29 +4,29 @@ describe String do
|
|
4
4
|
|
5
5
|
describe "#snakecase" do
|
6
6
|
it "lowercases one word CamelCase" do
|
7
|
-
"Merb".snakecase.
|
7
|
+
expect("Merb".snakecase).to eq("merb")
|
8
8
|
end
|
9
9
|
|
10
10
|
it "makes one underscore snakecase two word CamelCase" do
|
11
|
-
"MerbCore".snakecase.
|
11
|
+
expect("MerbCore".snakecase).to eq("merb_core")
|
12
12
|
end
|
13
13
|
|
14
14
|
it "handles CamelCase with more than 2 words" do
|
15
|
-
"SoYouWantContributeToMerbCore".snakecase.
|
15
|
+
expect("SoYouWantContributeToMerbCore".snakecase).to eq("so_you_want_contribute_to_merb_core")
|
16
16
|
end
|
17
17
|
|
18
18
|
it "handles CamelCase with more than 2 capital letter in a row" do
|
19
|
-
"CNN".snakecase.
|
20
|
-
"CNNNews".snakecase.
|
21
|
-
"HeadlineCNNNews".snakecase.
|
19
|
+
expect("CNN".snakecase).to eq("cnn")
|
20
|
+
expect("CNNNews".snakecase).to eq("cnn_news")
|
21
|
+
expect("HeadlineCNNNews".snakecase).to eq("headline_cnn_news")
|
22
22
|
end
|
23
23
|
|
24
24
|
it "does NOT change one word lowercase" do
|
25
|
-
"merb".snakecase.
|
25
|
+
expect("merb".snakecase).to eq("merb")
|
26
26
|
end
|
27
27
|
|
28
28
|
it "leaves snake_case as is" do
|
29
|
-
"merb_core".snakecase.
|
29
|
+
expect("merb_core".snakecase).to eq("merb_core")
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
data/spec/nori/nori_spec.rb
CHANGED
@@ -9,12 +9,12 @@ describe Nori do
|
|
9
9
|
|
10
10
|
it "should work with unnormalized characters" do
|
11
11
|
xml = '<root>&</root>'
|
12
|
-
parse(xml).
|
12
|
+
expect(parse(xml)).to eq({ 'root' => "&" })
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should transform a simple tag with content" do
|
16
16
|
xml = "<tag>This is the contents</tag>"
|
17
|
-
parse(xml).
|
17
|
+
expect(parse(xml)).to eq({ 'tag' => 'This is the contents' })
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should work with cdata tags" do
|
@@ -25,13 +25,13 @@ describe Nori do
|
|
25
25
|
]]>
|
26
26
|
</tag>
|
27
27
|
END
|
28
|
-
parse(xml)["tag"].strip.
|
28
|
+
expect(parse(xml)["tag"].strip).to eq("text inside cdata")
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should transform a simple tag with attributes" do
|
32
32
|
xml = "<tag attr1='1' attr2='2'></tag>"
|
33
33
|
hash = { 'tag' => { '@attr1' => '1', '@attr2' => '2' } }
|
34
|
-
parse(xml).
|
34
|
+
expect(parse(xml)).to eq(hash)
|
35
35
|
end
|
36
36
|
|
37
37
|
it "should transform repeating siblings into an array" do
|
@@ -42,7 +42,7 @@ describe Nori do
|
|
42
42
|
</opt>
|
43
43
|
XML
|
44
44
|
|
45
|
-
parse(xml)['opt']['user'].class.
|
45
|
+
expect(parse(xml)['opt']['user'].class).to eq(Array)
|
46
46
|
|
47
47
|
hash = {
|
48
48
|
'opt' => {
|
@@ -56,7 +56,7 @@ describe Nori do
|
|
56
56
|
}
|
57
57
|
}
|
58
58
|
|
59
|
-
parse(xml).
|
59
|
+
expect(parse(xml)).to eq(hash)
|
60
60
|
end
|
61
61
|
|
62
62
|
it "should not transform non-repeating siblings into an array" do
|
@@ -66,7 +66,7 @@ describe Nori do
|
|
66
66
|
</opt>
|
67
67
|
XML
|
68
68
|
|
69
|
-
parse(xml)['opt']['user'].class.
|
69
|
+
expect(parse(xml)['opt']['user'].class).to eq(Hash)
|
70
70
|
|
71
71
|
hash = {
|
72
72
|
'opt' => {
|
@@ -77,7 +77,7 @@ describe Nori do
|
|
77
77
|
}
|
78
78
|
}
|
79
79
|
|
80
|
-
parse(xml).
|
80
|
+
expect(parse(xml)).to eq(hash)
|
81
81
|
end
|
82
82
|
|
83
83
|
it "should prefix attributes with an @-sign to avoid problems with overwritten values" do
|
@@ -88,96 +88,101 @@ describe Nori do
|
|
88
88
|
</multiRef>
|
89
89
|
XML
|
90
90
|
|
91
|
-
parse(xml)["multiRef"].
|
91
|
+
expect(parse(xml)["multiRef"]).to eq({ "login" => "grep", "@id" => "id1", "id" => "76737" })
|
92
92
|
end
|
93
93
|
|
94
94
|
context "without advanced typecasting" do
|
95
95
|
it "should not transform 'true'" do
|
96
96
|
hash = parse("<value>true</value>", :advanced_typecasting => false)
|
97
|
-
hash["value"].
|
97
|
+
expect(hash["value"]).to eq("true")
|
98
98
|
end
|
99
99
|
|
100
100
|
it "should not transform 'false'" do
|
101
101
|
hash = parse("<value>false</value>", :advanced_typecasting => false)
|
102
|
-
hash["value"].
|
102
|
+
expect(hash["value"]).to eq("false")
|
103
103
|
end
|
104
104
|
|
105
105
|
it "should not transform Strings matching the xs:time format" do
|
106
106
|
hash = parse("<value>09:33:55Z</value>", :advanced_typecasting => false)
|
107
|
-
hash["value"].
|
107
|
+
expect(hash["value"]).to eq("09:33:55Z")
|
108
108
|
end
|
109
109
|
|
110
110
|
it "should not transform Strings matching the xs:date format" do
|
111
111
|
hash = parse("<value>1955-04-18-05:00</value>", :advanced_typecasting => false)
|
112
|
-
hash["value"].
|
112
|
+
expect(hash["value"]).to eq("1955-04-18-05:00")
|
113
113
|
end
|
114
114
|
|
115
115
|
it "should not transform Strings matching the xs:dateTime format" do
|
116
116
|
hash = parse("<value>1955-04-18T11:22:33-05:00</value>", :advanced_typecasting => false)
|
117
|
-
hash["value"].
|
117
|
+
expect(hash["value"]).to eq("1955-04-18T11:22:33-05:00")
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
121
121
|
context "with advanced typecasting" do
|
122
122
|
it "should transform 'true' to TrueClass" do
|
123
|
-
parse("<value>true</value>")["value"].
|
123
|
+
expect(parse("<value>true</value>")["value"]).to eq(true)
|
124
124
|
end
|
125
125
|
|
126
126
|
it "should transform 'false' to FalseClass" do
|
127
|
-
parse("<value>false</value>")["value"].
|
127
|
+
expect(parse("<value>false</value>")["value"]).to eq(false)
|
128
128
|
end
|
129
129
|
|
130
130
|
it "should transform Strings matching the xs:time format to Time objects" do
|
131
|
-
parse("<value>09:33:
|
131
|
+
expect(parse("<value>09:33:55.7Z</value>")["value"]).to eq(Time.parse("09:33:55.7Z"))
|
132
132
|
end
|
133
133
|
|
134
134
|
it "should transform Strings matching the xs:time format ahead of utc to Time objects" do
|
135
|
-
parse("<value>09:33:55+02:00</value>")["value"].
|
135
|
+
expect(parse("<value>09:33:55+02:00</value>")["value"]).to eq(Time.parse("09:33:55+02:00"))
|
136
136
|
end
|
137
137
|
|
138
138
|
it "should transform Strings matching the xs:date format to Date objects" do
|
139
|
-
parse("<value>1955-04-18-05:00</value>")["value"].
|
139
|
+
expect(parse("<value>1955-04-18-05:00</value>")["value"]).to eq(Date.parse("1955-04-18-05:00"))
|
140
140
|
end
|
141
141
|
|
142
142
|
it "should transform Strings matching the xs:dateTime format ahead of utc to Date objects" do
|
143
|
-
parse("<value>1955-04-18+02:00</value>")["value"].
|
143
|
+
expect(parse("<value>1955-04-18+02:00</value>")["value"]).to eq(Date.parse("1955-04-18+02:00"))
|
144
144
|
end
|
145
145
|
|
146
146
|
it "should transform Strings matching the xs:dateTime format to DateTime objects" do
|
147
|
-
parse("<value>1955-04-18T11:22:33
|
148
|
-
DateTime.parse("1955-04-18T11:22:33
|
147
|
+
expect(parse("<value>1955-04-18T11:22:33.5Z</value>")["value"]).to eq(
|
148
|
+
DateTime.parse("1955-04-18T11:22:33.5Z")
|
149
|
+
)
|
149
150
|
end
|
150
151
|
|
151
152
|
it "should transform Strings matching the xs:dateTime format ahead of utc to DateTime objects" do
|
152
|
-
parse("<value>1955-04-18T11:22:33+02:00</value>")["value"].
|
153
|
+
expect(parse("<value>1955-04-18T11:22:33+02:00</value>")["value"]).to eq(
|
153
154
|
DateTime.parse("1955-04-18T11:22:33+02:00")
|
155
|
+
)
|
154
156
|
end
|
155
157
|
|
156
158
|
it "should transform Strings matching the xs:dateTime format with seconds and an offset to DateTime objects" do
|
157
|
-
parse("<value>2004-04-12T13:20:15.5-05:00</value>")["value"].
|
159
|
+
expect(parse("<value>2004-04-12T13:20:15.5-05:00</value>")["value"]).to eq(
|
158
160
|
DateTime.parse("2004-04-12T13:20:15.5-05:00")
|
161
|
+
)
|
159
162
|
end
|
160
163
|
|
161
164
|
it "should not transform Strings containing an xs:time String and more" do
|
162
|
-
parse("<value>09:33:55Z is a time</value>")["value"].
|
163
|
-
parse("<value>09:33:55Z_is_a_file_name</value>")["value"].
|
165
|
+
expect(parse("<value>09:33:55Z is a time</value>")["value"]).to eq("09:33:55Z is a time")
|
166
|
+
expect(parse("<value>09:33:55Z_is_a_file_name</value>")["value"]).to eq("09:33:55Z_is_a_file_name")
|
164
167
|
end
|
165
168
|
|
166
169
|
it "should not transform Strings containing an xs:date String and more" do
|
167
|
-
parse("<value>1955-04-18-05:00 is a date</value>")["value"].
|
168
|
-
parse("<value>1955-04-18-05:00_is_a_file_name</value>")["value"].
|
170
|
+
expect(parse("<value>1955-04-18-05:00 is a date</value>")["value"]).to eq("1955-04-18-05:00 is a date")
|
171
|
+
expect(parse("<value>1955-04-18-05:00_is_a_file_name</value>")["value"]).to eq("1955-04-18-05:00_is_a_file_name")
|
169
172
|
end
|
170
173
|
|
171
174
|
it "should not transform Strings containing an xs:dateTime String and more" do
|
172
|
-
parse("<value>1955-04-18T11:22:33-05:00 is a dateTime</value>")["value"].
|
175
|
+
expect(parse("<value>1955-04-18T11:22:33-05:00 is a dateTime</value>")["value"]).to eq(
|
173
176
|
"1955-04-18T11:22:33-05:00 is a dateTime"
|
174
|
-
|
177
|
+
)
|
178
|
+
expect(parse("<value>1955-04-18T11:22:33-05:00_is_a_file_name</value>")["value"]).to eq(
|
175
179
|
"1955-04-18T11:22:33-05:00_is_a_file_name"
|
180
|
+
)
|
176
181
|
end
|
177
182
|
|
178
183
|
["00-00-00", "0000-00-00", "0000-00-00T00:00:00", "0569-23-0141", "DS2001-19-1312654773", "e6:53:01:00:ce:b4:06"].each do |date_string|
|
179
184
|
it "should not transform a String like '#{date_string}' to date or time" do
|
180
|
-
parse("<value>#{date_string}</value>")["value"].
|
185
|
+
expect(parse("<value>#{date_string}</value>")["value"]).to eq(date_string)
|
181
186
|
end
|
182
187
|
end
|
183
188
|
end
|
@@ -194,59 +199,59 @@ describe Nori do
|
|
194
199
|
end
|
195
200
|
|
196
201
|
it "correctly parse text nodes" do
|
197
|
-
@data.
|
202
|
+
expect(@data).to eq({
|
198
203
|
'opt' => {
|
199
204
|
'user' => [
|
200
205
|
'Gary R Epstein',
|
201
206
|
'Simon T Tyson'
|
202
207
|
]
|
203
208
|
}
|
204
|
-
}
|
209
|
+
})
|
205
210
|
end
|
206
211
|
|
207
|
-
it "
|
208
|
-
@data['opt']['user'][0].attributes.
|
212
|
+
it "parses attributes for text node if present" do
|
213
|
+
expect(@data['opt']['user'][0].attributes).to eq({'login' => 'grep'})
|
209
214
|
end
|
210
215
|
|
211
216
|
it "default attributes to empty hash if not present" do
|
212
|
-
@data['opt']['user'][1].attributes.
|
217
|
+
expect(@data['opt']['user'][1].attributes).to eq({})
|
213
218
|
end
|
214
219
|
|
215
220
|
it "add 'attributes' accessor methods to parsed instances of String" do
|
216
|
-
@data['opt']['user'][0].
|
217
|
-
@data['opt']['user'][0].
|
221
|
+
expect(@data['opt']['user'][0]).to respond_to(:attributes)
|
222
|
+
expect(@data['opt']['user'][0]).to respond_to(:attributes=)
|
218
223
|
end
|
219
224
|
|
220
225
|
it "not add 'attributes' accessor methods to all instances of String" do
|
221
|
-
"some-string".
|
222
|
-
"some-string".
|
226
|
+
expect("some-string").not_to respond_to(:attributes)
|
227
|
+
expect("some-string").not_to respond_to(:attributes=)
|
223
228
|
end
|
224
229
|
end
|
225
230
|
|
226
231
|
it "should typecast an integer" do
|
227
232
|
xml = "<tag type='integer'>10</tag>"
|
228
|
-
parse(xml)['tag'].
|
233
|
+
expect(parse(xml)['tag']).to eq(10)
|
229
234
|
end
|
230
235
|
|
231
236
|
it "should typecast a true boolean" do
|
232
237
|
xml = "<tag type='boolean'>true</tag>"
|
233
|
-
parse(xml)['tag'].
|
238
|
+
expect(parse(xml)['tag']).to be(true)
|
234
239
|
end
|
235
240
|
|
236
241
|
it "should typecast a false boolean" do
|
237
242
|
["false"].each do |w|
|
238
|
-
parse("<tag type='boolean'>#{w}</tag>")['tag'].
|
243
|
+
expect(parse("<tag type='boolean'>#{w}</tag>")['tag']).to be(false)
|
239
244
|
end
|
240
245
|
end
|
241
246
|
|
242
247
|
it "should typecast a datetime" do
|
243
248
|
xml = "<tag type='datetime'>2007-12-31 10:32</tag>"
|
244
|
-
parse(xml)['tag'].
|
249
|
+
expect(parse(xml)['tag']).to eq(Time.parse( '2007-12-31 10:32' ).utc)
|
245
250
|
end
|
246
251
|
|
247
252
|
it "should typecast a date" do
|
248
253
|
xml = "<tag type='date'>2007-12-31</tag>"
|
249
|
-
parse(xml)['tag'].
|
254
|
+
expect(parse(xml)['tag']).to eq(Date.parse('2007-12-31'))
|
250
255
|
end
|
251
256
|
|
252
257
|
xml_entities = {
|
@@ -260,51 +265,51 @@ describe Nori do
|
|
260
265
|
it "should unescape html entities" do
|
261
266
|
xml_entities.each do |k,v|
|
262
267
|
xml = "<tag>Some content #{v}</tag>"
|
263
|
-
parse(xml)['tag'].
|
268
|
+
expect(parse(xml)['tag']).to match(Regexp.new(k))
|
264
269
|
end
|
265
270
|
end
|
266
271
|
|
267
272
|
it "should unescape XML entities in attributes" do
|
268
273
|
xml_entities.each do |key, value|
|
269
274
|
xml = "<tag attr='Some content #{value}'></tag>"
|
270
|
-
parse(xml)['tag']['@attr'].
|
275
|
+
expect(parse(xml)['tag']['@attr']).to match(Regexp.new(key))
|
271
276
|
end
|
272
277
|
end
|
273
278
|
|
274
279
|
it "should undasherize keys as tags" do
|
275
280
|
xml = "<tag-1>Stuff</tag-1>"
|
276
|
-
parse(xml).keys.
|
281
|
+
expect(parse(xml).keys).to include('tag_1')
|
277
282
|
end
|
278
283
|
|
279
284
|
it "should undasherize keys as attributes" do
|
280
285
|
xml = "<tag1 attr-1='1'></tag1>"
|
281
|
-
parse(xml)['tag1'].keys.
|
286
|
+
expect(parse(xml)['tag1'].keys).to include('@attr_1')
|
282
287
|
end
|
283
288
|
|
284
289
|
it "should undasherize keys as tags and attributes" do
|
285
290
|
xml = "<tag-1 attr-1='1'></tag-1>"
|
286
|
-
parse(xml).keys.
|
287
|
-
parse(xml)['tag_1'].keys.
|
291
|
+
expect(parse(xml).keys).to include('tag_1')
|
292
|
+
expect(parse(xml)['tag_1'].keys).to include('@attr_1')
|
288
293
|
end
|
289
294
|
|
290
295
|
it "should render nested content correctly" do
|
291
296
|
xml = "<root><tag1>Tag1 Content <em><strong>This is strong</strong></em></tag1></root>"
|
292
|
-
parse(xml)['root']['tag1'].
|
297
|
+
expect(parse(xml)['root']['tag1']).to eq("Tag1 Content <em><strong>This is strong</strong></em>")
|
293
298
|
end
|
294
299
|
|
295
|
-
it "should render nested content with
|
300
|
+
it "should render nested content with text nodes correctly" do
|
296
301
|
xml = "<root>Tag1 Content<em>Stuff</em> Hi There</root>"
|
297
|
-
parse(xml)['root'].
|
302
|
+
expect(parse(xml)['root']).to eq("Tag1 Content<em>Stuff</em> Hi There")
|
298
303
|
end
|
299
304
|
|
300
305
|
it "should ignore attributes when a child is a text node" do
|
301
306
|
xml = "<root attr1='1'>Stuff</root>"
|
302
|
-
parse(xml).
|
307
|
+
expect(parse(xml)).to eq({ "root" => "Stuff" })
|
303
308
|
end
|
304
309
|
|
305
310
|
it "should ignore attributes when any child is a text node" do
|
306
311
|
xml = "<root attr1='1'>Stuff <em>in italics</em></root>"
|
307
|
-
parse(xml).
|
312
|
+
expect(parse(xml)).to eq({ "root" => "Stuff <em>in italics</em>" })
|
308
313
|
end
|
309
314
|
|
310
315
|
it "should correctly transform multiple children" do
|
@@ -329,7 +334,7 @@ describe Nori do
|
|
329
334
|
}
|
330
335
|
}
|
331
336
|
|
332
|
-
parse(xml).
|
337
|
+
expect(parse(xml)).to eq(hash)
|
333
338
|
end
|
334
339
|
|
335
340
|
it "should properly handle nil values (ActiveSupport Compatible)" do
|
@@ -359,7 +364,7 @@ describe Nori do
|
|
359
364
|
'nil_true' => nil,
|
360
365
|
'namespaced' => nil
|
361
366
|
}
|
362
|
-
parse(topic_xml)["topic"].
|
367
|
+
expect(parse(topic_xml)["topic"]).to eq(expected_topic_hash)
|
363
368
|
end
|
364
369
|
|
365
370
|
it "should handle a single record from xml (ActiveSupport Compatible)" do
|
@@ -404,7 +409,7 @@ describe Nori do
|
|
404
409
|
}
|
405
410
|
|
406
411
|
parse(topic_xml)["topic"].each do |k,v|
|
407
|
-
v.
|
412
|
+
expect(v).to eq(expected_topic_hash[k])
|
408
413
|
end
|
409
414
|
end
|
410
415
|
|
@@ -456,7 +461,7 @@ describe Nori do
|
|
456
461
|
|
457
462
|
# puts Nori.parse(topics_xml)['topics'].first.inspect
|
458
463
|
parse(topics_xml)["topics"].first.each do |k,v|
|
459
|
-
v.
|
464
|
+
expect(v).to eq(expected_topic_hash[k])
|
460
465
|
end
|
461
466
|
end
|
462
467
|
|
@@ -467,7 +472,7 @@ describe Nori do
|
|
467
472
|
<user name="value"><age>21</age></user>
|
468
473
|
XML
|
469
474
|
|
470
|
-
parse(xml, :convert_attributes_to => converter).
|
475
|
+
expect(parse(xml, :convert_attributes_to => converter)).to eq({'user' => {'@name_k' => 'value_v', 'age' => '21'}})
|
471
476
|
end
|
472
477
|
end
|
473
478
|
|
@@ -492,7 +497,7 @@ describe Nori do
|
|
492
497
|
}
|
493
498
|
|
494
499
|
parse(topic_xml)["rsp"]["photos"]["photo"].each do |k, v|
|
495
|
-
v.
|
500
|
+
expect(v).to eq(expected_topic_hash[k])
|
496
501
|
end
|
497
502
|
end
|
498
503
|
|
@@ -503,7 +508,7 @@ describe Nori do
|
|
503
508
|
</blog>
|
504
509
|
XML
|
505
510
|
expected_blog_hash = {"blog" => {"posts" => []}}
|
506
|
-
parse(blog_xml).
|
511
|
+
expect(parse(blog_xml)).to eq(expected_blog_hash)
|
507
512
|
end
|
508
513
|
|
509
514
|
it "should handle empty array with whitespace from xml (ActiveSupport Compatible)" do
|
@@ -514,7 +519,7 @@ describe Nori do
|
|
514
519
|
</blog>
|
515
520
|
XML
|
516
521
|
expected_blog_hash = {"blog" => {"posts" => []}}
|
517
|
-
parse(blog_xml).
|
522
|
+
expect(parse(blog_xml)).to eq(expected_blog_hash)
|
518
523
|
end
|
519
524
|
|
520
525
|
it "should handle array with one entry from_xml (ActiveSupport Compatible)" do
|
@@ -526,7 +531,7 @@ describe Nori do
|
|
526
531
|
</blog>
|
527
532
|
XML
|
528
533
|
expected_blog_hash = {"blog" => {"posts" => ["a post"]}}
|
529
|
-
parse(blog_xml).
|
534
|
+
expect(parse(blog_xml)).to eq(expected_blog_hash)
|
530
535
|
end
|
531
536
|
|
532
537
|
it "should handle array with multiple entries from xml (ActiveSupport Compatible)" do
|
@@ -539,7 +544,7 @@ describe Nori do
|
|
539
544
|
</blog>
|
540
545
|
XML
|
541
546
|
expected_blog_hash = {"blog" => {"posts" => ["a post", "another post"]}}
|
542
|
-
parse(blog_xml).
|
547
|
+
expect(parse(blog_xml)).to eq(expected_blog_hash)
|
543
548
|
end
|
544
549
|
|
545
550
|
it "should handle file types (ActiveSupport Compatible)" do
|
@@ -550,12 +555,12 @@ describe Nori do
|
|
550
555
|
</blog>
|
551
556
|
XML
|
552
557
|
hash = parse(blog_xml)
|
553
|
-
hash.keys.
|
554
|
-
hash['blog'].keys.
|
558
|
+
expect(hash.keys).to include('blog')
|
559
|
+
expect(hash['blog'].keys).to include('logo')
|
555
560
|
|
556
561
|
file = hash['blog']['logo']
|
557
|
-
file.original_filename.
|
558
|
-
file.content_type.
|
562
|
+
expect(file.original_filename).to eq('logo.png')
|
563
|
+
expect(file.content_type).to eq('image/png')
|
559
564
|
end
|
560
565
|
|
561
566
|
it "should handle file from xml with defaults (ActiveSupport Compatible)" do
|
@@ -566,8 +571,8 @@ describe Nori do
|
|
566
571
|
</blog>
|
567
572
|
XML
|
568
573
|
file = parse(blog_xml)['blog']['logo']
|
569
|
-
file.original_filename.
|
570
|
-
file.content_type.
|
574
|
+
expect(file.original_filename).to eq('untitled')
|
575
|
+
expect(file.content_type).to eq('application/octet-stream')
|
571
576
|
end
|
572
577
|
|
573
578
|
it "should handle xsd like types from xml (ActiveSupport Compatible)" do
|
@@ -591,7 +596,7 @@ describe Nori do
|
|
591
596
|
'illustration' => "babe.png"
|
592
597
|
}
|
593
598
|
|
594
|
-
parse(bacon_xml)["bacon"].
|
599
|
+
expect(parse(bacon_xml)["bacon"]).to eq(expected_bacon_hash)
|
595
600
|
end
|
596
601
|
|
597
602
|
it "should let type trickle through when unknown (ActiveSupport Compatible)" do
|
@@ -608,7 +613,7 @@ describe Nori do
|
|
608
613
|
'image' => {'@type' => 'ProductImage', 'filename' => 'image.gif' },
|
609
614
|
}
|
610
615
|
|
611
|
-
parse(product_xml)["product"].
|
616
|
+
expect(parse(product_xml)["product"]).to eq(expected_product_hash)
|
612
617
|
end
|
613
618
|
|
614
619
|
it "should handle unescaping from xml (ActiveResource Compatible)" do
|
@@ -618,16 +623,16 @@ describe Nori do
|
|
618
623
|
'pre_escaped_string' => 'First & Last Name'
|
619
624
|
}
|
620
625
|
|
621
|
-
parse(xml_string)['person'].
|
626
|
+
expect(parse(xml_string)['person']).to eq(expected_hash)
|
622
627
|
end
|
623
628
|
|
624
629
|
it "handle an empty xml string" do
|
625
|
-
parse('').
|
630
|
+
expect(parse('')).to eq({})
|
626
631
|
end
|
627
632
|
|
628
633
|
# As returned in the response body by the unfuddle XML API when creating objects
|
629
634
|
it "handle an xml string containing a single space" do
|
630
|
-
parse(' ').
|
635
|
+
expect(parse(' ')).to eq({})
|
631
636
|
end
|
632
637
|
|
633
638
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nori
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
5
|
-
prerelease:
|
4
|
+
version: 2.5.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Daniel Harrington
|
@@ -11,54 +10,48 @@ authors:
|
|
11
10
|
autorequire:
|
12
11
|
bindir: bin
|
13
12
|
cert_chain: []
|
14
|
-
date:
|
13
|
+
date: 2015-04-01 00:00:00.000000000 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: rake
|
18
17
|
requirement: !ruby/object:Gem::Requirement
|
19
|
-
none: false
|
20
18
|
requirements:
|
21
|
-
- - ~>
|
19
|
+
- - "~>"
|
22
20
|
- !ruby/object:Gem::Version
|
23
21
|
version: '10.0'
|
24
22
|
type: :development
|
25
23
|
prerelease: false
|
26
24
|
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
none: false
|
28
25
|
requirements:
|
29
|
-
- - ~>
|
26
|
+
- - "~>"
|
30
27
|
- !ruby/object:Gem::Version
|
31
28
|
version: '10.0'
|
32
29
|
- !ruby/object:Gem::Dependency
|
33
30
|
name: nokogiri
|
34
31
|
requirement: !ruby/object:Gem::Requirement
|
35
|
-
none: false
|
36
32
|
requirements:
|
37
|
-
- -
|
33
|
+
- - ">="
|
38
34
|
- !ruby/object:Gem::Version
|
39
35
|
version: 1.4.0
|
40
36
|
type: :development
|
41
37
|
prerelease: false
|
42
38
|
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
none: false
|
44
39
|
requirements:
|
45
|
-
- -
|
40
|
+
- - ">="
|
46
41
|
- !ruby/object:Gem::Version
|
47
42
|
version: 1.4.0
|
48
43
|
- !ruby/object:Gem::Dependency
|
49
44
|
name: rspec
|
50
45
|
requirement: !ruby/object:Gem::Requirement
|
51
|
-
none: false
|
52
46
|
requirements:
|
53
|
-
- - ~>
|
47
|
+
- - "~>"
|
54
48
|
- !ruby/object:Gem::Version
|
55
49
|
version: '2.12'
|
56
50
|
type: :development
|
57
51
|
prerelease: false
|
58
52
|
version_requirements: !ruby/object:Gem::Requirement
|
59
|
-
none: false
|
60
53
|
requirements:
|
61
|
-
- - ~>
|
54
|
+
- - "~>"
|
62
55
|
- !ruby/object:Gem::Version
|
63
56
|
version: '2.12'
|
64
57
|
description: XML to Hash translator
|
@@ -67,9 +60,9 @@ executables: []
|
|
67
60
|
extensions: []
|
68
61
|
extra_rdoc_files: []
|
69
62
|
files:
|
70
|
-
- .gitignore
|
71
|
-
- .rspec
|
72
|
-
- .travis.yml
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rspec"
|
65
|
+
- ".travis.yml"
|
73
66
|
- CHANGELOG.md
|
74
67
|
- Gemfile
|
75
68
|
- LICENSE
|
@@ -98,27 +91,26 @@ files:
|
|
98
91
|
homepage: https://github.com/savonrb/nori
|
99
92
|
licenses:
|
100
93
|
- MIT
|
94
|
+
metadata: {}
|
101
95
|
post_install_message:
|
102
96
|
rdoc_options: []
|
103
97
|
require_paths:
|
104
98
|
- lib
|
105
99
|
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
100
|
requirements:
|
108
|
-
- -
|
101
|
+
- - ">="
|
109
102
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
103
|
+
version: 1.9.2
|
111
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
|
-
none: false
|
113
105
|
requirements:
|
114
|
-
- -
|
106
|
+
- - ">="
|
115
107
|
- !ruby/object:Gem::Version
|
116
108
|
version: '0'
|
117
109
|
requirements: []
|
118
110
|
rubyforge_project: nori
|
119
|
-
rubygems_version:
|
111
|
+
rubygems_version: 2.2.2
|
120
112
|
signing_key:
|
121
|
-
specification_version:
|
113
|
+
specification_version: 4
|
122
114
|
summary: XML to Hash translator
|
123
115
|
test_files:
|
124
116
|
- spec/nori/api_spec.rb
|