spec/happymapper_spec.rb in nokogiri-happymapper-0.3.6 vs spec/happymapper_spec.rb in nokogiri-happymapper-0.5.1
- old
+ new
@@ -67,10 +67,28 @@
element :title, String
has_many :entries, Entry
end
end
+module Atom
+ class Feed
+ include HappyMapper
+ tag 'feed'
+
+ attribute :xmlns, String, :single => true
+ element :id, String, :single => true
+ element :title, String, :single => true
+ element :updated, DateTime, :single => true
+ element :link, String, :single => false, :attributes => {
+ :rel => String,
+ :type => String,
+ :href => String
+ }
+ # has_many :entries, Entry # nothing interesting in the entries
+ end
+end
+
class Address
include HappyMapper
tag 'address'
element :street, String
@@ -80,11 +98,11 @@
element :country, String
end
class Feature
include HappyMapper
- element :name, String, :tag => '.|.//text()'
+ element :name, String, :xpath => './/text()'
end
class FeatureBullet
include HappyMapper
@@ -284,11 +302,11 @@
class Country
include HappyMapper
attribute :code, String
- text_node :name, String
+ content :name, String
end
class Address
include HappyMapper
@@ -421,10 +439,107 @@
element :name, String
element :item, String
end
end
+class PublishOptions
+ include HappyMapper
+
+ tag 'publishOptions'
+
+ element :author, String, :tag => 'author'
+
+ element :draft, Boolean, :tag => 'draft'
+ element :scheduled_day, String, :tag => 'scheduledDay'
+ element :scheduled_time, String, :tag => 'scheduledTime'
+ element :published_day, String, :tag => 'publishDisplayDay'
+ element :published_time, String, :tag => 'publishDisplayTime'
+ element :created_day, String, :tag => 'publishDisplayDay'
+ element :created_time, String, :tag => 'publishDisplayTime'
+
+end
+
+class Article
+ include HappyMapper
+
+ tag 'Article'
+ namespace 'article'
+
+ attr_writer :xml_value
+
+ element :title, String
+ element :text, String
+ has_many :photos, 'Photo', :tag => 'Photo', :namespace => 'photo', :xpath => '/article:Article'
+ has_many :galleries, 'Gallery', :tag => 'Gallery', :namespace => 'gallery'
+
+ element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'article'
+
+end
+
+class PartiallyBadArticle
+ include HappyMapper
+
+ attr_writer :xml_value
+
+ tag 'Article'
+ namespace 'article'
+
+ element :title, String
+ element :text, String
+ has_many :photos, 'Photo', :tag => 'Photo', :namespace => 'photo', :xpath => '/article:Article'
+ has_many :videos, 'Video', :tag => 'Video', :namespace => 'video'
+
+ element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'article'
+
+end
+
+class Photo
+ include HappyMapper
+
+ tag 'Photo'
+ namespace 'photo'
+
+ attr_writer :xml_value
+
+ element :title, String
+ element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'photo'
+
+end
+
+class Gallery
+ include HappyMapper
+
+ tag 'Gallery'
+ namespace 'gallery'
+
+ attr_writer :xml_value
+
+ element :title, String
+
+end
+
+class Video
+ include HappyMapper
+
+ tag 'Video'
+ namespace 'video'
+
+ attr_writer :xml_value
+
+ element :title, String
+ element :publish_options, PublishOptions, :tag => 'publishOptions', :namespace => 'video'
+
+end
+
+class OptionalAttribute
+ include HappyMapper
+ tag 'address'
+
+ attribute :street, String
+end
+
+
describe HappyMapper do
describe "being included into another class" do
before do
@klass = Class.new do
@@ -484,19 +599,19 @@
it "should allow has one association" do
@klass.has_one(:user, User)
element = @klass.elements.first
element.name.should == 'user'
element.type.should == User
- element.options[:single] = true
+ element.options[:single].should == true
end
it "should allow has many association" do
@klass.has_many(:users, User)
element = @klass.elements.first
element.name.should == 'users'
element.type.should == User
- element.options[:single] = false
+ element.options[:single].should == false
end
it "should default tag name to lowercase class" do
@klass.tag_name.should == 'boo'
end
@@ -583,10 +698,16 @@
address = Address.parse(fixture_file('address.xml'), :single => true)
address.country.name.should == 'Germany'
address.country.code.should == 'de'
end
+ it "should treat Nokogiri::XML::Document as root" do
+ doc = Nokogiri::XML(fixture_file('address.xml'))
+ address = Address.parse(doc)
+ address.class.should == Address
+ end
+
it "should parse xml with default namespace (amazon)" do
file_contents = fixture_file('pita.xml')
items = PITA::Items.parse(file_contents, :single => true)
items.total_results.should == 22
items.total_pages.should == 3
@@ -609,10 +730,27 @@
first.feels_like.should == 51
first.current_condition.should == 'Sunny'
first.current_condition.icon.should == 'http://deskwx.weatherbug.com/images/Forecast/icons/cond007.gif'
end
+ it "parses xml with attributes of elements that aren't :single => true" do
+ feed = Atom::Feed.parse(fixture_file('atom.xml'))
+ feed.link.first.href.should == 'http://www.example.com'
+ feed.link.last.href.should == 'http://www.example.com/tv_shows.atom'
+ end
+
+ it "returns nil rather than empty array for absent values when :single => true" do
+ address = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :single => true)
+ address.should be_nil
+ end
+
+ it "should return same result for absent values when :single => true, regardless of :in_groups_of" do
+ addr1 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :single => true)
+ addr2 = Address.parse('<?xml version="1.0" encoding="UTF-8"?><foo/>', :single => true, :in_groups_of => 10)
+ addr1.should == addr2
+ end
+
it "should parse xml with nested elements" do
radars = Radar.parse(fixture_file('radar.xml'))
first = radars[0]
first.places.size.should == 1
first.places[0].name.should == 'Store'
@@ -766,10 +904,29 @@
it "should parse lastfm namespaces" do
l = Location.parse(fixture_file('lastfm.xml'))
l.first.latitude.should == "51.53469"
end
+
+ describe "Parse optional attributes" do
+
+ it "should parse an empty String as empty" do
+ a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
+ a[0].street.should == ""
+ end
+
+ it "should parse a String with value" do
+ a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
+ a[1].street.should == "Milchstrasse"
+ end
+
+ it "should parse a String with value" do
+ a = OptionalAttribute.parse(fixture_file('optional_attributes.xml'))
+ a[2].street.should be_nil
+ end
+
+ end
describe 'Xml Content' do
before(:each) do
file_contents = fixture_file('dictionary.xml')
@records = Dictionary::Record.parse(file_contents)
@@ -787,10 +944,67 @@
'<em>white</em> cockatoo'
end
end
it "should parse ambigous items" do
- items = AmbigousItems::Item.parse(fixture_file('ambigous_items.xml'),
- :xpath => '/ambigous/my-items')
+ items = AmbigousItems::Item.parse(fixture_file('ambigous_items.xml'), :xpath => '/ambigous/my-items')
items.map(&:name).should == %w(first second third).map{|s| "My #{s} item" }
end
+
+
+ context Article do
+ it "should parse the publish options for Article and Photo" do
+ @article.title.should_not be_nil
+ @article.text.should_not be_nil
+ @article.photos.should_not be_nil
+ @article.photos.first.title.should_not be_nil
+ end
+
+ it "should parse the publish options for Article" do
+ @article.publish_options.should_not be_nil
+ end
+
+ it "should parse the publish options for Photo" do
+ @article.photos.first.publish_options.should_not be_nil
+ end
+
+ it "should only find only items at the parent level" do
+ @article.photos.length.should == 1
+ end
+
+ before(:all) do
+ @article = Article.parse(fixture_file('subclass_namespace.xml'))
+ end
+
+ end
+
+ context "Namespace is missing because an optional element that uses it is not present" do
+ it "should parse successfully" do
+ @article = PartiallyBadArticle.parse(fixture_file('subclass_namespace.xml'))
+ @article.should_not be_nil
+ @article.title.should_not be_nil
+ @article.text.should_not be_nil
+ @article.photos.should_not be_nil
+ @article.photos.first.title.should_not be_nil
+ end
+ end
+
+
+ describe "with limit option" do
+ it "should return results with limited size: 6" do
+ sizes = []
+ posts = Post.parse(fixture_file('posts.xml'), :in_groups_of => 6) do |a|
+ sizes << a.size
+ end
+ sizes.should == [6, 6, 6, 2]
+ end
+
+ it "should return results with limited size: 10" do
+ sizes = []
+ posts = Post.parse(fixture_file('posts.xml'), :in_groups_of => 10) do |a|
+ sizes << a.size
+ end
+ sizes.should == [10, 10]
+ end
+ end
+
end