Skip to content
Browse files

Drop in artifice and start building the objects that will map the bac…

…kend XML
  • Loading branch information...
1 parent ee3c109 commit 8293a7534cadca87c878c25911f2edd2981b2183 @wycats committed Apr 10, 2010
View
6 Gemfile
@@ -1,10 +1,12 @@
-source :gemcutter
+# source :gemcutter
gem "nokogiri"
gem "resourceful"
+gem "activesupport", :path => "/Users/wycats/Code/rails/activesupport"
group :test do
gem "rspec", "2.0.0.beta.4"
gem "randexp"
- gem "fakeweb"
+ gem "artifice"
+ gem "sinatra"
end
View
1 feed.xml
@@ -0,0 +1 @@
+<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:app='http://www.w3.org/2007/app' xmlns:gCal='http://schemas.google.com/gCal/2005' xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='W/&quot;D04DRXc8cSp7IWA9WxBaFEQ.&quot;' gd:kind='calendar#calendarFeed'><id>http://www.google.com/calendar/feeds/default/allcalendars/full</id><updated>2010-03-25T05:46:14.979Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title>wycats@gmail.com's Calendar List</title><link rel='alternate' type='text/html' href='http://www.google.com/calendar/render'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full'/><author><name>wycats@gmail.com</name><email>wycats@gmail.com</email></author><generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator><openSearch:startIndex>1</openSearch:startIndex><entry gd:etag='W/&quot;AkAGRn47eCp7IWA9WxBaFEo.&quot;' gd:kind='calendar#calendar'><id>http://www.google.com/calendar/feeds/default/calendars/wycats%40gmail.com</id><published>2010-03-25T05:46:14.973Z</published><updated>2010-03-25T00:58:47.000Z</updated><app:edited>2010-03-25T00:58:47.000Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title type='text'>Yehuda Katz</title><content type='application/atom+xml' src='http://www.google.com/calendar/feeds/wycats%40gmail.com/private/full'/><link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/wycats%40gmail.com/private/full'/><link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/wycats%40gmail.com/private/full'/><link rel='http://schemas.google.com/acl/2007#accessControlList' type='application/atom+xml' href='http://www.google.com/calendar/feeds/wycats%40gmail.com/acl/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/wycats%40gmail.com'/><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/wycats%40gmail.com'/><author><name>wycats@gmail.com</name><email>wycats@gmail.com</email></author><gCal:accesslevel value='owner'/><gCal:color value='#5A6986'/><gCal:hidden value='false'/><gCal:selected value='true'/><gCal:timezone value='America/Los_Angeles'/><gCal:timesCleaned value='0'/></entry><entry gd:etag='W/&quot;CEIBQX47eCp7IWA9WxBbEkQ.&quot;' gd:kind='calendar#calendar'><id>http://www.google.com/calendar/feeds/default/calendars/sntr3glcbk14jtbps5kqp81a0s%40group.calendar.google.com</id><published>2010-03-25T05:46:14.974Z</published><updated>2010-03-11T07:29:10.000Z</updated><app:edited>2010-03-11T07:29:10.000Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title type='text'>Excelsior</title><summary type='text'>The Excelsior's Public Calendar</summary><content type='application/atom+xml' src='http://www.google.com/calendar/feeds/sntr3glcbk14jtbps5kqp81a0s%40group.calendar.google.com/private/full'/><link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/sntr3glcbk14jtbps5kqp81a0s%40group.calendar.google.com/private/full'/><link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/sntr3glcbk14jtbps5kqp81a0s%40group.calendar.google.com/private/full'/><link rel='http://schemas.google.com/acl/2007#accessControlList' type='application/atom+xml' href='http://www.google.com/calendar/feeds/sntr3glcbk14jtbps5kqp81a0s%40group.calendar.google.com/acl/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/sntr3glcbk14jtbps5kqp81a0s%40group.calendar.google.com'/><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/sntr3glcbk14jtbps5kqp81a0s%40group.calendar.google.com'/><author><name>Excelsior</name></author><gCal:accesslevel value='owner'/><gCal:color value='#528800'/><gCal:hidden value='true'/><gd:where valueString='Brooklyn College'/><gCal:selected value='false'/><gCal:timezone value='America/New_York'/><gCal:timesCleaned value='0'/></entry><entry gd:etag='W/&quot;AkcGSX47eCp7IWA9WxBaFEo.&quot;' gd:kind='calendar#calendar'><id>http://www.google.com/calendar/feeds/default/calendars/9irqghjmeesv85bj45dr070q6ja87auc%40import.calendar.google.com</id><published>2010-03-25T05:46:14.975Z</published><updated>2010-03-25T00:47:08.000Z</updated><app:edited>2010-03-25T00:47:08.000Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title type='text'>Conferences</title><content type='application/atom+xml' src='http://www.google.com/calendar/feeds/9irqghjmeesv85bj45dr070q6ja87auc%40import.calendar.google.com/private/full'/><link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/9irqghjmeesv85bj45dr070q6ja87auc%40import.calendar.google.com/private/full'/><link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/9irqghjmeesv85bj45dr070q6ja87auc%40import.calendar.google.com/private/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/9irqghjmeesv85bj45dr070q6ja87auc%40import.calendar.google.com'/><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/9irqghjmeesv85bj45dr070q6ja87auc%40import.calendar.google.com'/><author><name>Conferences</name></author><gCal:accesslevel value='read'/><gCal:color value='#A32929'/><gCal:hidden value='false'/><gCal:overridename value='Conferences'/><gCal:selected value='true'/><gCal:timezone value='America/Los_Angeles'/><gCal:timesCleaned value='0'/></entry><entry gd:etag='W/&quot;D0cASH47eCp7IWA9WxBbGUQ.&quot;' gd:kind='calendar#calendar'><id>http://www.google.com/calendar/feeds/default/calendars/laurendarson%40gmail.com</id><published>2010-03-25T05:46:14.974Z</published><updated>2010-03-19T10:37:29.000Z</updated><app:edited>2010-03-19T10:37:29.000Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title type='text'>Lauren Darson</title><content type='application/atom+xml' src='http://www.google.com/calendar/feeds/laurendarson%40gmail.com/private/full'/><link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/laurendarson%40gmail.com/private/full'/><link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/laurendarson%40gmail.com/private/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/laurendarson%40gmail.com'/><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/laurendarson%40gmail.com'/><author><name>laurendarson@gmail.com</name><email>laurendarson@gmail.com</email></author><gCal:accesslevel value='read'/><gCal:color value='#7A367A'/><gCal:hidden value='true'/><gCal:selected value='false'/><gCal:timezone value='America/New_York'/><gCal:timesCleaned value='0'/></entry><entry gd:etag='W/&quot;DkANRH47eCp7IWA9WxBaFEU.&quot;' gd:kind='calendar#calendar'><id>http://www.google.com/calendar/feeds/default/calendars/leahparker2%40gmail.com</id><published>2010-03-25T05:46:14.973Z</published><updated>2010-03-25T02:39:55.000Z</updated><app:edited>2010-03-25T02:39:55.000Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title type='text'>Leah Silber (Home)</title><content type='application/atom+xml' src='http://www.google.com/calendar/feeds/leahparker2%40gmail.com/private/full'/><link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/leahparker2%40gmail.com/private/full'/><link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/leahparker2%40gmail.com/private/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/leahparker2%40gmail.com'/><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/leahparker2%40gmail.com'/><author><name>leahparker2@gmail.com</name><email>leahparker2@gmail.com</email></author><gCal:accesslevel value='editor'/><gCal:color value='#528800'/><gCal:hidden value='false'/><gCal:selected value='true'/><gCal:timezone value='America/Los_Angeles'/><gCal:timesCleaned value='0'/></entry><entry gd:etag='W/&quot;DkAMR347eCp7IWA9WxBaFEU.&quot;' gd:kind='calendar#calendar'><id>http://www.google.com/calendar/feeds/default/calendars/lsilber%40engineyard.com</id><published>2010-03-25T05:46:14.973Z</published><updated>2010-03-25T02:39:46.000Z</updated><app:edited>2010-03-25T02:39:46.000Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title type='text'>Leah Silber (Work)</title><content type='application/atom+xml' src='http://www.google.com/calendar/feeds/lsilber%40engineyard.com/private/full'/><link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/lsilber%40engineyard.com/private/full'/><link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/lsilber%40engineyard.com/private/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/lsilber%40engineyard.com'/><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/lsilber%40engineyard.com'/><author><name>lsilber@engineyard.com</name><email>lsilber@engineyard.com</email></author><gCal:accesslevel value='read'/><gCal:color value='#2952A3'/><gCal:hidden value='false'/><gCal:selected value='true'/><gCal:timezone value='America/Los_Angeles'/><gCal:timesCleaned value='0'/></entry><entry gd:etag='W/&quot;CkIHQH47eCp7IWA9WxBaFEo.&quot;' gd:kind='calendar#calendar'><id>http://www.google.com/calendar/feeds/default/calendars/usa%40holiday.calendar.google.com</id><published>2010-03-25T05:46:14.973Z</published><updated>2010-03-24T22:42:11.000Z</updated><app:edited>2010-03-24T22:42:11.000Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title type='text'>US Holidays</title><summary type='text'>US Holidays</summary><content type='application/atom+xml' src='http://www.google.com/calendar/feeds/usa%40holiday.calendar.google.com/private/full'/><link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/usa%40holiday.calendar.google.com/private/full'/><link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/usa%40holiday.calendar.google.com/private/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/usa%40holiday.calendar.google.com'/><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/usa%40holiday.calendar.google.com'/><author><name>US Holidays</name></author><gCal:accesslevel value='read'/><gCal:color value='#4A716C'/><gCal:hidden value='false'/><gCal:selected value='false'/><gCal:timezone value='America/Los_Angeles'/><gCal:timesCleaned value='0'/></entry><entry gd:etag='W/&quot;C0MARH47eCp7IWA9WxBbFk4.&quot;' gd:kind='calendar#calendar'><id>http://www.google.com/calendar/feeds/default/calendars/yct.abraham%40gmail.com</id><published>2010-03-25T05:46:14.973Z</published><updated>2010-03-15T05:37:25.000Z</updated><app:edited>2010-03-15T05:37:25.000Z</app:edited><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/gCal/2005#calendarmeta'/><title type='text'>Yael Abraham</title><content type='application/atom+xml' src='http://www.google.com/calendar/feeds/yct.abraham%40gmail.com/private/full'/><link rel='alternate' type='application/atom+xml' href='http://www.google.com/calendar/feeds/yct.abraham%40gmail.com/private/full'/><link rel='http://schemas.google.com/gCal/2005#eventFeed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/yct.abraham%40gmail.com/private/full'/><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/yct.abraham%40gmail.com'/><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/allcalendars/full/yct.abraham%40gmail.com'/><author><name>yct.abraham@gmail.com</name><email>yct.abraham@gmail.com</email></author><gCal:accesslevel value='read'/><gCal:color value='#2952A3'/><gCal:hidden value='false'/><gCal:selected value='false'/><gCal:timezone value='America/New_York'/><gCal:timesCleaned value='0'/></entry></feed>
View
9 lib/alexandria.rb
@@ -1,7 +1,8 @@
+require "time"
require "resourceful"
-require "alexandria/resourceful_ext"
require "alexandria/resourceful_backend"
require "alexandria/constants"
+require "alexandria/response_document"
# Alexandria is a library for connecting to APIs that work
# with the Google Data protocol.
@@ -56,5 +57,9 @@ def token_for(service)
)
end
end
-
+
+ def get(service, url, params = {})
+ token = token_for(service)
+ @backend.authenticated_get(token, url, params)
+ end
end
View
20 lib/alexandria/resourceful_backend.rb
@@ -20,7 +20,7 @@ def initialize(http = Resourceful::HttpAccessor.new)
# @option params [String] Email An email address or
# Google ID
# @option params [String] Passwd The user's password
- # @option params [String] service The service to
+ # @option params [String] service The service to
# authenticate for.
# @option params [String] source A short string
# identifying the application
@@ -33,16 +33,32 @@ def authenticate(params)
data = body_parameters(params)
resource = @http.resource(AUTH_URL)
- response = resource.post(data, :content_type => CONTENT_TYPE)
+ response = resource.post(data, headers)
response.body.match(/^Auth=([^\n]*)/)[1]
rescue Resourceful::UnsuccessfulHttpRequestError => e
response = e.http_response.body
+ # TODO Handle other kinds of output
code = response.match(/^Error=([^\n]*)/)[1]
raise AuthenticationFailure.new(code)
end
+ def authenticated_get(token, url, params)
+ data = body_parameters(params)
+
+ resource = @http.resource(url)
+ full_headers = headers.merge("Authorization" => "GoogleLogin auth=\"#{token}\"")
+ resource.get(full_headers)
+ end
+
private
+ def headers
+ {
+ "Content-Type" => CONTENT_TYPE,
+ "GData-Version" => "2"
+ }
+ end
+
def body_parameters(hash)
uri = Addressable::URI.new
uri.query_values = hash
View
12 lib/alexandria/resourceful_ext.rb
@@ -1,12 +0,0 @@
-class Alexandria
- module Net
- class HTTP < ::Net::HTTP
- def initialize(*)
- super
- self.verify_mode = OpenSSL::SSL::VERIFY_NONE if port == 443
- end
- end
- end
-end
-
-Resourceful::NetHttpAdapter::Net = Alexandria::Net
View
102 lib/alexandria/response_document.rb
@@ -0,0 +1,102 @@
+require "date"
+require "nokogiri"
+require "active_support/core_ext/class/attribute"
+
+class Alexandria
+ class ResponseDocument
+ # @todo Do we want to allow modification of a parent class' attributes
+ # at runtime? If so, we need to use a different kind of accessor
+
+ class_attribute :types
+ class_attribute :type_attributes
+ class_attribute :root_name
+ self.types = {}
+ self.type_attributes = Hash.new {|h,k| h[k] = [] }
+ self.root_name = "feed"
+
+ class << self
+ attr_accessor :children
+ end
+
+ def children
+ self.class.children || []
+ end
+
+ # The type method defines a new type that you can use to declare
+ # attributes.
+ #
+ # @param [Symbol] type the name of the type you are creating,
+ # for instance, :string
+ # @yields [String] some text that Alexandria extracted from an
+ # XML file
+ # @block_returns [Object] a result in the form of the type,
+ # for instance, the :time type would return a Time
+ #
+ # @todo how to document blocks like this
+ def self.type(type, &block)
+ self.type_attributes = self.type_attributes.merge(type => [])
+
+ class_eval <<-RUBY
+ def self.#{type}(name, selector = name.to_s, attribute = nil)
+ self.type_attributes[:#{type}] += [[name, selector, attribute]]
+ attr_accessor name
+ end
+ RUBY
+
+ self.types = self.types.merge(type => block)
+ end
+
+ def self.has_one(name, type, selector)
+ self.children ||= []
+ self.children << [name, type, selector]
+ attr_accessor name
+ end
+
+ type(:string) { |text| text }
+ type(:time) { |text| Time.parse(text) }
+
+ # @param [String, Nokogiri::XML::Document] xml A valid XML document
+ # in String or already parsed form
+ # @param [String] root_name A prefix that should be used before the
+ # the selector. If not supplied, the class-level #root_name will
+ # be used
+ def initialize(xml, root_name = nil)
+ @root = xml.is_a?(String) ? Nokogiri::XML(xml) : xml
+ self.root_name = root_name if root_name
+
+ # Loops through all the registered types
+ types.each do |type, block|
+ # Loop through the registered attributes for each type
+ type_attributes[type].each do |name, selector, attribute|
+ selector = [self.root_name, selector].compact.join(" > ")
+ text = get_node(selector, attribute)
+ next unless text
+ instance_variable_set("@#{name}", block.call(text))
+ end
+ end
+
+ children.each do |name, type, selector|
+ # Pass in the full XML document, but prefix the root name
+ # with the full selector to this point
+ selector = [self.root_name, selector].compact.join(" > ")
+
+ # But set the child to nil if the selector doesn't exist
+ unless @root.css(selector).empty?
+ instance_variable_set("@#{name}", type.new(@root, selector))
+ end
+ end
+ end
+
+ private
+ def get_node(selector, attribute)
+ result = @root.css(selector)[0]
+ return nil unless result
+ text = attribute ? result[attribute] : result.text
+ return nil unless text && !text.empty?
+ text
+ end
+ end
+end
+
+require "alexandria/response_document/feed"
+require "alexandria/response_document/entry"
View
6 lib/alexandria/response_document/author.rb
@@ -0,0 +1,6 @@
+class Alexandria
+ class Author < ResponseDocument
+ string :name
+ string :email
+ end
+end
View
6 lib/alexandria/response_document/category.rb
@@ -0,0 +1,6 @@
+class Alexandria
+ class Category < ResponseDocument
+ string :name, nil, "term"
+ string :scheme, nil, "scheme"
+ end
+end
View
5 lib/alexandria/response_document/entry.rb
@@ -0,0 +1,5 @@
+class Alexandria
+ class Entry < ResponseDocument
+
+ end
+end
View
17 lib/alexandria/response_document/feed.rb
@@ -0,0 +1,17 @@
+require "alexandria/response_document/author"
+require "alexandria/response_document/category"
+
+class Alexandria
+ class Feed < ResponseDocument
+ string :id
+ string :title
+ string :summary
+ string :content
+
+ time :published
+ time :updated
+
+ has_one :author, Author, "author"
+ has_one :category, Category, "category"
+ end
+end
View
35 spec/resourceful_backend_spec.rb
@@ -1,34 +1,35 @@
+require "artifice"
+require "sinatra"
+
+class FakeGoogle < Sinatra::Base
+ post "/accounts/ClientLogin" do
+ if params["Passwd"] == "s3kr17"
+ "Auth=#{/\w{224}/.gen}"
+ else
+ status 403
+ "Error=BadAuthentication"
+ end
+ end
+end
+
require "spec_helper"
-require "fakeweb"
+
+Artifice.activate_with(FakeGoogle.new)
describe "With the Alexandria::ResourcefulBackend" do
before do |example|
backend_klass = Alexandria::ResourcefulBackend
url = backend_klass::AUTH_URL
@backend = backend_klass.new
-
- p example.running_example.class
-
- if example.running_example.metadata[:valid]
- FakeWeb.register_uri(url,
- :body => "Auth=#{/\w{224}/.gen}", :status => 200)
- else
- FakeWeb.register_uri(url,
- :body => "Error=BadAuthentication", :status => 403)
- end
- end
-
- after do
- FakeWeb.clean_registry
end
- it "using valid credentials, it returns a token", :valid => true do
+ it "using valid credentials, it returns a token" do
response = @backend.authenticate(Alexandria::TestBackend.valid_params)
response.should be_kind_of(String)
end
- it "using invalid credentials, it raises", :valid => false do
+ it "using invalid credentials, it raises" do
params = Alexandria::TestBackend.valid_params.merge("Passwd" => "s3krit")
lambda do
View
68 spec/response_documents/base_spec.rb
@@ -0,0 +1,68 @@
+require "spec_helper"
+
+describe "Alexandria::ResponseDocument" do
+ before do
+ @xml = <<-XML
+ <?xml version='1.0' encoding='utf-8'?>
+ <feed xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='W/"C0QBRXcycSp7ImA9WxRVFUk."'>
+ <title>Foo</title>
+ <updated>2006-01-23T16:25:00-08:00</updated>
+ <id>http://www.example.com/myFeed</id>
+ <author><name>Jo March</name></author>
+ <time updated="2006-01-23T16:25:00-08:00" />
+ <link href='/myFeed' rel='self'/>
+ </feed>
+ XML
+ end
+
+ describe "a response document needing no custom selectors" do
+ result_class = Class.new(Alexandria::ResponseDocument) do
+ string :title
+ string :id
+ time :updated
+ end
+
+ before do
+ @result = result_class.new(@xml)
+ end
+
+ it "can get String elements" do
+ @result.title.should == "Foo"
+ @result.id.should == "http://www.example.com/myFeed"
+ end
+
+ it "can get Time elements" do
+ @result.updated.should == Time.parse("2006-01-23T16:25:00-08:00")
+ end
+ end
+
+ describe "a response document needed a custom selector" do
+ result_class = Class.new(Alexandria::ResponseDocument) do
+ string :title
+ string :id
+ string :author_name, "author name"
+ string :url, "link[rel=self]", "href"
+ time :updated
+ time :time_updated, "time", "updated"
+ end
+
+ before do
+ @result = result_class.new(@xml)
+ end
+
+ it "can get elements without custom selectors" do
+ @result.title.should == "Foo"
+ @result.id.should == "http://www.example.com/myFeed"
+ @result.updated.should == Time.parse("2006-01-23T16:25:00-08:00")
+ @result.author_name.should == "Jo March"
+ end
+
+ it "can get String elements with the custom selectors" do
+ @result.url.should == "/myFeed"
+ end
+
+ it "can get Time elements with the custom selectors" do
+ @result.time_updated.should == Time.parse("2006-01-23T16:25:00-08:00")
+ end
+ end
+end
View
5 spec/response_documents/entry_spec.rb
@@ -0,0 +1,5 @@
+require "spec_helper"
+
+describe "Alexandria::Entry" do
+
+end
View
21 spec/response_documents/feed.xml
@@ -0,0 +1,21 @@
+<?xml version='1.0' encoding='utf-8'?>
+<feed xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='W/"D08FQn8-eil7ImA9WxZbFEw."'>
+ <title>Foo</title>
+ <updated>2006-01-23T16:28:05-08:00</updated>
+ <id>http://www.example.com/myFeed</id>
+ <author>
+ <name>Jo March</name>
+ </author>
+ <link href='/myFeed' rel='self'/>
+ <entry gd:etag='"FkkOQgZGeip7ImA6WhVR"'>
+ <id>http://www.example.com/id/1</id>
+ <link rel='edit' href='http://example.com/myFeed/1/'/>
+ <updated>2006-01-23T16:28:05-08:00</updated>
+ <author>
+ <name>Elizabeth Bennet</name>
+ <email>liz@gmail.com</email>
+ </author>
+ <title type='text'>Entry 1</title>
+ <content type='text'>This is my first entry.</content>
+ </entry>
+</feed>
View
43 spec/response_documents/feed_spec.rb
@@ -0,0 +1,43 @@
+require "spec_helper"
+
+describe "Alexandria::Feed" do
+ before do
+ xml = File.read(File.expand_path("../feed.xml", __FILE__))
+ @feed = Alexandria::Feed.new(xml)
+
+ xml = File.read(File.expand_path("../feed_with_category.xml", __FILE__))
+ @feed_with_category = Alexandria::Feed.new(xml)
+ end
+
+ it "can find its id" do
+ @feed.id.should == "http://www.example.com/myFeed"
+ end
+
+ it "can find its title" do
+ @feed.title.should == "Foo"
+ end
+
+ it "returns an Author object" do
+ author = @feed.author
+ author.name.should == "Jo March"
+ author.email.should == nil
+ end
+
+ it "returns nil for a non-existent category" do
+ @feed.category.should == nil
+ end
+
+ it "returns a Category if it does exist" do
+ category = @feed_with_category.category
+ category.name.should == "foo"
+ category.scheme.should == "bar"
+ end
+
+ it "returns nil for a non-existent published date" do
+ @feed.published.should == nil
+ end
+
+ it "can find its last updated date" do
+ @feed.updated.should == Time.parse("2006-01-23T16:28:05-08:00")
+ end
+end
View
22 spec/response_documents/feed_with_category.xml
@@ -0,0 +1,22 @@
+<?xml version='1.0' encoding='utf-8'?>
+<feed xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005' gd:etag='W/"D08FQn8-eil7ImA9WxZbFEw."'>
+ <title>Foo</title>
+ <updated>2006-01-23T16:28:05-08:00</updated>
+ <id>http://www.example.com/myFeed</id>
+ <category term="foo" scheme="bar" />
+ <author>
+ <name>Jo March</name>
+ </author>
+ <link href='/myFeed' rel='self'/>
+ <entry gd:etag='"FkkOQgZGeip7ImA6WhVR"'>
+ <id>http://www.example.com/id/1</id>
+ <link rel='edit' href='http://example.com/myFeed/1/'/>
+ <updated>2006-01-23T16:28:05-08:00</updated>
+ <author>
+ <name>Elizabeth Bennet</name>
+ <email>liz@gmail.com</email>
+ </author>
+ <title type='text'>Entry 1</title>
+ <content type='text'>This is my first entry.</content>
+ </entry>
+</feed>

0 comments on commit 8293a75

Please sign in to comment.
Something went wrong with that request. Please try again.