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