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 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
+ ```
@@ -1,3 +1,3 @@
1
1
  module Traverse
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
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
- num_children = @document.children.count
71
- return false unless num_children == 1
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 = Nokogiri::XML(document)
125
+ @document = find_first_non_comment_node document
118
126
  rescue
119
- return nil
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
- @doc = Traverse::Document.new xml
59
+ @book = Traverse::Document.new xml
60
60
  end
61
61
 
62
62
  it "helps you access attributes" do
63
- @doc.book.title.must_equal "Vineland"
63
+ @book.title.must_equal "Vineland"
64
64
  end
65
65
 
66
66
  it "also helps you access attributes shadowed by children" do
67
- @doc.book.author.wont_equal "Thomas Pynchon"
68
- @doc.book['author'].must_equal "Thomas Pynchon"
69
- @doc.book.author.name.must_equal "Thomas Pynchon"
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
- it "helps you get at child nodes" do
73
- @doc.book.review.reviewer.must_equal "Salman Rushdie"
74
- @doc.book.epigraph.author.must_equal "Johnny Copeland"
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 @doc.book.epigraph.send(:text_node?)
96
+ assert @book.epigraph.send(:text_node?)
79
97
  end
80
98
 
81
99
  it "handles annoying text nodes transparently" do
82
- @doc.book.epigraph.text.must_match(/Every dog has his day/)
83
- @doc.book.review.text.must_match(/that rarest of birds/)
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
- @doc.book.text['text'].must_match(/seriously/)
88
- @doc.book.text.text.must_match(/rilly/)
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
- @doc.book.pagecount.must_equal "385"
110
+ @book.pagecount.must_equal "385"
93
111
  end
94
112
 
95
113
  it "knows to collect children with the same name" do
96
- @doc.book.author.books.count.must_equal 8
97
- assert @doc.book.author.books.all? do |book|
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
- @doc.book.quotations.count.must_equal 2
104
- @doc.book.quotations.last.text.must_match(/more like an idiot savant/)
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.2
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-03 00:00:00.000000000 -04:00
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: &2157314300 !ruby/object:Gem::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: *2157314300
25
+ version_requirements: *2152908620
26
26
  description: Easily traverse an XML document.
27
27
  email:
28
28
  - alan.m.odonnell@gmail.com