spec/happymapper_spec.rb in happymapper-0.1.7 vs spec/happymapper_spec.rb in happymapper-0.2.0

- old
+ new

@@ -1,10 +1,129 @@ require File.dirname(__FILE__) + '/spec_helper.rb' +require 'pp' -class Place +class Feature include HappyMapper + element :name, String, :tag => '.|.//text()' +end +class FeatureBullet + include HappyMapper + + tag 'features_bullets' + has_many :features, Feature + element :bug, String +end + +class Product + include HappyMapper + + element :title, String + has_one :feature_bullets, FeatureBullet +end + +module FamilySearch + class Person + include HappyMapper + + attribute :version, String + attribute :modified, Time + attribute :id, String + end + + class Persons + include HappyMapper + has_many :person, Person + end + + class FamilyTree + include HappyMapper + + tag 'familytree', :root => true + attribute :version, String + attribute :status_message, String, :tag => 'statusMessage' + attribute :status_code, String, :tag => 'statusCode' + has_one :persons, Persons + end +end + +module FedEx + class Address + include HappyMapper + + tag 'Address' + element :city, String, :tag => 'City' + element :state, String, :tag => 'StateOrProvinceCode' + element :zip, String, :tag => 'PostalCode' + element :countrycode, String, :tag => 'CountryCode' + element :residential, Boolean, :tag => 'Residential' + end + + class Event + include HappyMapper + + tag 'Events' + element :timestamp, String, :tag => 'Timestamp' + element :eventtype, String, :tag => 'EventType' + element :eventdescription, String, :tag => 'EventDescription' + has_one :address, Address + end + + class PackageWeight + include HappyMapper + + tag 'PackageWeight' + element :units, String, :tag => 'Units' + element :value, Integer, :tag => 'Value' + end + + class TrackDetails + include HappyMapper + + tag 'TrackDetails' + element :tracking_number, String, :tag => 'TrackingNumber' + element :status_code, String, :tag => 'StatusCode' + element :status_desc, String, :tag => 'StatusDescription' + element :carrier_code, String, :tag => 'CarrierCode' + element :service_info, String, :tag => 'ServiceInfo' + has_one :weight, PackageWeight, :tag => 'PackageWeight' + element :est_delivery, String, :tag => 'EstimatedDeliveryTimestamp' + has_many :events, Event + end + + class Notification + include HappyMapper + + tag 'Notifications' + element :severity, String, :tag => 'Severity' + element :source, String, :tag => 'Source' + element :code, Integer, :tag => 'Code' + element :message, String, :tag => 'Message' + element :localized_message, String, :tag => 'LocalizedMessage' + end + + class TransactionDetail + include HappyMapper + + tag 'TransactionDetail' + element :cust_tran_id, String, :tag => 'CustomerTransactionId' + end + + class TrackReply + include HappyMapper + + tag 'TrackReply', :root => true + element :highest_severity, String, :tag => 'HighestSeverity' + element :more_data, Boolean, :tag => 'MoreData' + has_many :notifications, Notification, :tag => 'Notifications' + has_many :trackdetails, TrackDetails, :tag => 'TrackDetails' + has_one :tran_detail, TransactionDetail, :tab => 'TransactionDetail' + end +end + +class Place + include HappyMapper element :name, String end class Radar include HappyMapper @@ -51,19 +170,21 @@ has_one :user, User end class CurrentWeather include HappyMapper - tag 'aws:ob' - element :temperature, Integer, :tag => 'aws:temp' - element :feels_like, Integer, :tag => 'aws:feels-like' - element :current_condition, String, :tag => 'aws:current-condition', :attributes => {:icon => String} + + tag 'ob' + element :temperature, Integer, :tag => 'temp' + element :feels_like, Integer, :tag => 'feels-like' + element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String} end class Address include HappyMapper + tag 'address', :root => true element :street, String element :postcode, String element :housenumber, String element :city, String element :country, String @@ -91,12 +212,11 @@ module GitHub class Commit include HappyMapper - tag "commit" - + tag "commit", :root => true element :url, String element :tree, String element :message, String element :id, String element :'committed-date', Date @@ -169,14 +289,19 @@ element.name.should == 'users' element.type.should == User element.options[:single] = false end - it "should default tag name to class" do + it "should default tag name to lowercase class" do Foo.get_tag_name.should == 'foo' end + it "should default tag name of class in modules to the last constant lowercase" do + module Bar; class Baz; include HappyMapper; end; end + Bar::Baz.get_tag_name.should == 'baz' + end + it "should allow setting tag name" do Foo.tag('FooBar') Foo.get_tag_name.should == 'FooBar' end @@ -197,141 +322,174 @@ Post.elements.size.should == 0 Status.elements.size.should == 9 end end - describe "#parse (with xml attributes mapping to ruby attributes)" do - before do - @posts = Post.parse(File.read(File.dirname(__FILE__) + '/fixtures/posts.xml')) - end - - it "should get the correct number of elements" do - @posts.size.should == 20 - end - - it "should properly create objects" do - first = @posts.first - first.href.should == 'http://roxml.rubyforge.org/' - first.hash.should == '19bba2ab667be03a19f67fb67dc56917' - first.description.should == 'ROXML - Ruby Object to XML Mapping Library' - first.tag.should == 'ruby xml gems mapping' - first.time.should == Time.utc(2008, 8, 9, 5, 24, 20) - first.others.should == 56 - first.extended.should == 'ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes.' - end + it "should parse xml attributes into ruby objects" do + posts = Post.parse(fixture_file('posts.xml')) + posts.size.should == 20 + first = posts.first + first.href.should == 'http://roxml.rubyforge.org/' + first.hash.should == '19bba2ab667be03a19f67fb67dc56917' + first.description.should == 'ROXML - Ruby Object to XML Mapping Library' + first.tag.should == 'ruby xml gems mapping' + first.time.should == Time.utc(2008, 8, 9, 5, 24, 20) + first.others.should == 56 + first.extended.should == 'ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes.' end - describe "#parse (with xml elements mapping to ruby attributes)" do - before do - @statuses = Status.parse(File.read(File.dirname(__FILE__) + '/fixtures/statuses.xml')) - end - - it "should get the correct number of elements" do - @statuses.size.should == 20 - end - - it "should properly create objects" do - first = @statuses.first - first.id.should == 882281424 - first.created_at.should == Time.utc(2008, 8, 9, 5, 38, 12) - first.source.should == 'web' - first.truncated.should be_false - first.in_reply_to_status_id.should == 1234 - first.in_reply_to_user_id.should == 12345 - first.favorited.should be_false - first.user.id.should == 4243 - first.user.name.should == 'John Nunemaker' - first.user.screen_name.should == 'jnunemaker' - first.user.location.should == 'Mishawaka, IN, US' - first.user.description.should == 'Loves his wife, ruby, notre dame football and iu basketball' - first.user.profile_image_url.should == 'http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg' - first.user.url.should == 'http://addictedtonew.com' - first.user.protected.should be_false - first.user.followers_count.should == 486 - end + it "should parse xml elements to ruby objcts" do + statuses = Status.parse(fixture_file('statuses.xml')) + statuses.size.should == 20 + first = statuses.first + first.id.should == 882281424 + first.created_at.should == Time.utc(2008, 8, 9, 5, 38, 12) + first.source.should == 'web' + first.truncated.should be_false + first.in_reply_to_status_id.should == 1234 + first.in_reply_to_user_id.should == 12345 + first.favorited.should be_false + first.user.id.should == 4243 + first.user.name.should == 'John Nunemaker' + first.user.screen_name.should == 'jnunemaker' + first.user.location.should == 'Mishawaka, IN, US' + first.user.description.should == 'Loves his wife, ruby, notre dame football and iu basketball' + first.user.profile_image_url.should == 'http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg' + first.user.url.should == 'http://addictedtonew.com' + first.user.protected.should be_false + first.user.followers_count.should == 486 end - - describe "#parse (with xml containing the desired element as root node)" do - before do - file_contents = File.read(File.dirname(__FILE__) + '/fixtures/address.xml') - @address = Address.parse(file_contents, :single => true) - end - - it "should properly create objects" do - @address.street.should == 'Milchstrasse' - @address.postcode.should == '26131' - @address.housenumber.should == '23' - @address.city.should == 'Oldenburg' - @address.country.should == 'Germany' - end - end - # TODO: someone please get xml with namespaces working, kthxbai - describe "#parse (with xml that has namespace)" do - before do - file_contents = File.read(File.dirname(__FILE__) + '/fixtures/pita.xml') - @items = PITA::Items.parse(file_contents, :single => true, :use_default_namespace => true) - end - - it "should properly create objects" do - @items.total_results.should == 22 - @items.total_pages.should == 3 - first = @items.items[0] - second = @items.items[1] - first.asin.should == '0321480791' - first.detail_page_url.should == 'http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh' - first.manufacturer.should == 'Addison-Wesley Professional' - second.asin.should == '047022388X' - second.manufacturer.should == 'Wrox' - end + it "should parse xml containing the desired element as root node" do + address = Address.parse(fixture_file('address.xml'), :single => true) + address.street.should == 'Milchstrasse' + address.postcode.should == '26131' + address.housenumber.should == '23' + address.city.should == 'Oldenburg' + address.country.should == 'Germany' end - describe "#parse (with xml that has attributes of elements)" do - before do - file_contents = File.read(File.dirname(__FILE__) + '/fixtures/current_weather.xml') - @items = CurrentWeather.parse(file_contents) - end - - it "should properly create objects" do - @first = @items[0] - @first.temperature.should == 51 - @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 "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 + first = items.items[0] + second = items.items[1] + first.asin.should == '0321480791' + first.detail_page_url.should == 'http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh' + first.manufacturer.should == 'Addison-Wesley Professional' + second.asin.should == '047022388X' + second.manufacturer.should == 'Wrox' end - describe "#parse (with xml that has nested elements)" do - before do - file_contents = File.read(File.dirname(__FILE__) + '/fixtures/radar.xml') - @radars = Radar.parse(file_contents) - end - - it "should properly create objects" do - @first = @radars[0] - @first.places.size.should == 1 - @first.places[0].name.should == 'Store' - @second = @radars[1] - @second.places.size.should == 0 - @third = @radars[2] - @third.places.size.should == 2 - @third.places[0].name.should == 'Work' - @third.places[1].name.should == 'Home' - end + it "should parse xml that has attributes of elements" do + items = CurrentWeather.parse(fixture_file('current_weather.xml')) + first = items[0] + first.temperature.should == 51 + 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 - describe "#parse (with xml that has elements with dashes in them)" do - before do - file_contents = File.read(File.dirname(__FILE__) + '/fixtures/commit.xml') - @commit = GitHub::Commit.parse(file_contents).first - end - - it "should properly create objects" do - @commit.message.should == "move commands.rb and helpers.rb into commands/ dir" - @commit.url.should == "http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b" - @commit.id.should == "c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b" - @commit.committed_date.should == Date.parse("2008-03-02T16:45:41-08:00") - @commit.tree.should == "28a1a1ca3e663d35ba8bf07d3f1781af71359b76" - 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' + second = radars[1] + second.places.size.should == 0 + third = radars[2] + third.places.size.should == 2 + third.places[0].name.should == 'Work' + third.places[1].name.should == 'Home' + end + + it "should parse xml that has elements with dashes" do + commit = GitHub::Commit.parse(fixture_file('commit.xml')) + commit.message.should == "move commands.rb and helpers.rb into commands/ dir" + commit.url.should == "http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b" + commit.id.should == "c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b" + commit.committed_date.should == Date.parse("2008-03-02T16:45:41-08:00") + commit.tree.should == "28a1a1ca3e663d35ba8bf07d3f1781af71359b76" + end + + it "should parse xml with no namespace" do + product = Product.parse(fixture_file('product_no_namespace.xml'), :single => true) + product.title.should == "A Title" + product.feature_bullets.bug.should == 'This is a bug' + product.feature_bullets.features.size.should == 2 + product.feature_bullets.features[0].name.should == 'This is feature text 1' + product.feature_bullets.features[1].name.should == 'This is feature text 2' + end + + it "should parse xml with default namespace" do + product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true) + product.title.should == "A Title" + product.feature_bullets.bug.should == 'This is a bug' + product.feature_bullets.features.size.should == 2 + product.feature_bullets.features[0].name.should == 'This is feature text 1' + product.feature_bullets.features[1].name.should == 'This is feature text 2' + end + + it "should parse xml with single namespace" do + product = Product.parse(fixture_file('product_single_namespace.xml'), :single => true) + product.title.should == "A Title" + product.feature_bullets.bug.should == 'This is a bug' + product.feature_bullets.features.size.should == 2 + product.feature_bullets.features[0].name.should == 'This is feature text 1' + product.feature_bullets.features[1].name.should == 'This is feature text 2' + end + + it "should parse xml with multiple namespaces" do + track = FedEx::TrackReply.parse(fixture_file('multiple_namespaces.xml')) + track.highest_severity.should == 'SUCCESS' + track.more_data.should be_false + notification = track.notifications.first + notification.code.should == 0 + notification.localized_message.should == 'Request was successfully processed.' + notification.message.should == 'Request was successfully processed.' + notification.severity.should == 'SUCCESS' + notification.source.should == 'trck' + detail = track.trackdetails.first + detail.carrier_code.should == 'FDXG' + detail.est_delivery.should == '2009-01-02T00:00:00' + detail.service_info.should == 'Ground-Package Returns Program-Domestic' + detail.status_code.should == 'OD' + detail.status_desc.should == 'On FedEx vehicle for delivery' + detail.tracking_number.should == '9611018034267800045212' + detail.weight.units.should == 'LB' + detail.weight.value.should == 2 + events = detail.events + events.size.should == 10 + first_event = events[0] + first_event.eventdescription.should == 'On FedEx vehicle for delivery' + first_event.eventtype.should == 'OD' + first_event.timestamp.should == '2009-01-02T06:00:00' + first_event.address.city.should == 'WICHITA' + first_event.address.countrycode.should == 'US' + first_event.address.residential.should be_false + first_event.address.state.should == 'KS' + first_event.address.zip.should == '67226' + last_event = events[-1] + last_event.eventdescription.should == 'In FedEx possession' + last_event.eventtype.should == 'IP' + last_event.timestamp.should == '2008-12-27T09:40:00' + last_event.address.city.should == 'LONGWOOD' + last_event.address.countrycode.should == 'US' + last_event.address.residential.should be_false + last_event.address.state.should == 'FL' + last_event.address.zip.should == '327506398' + track.tran_detail.cust_tran_id.should == '20090102-111321' + end + + xit "should parse family search xml" do + tree = FamilySearch::FamilyTree.parse(fixture_file('family_tree.xml')) + tree.version.should == '1.0.20071213.942' + tree.status_message.should == 'OK' + tree.status_code.should == '200' + # tree.people.size.should == 1 + # tree.people.first.version.should == '1199378491000' + # tree.people.first.modified.should == Time.utc(2008, 1, 3, 16, 41, 31) # 2008-01-03T09:41:31-07:00 + # tree.people.first.id.should == 'KWQS-BBQ' end end