sergio 0.0.1 → 0.0.2
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/.gitignore +3 -0
- data/Gemfile.lock +0 -2
- data/lib/sergio/hash_methods.rb +38 -2
- data/lib/sergio/sergio_config.rb +4 -2
- data/lib/sergio/sergio_element.rb +9 -6
- data/lib/sergio/sergio_parsed_document.rb +4 -14
- data/lib/sergio/sergio_sax.rb +29 -10
- data/lib/sergio/version.rb +3 -0
- data/readme.markdown +91 -0
- data/sergio.gemspec +27 -0
- data/spec/unit/sergio_hash_methods_spec.rb +77 -1
- data/spec/unit/sergio_spec.rb +54 -8
- metadata +6 -2
data/.gitignore
ADDED
data/Gemfile.lock
CHANGED
data/lib/sergio/hash_methods.rb
CHANGED
@@ -17,8 +17,12 @@ module Sergio
|
|
17
17
|
k = k.is_a?(Array) ? k[0] : k
|
18
18
|
v = hash[k]
|
19
19
|
if v
|
20
|
-
if
|
21
|
-
|
20
|
+
if path.length > 0
|
21
|
+
if v.is_a?(Hash)
|
22
|
+
value_at_path(path, v)
|
23
|
+
elsif v.last.is_a?(Hash)
|
24
|
+
value_at_path(path, v.last)
|
25
|
+
end
|
22
26
|
else
|
23
27
|
v
|
24
28
|
end
|
@@ -54,5 +58,37 @@ module Sergio
|
|
54
58
|
end
|
55
59
|
v
|
56
60
|
end
|
61
|
+
|
62
|
+
def hash_recursive_append(lval, rval)
|
63
|
+
r = {}
|
64
|
+
v = lval.merge(rval) do |key, oldval, newval|
|
65
|
+
r[key] = if oldval.is_a?(Hash) && newval.is_a?(Hash)
|
66
|
+
if newval.size == 0
|
67
|
+
[oldval, newval]
|
68
|
+
else
|
69
|
+
hash_recursive_append(oldval, newval)
|
70
|
+
end
|
71
|
+
else
|
72
|
+
if oldval.is_a?(Array)
|
73
|
+
if oldval.last.is_a?(Hash) && newval.is_a?(Hash) && newval.size > 0
|
74
|
+
oldval << hash_recursive_append(oldval.pop, newval)
|
75
|
+
else
|
76
|
+
oldval << newval
|
77
|
+
end
|
78
|
+
elsif newval.is_a?(Array)
|
79
|
+
newval << oldval
|
80
|
+
else
|
81
|
+
[oldval] << newval
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
v
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def remove_empty_hashes(hash)
|
90
|
+
hash.delete_if do |k,v|
|
91
|
+
true
|
92
|
+
end
|
57
93
|
end
|
58
94
|
end
|
data/lib/sergio/sergio_config.rb
CHANGED
@@ -23,6 +23,7 @@ module Sergio
|
|
23
23
|
newname = name unless newname
|
24
24
|
name = [name] unless name.is_a?(Array)
|
25
25
|
newname = [newname] unless newname.is_a?(Array)
|
26
|
+
aggregate_element = false
|
26
27
|
|
27
28
|
name.each do |n|
|
28
29
|
@current_path << n
|
@@ -42,11 +43,12 @@ module Sergio
|
|
42
43
|
if blk.arity < 1
|
43
44
|
blk.call
|
44
45
|
callback = lambda {|v|{}}
|
46
|
+
aggregate_element = true
|
45
47
|
else
|
46
48
|
callback = blk
|
47
49
|
end
|
48
50
|
|
49
|
-
elem =
|
51
|
+
elem = Sergio::Element.new(new_path, args, callback, aggregate_element)
|
50
52
|
|
51
53
|
@parsing_elements = hash_recursive_merge_to_arrays(@parsing_elements, hash_from_path(current_path, {:sergio_elem => elem}))
|
52
54
|
current_path.pop(name.length)
|
@@ -60,7 +62,7 @@ module Sergio
|
|
60
62
|
if v
|
61
63
|
v = v[:sergio_elem]
|
62
64
|
if v
|
63
|
-
v = [v] if v.is_a?(
|
65
|
+
v = [v] if v.is_a?(Sergio::Element)
|
64
66
|
vs = v.select do |v|
|
65
67
|
if v.options[:having]
|
66
68
|
match = v.options[:having].any? do |attr,value|
|
@@ -1,8 +1,11 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module Sergio
|
2
|
+
class Element
|
3
|
+
attr_accessor :new_path, :callback, :options, :aggregate_element
|
4
|
+
def initialize(new_path, args, callback, aggregate_element)
|
5
|
+
@new_path = new_path.clone
|
6
|
+
@callback = callback
|
7
|
+
@options = args
|
8
|
+
@aggregate_element = aggregate_element
|
9
|
+
end
|
7
10
|
end
|
8
11
|
end
|
@@ -8,24 +8,14 @@ module Sergio
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def set_element(path, val, options = {})
|
11
|
-
|
11
|
+
old_val = value_at_path(path.clone, self.parsed_hash)
|
12
12
|
|
13
|
-
val
|
14
|
-
|
15
|
-
v << val
|
16
|
-
else
|
17
|
-
if val.is_a?(Hash) && val.empty?
|
18
|
-
options[:as_array] ? [v] : v
|
19
|
-
else
|
20
|
-
[v] << val
|
21
|
-
end
|
22
|
-
end
|
23
|
-
else
|
24
|
-
options[:as_array] ? [val] : val
|
13
|
+
if options[:as_array] && !val.is_a?(Array) && !old_val.is_a?(Array)
|
14
|
+
val = [val]
|
25
15
|
end
|
26
16
|
|
27
17
|
h = hash_from_path(path, val)
|
28
|
-
@parsed_hash =
|
18
|
+
@parsed_hash = hash_recursive_append(self.parsed_hash, h)
|
29
19
|
@parsed_hash
|
30
20
|
end
|
31
21
|
end
|
data/lib/sergio/sergio_sax.rb
CHANGED
@@ -2,10 +2,21 @@ class SergioSax < Nokogiri::XML::SAX::Document
|
|
2
2
|
def initialize(object)
|
3
3
|
@stack = []
|
4
4
|
@object = object
|
5
|
+
@current_configs = []
|
6
|
+
@parent_callbacks = []
|
5
7
|
end
|
6
8
|
|
7
9
|
def start_element(name, attrs = [])
|
8
10
|
@stack << [name, attrs]
|
11
|
+
if current_configs = @object.class.sergio_config.get_element_configs(@stack.clone)
|
12
|
+
current_configs.each do |c|
|
13
|
+
if c.aggregate_element
|
14
|
+
@parent_callbacks << lambda do
|
15
|
+
@object.sergio_parsed_document.set_element(c.new_path, {}, c.options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
9
20
|
end
|
10
21
|
|
11
22
|
def characters(string)
|
@@ -18,28 +29,36 @@ class SergioSax < Nokogiri::XML::SAX::Document
|
|
18
29
|
end
|
19
30
|
|
20
31
|
def end_element(name)
|
21
|
-
|
32
|
+
current_configs = @object.class.sergio_config.get_element_configs(@stack.clone)
|
22
33
|
name, attrs = @stack.pop
|
23
|
-
if
|
24
|
-
|
25
|
-
attr =
|
34
|
+
if current_configs
|
35
|
+
current_configs.each do |c|
|
36
|
+
attr = c.options[:attribute]
|
26
37
|
val = attrs.assoc(attr)
|
27
|
-
|
28
|
-
val = val[1]
|
29
|
-
hash_path = sergio_element.new_path
|
30
|
-
callback = sergio_element.callback
|
38
|
+
callback = c.callback
|
31
39
|
|
40
|
+
if val && !c.aggregate_element
|
41
|
+
val = val[1]
|
32
42
|
r = if callback.arity == 1
|
33
43
|
callback.call(val)
|
34
44
|
elsif callback.arity == 2
|
35
45
|
h = Hash[*attrs.flatten]
|
36
46
|
h.delete('@text')
|
37
|
-
callback.call(val,
|
47
|
+
callback.call(val, h)
|
48
|
+
end
|
49
|
+
|
50
|
+
#only builds parent elements if at least one of their child elements has a match
|
51
|
+
@parent_callbacks.each do |c|
|
52
|
+
c.call
|
38
53
|
end
|
54
|
+
@parent_callbacks = []
|
39
55
|
|
40
|
-
|
56
|
+
#build an array of hashes if return value from callback is a hash
|
57
|
+
@object.sergio_parsed_document.set_element(c.new_path, {}, c.options) if r.is_a?(Hash)
|
58
|
+
@object.sergio_parsed_document.set_element(c.new_path, r, c.options)
|
41
59
|
end
|
42
60
|
end
|
43
61
|
end
|
62
|
+
@parent_callbacks = []
|
44
63
|
end
|
45
64
|
end
|
data/readme.markdown
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
<a href='http://www.youtube.com/watch?v=GaoLU6zKaws'><img src="http://i.imgur.com/HThQt.jpg" alt="" title="Hosted by imgur.com" /></a>
|
2
|
+
### Sergio is a SAX parser with a handy dsl for transforming xml into hashes
|
3
|
+
|
4
|
+
##Usage
|
5
|
+
require 'sergio'
|
6
|
+
|
7
|
+
class MyXmlMunger
|
8
|
+
include Sergio
|
9
|
+
|
10
|
+
#the hash key will be renamed to the second argument passed to element if one is provided
|
11
|
+
element 'body', 'bro' do
|
12
|
+
|
13
|
+
#if a second argument isn't provided it will just use the original name of the element
|
14
|
+
element 'id'
|
15
|
+
|
16
|
+
#the :attribute option specifies what attribute to draw the value from for the resulting hash
|
17
|
+
element 'a', 'link', :attribute => 'href'
|
18
|
+
|
19
|
+
#You can pass a block to #element with a value argument and the hash value will be set to the result of the block
|
20
|
+
element 'p', 'content' do |v|
|
21
|
+
v.reverse
|
22
|
+
end
|
23
|
+
|
24
|
+
#You can pass :having to #element to specify attributes required to match against
|
25
|
+
element 'div', 'cars', :having => {'class' => 'car'} do
|
26
|
+
|
27
|
+
#You can pass value and attributes arguments into the block you pass to element
|
28
|
+
element 'p', 'description' do |value, attributes|
|
29
|
+
"#{value} #{attributes['attribute']}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
#You can pass arbitrary nestings to match against and merge to
|
34
|
+
element ['some', 'nesting'], ['some', 'other', 'nesting']
|
35
|
+
|
36
|
+
#Duplicate elements in the same scope are automatically made into an array:
|
37
|
+
element 'some', 'thing'
|
38
|
+
|
39
|
+
#parses
|
40
|
+
#<body><some>hey</some><some>hi</some></body>
|
41
|
+
#as
|
42
|
+
#{'document' => {'thing' => ['hey, 'hi']}}
|
43
|
+
#and
|
44
|
+
#<body><some>hi</some></body>
|
45
|
+
#as
|
46
|
+
#{'document' => {'thing' => 'hi'}}
|
47
|
+
|
48
|
+
#You can force arrays for even a single matching element within a given scope using the :as_array option
|
49
|
+
element 'some', 'thing', :as_array => true
|
50
|
+
|
51
|
+
#parses
|
52
|
+
#<body><some>hi</some></body>
|
53
|
+
#as
|
54
|
+
#{'document' => {'thing' => ['hi']}}
|
55
|
+
#and
|
56
|
+
#<body><some>hey</some><some>hi</some></body>
|
57
|
+
#as
|
58
|
+
#{'document' => {'thing' => ['hey', 'hi']}}
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
###To parse a document into a hash, call parse on an instance of your parsing class with a document string as an argument
|
63
|
+
MyXmlMunger.new.parse("<body><id>1</id><a href='dude'>something</a></body>")
|
64
|
+
#returns {'bro' => {'id' => '1', 'link' => 'dude'}}
|
65
|
+
|
66
|
+
##LICENSE
|
67
|
+
|
68
|
+
(The MIT License)
|
69
|
+
|
70
|
+
Copyright © 2011:
|
71
|
+
|
72
|
+
Max Justus Spransy
|
73
|
+
|
74
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
75
|
+
a copy of this software and associated documentation files (the
|
76
|
+
‘Software’), to deal in the Software without restriction, including
|
77
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
78
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
79
|
+
permit persons to whom the Software is furnished to do so, subject to
|
80
|
+
the following conditions:
|
81
|
+
|
82
|
+
The above copyright notice and this permission notice shall be
|
83
|
+
included in all copies or substantial portions of the Software.
|
84
|
+
|
85
|
+
THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND,
|
86
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
87
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
88
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
89
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
90
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
91
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/sergio.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "sergio/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "sergio"
|
7
|
+
s.version = Sergio::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Max Justus Spransy"]
|
10
|
+
s.email = ["maxjustus@gmail.com"]
|
11
|
+
s.homepage = "https://github.com/maxjustus/Sergio"
|
12
|
+
s.summary = %q{SAXy xml to hash transformation.}
|
13
|
+
s.description = %q{
|
14
|
+
Sergio provides a declarative syntax for parsing unruly xml into nice pretty hashes.
|
15
|
+
}
|
16
|
+
|
17
|
+
s.rubyforge_project = "sergio"
|
18
|
+
|
19
|
+
s.add_dependency 'nokogiri'
|
20
|
+
s.add_development_dependency 'rspec', '~> 2.5.0'
|
21
|
+
s.add_development_dependency 'rake'
|
22
|
+
|
23
|
+
s.files = `git ls-files`.split("\n")
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
@@ -13,6 +13,12 @@ describe Sergio::HashMethods do
|
|
13
13
|
v.should == '2'
|
14
14
|
end
|
15
15
|
|
16
|
+
it 'gets the value from last hash in array of hashes in passed in hash at point in heirarchy specified by passed in array' do
|
17
|
+
v = @s.value_at_path([['thing'], ['stuff']], {'thing' => [{'stuff' => '1'}, {'stuff' => '2'}]})
|
18
|
+
v = @s.value_at_path([['thing']], {'thing' => [{'stuff' => '1'}, {'stuff' => '2'}]})
|
19
|
+
v.should == [{'stuff' => '1'}, {'stuff' => '2'}]
|
20
|
+
end
|
21
|
+
|
16
22
|
it 'gets the value from passed in hash at point in heirarchy specified by passed in array if array is one element long' do
|
17
23
|
v = @s.value_at_path([['thing']], {'thing' => {'stuff' => '2'}})
|
18
24
|
v.should == {'stuff' => '2'}
|
@@ -31,7 +37,6 @@ describe Sergio::HashMethods do
|
|
31
37
|
end.new
|
32
38
|
end
|
33
39
|
|
34
|
-
|
35
40
|
it 'merges subhashes together' do
|
36
41
|
h1 = {:thing => {'guy' => 'cool'}}
|
37
42
|
h2 = {:thing => {'guys' => 'cool'}}
|
@@ -75,5 +80,76 @@ describe Sergio::HashMethods do
|
|
75
80
|
h2 = {:thing => {'guy' => 'cools'}}
|
76
81
|
@s.hash_recursive_merge(h1, h2).should == {:thing => {'guy' => 'cools'}}
|
77
82
|
end
|
83
|
+
|
84
|
+
it 'merges new key values into existing hash if one is present' do
|
85
|
+
h1 = {:thing => {'guy' => 'cool'}}
|
86
|
+
h2 = {:thing => {'neat' => 'cools'}}
|
87
|
+
@s.hash_recursive_merge(h1, h2).should == {:thing => {'guy' => 'cool', 'neat' => 'cools'}}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'hash_recursive_append' do
|
92
|
+
before do
|
93
|
+
@s = Class.new do
|
94
|
+
include Sergio::HashMethods
|
95
|
+
end.new
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'merges subhashes together' do
|
99
|
+
h1 = {:thing => {'guy' => 'cool'}}
|
100
|
+
h2 = {:thing => {'guys' => 'cool'}}
|
101
|
+
@s.hash_recursive_append(h1, h2).should == {:thing => {'guy' => 'cool', 'guys' => 'cool'}}
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'aggregates intersecting key values into an array' do
|
105
|
+
h1 = {:thing => {'guy' => 'cool'}}
|
106
|
+
h2 = {:thing => {'guy' => 'cools'}}
|
107
|
+
@s.hash_recursive_append(h1, h2).should == {:thing => {'guy' => ['cool', 'cools']}}
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'aggregates intersecting key values into an array of values where values are not hashes' do
|
111
|
+
h1 = {:thing => {'guy' => 'cool'}}
|
112
|
+
h2 = {:thing => {'guy' => 'cools'}}
|
113
|
+
@s.hash_recursive_append(h1, h2).should == {:thing => {'guy' => ['cool', 'cools']}}
|
114
|
+
h1 = {:thing => {'guy' => {'cool' => '1'}}}
|
115
|
+
h2 = {:thing => {'guy' => {'cool' => '3'}}}
|
116
|
+
@s.hash_recursive_append(h1, h2).should == {:thing => {'guy' => {'cool' => ['1', '3']}}}
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'merges new key values into existing hash if one is present' do
|
120
|
+
h1 = {:thing => {'guy' => 'cool'}}
|
121
|
+
h2 = {:thing => {'neat' => 'cools'}}
|
122
|
+
@s.hash_recursive_append(h1, h2).should == {:thing => {'guy' => 'cool', 'neat' => 'cools'}}
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'creates an array of hashes at given value if new hash value is an empty hash' do
|
126
|
+
h1 = {:thing => {'guy' => 'cool'}}
|
127
|
+
h2 = {:thing => {}}
|
128
|
+
@s.hash_recursive_append(h1, h2).should == {:thing => [{'guy' => 'cool'}, {}]}
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'merges key values into last hash in existing array of hashes if one is present' do
|
132
|
+
h1 = {:thing => {'guy' => 'cool'}}
|
133
|
+
h2 = {:thing => {'neat' => 'cools'}}
|
134
|
+
h1 = @s.hash_recursive_append(h1, h2)
|
135
|
+
h2 = {:thing => {}}
|
136
|
+
h1 = @s.hash_recursive_append(h1, h2)
|
137
|
+
h1.should == {:thing => [{'guy' => 'cool', 'neat' => 'cools'}, {}]}
|
138
|
+
h2 = {:thing => {'guy' => 'cools'}}
|
139
|
+
h1 = @s.hash_recursive_append(h1, h2)
|
140
|
+
h1.should == {:thing => [{'guy' => 'cool', 'neat' => 'cools'}, {'guy' => 'cools'}]}
|
141
|
+
h2 = {:thing => {'neat' => 'cools'}}
|
142
|
+
h1 = @s.hash_recursive_append(h1, h2)
|
143
|
+
h1.should == {:thing => [{'guy' => 'cool', 'neat' => 'cools'}, {'guy' => 'cools', 'neat' => 'cools'}]}
|
144
|
+
h2 = {:thing => {'neat' => 'cools'}}
|
145
|
+
h1 = @s.hash_recursive_append(h1, h2)
|
146
|
+
h1.should == {:thing => [{'guy' => 'cool', 'neat' => 'cools'}, {'guy' => 'cools', 'neat' => ['cools', 'cools']}]}
|
147
|
+
h2 = {:thing => {}}
|
148
|
+
h1 = @s.hash_recursive_append(h1, h2)
|
149
|
+
h1.should == {:thing => [{'guy' => 'cool', 'neat' => 'cools'}, {'guy' => 'cools', 'neat' => ['cools', 'cools']}, {}]}
|
150
|
+
h2 = {:thing => {'hi' => 'hey'}}
|
151
|
+
h1 = @s.hash_recursive_append(h1, h2)
|
152
|
+
h1.should == {:thing => [{'guy' => 'cool', 'neat' => 'cools'}, {'guy' => 'cools', 'neat' => ['cools', 'cools']}, {'hi' => 'hey'}]}
|
153
|
+
end
|
78
154
|
end
|
79
155
|
end
|
data/spec/unit/sergio_spec.rb
CHANGED
@@ -15,27 +15,65 @@ describe Sergio do
|
|
15
15
|
it 'parses duplicate elements into an array' do
|
16
16
|
s = new_sergio do
|
17
17
|
element 'parent' do
|
18
|
-
element '
|
18
|
+
element 'post', 'posts' do
|
19
|
+
element 'id', :as_array => true
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
|
-
@xml = "<parent><id>1</id><id>2</id></parent>"
|
24
|
+
@xml = "<parent><post><id>1</id><id>2</id></post><post><id>3</id></post><post></post></parent>"
|
23
25
|
@hash = s.new.parse(@xml)
|
24
|
-
@hash['parent']['id'].should == ['1', '2']
|
26
|
+
@hash['parent']['posts'][0]['id'].should == ['1', '2']
|
27
|
+
@hash['parent']['posts'][1]['id'].should == ['3']
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'ignores empty adjacent elements' do
|
31
|
+
s = new_sergio do
|
32
|
+
element 'a' do
|
33
|
+
element 'b' do
|
34
|
+
element 'f'
|
35
|
+
end
|
36
|
+
element 'c', 'b' do
|
37
|
+
element 'e'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
@xml = '<a>
|
42
|
+
<b></b>
|
43
|
+
<b><f>a</f></b>
|
44
|
+
<b>he</b>
|
45
|
+
<c>a</c>
|
46
|
+
<c>
|
47
|
+
<e>e</e>
|
48
|
+
</c>
|
49
|
+
</a>'
|
50
|
+
h = s.new.parse(@xml)
|
51
|
+
h.should == {'a' => {'b' => [{'f' => 'a'}, {'e' => 'e'}]}}
|
25
52
|
end
|
26
53
|
|
27
54
|
it 'parses duplicate elements whose callbacks return a hash into an array' do
|
28
55
|
s = new_sergio do
|
29
56
|
element 'parent' do
|
30
|
-
element '
|
31
|
-
|
57
|
+
element 'p' do
|
58
|
+
element 'id', do |v, attributes|
|
59
|
+
{'v' => v}
|
60
|
+
end
|
32
61
|
end
|
33
62
|
end
|
34
63
|
end
|
35
64
|
|
36
|
-
@xml = "<parent
|
65
|
+
@xml = "<parent>
|
66
|
+
<p>
|
67
|
+
<id cool='neat'>1</id>
|
68
|
+
<id>2</id>
|
69
|
+
</p>
|
70
|
+
<p>
|
71
|
+
<id>5</id>
|
72
|
+
</p>
|
73
|
+
</parent>"
|
37
74
|
@hash = s.new.parse(@xml)
|
38
|
-
@hash['parent']['id'].should == [{'v' => '1'
|
75
|
+
@hash['parent']['p'][0]['id'].should == [{'v' => '1'}, {'v' => '2'}]
|
76
|
+
@hash['parent']['p'][1]['id'].should == {'v' => '5'}
|
39
77
|
end
|
40
78
|
|
41
79
|
it 'parses a nested element' do
|
@@ -105,7 +143,7 @@ describe Sergio do
|
|
105
143
|
|
106
144
|
@xml = "<parent><id>1</id><id>2</id></parent>"
|
107
145
|
@hash = s.new.parse(@xml)
|
108
|
-
@hash['post'].should ==
|
146
|
+
@hash['post'].keys.should == ['di']
|
109
147
|
end
|
110
148
|
|
111
149
|
it 'matches against attributes using :having argument' do
|
@@ -244,5 +282,13 @@ describe Sergio do
|
|
244
282
|
v = @s.new.sergio_parsed_document.set_element(['thing', 'stuff'], '1')
|
245
283
|
v.should == {'thing' => {'stuff' => '1'}}
|
246
284
|
end
|
285
|
+
|
286
|
+
it 'aggregates adjacent parents into arrays' do
|
287
|
+
s = @s.new
|
288
|
+
s.sergio_parsed_document.set_element(['thing', 'stuff'], '1')
|
289
|
+
s.sergio_parsed_document.set_element(['thing'], {})
|
290
|
+
v = s.sergio_parsed_document.set_element(['thing', 'stuff'], '2')
|
291
|
+
v.should == {'thing' => [{'stuff' => '1'}, {'stuff' => '2'}]}
|
292
|
+
end
|
247
293
|
end
|
248
294
|
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: sergio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Max Justus Spransy
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05-
|
13
|
+
date: 2011-05-26 00:00:00 -05:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -56,6 +56,7 @@ extensions: []
|
|
56
56
|
extra_rdoc_files: []
|
57
57
|
|
58
58
|
files:
|
59
|
+
- .gitignore
|
59
60
|
- Gemfile
|
60
61
|
- Gemfile.lock
|
61
62
|
- Rakefile
|
@@ -65,6 +66,9 @@ files:
|
|
65
66
|
- lib/sergio/sergio_element.rb
|
66
67
|
- lib/sergio/sergio_parsed_document.rb
|
67
68
|
- lib/sergio/sergio_sax.rb
|
69
|
+
- lib/sergio/version.rb
|
70
|
+
- readme.markdown
|
71
|
+
- sergio.gemspec
|
68
72
|
- spec/spec_helper.rb
|
69
73
|
- spec/support/buzz_activity_stream.xml
|
70
74
|
- spec/support/facebook_activity_stream.xml
|