require File.dirname(__FILE__) + '/../spec_helper'
describe "SAXMachine" do
describe "element" do
describe "when parsing a single element" do
before :each do
@klass = Class.new do
include SAXMachine
element :title
end
end
it "should provide an accessor" do
document = @klass.new
document.title = "Title"
document.title.should == "Title"
end
it "should allow introspection of the elements" do
@klass.column_names.should =~ [:title]
end
it "should not overwrite the setter if there is already one present" do
@klass = Class.new do
def title=(val)
@title = "#{val} **"
end
include SAXMachine
element :title
end
document = @klass.new
document.title = "Title"
document.title.should == "Title **"
end
describe "the class attribute" do
before(:each) do
@klass = Class.new do
include SAXMachine
element :date, :class => DateTime
end
@document = @klass.new
@document.date = DateTime.now.to_s
end
it "should be available" do
@klass.data_class(:date).should == DateTime
end
end
describe "the required attribute" do
it "should be available" do
@klass = Class.new do
include SAXMachine
element :date, :required => true
end
@klass.required?(:date).should be_true
end
end
it "should not overwrite the accessor when the element is not present" do
document = @klass.new
document.title = "Title"
document.parse("")
document.title.should == "Title"
end
it "should *not* overwrite the value when the element is present (new behaviour!)" do
document = @klass.new
document.title = "Old title"
document.parse("
New title")
document.title.should == "Old title"
end
it "should save the element text into an accessor" do
document = @klass.parse("My Title")
document.title.should == "My Title"
end
it "should save cdata into an accessor" do
document = @klass.parse("")
document.title.should == "A Title"
end
it "should save the element text into an accessor when there are multiple elements" do
document = @klass.parse("My Titlebar")
document.title.should == "My Title"
end
it "should save the first element text when there are multiple of the same element" do
document = @klass.parse("My Titlebar")
document.title.should == "My Title"
end
end
describe "when parsing multiple elements" do
before :each do
@klass = Class.new do
include SAXMachine
element :title
element :name
end
end
it "should save the element text for a second tag" do
document = @klass.parse("My TitlePaul")
document.name.should == "Paul"
document.title.should == "My Title"
end
end
describe "when using options for parsing elements" do
describe "using the 'as' option" do
before :each do
@klass = Class.new do
include SAXMachine
element :description, :as => :summary
end
end
it "should provide an accessor using the 'as' name" do
document = @klass.new
document.summary = "a small summary"
document.summary.should == "a small summary"
end
it "should save the element text into the 'as' accessor" do
document = @klass.parse("here is a description")
document.summary.should == "here is a description"
end
end
describe "using the :with option" do
describe "and the :value option" do
before :each do
@klass = Class.new do
include SAXMachine
element :link, :value => :href, :with => {:foo => "bar"}
end
end
it "should escape correctly the ampersand" do
document = @klass.parse("asdf")
document.link.should == "http://api.flickr.com/services/feeds/photos_public.gne?id=49724566@N00&lang=en-us&format=atom"
end
it "should save the value of a matching element" do
document = @klass.parse("asdf")
document.link.should == "test"
end
it "should save the value of the first matching element" do
document = @klass.parse("")
document.link.should == "first"
end
describe "and the :as option" do
before :each do
@klass = Class.new do
include SAXMachine
element :link, :value => :href, :as => :url, :with => {:foo => "bar"}
element :link, :value => :href, :as => :second_url, :with => {:asdf => "jkl"}
end
end
it "should save the value of the first matching element" do
document = @klass.parse("")
document.url.should == "first"
document.second_url.should == "second"
end
end
end
describe "with only one element" do
before :each do
@klass = Class.new do
include SAXMachine
element :link, :with => {:foo => "bar"}
end
end
it "should save the text of an element that has matching attributes" do
document = @klass.parse("match")
document.link.should == "match"
end
it "should not save the text of an element that doesn't have matching attributes" do
document = @klass.parse("no match")
document.link.should be_nil
end
it "should save the text of an element that has matching attributes when it is the second of that type" do
document = @klass.parse("no matchmatch")
document.link.should == "match"
end
it "should save the text of an element that has matching attributes plus a few more" do
document = @klass.parse("no matchmatch")
document.link.should == "match"
end
end
describe "with multiple elements of same tag" do
before :each do
@klass = Class.new do
include SAXMachine
element :link, :as => :first, :with => {:foo => "bar"}
element :link, :as => :second, :with => {:asdf => "jkl"}
end
end
it "should match the first element" do
document = @klass.parse("no matchfirst matchno match")
document.first.should == "first match"
end
it "should match the second element" do
document = @klass.parse("no matchfirst matchsecond matchhi")
document.second.should == "second match"
end
end
end # using the 'with' option
describe "using the 'value' option" do
before :each do
@klass = Class.new do
include SAXMachine
element :link, :value => :foo
end
end
it "should save the attribute value" do
document = @klass.parse("hello")
document.link.should == 'test'
end
it "should save the attribute value when there is no text enclosed by the tag" do
document = @klass.parse("")
document.link.should == 'test'
end
it "should save the attribute value when the tag close is in the open" do
document = @klass.parse("")
document.link.should == 'test'
end
it "should save two different attribute values on a single tag" do
@klass = Class.new do
include SAXMachine
element :link, :value => :foo, :as => :first
element :link, :value => :bar, :as => :second
end
document = @klass.parse("")
document.first.should == "foo value"
document.second.should == "bar value"
end
it "should not fail if one of the attribute hasn't been defined" do
@klass = Class.new do
include SAXMachine
element :link, :value => :foo, :as => :first
element :link, :value => :bar, :as => :second
end
document = @klass.parse("")
document.first.should == "foo value"
document.second.should be_nil
end
end
describe "when desiring both the content and attributes of an element" do
before :each do
@klass = Class.new do
include SAXMachine
element :link
element :link, :value => :foo, :as => :link_foo
element :link, :value => :bar, :as => :link_bar
end
end
it "should parse the element and attribute values" do
document = @klass.parse("hello")
document.link.should == 'hello'
document.link_foo.should == 'test1'
document.link_bar.should == 'test2'
end
end
describe "when specifying namespaces" do
before :all do
@klass = Class.new do
include SAXMachine
element :a, :xmlns => 'urn:test'
element :b, :xmlns => ['', 'urn:test']
end
end
it "should get the element with the xmlns" do
document = @klass.parse("hello")
document.a.should == 'hello'
end
it "shouldn't get the element without the xmlns" do
document = @klass.parse("hello")
document.a.should be_nil
end
it "shouldn't get the element with the wrong xmlns" do
document = @klass.parse("hello")
document.a.should be_nil
end
it "should get an element without xmlns if the empty namespace is desired" do
document = @klass.parse("hello")
document.b.should == 'hello'
end
it "should get an element with the right prefix" do
document = @klass.parse("hello")
document.a.should == 'hello'
end
it "should not get an element with the wrong prefix" do
document = @klass.parse("hello")
document.a.should be_nil
end
it "should get a prefixed element without xmlns if the empty namespace is desired" do
pending "this needs a less pickier nokogiri push parser"
document = @klass.parse("hello")
document.b.should == 'hello'
end
it "should get the namespaced element even it's not first" do
document = @klass.parse("foofoobar")
document.a.should == 'bar'
end
end
end
end
describe "elements" do
describe "when parsing multiple elements" do
before :each do
@klass = Class.new do
include SAXMachine
elements :entry, :as => :entries
end
end
it "should provide a collection accessor" do
document = @klass.new
document.entries << :foo
document.entries.should == [:foo]
end
it "should parse a single element" do
document = @klass.parse("hello")
document.entries.should == ["hello"]
end
it "should parse multiple elements" do
document = @klass.parse("helloworld")
document.entries.should == ["hello", "world"]
end
it "should parse multiple elements when taking an attribute value" do
attribute_klass = Class.new do
include SAXMachine
elements :entry, :as => :entries, :value => :foo
end
doc = attribute_klass.parse("")
doc.entries.should == ["asdf", "jkl"]
end
end
describe "when using the class option" do
before :each do
class Foo
include SAXMachine
element :title
end
@klass = Class.new do
include SAXMachine
elements :entry, :as => :entries, :class => Foo
end
end
it "should parse a single element with children" do
document = @klass.parse("a title")
document.entries.size.should == 1
document.entries.first.title.should == "a title"
end
it "should parse multiple elements with children" do
document = @klass.parse("title 1title 2")
document.entries.size.should == 2
document.entries.first.title.should == "title 1"
document.entries.last.title.should == "title 2"
end
it "should not parse a top level element that is specified only in a child" do
document = @klass.parse("no parsecorrect title")
document.entries.size.should == 1
document.entries.first.title.should == "correct title"
end
it "should parse out an attribute value from the tag that starts the collection" do
class Foo
element :entry, :value => :href, :as => :url
end
document = @klass.parse("paul")
document.entries.size.should == 1
document.entries.first.title.should == "paul"
document.entries.first.url.should == "http://pauldix.net"
end
end
end
describe "full example" do
XMLNS_ATOM = "http://www.w3.org/2005/Atom"
XMLNS_FEEDBURNER = "http://rssnamespace.org/feedburner/ext/1.0"
before :each do
@xml = File.read('spec/sax-machine/atom.xml')
class AtomEntry
include SAXMachine
element :title
element :name, :as => :author
element :origLink, :as => :orig_link, :xmlns => XMLNS_FEEDBURNER
element :summary
element :content
element :published
end
class Atom
include SAXMachine
element :title
element :link, :value => :href, :as => :url, :with => {:type => "text/html"}
element :link, :value => :href, :as => :feed_url, :with => {:type => "application/atom+xml"}
elements :entry, :as => :entries, :class => AtomEntry, :xmlns => XMLNS_ATOM
end
end # before
it "should parse the url" do
f = Atom.parse(@xml)
f.url.should == "http://www.pauldix.net/"
end
it "should parse all entries" do
f = Atom.parse(@xml)
f.entries.length.should == 5
end
it "should parse the feedburner:origLink" do
f = Atom.parse(@xml)
f.entries[0].orig_link.should == 'http://www.pauldix.net/2008/09/marshal-data-to.html'
end
end
end