traverse 0.0.2 → 0.0.3
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.md +36 -1
- data/lib/traverse/version.rb +1 -1
- data/lib/traverse.rb +33 -29
- data/spec/spec.rb +36 -18
- metadata +4 -4
data/README.md
CHANGED
@@ -1,3 +1,38 @@
|
|
1
1
|
# Traverse
|
2
2
|
|
3
|
-
Traverse is a simple tool that makes it easy to traverse XML.
|
3
|
+
Traverse is a simple tool that makes it easy to traverse XML.
|
4
|
+
|
5
|
+
Let's say you're messing around with Twitter's
|
6
|
+
[public timeline](http://api.twitter.com/statuses/public_timeline.xml).
|
7
|
+
Traverse let's you do things like this:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
timeline = Traverse::Document.new(open "http://api.twitter.com/statuses/public_timeline.xml")
|
11
|
+
|
12
|
+
timeline.statuses.each do |status|
|
13
|
+
puts "#{status.user.name} says: #{status.text}"
|
14
|
+
end
|
15
|
+
```
|
16
|
+
|
17
|
+
For a slightly more complicated example, take a look at a
|
18
|
+
[boxscore](http://gd2.mlb.com/components/game/mlb/year_2011/month_03/day_31/gid_2011_03_31_detmlb_nyamlb_1/boxscore.xml)
|
19
|
+
pulled from Major League Baseball's public API.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
url = "http://gd2.mlb.com/components/game/mlb/year_2011/month_03/day_31/gid_2011_03_31_detmlb_nyamlb_1/boxscore.xml"
|
23
|
+
boxscore = Traverse::Document.new(open url)
|
24
|
+
|
25
|
+
# let's start traversing!
|
26
|
+
|
27
|
+
boxscore.game_id # => '2011/03/31/detmlb-nyamlb-1'
|
28
|
+
|
29
|
+
boxscore.battings[0].batters[1].name_display_first_last # => 'Derek Jeter'
|
30
|
+
|
31
|
+
boxscore.battings[0].batters.select do |batter|
|
32
|
+
batter.rbi.to_i > 0
|
33
|
+
end.count # => 4
|
34
|
+
|
35
|
+
boxscore.pitchings.find do |pitching|
|
36
|
+
pitching.team_flag == 'away'
|
37
|
+
end.out # => '24'
|
38
|
+
```
|
data/lib/traverse/version.rb
CHANGED
data/lib/traverse.rb
CHANGED
@@ -53,24 +53,26 @@ module Traverse
|
|
53
53
|
@document.get_attribute attr
|
54
54
|
end
|
55
55
|
|
56
|
+
def attributes
|
57
|
+
name_value_pairs = @document.attributes.map do |name, attribute|
|
58
|
+
[name, attribute.value]
|
59
|
+
end
|
60
|
+
Hash[ name_value_pairs ]
|
61
|
+
end
|
62
|
+
|
63
|
+
def children
|
64
|
+
real_children.map { |child| Document.new child }
|
65
|
+
end
|
66
|
+
|
56
67
|
private
|
57
68
|
def method_missing m, *args, &block
|
58
69
|
self[m] or super
|
59
70
|
end
|
60
71
|
|
61
|
-
def attributes
|
62
|
-
if @document.is_a? Nokogiri::XML::Document
|
63
|
-
[]
|
64
|
-
else
|
65
|
-
@document.attributes
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
72
|
def text_node?
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
@document.children.first.is_a? Nokogiri::XML::Text
|
73
|
+
@document.children.all? do |child|
|
74
|
+
child.is_a? Nokogiri::XML::Text
|
75
|
+
end
|
74
76
|
end
|
75
77
|
|
76
78
|
def text_only_node? node
|
@@ -103,7 +105,7 @@ module Traverse
|
|
103
105
|
real_children.select do |child|
|
104
106
|
child.children.all? do |baby|
|
105
107
|
if baby.class == Nokogiri::XML::Text
|
106
|
-
true
|
108
|
+
true # ignore text children
|
107
109
|
else
|
108
110
|
baby.name == child.name.singularize
|
109
111
|
end
|
@@ -111,12 +113,28 @@ module Traverse
|
|
111
113
|
end
|
112
114
|
end
|
113
115
|
|
116
|
+
def find_first_non_comment_node xml_string
|
117
|
+
Nokogiri::XML(xml_string).children.find do |child|
|
118
|
+
!child.comment?
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
114
122
|
def setup_underlying_document document
|
115
123
|
if document.is_a? String
|
116
124
|
begin
|
117
|
-
@document =
|
125
|
+
@document = find_first_non_comment_node document
|
118
126
|
rescue
|
119
|
-
|
127
|
+
nil
|
128
|
+
end
|
129
|
+
elsif document.respond_to? :read # is it file-like...
|
130
|
+
begin
|
131
|
+
@document = find_first_non_comment_node document.read
|
132
|
+
rescue
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
elsif document.is_a? Nokogiri::XML::Document
|
136
|
+
@document = document.children.find do |child|
|
137
|
+
!child.comment?
|
120
138
|
end
|
121
139
|
else
|
122
140
|
@document = document
|
@@ -127,18 +145,4 @@ module Traverse
|
|
127
145
|
"<Traversable... >"
|
128
146
|
end
|
129
147
|
end
|
130
|
-
|
131
|
-
module Proxy
|
132
|
-
private
|
133
|
-
def proxy *args
|
134
|
-
if args.empty?
|
135
|
-
@proxy
|
136
|
-
else
|
137
|
-
@proxy = args.first
|
138
|
-
def method_missing m
|
139
|
-
@proxy.send m
|
140
|
-
end
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
148
|
end
|
data/spec/spec.rb
CHANGED
@@ -56,51 +56,69 @@ xml = %{
|
|
56
56
|
|
57
57
|
describe Traverse::Document do
|
58
58
|
before do
|
59
|
-
@
|
59
|
+
@book = Traverse::Document.new xml
|
60
60
|
end
|
61
61
|
|
62
62
|
it "helps you access attributes" do
|
63
|
-
@
|
63
|
+
@book.title.must_equal "Vineland"
|
64
64
|
end
|
65
65
|
|
66
66
|
it "also helps you access attributes shadowed by children" do
|
67
|
-
@
|
68
|
-
@
|
69
|
-
@
|
67
|
+
@book.author.wont_equal "Thomas Pynchon"
|
68
|
+
@book['author'].must_equal "Thomas Pynchon"
|
69
|
+
@book.author.name.must_equal "Thomas Pynchon"
|
70
70
|
end
|
71
71
|
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
describe "support for enumerable" do
|
73
|
+
|
74
|
+
it "gives you access to the current node's attributes" do
|
75
|
+
@book.attributes.any? do |name, value|
|
76
|
+
value == "Vineland"
|
77
|
+
end.must_equal true
|
78
|
+
end
|
79
|
+
|
80
|
+
it "gives you access to the current node's children as traversable documents" do
|
81
|
+
assert @book.children.any? do |child|
|
82
|
+
child.attributes.any? do |name, value|
|
83
|
+
name == "reviewer" and value == "Salman Rushdie"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
it "helps you traverse to child nodes" do
|
91
|
+
@book.review.reviewer.must_equal "Salman Rushdie"
|
92
|
+
@book.epigraph.author.must_equal "Johnny Copeland"
|
75
93
|
end
|
76
94
|
|
77
95
|
it "knows when a node contains only text" do
|
78
|
-
assert @
|
96
|
+
assert @book.epigraph.send(:text_node?)
|
79
97
|
end
|
80
98
|
|
81
99
|
it "handles annoying text nodes transparently" do
|
82
|
-
@
|
83
|
-
@
|
100
|
+
@book.epigraph.text.must_match(/Every dog has his day/)
|
101
|
+
@book.review.text.must_match(/that rarest of birds/)
|
84
102
|
end
|
85
103
|
|
86
104
|
it "nevertheless handles attributes named 'text'" do
|
87
|
-
@
|
88
|
-
@
|
105
|
+
@book.text['text'].must_match(/seriously/)
|
106
|
+
@book.text.text.must_match(/rilly/)
|
89
107
|
end
|
90
108
|
|
91
109
|
it "knows when a node has only text and no attributes" do
|
92
|
-
@
|
110
|
+
@book.pagecount.must_equal "385"
|
93
111
|
end
|
94
112
|
|
95
113
|
it "knows to collect children with the same name" do
|
96
|
-
@
|
97
|
-
assert @
|
114
|
+
@book.author.books.count.must_equal 8
|
115
|
+
assert @book.author.books.all? do |book|
|
98
116
|
book.is_a? String
|
99
117
|
end
|
100
118
|
end
|
101
119
|
|
102
120
|
it "knows to collect children of a pluralized parent" do
|
103
|
-
@
|
104
|
-
@
|
121
|
+
@book.quotations.count.must_equal 2
|
122
|
+
@book.quotations.last.text.must_match(/more like an idiot savant/)
|
105
123
|
end
|
106
124
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: traverse
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,12 +9,12 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-08-
|
12
|
+
date: 2011-08-05 00:00:00.000000000 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: nokogiri
|
17
|
-
requirement: &
|
17
|
+
requirement: &2152908620 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
@@ -22,7 +22,7 @@ dependencies:
|
|
22
22
|
version: '1.5'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2152908620
|
26
26
|
description: Easily traverse an XML document.
|
27
27
|
email:
|
28
28
|
- alan.m.odonnell@gmail.com
|