traverse 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +177 -4
- data/Rakefile +3 -1
- data/lib/traverse.rb +107 -7
- data/lib/traverse/version.rb +1 -1
- data/spec/json.rb +43 -0
- data/spec/{spec.rb → xml.rb} +48 -45
- data/traverse.gemspec +7 -3
- metadata +55 -8
data/README.md
CHANGED
@@ -1,12 +1,20 @@
|
|
1
1
|
# Traverse
|
2
2
|
|
3
|
-
|
3
|
+
```bash
|
4
|
+
gem install traverse
|
5
|
+
```
|
6
|
+
|
7
|
+
## Introduction
|
8
|
+
|
9
|
+
Traverse is a simple tool that makes it easy to traverse XML and JSON.
|
4
10
|
|
5
|
-
Let's say you're messing around with Twitter's
|
11
|
+
Let's say you're messing around with Twitter's XML
|
6
12
|
[public timeline](http://api.twitter.com/statuses/public_timeline.xml).
|
7
13
|
Traverse let's you do things like this:
|
8
14
|
|
9
15
|
```ruby
|
16
|
+
require 'open-uri'
|
17
|
+
|
10
18
|
timeline = Traverse::Document.new(open "http://api.twitter.com/statuses/public_timeline.xml")
|
11
19
|
|
12
20
|
timeline.statuses.each do |status|
|
@@ -14,6 +22,18 @@ timeline.statuses.each do |status|
|
|
14
22
|
end
|
15
23
|
```
|
16
24
|
|
25
|
+
Or, let's say you're foolin' with Spotify's JSON [Search
|
26
|
+
API](http://ws.spotify.com/search/1/track.json?q=like+a+virgin).
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
search = Traverse::Document.new(open "http://ws.spotify.com/search/1/track.json?q=like+a+virgin")
|
30
|
+
|
31
|
+
search.tracks.each do |track|
|
32
|
+
puts "Track: #{track.name}"
|
33
|
+
puts "Album: #{track.album.name}"
|
34
|
+
end
|
35
|
+
```
|
36
|
+
|
17
37
|
For a slightly more complicated example, take a look at a
|
18
38
|
[boxscore](http://gd2.mlb.com/components/game/mlb/year_2011/month_03/day_31/gid_2011_03_31_detmlb_nyamlb_1/boxscore.xml)
|
19
39
|
pulled from Major League Baseball's public API.
|
@@ -22,8 +42,6 @@ pulled from Major League Baseball's public API.
|
|
22
42
|
url = "http://gd2.mlb.com/components/game/mlb/year_2011/month_03/day_31/gid_2011_03_31_detmlb_nyamlb_1/boxscore.xml"
|
23
43
|
boxscore = Traverse::Document.new(open url)
|
24
44
|
|
25
|
-
# let's start traversing!
|
26
|
-
|
27
45
|
boxscore.game_id # => '2011/03/31/detmlb-nyamlb-1'
|
28
46
|
|
29
47
|
boxscore.battings[0].batters[1].name_display_first_last # => 'Derek Jeter'
|
@@ -36,3 +54,158 @@ boxscore.pitchings.find do |pitching|
|
|
36
54
|
pitching.team_flag == 'away'
|
37
55
|
end.out # => '24'
|
38
56
|
```
|
57
|
+
|
58
|
+
## Traverse's XML API
|
59
|
+
|
60
|
+
When in doubt, check the spec file.
|
61
|
+
|
62
|
+
### Children
|
63
|
+
|
64
|
+
Let's say you're working with the following node of XML:
|
65
|
+
|
66
|
+
```xml
|
67
|
+
<foo>
|
68
|
+
<bar ...>
|
69
|
+
...
|
70
|
+
</bar>
|
71
|
+
</foo>
|
72
|
+
```
|
73
|
+
|
74
|
+
Assuming you've wrapped the XML in a `Traverse::Document` named `foo`, you can
|
75
|
+
traverse to the `bar` node with a simple method call:
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
foo.bar # => returns a representation of the bar node
|
79
|
+
```
|
80
|
+
|
81
|
+
If there are in fact many `bar`s inside `foo`, Traverse will transparently
|
82
|
+
collect them in an array. You can access that array by pluralizing the name of
|
83
|
+
the individual nodes:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
foo.bars # => an array containing all of the bars
|
87
|
+
foo.bars.first # => grab the first bar
|
88
|
+
```
|
89
|
+
|
90
|
+
Traverse will also do its best to transparently collect singularly-named nodes
|
91
|
+
inside of pluralized parents. Example:
|
92
|
+
|
93
|
+
```xml
|
94
|
+
<foo>
|
95
|
+
<bars>
|
96
|
+
<bar ...>
|
97
|
+
...
|
98
|
+
</bar>
|
99
|
+
...
|
100
|
+
<bar ...>
|
101
|
+
...
|
102
|
+
</bar>
|
103
|
+
</bars>
|
104
|
+
</foo>
|
105
|
+
```
|
106
|
+
```ruby
|
107
|
+
foo.bars # => an array of all of the bars
|
108
|
+
foo.bars.first # => the first bar
|
109
|
+
```
|
110
|
+
|
111
|
+
This won't work if the pluralized parent node has attributes or if its children
|
112
|
+
aren't all singularized versions of itself! Twitter's timeline is an example;
|
113
|
+
the parent node's name is `statuses`, and its children are all named
|
114
|
+
`status`, but the `statuses` node has an attribute.
|
115
|
+
|
116
|
+
### Attributes
|
117
|
+
|
118
|
+
If your XML node has an attribute named `foo`, you can access that attribute
|
119
|
+
with a simple method call:
|
120
|
+
|
121
|
+
```ruby
|
122
|
+
my_node.foo # => return the attribute's value
|
123
|
+
```
|
124
|
+
|
125
|
+
Notice that there might be a conflict if your node has both an attribute named
|
126
|
+
`foo` _and_ a child `foo`. Traverse puts children first, so the attribute `foo`
|
127
|
+
will get clobbered.
|
128
|
+
|
129
|
+
To get around this, Traverse provides a backdoor for when you really want the
|
130
|
+
attribute:
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
my_node.foo # => grabs the child named foo
|
134
|
+
my_node['foo'] # => grabs the attribute named foo
|
135
|
+
```
|
136
|
+
|
137
|
+
### Text
|
138
|
+
|
139
|
+
If you traverse to a node that has no attributes and contains only text, you
|
140
|
+
can grab that text with a simple method call. Let's suppose you have the
|
141
|
+
following XML:
|
142
|
+
|
143
|
+
```xml
|
144
|
+
<foo>
|
145
|
+
<bar>
|
146
|
+
This bar rocks!
|
147
|
+
</bar>
|
148
|
+
</foo>
|
149
|
+
```
|
150
|
+
|
151
|
+
You can grab the text like this:
|
152
|
+
|
153
|
+
```ruby
|
154
|
+
foo.bar # => "This bar rocks!"
|
155
|
+
```
|
156
|
+
|
157
|
+
What if `bar` does have attributes? Then you'll need to use the `text` method:
|
158
|
+
|
159
|
+
```xml
|
160
|
+
<foo>
|
161
|
+
<bar baz="quux">
|
162
|
+
This bar rocks!
|
163
|
+
</bar>
|
164
|
+
</foo>
|
165
|
+
```
|
166
|
+
```ruby
|
167
|
+
foo.bar # => grabs a representation of the node, not the text!
|
168
|
+
foo.bar.text # => "This bar rocks!"
|
169
|
+
```
|
170
|
+
|
171
|
+
I know what you're thinking: what the hell do I do if my node has text inside
|
172
|
+
it but I want to grab its attribute named `text`???
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
foo.bar['text'] # => grab bar's attribute named 'text'
|
176
|
+
foo.bar.text # => grab bar's text contents
|
177
|
+
```
|
178
|
+
|
179
|
+
## Traverse's JSON API
|
180
|
+
|
181
|
+
Again, when in doubt, check the spec file.
|
182
|
+
|
183
|
+
Traverse doesn't really do anything magical with JSON data; under the hood, it
|
184
|
+
uses `YAJL` to parse JSON into a `Hash`, and hashes are alredy pretty
|
185
|
+
traversable in Ruby. But, to maintain consistency with the XML API, you can
|
186
|
+
happily traverse JSON using method calls instead of querying a hash.
|
187
|
+
|
188
|
+
## Helper methods
|
189
|
+
Traverse provides a few helper methods to help with traversal.
|
190
|
+
|
191
|
+
If you're traversing some JSON, the ```_keys_``` method will be available. It
|
192
|
+
returns an array containing the names of the JSON object's keys.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
search._keys_.count
|
196
|
+
# => 2
|
197
|
+
|
198
|
+
search.first._keys_
|
199
|
+
# => ["user","favorited","source","id","text","created_at"]
|
200
|
+
```
|
201
|
+
|
202
|
+
If you're looking at XML, the ```_children_``` and ```_attributes_``` methods
|
203
|
+
will be available. The ```_children_``` method gives you an array of
|
204
|
+
traversable child nodes, and ```_attributes_``` gives you a hash of
|
205
|
+
attribute-name/attribute-value pairs.
|
206
|
+
|
207
|
+
## Contributors!
|
208
|
+
|
209
|
+
Traverse wouldn't be possible without help from friends. Thanks!
|
210
|
+
|
211
|
+
- [muffs](https://github.com/muffs)
|
data/Rakefile
CHANGED
data/lib/traverse.rb
CHANGED
@@ -1,10 +1,53 @@
|
|
1
1
|
require "traverse/version"
|
2
2
|
require 'nokogiri'
|
3
|
-
require '
|
3
|
+
require 'yajl'
|
4
4
|
require 'active_support/inflector'
|
5
5
|
|
6
6
|
module Traverse
|
7
7
|
class Document
|
8
|
+
def initialize document
|
9
|
+
if xml? document
|
10
|
+
@proxy = XML.new document
|
11
|
+
elsif json? document
|
12
|
+
@proxy = JSON.new document
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def method_missing m, *args, &block
|
18
|
+
@proxy.send m, *args, &block
|
19
|
+
end
|
20
|
+
|
21
|
+
def xml? document
|
22
|
+
begin
|
23
|
+
Nokogiri::XML(document) do |config|
|
24
|
+
config.options = Nokogiri::XML::ParseOptions::STRICT
|
25
|
+
end
|
26
|
+
true
|
27
|
+
rescue Nokogiri::XML::SyntaxError
|
28
|
+
false
|
29
|
+
ensure
|
30
|
+
document.rewind if document.respond_to? :read
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def json? document
|
35
|
+
begin
|
36
|
+
Yajl::Parser.new.parse(document)
|
37
|
+
true
|
38
|
+
rescue Yajl::ParseError
|
39
|
+
false
|
40
|
+
ensure
|
41
|
+
document.rewind if document.respond_to? :read
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
"<Traverse::Document...>"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class XML
|
8
51
|
def initialize document
|
9
52
|
setup_underlying_document document
|
10
53
|
|
@@ -23,7 +66,7 @@ module Traverse
|
|
23
66
|
end
|
24
67
|
else
|
25
68
|
define_singleton_method name do
|
26
|
-
|
69
|
+
XML.new child
|
27
70
|
end
|
28
71
|
end
|
29
72
|
else
|
@@ -32,7 +75,7 @@ module Traverse
|
|
32
75
|
if text_only_node? child
|
33
76
|
child.content.strip
|
34
77
|
else
|
35
|
-
|
78
|
+
XML.new child
|
36
79
|
end
|
37
80
|
end
|
38
81
|
end
|
@@ -43,7 +86,7 @@ module Traverse
|
|
43
86
|
define_singleton_method pluralized_child.name do
|
44
87
|
pluralized_child.children.reject do |baby|
|
45
88
|
baby.class == Nokogiri::XML::Text
|
46
|
-
end.map { |child|
|
89
|
+
end.map { |child| XML.new child }
|
47
90
|
end
|
48
91
|
end
|
49
92
|
|
@@ -53,15 +96,15 @@ module Traverse
|
|
53
96
|
@document.get_attribute attr
|
54
97
|
end
|
55
98
|
|
56
|
-
def
|
99
|
+
def _attributes_
|
57
100
|
name_value_pairs = @document.attributes.map do |name, attribute|
|
58
101
|
[name, attribute.value]
|
59
102
|
end
|
60
103
|
Hash[ name_value_pairs ]
|
61
104
|
end
|
62
105
|
|
63
|
-
def
|
64
|
-
real_children.map { |child|
|
106
|
+
def _children_
|
107
|
+
real_children.map { |child| XML.new child }
|
65
108
|
end
|
66
109
|
|
67
110
|
private
|
@@ -145,4 +188,61 @@ module Traverse
|
|
145
188
|
"<Traversable... >"
|
146
189
|
end
|
147
190
|
end
|
191
|
+
|
192
|
+
class JSON
|
193
|
+
|
194
|
+
def initialize json
|
195
|
+
|
196
|
+
setup_underlying_json json
|
197
|
+
|
198
|
+
if @json.is_a? Array
|
199
|
+
@proxy = @json.map do |item|
|
200
|
+
JSON.new item
|
201
|
+
end
|
202
|
+
elsif @json.is_a? Hash
|
203
|
+
@json.each_pair do |k,v|
|
204
|
+
define_singleton_method k do
|
205
|
+
if v.is_a? Hash
|
206
|
+
JSON.new(v)
|
207
|
+
elsif v.is_a? Array
|
208
|
+
v.map { |i| JSON.new(i) }
|
209
|
+
else
|
210
|
+
v
|
211
|
+
end
|
212
|
+
end
|
213
|
+
define_singleton_method "_keys_" do
|
214
|
+
@json.keys
|
215
|
+
end
|
216
|
+
end
|
217
|
+
elsif @json.is_a? Array
|
218
|
+
@json.map! { |i| JSON.new i }
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
private
|
223
|
+
def method_missing m, *args, &block
|
224
|
+
if @proxy
|
225
|
+
@proxy.send m, *args, &block
|
226
|
+
else
|
227
|
+
super
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def setup_underlying_json document
|
232
|
+
if document.is_a? String
|
233
|
+
@json = Yajl::Parser.new.parse document
|
234
|
+
elsif document.respond_to? :read # Tempfile / StringIO
|
235
|
+
begin
|
236
|
+
parser = Yajl::Parser.new
|
237
|
+
@json = parser.parse(document)
|
238
|
+
rescue
|
239
|
+
nil
|
240
|
+
ensure
|
241
|
+
document.rewind
|
242
|
+
end
|
243
|
+
elsif document.is_a? Hash
|
244
|
+
@json = document
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
148
248
|
end
|
data/lib/traverse/version.rb
CHANGED
data/spec/json.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'traverse'
|
2
|
+
|
3
|
+
gem 'minitest'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'minitest/pride'
|
6
|
+
|
7
|
+
json = %{
|
8
|
+
{
|
9
|
+
"menu": {
|
10
|
+
"id": "file",
|
11
|
+
"value": "File",
|
12
|
+
"popup": {
|
13
|
+
"menuitem": [
|
14
|
+
{"value": "New", "onclick": "CreateNewDoc()"},
|
15
|
+
{"value": "Open", "onclick": "OpenDoc()"},
|
16
|
+
{"value": "Close", "onclick": "CloseDoc()"}
|
17
|
+
]
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
describe Traverse::Document do
|
24
|
+
before do
|
25
|
+
@doc = Traverse::Document.new json
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "Grabbing simple attributes" do
|
29
|
+
it "helps you access attributes" do
|
30
|
+
@doc.menu.id.must_equal "file"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "Grabbing attributes that are arrays" do
|
35
|
+
it "knows how to handle json arrays" do
|
36
|
+
@doc.menu.popup.menuitem.count.must_equal 3
|
37
|
+
end
|
38
|
+
|
39
|
+
it "traversifies the elements of json arrays" do
|
40
|
+
@doc.menu.popup.menuitem.last.value.must_equal "Close"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/spec/{spec.rb → xml.rb}
RENAMED
@@ -1,4 +1,3 @@
|
|
1
|
-
$:.push '../'
|
2
1
|
require 'traverse'
|
3
2
|
|
4
3
|
gem 'minitest'
|
@@ -38,7 +37,7 @@ xml = %{
|
|
38
37
|
expert. Not a genius, exactly, more like an idiot savant with X-ray
|
39
38
|
vision.
|
40
39
|
</quotation>
|
41
|
-
</
|
40
|
+
</quotations>
|
42
41
|
<review reviewer="Salman Rushdie">
|
43
42
|
What is interesting is to have before us, at the end of the Greed
|
44
43
|
Decade, that rarest of birds: a major political novel about what
|
@@ -59,66 +58,70 @@ describe Traverse::Document do
|
|
59
58
|
@book = Traverse::Document.new xml
|
60
59
|
end
|
61
60
|
|
62
|
-
|
63
|
-
|
64
|
-
|
61
|
+
describe "Grabbing attributes" do
|
62
|
+
it "helps you access attributes" do
|
63
|
+
@book.title.must_equal "Vineland"
|
64
|
+
end
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
@book.author.name.must_equal "Thomas Pynchon"
|
70
|
-
end
|
66
|
+
it "also lets you access attributes shadowed by children" do
|
67
|
+
@book.author.wont_equal "Thomas Pynchon"
|
68
|
+
@book.author.class.wont_equal String
|
71
69
|
|
72
|
-
|
70
|
+
@book['author'].must_equal "Thomas Pynchon"
|
71
|
+
end
|
72
|
+
end
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
74
|
+
describe "Traversing to children" do
|
75
|
+
it "helps you traverse to child nodes" do
|
76
|
+
@book.review.reviewer.must_equal "Salman Rushdie"
|
77
|
+
@book.epigraph.author.must_equal "Johnny Copeland"
|
78
78
|
end
|
79
79
|
|
80
|
-
it "
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
80
|
+
it "knows to collect children with the same name" do
|
81
|
+
@book.author.books.class.must_equal Array
|
82
|
+
@book.author.books.count.must_equal 8
|
83
|
+
assert @book.author.books.all? do |book|
|
84
|
+
book.is_a? String
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
+
it "knows to collect singularized children of a pluralized parent" do
|
89
|
+
@book.quotations.count.must_equal 2
|
90
|
+
@book.quotations.last.text.must_match(/more like an idiot savant/)
|
91
|
+
end
|
88
92
|
end
|
89
93
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
+
describe "Dealing with text nodes" do
|
95
|
+
it "handles annoying text nodes transparently" do
|
96
|
+
@book.epigraph.text.must_match(/Every dog has his day/)
|
97
|
+
@book.review.text.must_match(/that rarest of birds/)
|
98
|
+
end
|
94
99
|
|
95
|
-
|
96
|
-
|
97
|
-
|
100
|
+
it "nevertheless handles attributes named 'text'" do
|
101
|
+
@book.text['text'].must_match(/seriously/)
|
102
|
+
@book.text.text.must_match(/rilly/)
|
103
|
+
end
|
98
104
|
|
99
|
-
|
100
|
-
|
101
|
-
|
105
|
+
it "handles nodes with only text and no attributes" do
|
106
|
+
@book.pagecount.must_equal "385"
|
107
|
+
end
|
102
108
|
end
|
103
109
|
|
104
|
-
it "nevertheless handles attributes named 'text'" do
|
105
|
-
@book.text['text'].must_match(/seriously/)
|
106
|
-
@book.text.text.must_match(/rilly/)
|
107
|
-
end
|
108
110
|
|
109
|
-
|
110
|
-
|
111
|
-
|
111
|
+
describe "Support for enumerable" do
|
112
|
+
it "gives you access to the current node's attributes" do
|
113
|
+
@book._attributes_.any? do |name, value|
|
114
|
+
value == "Vineland"
|
115
|
+
end.must_equal true
|
116
|
+
end
|
112
117
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
118
|
+
it "gives you access to the current node's children as traversable documents" do
|
119
|
+
assert @book._children_.any? do |child|
|
120
|
+
child.attributes.any? do |name, value|
|
121
|
+
name == "reviewer" and value == "Salman Rushdie"
|
122
|
+
end
|
123
|
+
end
|
117
124
|
end
|
118
125
|
end
|
119
126
|
|
120
|
-
it "knows to collect children of a pluralized parent" do
|
121
|
-
@book.quotations.count.must_equal 2
|
122
|
-
@book.quotations.last.text.must_match(/more like an idiot savant/)
|
123
|
-
end
|
124
127
|
end
|
data/traverse.gemspec
CHANGED
@@ -5,11 +5,11 @@ require "traverse/version"
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "traverse"
|
7
7
|
s.version = Traverse::VERSION
|
8
|
-
s.authors = ["happy4crazy"]
|
8
|
+
s.authors = ["happy4crazy", "muffs"]
|
9
9
|
s.email = ["alan.m.odonnell@gmail.com"]
|
10
10
|
s.homepage = "https://github.com/happy4crazy/traverse"
|
11
|
-
s.summary = %q{Easily traverse
|
12
|
-
s.description = %q{Easily traverse
|
11
|
+
s.summary = %q{Easily traverse XML and JSON.}
|
12
|
+
s.description = %q{Easily traverse XML and JSON.}
|
13
13
|
|
14
14
|
s.rubyforge_project = "traverse"
|
15
15
|
|
@@ -18,5 +18,9 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
19
|
s.require_paths = ["lib"]
|
20
20
|
|
21
|
+
s.add_development_dependency 'minitest'
|
21
22
|
s.add_dependency 'nokogiri', '~> 1.5'
|
23
|
+
s.add_dependency 'active_support'
|
24
|
+
s.add_dependency 'i18n'
|
25
|
+
s.add_dependency 'yajl-ruby'
|
22
26
|
end
|
metadata
CHANGED
@@ -1,20 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: traverse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- happy4crazy
|
9
|
+
- muffs
|
9
10
|
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date: 2011-08-
|
13
|
+
date: 2011-08-18 00:00:00.000000000 -04:00
|
13
14
|
default_executable:
|
14
15
|
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: minitest
|
18
|
+
requirement: &2157763120 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ! '>='
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '0'
|
24
|
+
type: :development
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: *2157763120
|
15
27
|
- !ruby/object:Gem::Dependency
|
16
28
|
name: nokogiri
|
17
|
-
requirement: &
|
29
|
+
requirement: &2157762620 !ruby/object:Gem::Requirement
|
18
30
|
none: false
|
19
31
|
requirements:
|
20
32
|
- - ~>
|
@@ -22,8 +34,41 @@ dependencies:
|
|
22
34
|
version: '1.5'
|
23
35
|
type: :runtime
|
24
36
|
prerelease: false
|
25
|
-
version_requirements: *
|
26
|
-
|
37
|
+
version_requirements: *2157762620
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: active_support
|
40
|
+
requirement: &2157762200 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
type: :runtime
|
47
|
+
prerelease: false
|
48
|
+
version_requirements: *2157762200
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: i18n
|
51
|
+
requirement: &2152011700 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ! '>='
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
type: :runtime
|
58
|
+
prerelease: false
|
59
|
+
version_requirements: *2152011700
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: yajl-ruby
|
62
|
+
requirement: &2152011280 !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :runtime
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: *2152011280
|
71
|
+
description: Easily traverse XML and JSON.
|
27
72
|
email:
|
28
73
|
- alan.m.odonnell@gmail.com
|
29
74
|
executables: []
|
@@ -36,7 +81,8 @@ files:
|
|
36
81
|
- Rakefile
|
37
82
|
- lib/traverse.rb
|
38
83
|
- lib/traverse/version.rb
|
39
|
-
- spec/
|
84
|
+
- spec/json.rb
|
85
|
+
- spec/xml.rb
|
40
86
|
- traverse.gemspec
|
41
87
|
has_rdoc: true
|
42
88
|
homepage: https://github.com/happy4crazy/traverse
|
@@ -62,6 +108,7 @@ rubyforge_project: traverse
|
|
62
108
|
rubygems_version: 1.6.2
|
63
109
|
signing_key:
|
64
110
|
specification_version: 3
|
65
|
-
summary: Easily traverse
|
111
|
+
summary: Easily traverse XML and JSON.
|
66
112
|
test_files:
|
67
|
-
- spec/
|
113
|
+
- spec/json.rb
|
114
|
+
- spec/xml.rb
|