astro-sax-machine 0.0.12.20090419

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.textile ADDED
@@ -0,0 +1,87 @@
1
+ h1. SAX Machine
2
+
3
+ "http://github.com/pauldix/sax-machine/wikis":http://github.com/pauldix/sax-machine/wikis
4
+
5
+ "http://github.com/pauldix/sax-machine/tree/master":http://github.com/pauldix/sax-machine/tree/master
6
+
7
+ h2. Description
8
+
9
+ A declarative SAX parsing library backed by Nokogiri
10
+
11
+ h2. Usage
12
+
13
+ <pre>
14
+ require 'sax-machine'
15
+
16
+ # Class for parsing an atom entry out of a feedburner atom feed
17
+ class AtomEntry
18
+ include SAXMachine
19
+ element :title
20
+ # the :as argument makes this available through atom_entry.author instead of .name
21
+ element :name, :as => :author
22
+ element "feedburner:origLink", :as => :url
23
+ element :summary
24
+ element :content
25
+ element :published
26
+ end
27
+
28
+ # Class for parsing Atom feeds
29
+ class Atom
30
+ include SAXMachine
31
+ element :title
32
+ # the :with argument means that you only match a link tag that has an attribute of :type => "text/html"
33
+ # the :value argument means that instead of setting the value to the text between the tag,
34
+ # it sets it to the attribute value of :href
35
+ element :link, :value => :href, :as => :url, :with => {:type => "text/html"}
36
+ element :link, :value => :href, :as => :feed_url, :with => {:type => "application/atom+xml"}
37
+ elements :entry, :as => :entries, :class => AtomEntry
38
+ end
39
+
40
+ # you can then parse like this
41
+ feed = Atom.parse(xml_text)
42
+ # then you're ready to rock
43
+ feed.title # => whatever the title of the blog is
44
+ feed.url # => the main url of the blog
45
+ feed.feed_url # => goes to the feedburner feed
46
+
47
+ feed.entries.first.title # => title of the first entry
48
+ feed.entries.first.author # => the author of the first entry
49
+ feed.entries.first.url # => the permalink on the blog for this entry
50
+ # etc ...
51
+
52
+ # you can also use the elements method without specifying a class like so
53
+ class SomeServiceResponse
54
+ elements :message, :as => :messages
55
+ end
56
+
57
+ response = SomeServiceResponse.parse("<response><message>hi</message><message>world</message></response>")
58
+ response.messages.first # => "hi"
59
+ response.messages.last # => "world"
60
+ </pre>
61
+
62
+ h2. LICENSE
63
+
64
+ (The MIT License)
65
+
66
+ Copyright (c) 2009:
67
+
68
+ "Paul Dix":http://pauldix.net
69
+
70
+ Permission is hereby granted, free of charge, to any person obtaining
71
+ a copy of this software and associated documentation files (the
72
+ 'Software'), to deal in the Software without restriction, including
73
+ without limitation the rights to use, copy, modify, merge, publish,
74
+ distribute, sublicense, and/or sell copies of the Software, and to
75
+ permit persons to whom the Software is furnished to do so, subject to
76
+ the following conditions:
77
+
78
+ The above copyright notice and this permission notice shall be
79
+ included in all copies or substantial portions of the Software.
80
+
81
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
82
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
83
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
84
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
85
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
86
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
87
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,14 @@
1
+ require "spec"
2
+ require "spec/rake/spectask"
3
+ require 'lib/sax-machine.rb'
4
+
5
+ Spec::Rake::SpecTask.new do |t|
6
+ t.spec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
7
+ t.spec_files = FileList['spec/**/*_spec.rb']
8
+ end
9
+
10
+ task :install do
11
+ rm_rf "*.gem"
12
+ puts `gem build sax-machine.gemspec`
13
+ puts `sudo gem install sax-machine-#{SAXMachine::VERSION}.gem`
14
+ end
@@ -0,0 +1,11 @@
1
+ require "rubygems"
2
+
3
+ $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
4
+
5
+ require "sax-machine/sax_document"
6
+ require "sax-machine/sax_handler"
7
+ require "sax-machine/sax_config"
8
+
9
+ module SAXMachine
10
+ VERSION = "0.0.12"
11
+ end
@@ -0,0 +1,33 @@
1
+ module SAXMachine
2
+ class SAXConfig
3
+
4
+ class CollectionConfig
5
+ attr_reader :name
6
+
7
+ def initialize(name, options)
8
+ @name = name.to_s
9
+ @class = options[:class]
10
+ @as = options[:as].to_s
11
+ end
12
+
13
+ def handler
14
+ SAXHandler.new(@class.new)
15
+ end
16
+
17
+ def accessor
18
+ as
19
+ end
20
+
21
+ protected
22
+
23
+ def as
24
+ @as
25
+ end
26
+
27
+ def class
28
+ @class || @name
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ require "sax-machine/sax_element_config"
2
+ require "sax-machine/sax_collection_config"
3
+
4
+ module SAXMachine
5
+ class SAXConfig
6
+ def initialize
7
+ @top_level_elements = []
8
+ @collection_elements = []
9
+ end
10
+
11
+ def add_top_level_element(name, options)
12
+ @top_level_elements << ElementConfig.new(name, options)
13
+ end
14
+
15
+ def add_collection_element(name, options)
16
+ @collection_elements << CollectionConfig.new(name, options)
17
+ end
18
+
19
+ def collection_config(name)
20
+ @collection_elements.detect { |ce| ce.name.to_s == name.to_s }
21
+ end
22
+
23
+ def element_config_for_attribute(name, attrs)
24
+ element_configs = @top_level_elements.select do |element_config|
25
+ element_config.name == name &&
26
+ element_config.has_value_and_attrs_match?(attrs)
27
+ end
28
+ element_configs.empty? ? nil : element_configs
29
+ end
30
+
31
+ def element_config_for_tag(name, attrs)
32
+ @top_level_elements.detect do |element_config|
33
+ element_config.name == name &&
34
+ element_config.attrs_match?(attrs)
35
+ end
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,74 @@
1
+ require "nokogiri"
2
+
3
+ module SAXMachine
4
+
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ def parse(xml_text)
10
+ unless @parser
11
+ sax_handler = SAXHandler.new(self)
12
+ @parser = Nokogiri::XML::SAX::PushParser.new(sax_handler)
13
+ end
14
+ @parser << xml_text
15
+ self
16
+ end
17
+
18
+ def parse_finish
19
+ if @parser
20
+ @parser.finish
21
+ end
22
+ self
23
+ end
24
+
25
+ module ClassMethods
26
+
27
+ def parse(xml_text)
28
+ # It might be cleaner to aditionally call parse_finish here, but
29
+ # then Nokogiri/libxml2 barfs on incomplete documents. Desired
30
+ # behaviour?
31
+ new.parse(xml_text)
32
+ end
33
+
34
+ def element(name, options = {})
35
+ options[:as] ||= name
36
+ sax_config.add_top_level_element(name, options)
37
+
38
+ # we only want to insert the getter and setter if they haven't defined it from elsewhere.
39
+ # this is how we allow custom parsing behavior. So you could define the setter
40
+ # and have it parse the string into a date or whatever.
41
+ attr_reader options[:as] unless instance_methods.include?(options[:as].to_s)
42
+ attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
43
+ end
44
+
45
+ def elements(name, options = {})
46
+ options[:as] ||= name
47
+ if options[:class]
48
+ sax_config.add_collection_element(name, options)
49
+ else
50
+ class_eval <<-SRC
51
+ def add_#{options[:as]}(value)
52
+ #{options[:as]} << value
53
+ end
54
+ SRC
55
+ sax_config.add_top_level_element(name, options.merge(:collection => true))
56
+ end
57
+
58
+ if !instance_methods.include?(options[:as].to_s)
59
+ class_eval <<-SRC
60
+ def #{options[:as]}
61
+ @#{options[:as]} ||= []
62
+ end
63
+ SRC
64
+ end
65
+
66
+ attr_writer options[:as] unless instance_methods.include?("#{options[:as]}=")
67
+ end
68
+
69
+ def sax_config
70
+ @sax_config ||= SAXConfig.new
71
+ end
72
+ end
73
+
74
+ end
@@ -0,0 +1,55 @@
1
+ module SAXMachine
2
+ class SAXConfig
3
+
4
+ class ElementConfig
5
+ attr_reader :name, :setter
6
+
7
+ def initialize(name, options)
8
+ @name = name.to_s
9
+
10
+ if options.has_key?(:with)
11
+ # for faster comparisons later
12
+ @with = options[:with].to_a.flatten.collect {|o| o.to_s}
13
+ else
14
+ @with = nil
15
+ end
16
+
17
+ if options.has_key?(:value)
18
+ @value = options[:value].to_s
19
+ else
20
+ @value = nil
21
+ end
22
+
23
+ @as = options[:as]
24
+ @collection = options[:collection]
25
+
26
+ if @collection
27
+ @setter = "add_#{options[:as]}"
28
+ else
29
+ @setter = "#{@as}="
30
+ end
31
+ end
32
+
33
+ def value_from_attrs(attrs)
34
+ attrs.index(@value) ? attrs[attrs.index(@value) + 1] : nil
35
+ end
36
+
37
+ def attrs_match?(attrs)
38
+ if @with
39
+ @with == (@with & attrs)
40
+ else
41
+ true
42
+ end
43
+ end
44
+
45
+ def has_value_and_attrs_match?(attrs)
46
+ !@value.nil? && attrs_match?(attrs)
47
+ end
48
+
49
+ def collection?
50
+ @collection
51
+ end
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,105 @@
1
+ require "nokogiri"
2
+
3
+ module SAXMachine
4
+ class SAXHandler < Nokogiri::XML::SAX::Document
5
+ attr_reader :object
6
+
7
+ def initialize(object)
8
+ @object = object
9
+ @parsed_configs = {}
10
+ end
11
+
12
+ def characters(string)
13
+ if parsing_collection?
14
+ @collection_handler.characters(string)
15
+ elsif @element_config
16
+ @value << string
17
+ end
18
+ end
19
+
20
+ def cdata_block(string)
21
+ characters(string)
22
+ end
23
+
24
+ def start_element(name, attrs = [])
25
+ @name = name
26
+ @attrs = attrs
27
+
28
+ if parsing_collection?
29
+ @collection_handler.start_element(@name, @attrs)
30
+
31
+ elsif @collection_config = sax_config.collection_config(@name)
32
+ @collection_handler = @collection_config.handler
33
+ @collection_handler.start_element(@name, @attrs)
34
+
35
+ elsif @element_config = sax_config.element_config_for_attribute(@name, @attrs)
36
+ parse_element_attribute
37
+
38
+ else
39
+ @value = ""
40
+ @element_config = sax_config.element_config_for_tag(@name, @attrs)
41
+ end
42
+ end
43
+
44
+ def end_element(name)
45
+ if parsing_collection? && @collection_config.name == name
46
+ @object.send(@collection_config.accessor) << @collection_handler.object
47
+ reset_current_collection
48
+
49
+ elsif parsing_collection?
50
+ @collection_handler.end_element(name)
51
+
52
+ elsif characaters_captured? && !parsed_config?
53
+ mark_as_parsed
54
+ @object.send(@element_config.setter, @value)
55
+ end
56
+
57
+ reset_current_tag
58
+ end
59
+
60
+ def characaters_captured?
61
+ !@value.nil? && !@value.empty?
62
+ end
63
+
64
+ def parsing_collection?
65
+ !@collection_handler.nil?
66
+ end
67
+
68
+ def parse_element_attribute
69
+ unless parsed_config?
70
+ mark_as_parsed
71
+ @element_config.each do |config|
72
+ @object.send(config.setter, config.value_from_attrs(@attrs))
73
+ end
74
+ end
75
+
76
+ @element_config = nil
77
+ end
78
+
79
+ def mark_as_parsed
80
+ # TODO: make this code not suck like this
81
+ @parsed_configs[@element_config] = true unless (@element_config.respond_to?(:collection?) && @element_config.collection?) ||
82
+ (@element_config.class == Array && @element_config.first.collection?)
83
+ end
84
+
85
+ def parsed_config?
86
+ @parsed_configs[@element_config]
87
+ end
88
+
89
+ def reset_current_collection
90
+ @collection_handler = nil
91
+ @collection_config = nil
92
+ end
93
+
94
+ def reset_current_tag
95
+ @name = nil
96
+ @attrs = nil
97
+ @value = nil
98
+ @element_config = nil
99
+ end
100
+
101
+ def sax_config
102
+ @object.class.sax_config
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,343 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe "SAXMachine" do
4
+ describe "element" do
5
+ describe "when parsing a single element" do
6
+ before :each do
7
+ @klass = Class.new do
8
+ include SAXMachine
9
+ element :title
10
+ end
11
+ end
12
+
13
+ it "should provide an accessor" do
14
+ document = @klass.new
15
+ document.title = "Title"
16
+ document.title.should == "Title"
17
+ end
18
+
19
+ it "should not overwrite the setter if there is already one present" do
20
+ @klass = Class.new do
21
+ def title=(val)
22
+ @title = "#{val} **"
23
+ end
24
+ include SAXMachine
25
+ element :title
26
+ end
27
+ document = @klass.new
28
+ document.title = "Title"
29
+ document.title.should == "Title **"
30
+ end
31
+
32
+ it "should not overwrite the accessor when the element is not present" do
33
+ document = @klass.new
34
+ document.title = "Title"
35
+ document.parse("<foo></foo>")
36
+ document.title.should == "Title"
37
+ end
38
+
39
+ it "should overwrite the value when the element is present" do
40
+ document = @klass.new
41
+ document.title = "Old title"
42
+ document.parse("<title>New title</title>")
43
+ document.title.should == "New title"
44
+ end
45
+
46
+ it "should save the element text into an accessor" do
47
+ document = @klass.parse("<title>My Title</title>")
48
+ document.title.should == "My Title"
49
+ end
50
+
51
+ it "should save cdata into an accessor" do
52
+ document = @klass.parse("<title><![CDATA[A Title]]></title>")
53
+ document.title.should == "A Title"
54
+ end
55
+
56
+ it "should save the element text into an accessor when there are multiple elements" do
57
+ document = @klass.parse("<xml><title>My Title</title><foo>bar</foo></xml>")
58
+ document.title.should == "My Title"
59
+ end
60
+
61
+ it "should save the first element text when there are multiple of the same element" do
62
+ document = @klass.parse("<xml><title>My Title</title><title>bar</title></xml>")
63
+ document.title.should == "My Title"
64
+ end
65
+ end
66
+
67
+ describe "when parsing multiple elements" do
68
+ before :each do
69
+ @klass = Class.new do
70
+ include SAXMachine
71
+ element :title
72
+ element :name
73
+ end
74
+ end
75
+
76
+ it "should save the element text for a second tag" do
77
+ document = @klass.parse("<xml><title>My Title</title><name>Paul</name></xml>")
78
+ document.name.should == "Paul"
79
+ document.title.should == "My Title"
80
+ end
81
+ end
82
+
83
+ describe "when using options for parsing elements" do
84
+ describe "using the 'as' option" do
85
+ before :each do
86
+ @klass = Class.new do
87
+ include SAXMachine
88
+ element :description, :as => :summary
89
+ end
90
+ end
91
+
92
+ it "should provide an accessor using the 'as' name" do
93
+ document = @klass.new
94
+ document.summary = "a small summary"
95
+ document.summary.should == "a small summary"
96
+ end
97
+
98
+ it "should save the element text into the 'as' accessor" do
99
+ document = @klass.parse("<description>here is a description</description>")
100
+ document.summary.should == "here is a description"
101
+ end
102
+ end
103
+
104
+ describe "using the :with option" do
105
+ describe "and the :value option" do
106
+ before :each do
107
+ @klass = Class.new do
108
+ include SAXMachine
109
+ element :link, :value => :href, :with => {:foo => "bar"}
110
+ end
111
+ end
112
+
113
+ it "should save the value of a matching element" do
114
+ document = @klass.parse("<link href='test' foo='bar'>asdf</link>")
115
+ document.link.should == "test"
116
+ end
117
+
118
+ it "should save the value of the first matching element" do
119
+ document = @klass.parse("<xml><link href='first' foo='bar' /><link href='second' foo='bar' /></xml>")
120
+ document.link.should == "first"
121
+ end
122
+
123
+ describe "and the :as option" do
124
+ before :each do
125
+ @klass = Class.new do
126
+ include SAXMachine
127
+ element :link, :value => :href, :as => :url, :with => {:foo => "bar"}
128
+ element :link, :value => :href, :as => :second_url, :with => {:asdf => "jkl"}
129
+ end
130
+ end
131
+
132
+ it "should save the value of the first matching element" do
133
+ document = @klass.parse("<xml><link href='first' foo='bar' /><link href='second' asdf='jkl' /><link href='second' foo='bar' /></xml>")
134
+ document.url.should == "first"
135
+ document.second_url.should == "second"
136
+ end
137
+ end
138
+ end
139
+
140
+ describe "with only one element" do
141
+ before :each do
142
+ @klass = Class.new do
143
+ include SAXMachine
144
+ element :link, :with => {:foo => "bar"}
145
+ end
146
+ end
147
+
148
+ it "should save the text of an element that has matching attributes" do
149
+ document = @klass.parse("<link foo=\"bar\">match</link>")
150
+ document.link.should == "match"
151
+ end
152
+
153
+ it "should not save the text of an element that doesn't have matching attributes" do
154
+ document = @klass.parse("<link>no match</link>")
155
+ document.link.should be_nil
156
+ end
157
+
158
+ it "should save the text of an element that has matching attributes when it is the second of that type" do
159
+ document = @klass.parse("<xml><link>no match</link><link foo=\"bar\">match</link></xml>")
160
+ document.link.should == "match"
161
+ end
162
+
163
+ it "should save the text of an element that has matching attributes plus a few more" do
164
+ document = @klass.parse("<xml><link>no match</link><link asdf='jkl' foo='bar'>match</link>")
165
+ document.link.should == "match"
166
+ end
167
+ end
168
+
169
+ describe "with multiple elements of same tag" do
170
+ before :each do
171
+ @klass = Class.new do
172
+ include SAXMachine
173
+ element :link, :as => :first, :with => {:foo => "bar"}
174
+ element :link, :as => :second, :with => {:asdf => "jkl"}
175
+ end
176
+ end
177
+
178
+ it "should match the first element" do
179
+ document = @klass.parse("<xml><link>no match</link><link foo=\"bar\">first match</link><link>no match</link></xml>")
180
+ document.first.should == "first match"
181
+ end
182
+
183
+ it "should match the second element" do
184
+ document = @klass.parse("<xml><link>no match</link><link foo='bar'>first match</link><link asdf='jkl'>second match</link><link>hi</link></xml>")
185
+ document.second.should == "second match"
186
+ end
187
+ end
188
+ end # using the 'with' option
189
+
190
+ describe "using the 'value' option" do
191
+ before :each do
192
+ @klass = Class.new do
193
+ include SAXMachine
194
+ element :link, :value => :foo
195
+ end
196
+ end
197
+
198
+ it "should save the attribute value" do
199
+ document = @klass.parse("<link foo='test'>hello</link>")
200
+ document.link.should == 'test'
201
+ end
202
+
203
+ it "should save the attribute value when there is no text enclosed by the tag" do
204
+ document = @klass.parse("<link foo='test'></link>")
205
+ document.link.should == 'test'
206
+ end
207
+
208
+ it "should save the attribute value when the tag close is in the open" do
209
+ document = @klass.parse("<link foo='test'/>")
210
+ document.link.should == 'test'
211
+ end
212
+
213
+ it "should save two different attribute values on a single tag" do
214
+ @klass = Class.new do
215
+ include SAXMachine
216
+ element :link, :value => :foo, :as => :first
217
+ element :link, :value => :bar, :as => :second
218
+ end
219
+ document = @klass.parse("<link foo='foo value' bar='bar value'></link>")
220
+ document.first.should == "foo value"
221
+ document.second.should == "bar value"
222
+ end
223
+
224
+ it "should not fail if one of the attribute hasn't been defined" do
225
+ @klass = Class.new do
226
+ include SAXMachine
227
+ element :link, :value => :foo, :as => :first
228
+ element :link, :value => :bar, :as => :second
229
+ end
230
+ document = @klass.parse("<link foo='foo value'></link>")
231
+ document.first.should == "foo value"
232
+ document.second.should be_nil
233
+ end
234
+ end
235
+ end
236
+ end
237
+
238
+ describe "elements" do
239
+ describe "when parsing multiple elements" do
240
+ before :each do
241
+ @klass = Class.new do
242
+ include SAXMachine
243
+ elements :entry, :as => :entries
244
+ end
245
+ end
246
+
247
+ it "should provide a collection accessor" do
248
+ document = @klass.new
249
+ document.entries << :foo
250
+ document.entries.should == [:foo]
251
+ end
252
+
253
+ it "should parse a single element" do
254
+ document = @klass.parse("<entry>hello</entry>")
255
+ document.entries.should == ["hello"]
256
+ end
257
+
258
+ it "should parse multiple elements" do
259
+ document = @klass.parse("<xml><entry>hello</entry><entry>world</entry></xml>")
260
+ document.entries.should == ["hello", "world"]
261
+ end
262
+
263
+ it "should parse multiple elements when taking an attribute value" do
264
+ attribute_klass = Class.new do
265
+ include SAXMachine
266
+ elements :entry, :as => :entries, :value => :foo
267
+ end
268
+ doc = attribute_klass.parse("<xml><entry foo='asdf' /><entry foo='jkl' /></xml>")
269
+ doc.entries.should == ["asdf", "jkl"]
270
+ end
271
+ end
272
+
273
+ describe "when using the class option" do
274
+ before :each do
275
+ class Foo
276
+ include SAXMachine
277
+ element :title
278
+ end
279
+ @klass = Class.new do
280
+ include SAXMachine
281
+ elements :entry, :as => :entries, :class => Foo
282
+ end
283
+ end
284
+
285
+ it "should parse a single element with children" do
286
+ document = @klass.parse("<entry><title>a title</title></entry>")
287
+ document.entries.size.should == 1
288
+ document.entries.first.title.should == "a title"
289
+ end
290
+
291
+ it "should parse multiple elements with children" do
292
+ document = @klass.parse("<xml><entry><title>title 1</title></entry><entry><title>title 2</title></entry></xml>")
293
+ document.entries.size.should == 2
294
+ document.entries.first.title.should == "title 1"
295
+ document.entries.last.title.should == "title 2"
296
+ end
297
+
298
+ it "should not parse a top level element that is specified only in a child" do
299
+ document = @klass.parse("<xml><title>no parse</title><entry><title>correct title</title></entry></xml>")
300
+ document.entries.size.should == 1
301
+ document.entries.first.title.should == "correct title"
302
+ end
303
+
304
+ it "should parse out an attribute value from the tag that starts the collection" do
305
+ class Foo
306
+ element :entry, :value => :href, :as => :url
307
+ end
308
+ document = @klass.parse("<xml><entry href='http://pauldix.net'><title>paul</title></entry></xml>")
309
+ document.entries.size.should == 1
310
+ document.entries.first.title.should == "paul"
311
+ document.entries.first.url.should == "http://pauldix.net"
312
+ end
313
+ end
314
+ end
315
+
316
+ describe "full example" do
317
+ before :each do
318
+ @xml = File.read('spec/sax-machine/atom.xml')
319
+ class AtomEntry
320
+ include SAXMachine
321
+ element :title
322
+ element :name, :as => :author
323
+ element "feedburner:origLink", :as => :url
324
+ element :summary
325
+ element :content
326
+ element :published
327
+ end
328
+
329
+ class Atom
330
+ include SAXMachine
331
+ element :title
332
+ element :link, :value => :href, :as => :url, :with => {:type => "text/html"}
333
+ element :link, :value => :href, :as => :feed_url, :with => {:type => "application/atom+xml"}
334
+ elements :entry, :as => :entries, :class => AtomEntry
335
+ end
336
+ end # before
337
+
338
+ it "should parse the url" do
339
+ f = Atom.parse(@xml)
340
+ f.url.should == "http://www.pauldix.net/"
341
+ end
342
+ end
343
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --diff
2
+ --color
@@ -0,0 +1,13 @@
1
+ require "rubygems"
2
+ require "spec"
3
+
4
+ # gem install redgreen for colored test output
5
+ begin require "redgreen" unless ENV['TM_CURRENT_LINE']; rescue LoadError; end
6
+
7
+ path = File.expand_path(File.dirname(__FILE__) + "/../lib/")
8
+ $LOAD_PATH.unshift(path) unless $LOAD_PATH.include?(path)
9
+
10
+ require "lib/sax-machine"
11
+
12
+ # Spec::Runner.configure do |config|
13
+ # end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: astro-sax-machine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.12.20090419
5
+ platform: ruby
6
+ authors:
7
+ - Paul Dix
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-01-13 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: nokogiri
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ description:
26
+ email: paul@pauldix.net
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/sax-machine.rb
35
+ - lib/sax-machine/sax_config.rb
36
+ - lib/sax-machine/sax_collection_config.rb
37
+ - lib/sax-machine/sax_element_config.rb
38
+ - lib/sax-machine/sax_document.rb
39
+ - lib/sax-machine/sax_handler.rb
40
+ - README.textile
41
+ - Rakefile
42
+ - spec/spec.opts
43
+ - spec/spec_helper.rb
44
+ - spec/sax-machine/sax_document_spec.rb
45
+ has_rdoc: false
46
+ homepage: http://github.com/pauldix/sax-machine
47
+ post_install_message:
48
+ rdoc_options: []
49
+
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ requirements: []
65
+
66
+ rubyforge_project:
67
+ rubygems_version: 1.2.0
68
+ signing_key:
69
+ specification_version: 2
70
+ summary: Declarative SAX Parsing with Nokogiri
71
+ test_files: []
72
+