fleakr 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +149 -0
- data/Rakefile +40 -0
- data/lib/fleakr/api/request.rb +58 -0
- data/lib/fleakr/api/response.rb +35 -0
- data/lib/fleakr/objects/contact.rb +31 -0
- data/lib/fleakr/objects/error.rb +22 -0
- data/lib/fleakr/objects/group.rb +26 -0
- data/lib/fleakr/objects/image.rb +51 -0
- data/lib/fleakr/objects/photo.rb +55 -0
- data/lib/fleakr/objects/search.rb +33 -0
- data/lib/fleakr/objects/set.rb +45 -0
- data/lib/fleakr/objects/user.rb +106 -0
- data/lib/fleakr/support/attribute.rb +28 -0
- data/lib/fleakr/support/object.rb +88 -0
- data/lib/fleakr/version.rb +13 -0
- data/lib/fleakr.rb +74 -0
- data/test/fixtures/contacts.getPublicList.xml +7 -0
- data/test/fixtures/groups.pools.getPhotos.xml +7 -0
- data/test/fixtures/people.findByEmail.xml +6 -0
- data/test/fixtures/people.findByUsername.xml +6 -0
- data/test/fixtures/people.getInfo.xml +18 -0
- data/test/fixtures/people.getPublicGroups.xml +7 -0
- data/test/fixtures/people.getPublicPhotos.xml +7 -0
- data/test/fixtures/photos.getSizes.xml +10 -0
- data/test/fixtures/photos.search.xml +7 -0
- data/test/fixtures/photosets.getList.xml +13 -0
- data/test/fixtures/photosets.getPhotos.xml +7 -0
- data/test/test_helper.rb +123 -0
- data/test/unit/fleakr/api/request_test.rb +93 -0
- data/test/unit/fleakr/api/response_test.rb +49 -0
- data/test/unit/fleakr/objects/contact_test.rb +58 -0
- data/test/unit/fleakr/objects/error_test.rb +21 -0
- data/test/unit/fleakr/objects/group_test.rb +31 -0
- data/test/unit/fleakr/objects/image_test.rb +76 -0
- data/test/unit/fleakr/objects/photo_test.rb +101 -0
- data/test/unit/fleakr/objects/search_test.rb +74 -0
- data/test/unit/fleakr/objects/set_test.rb +71 -0
- data/test/unit/fleakr/objects/user_test.rb +104 -0
- data/test/unit/fleakr/support/attribute_test.rb +68 -0
- data/test/unit/fleakr/support/object_test.rb +95 -0
- data/test/unit/fleakr_test.rb +44 -0
- metadata +123 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Support # :nodoc:all
|
3
|
+
module Object
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
|
7
|
+
def attributes
|
8
|
+
@attributes ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def flickr_attribute(name, options = {})
|
12
|
+
self.attributes << Attribute.new(name, options)
|
13
|
+
class_eval "attr_accessor :#{name}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def has_many(*attributes)
|
17
|
+
options = attributes.extract_options!
|
18
|
+
class_name = self.name
|
19
|
+
|
20
|
+
attributes.each do |attribute|
|
21
|
+
target = "Fleakr::Objects::#{attribute.to_s.classify}"
|
22
|
+
finder_attribute = options[:using].nil? ? "#{class_name.demodulize.underscore}_id": options[:using]
|
23
|
+
class_eval <<-CODE
|
24
|
+
def #{attribute}
|
25
|
+
@#{attribute} ||= #{target}.send("find_all_by_#{finder_attribute}".to_sym, self.id)
|
26
|
+
end
|
27
|
+
CODE
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_all(condition, options)
|
32
|
+
attribute = options[:using].nil? ? condition.to_s.sub(/^by_/, '') : options[:using]
|
33
|
+
target_class = options[:class_name].nil? ? self.name : "Fleakr::Objects::#{options[:class_name]}"
|
34
|
+
|
35
|
+
class_eval <<-CODE
|
36
|
+
def self.find_all_#{condition}(value)
|
37
|
+
response = Fleakr::Api::Request.with_response!('#{options[:call]}', :#{attribute} => value)
|
38
|
+
(response.body/'rsp/#{options[:path]}').map {|e| #{target_class}.new(e) }
|
39
|
+
end
|
40
|
+
CODE
|
41
|
+
end
|
42
|
+
|
43
|
+
def find_one(condition, options)
|
44
|
+
attribute = options[:using].nil? ? condition.to_s.sub(/^by_/, '') : options[:using]
|
45
|
+
|
46
|
+
class_eval <<-CODE
|
47
|
+
def self.find_#{condition}(value)
|
48
|
+
response = Fleakr::Api::Request.with_response!('#{options[:call]}', :#{attribute} => value)
|
49
|
+
#{self.name}.new(response.body)
|
50
|
+
end
|
51
|
+
CODE
|
52
|
+
end
|
53
|
+
|
54
|
+
def scoped_search
|
55
|
+
key = "#{self.name.demodulize.underscore.downcase}_id".to_sym
|
56
|
+
|
57
|
+
class_eval <<-CODE
|
58
|
+
def search(search_text)
|
59
|
+
Fleakr::Objects::Search.new(:text => search_text, :#{key} => self.id).results
|
60
|
+
end
|
61
|
+
CODE
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
module InstanceMethods
|
67
|
+
|
68
|
+
def initialize(document = nil)
|
69
|
+
self.populate_from(document) unless document.nil?
|
70
|
+
end
|
71
|
+
|
72
|
+
def populate_from(document)
|
73
|
+
self.class.attributes.each do |attribute|
|
74
|
+
value = attribute.value_from(document)
|
75
|
+
self.send("#{attribute.name}=".to_sym, value) unless value.nil?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.included(other)
|
82
|
+
other.send(:extend, Fleakr::Support::Object::ClassMethods)
|
83
|
+
other.send(:include, Fleakr::Support::Object::InstanceMethods)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/fleakr.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require 'uri'
|
4
|
+
require 'cgi'
|
5
|
+
require 'net/http'
|
6
|
+
require 'rubygems'
|
7
|
+
require 'hpricot'
|
8
|
+
require 'activesupport'
|
9
|
+
|
10
|
+
%w(support api objects).each do |path|
|
11
|
+
full_path = File.expand_path(File.dirname(__FILE__)) + "/fleakr/#{path}"
|
12
|
+
Dir["#{full_path}/*.rb"].each {|f| require f }
|
13
|
+
end
|
14
|
+
|
15
|
+
# = Fleakr: A teeny tiny gem to interface with Flickr
|
16
|
+
#
|
17
|
+
# Getting started is easy, just make sure you have a valid API key from Flickr and you can
|
18
|
+
# then start making any non-authenticated request to pull back data for yours and others'
|
19
|
+
# photostreams, sets, contacts, groups, etc...
|
20
|
+
#
|
21
|
+
# For now, all activity originates from a single user which you can find by username or
|
22
|
+
# email address.
|
23
|
+
#
|
24
|
+
# Example:
|
25
|
+
#
|
26
|
+
# require 'rubygems'
|
27
|
+
# require 'fleakr'
|
28
|
+
#
|
29
|
+
# # Our API key is ABC123 (http://www.flickr.com/services/api/keys/apply/)
|
30
|
+
# Fleakr.api_key = 'ABC123'
|
31
|
+
# user = Fleakr.user('bees')
|
32
|
+
# user = Fleakr.user('user@host.com')
|
33
|
+
# # Grab a list of sets
|
34
|
+
# user.sets
|
35
|
+
# # Grab a list of the user's public groups
|
36
|
+
# user.groups
|
37
|
+
#
|
38
|
+
# To see what other associations and attributes are available, see the Fleakr::Objects::User class
|
39
|
+
#
|
40
|
+
module Fleakr
|
41
|
+
|
42
|
+
mattr_accessor :api_key
|
43
|
+
|
44
|
+
# Find a user based on some unique user data. This method will try to find
|
45
|
+
# the user based on username and will fall back to email if that fails. Example:
|
46
|
+
#
|
47
|
+
# Fleakr.api_key = 'ABC123'
|
48
|
+
# Fleakr.user('the decapitator') # => #<Fleakr::Objects::User:0x692648 @username="the decapitator", @id="21775151@N06">
|
49
|
+
# Fleakr.user('user@host.com') # => #<Fleakr::Objects::User:0x11f484c @username="bckspcr", @id="84481630@N00">
|
50
|
+
#
|
51
|
+
def self.user(user_data)
|
52
|
+
begin
|
53
|
+
Objects::User.find_by_username(user_data)
|
54
|
+
rescue Api::Request::ApiError
|
55
|
+
Objects::User.find_by_email(user_data)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Search all photos on the Flickr site. By default, this searches based on text, but you can pass
|
60
|
+
# different search parameters (passed as hash keys):
|
61
|
+
#
|
62
|
+
# [tags] The list of tags to search on (either as an array or comma-separated)
|
63
|
+
# [user_id] Scope the search to this user
|
64
|
+
# [group_id] Scope the search to this group
|
65
|
+
#
|
66
|
+
# If you're interested in User- and Group-scoped searches, you may want to use User#search and Group#search
|
67
|
+
# instead.
|
68
|
+
#
|
69
|
+
def self.search(params)
|
70
|
+
params = {:text => params} unless params.is_a?(Hash)
|
71
|
+
Objects::Search.new(params).results
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<rsp stat="ok">
|
3
|
+
<contacts page="1" pages="1" per_page="1000" perpage="1000" total="17">
|
4
|
+
<contact nsid="9302864@N42" username="blinky" iconserver="2263" iconfarm="3" ignored="0" />
|
5
|
+
<contact nsid="63204625@N20" username="inky" iconserver="53" iconfarm="1" ignored="0" />
|
6
|
+
</contacts>
|
7
|
+
</rsp>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<rsp stat="ok">
|
3
|
+
<photos page="1" pages="796" perpage="100" total="79509">
|
4
|
+
<photo id="3101830908" owner="64008250@N00" secret="e85e249e72" server="3042" farm="4" title="Canal Gate" ispublic="1" isfriend="0" isfamily="0" ownername="oakraidr" dateadded="1229049777" />
|
5
|
+
<photo id="3100780049" owner="98821864@N00" secret="f46fbe211b" server="3274" farm="4" title="2alarm" ispublic="1" isfriend="0" isfamily="0" ownername="LooknFeel" dateadded="1229042651" />
|
6
|
+
</photos>
|
7
|
+
</rsp>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<rsp stat="ok">
|
3
|
+
<person id="31066442@N69" nsid="31066442@N69" isadmin="0" ispro="1" iconserver="30" iconfarm="1">
|
4
|
+
<username>frootpantz</username>
|
5
|
+
<realname>Sir Froot Pantz</realname>
|
6
|
+
<mbox_sha1sum>e52ed1e5b91c763694995460e9796fc2adc02019</mbox_sha1sum>
|
7
|
+
<location />
|
8
|
+
<photosurl>http://www.flickr.com/photos/frootpantz/</photosurl>
|
9
|
+
<profileurl>http://www.flickr.com/people/frootpantz/</profileurl>
|
10
|
+
<mobileurl>http://m.flickr.com/photostream.gne?id=34225</mobileurl>
|
11
|
+
<photos>
|
12
|
+
<firstdatetaken>2006-10-11 08:19:57</firstdatetaken>
|
13
|
+
<firstdate>1160612247</firstdate>
|
14
|
+
<count>3907</count>
|
15
|
+
<views>9002</views>
|
16
|
+
</photos>
|
17
|
+
</person>
|
18
|
+
</rsp>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<rsp stat="ok">
|
3
|
+
<photos page="1" pages="1" perpage="100" total="76">
|
4
|
+
<photo id="2924549350" owner="21775151@N06" secret="cbc1804258" server="3250" farm="4" title="Photo #1" ispublic="1" isfriend="0" isfamily="0" />
|
5
|
+
<photo id="2923697303" owner="21775151@N06" secret="649aa95f29" server="3208" farm="4" title="Photo #2" ispublic="1" isfriend="0" isfamily="0" />
|
6
|
+
</photos>
|
7
|
+
</rsp>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<rsp stat="ok">
|
3
|
+
<sizes canblog="0" canprint="0" candownload="1">
|
4
|
+
<size label="Square" width="75" height="75" source="http://farm4.static.flickr.com/3093/2409912100_71e14ed08a_s.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/sq/" media="photo" />
|
5
|
+
<size label="Thumbnail" width="100" height="67" source="http://farm4.static.flickr.com/3093/2409912100_71e14ed08a_t.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/t/" media="photo" />
|
6
|
+
<size label="Small" width="240" height="160" source="http://farm4.static.flickr.com/3093/2409912100_71e14ed08a_m.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/s/" media="photo" />
|
7
|
+
<size label="Medium" width="500" height="334" source="http://farm4.static.flickr.com/3093/2409912100_71e14ed08a.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/m/" media="photo" />
|
8
|
+
<size label="Original" width="700" height="467" source="http://farm4.static.flickr.com/3093/2409912100_3305c4a108_o.jpg" url="http://www.flickr.com/photos/the_decapitator/2409912100/sizes/o/" media="photo" />
|
9
|
+
</sizes>
|
10
|
+
</rsp>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<rsp stat="ok">
|
3
|
+
<photos page="1" pages="385" perpage="100" total="38424">
|
4
|
+
<photo id="3076020861" owner="31987693@N05" secret="b956549c07" server="3278" farm="4" title="Mona and Lisa" ispublic="1" isfriend="0" isfamily="0" />
|
5
|
+
<photo id="3075386827" owner="9377349@N05" secret="4e40291b2d" server="3151" farm="4" title="IMG_0055 1.JPG" ispublic="1" isfriend="0" isfamily="0" />
|
6
|
+
</photos>
|
7
|
+
</rsp>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
<rsp stat="ok">
|
3
|
+
<photosets>
|
4
|
+
<photoset videos="0" primary="3044180117" farm="4" photos="138" id="72157609490909659" server="3012" secret="01cd1a741d">
|
5
|
+
<title>Second Set</title>
|
6
|
+
<description>This is the second set.</description>
|
7
|
+
</photoset>
|
8
|
+
<photoset videos="0" primary="2988511085" farm="4" photos="139" id="72157608538140671" server="3241" secret="a7b90926ba">
|
9
|
+
<title>First Set</title>
|
10
|
+
<description>This is the first set.</description>
|
11
|
+
</photoset>
|
12
|
+
</photosets>
|
13
|
+
</rsp>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8" ?>
|
2
|
+
<rsp stat="ok">
|
3
|
+
<photoset id="72157609490909659" primary="3044180117" owner="31066442@N69" ownername="frootpantz" page="1" per_page="500" perpage="500" pages="1" total="138">
|
4
|
+
<photo id="3044163577" secret="fa27e5a824" server="3153" farm="4" title="Photo #1" isprimary="0" />
|
5
|
+
<photo id="3045001128" secret="a8c0e51b39" server="3204" farm="4" title="Photo #2" isprimary="0" />
|
6
|
+
</photoset>
|
7
|
+
</rsp>
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
$:.reject! { |e| e.include? 'TextMate' }
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'matchy'
|
5
|
+
require 'context'
|
6
|
+
require 'mocha'
|
7
|
+
|
8
|
+
require File.dirname(__FILE__) + '/../lib/fleakr'
|
9
|
+
|
10
|
+
class Test::Unit::TestCase
|
11
|
+
|
12
|
+
def self.should_have_a_value_for(attribute_test)
|
13
|
+
it "should have a value for :#{attribute_test.keys.first}" do
|
14
|
+
@object.send(attribute_test.keys.first).should == attribute_test.values.first
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.should_search_by(key)
|
19
|
+
it "should be able to perform a scoped search by :#{key}" do
|
20
|
+
photos = [stub()]
|
21
|
+
search = stub(:results => photos)
|
22
|
+
|
23
|
+
klass = self.class.name.sub(/Test$/, '').constantize
|
24
|
+
|
25
|
+
instance = klass.new
|
26
|
+
instance.stubs(:id).with().returns('1')
|
27
|
+
|
28
|
+
Fleakr::Objects::Search.expects(:new).with(:text => 'foo', key => '1').returns(search)
|
29
|
+
|
30
|
+
instance.search('foo').should == photos
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.should_have_many(*attributes)
|
35
|
+
class_name = self.name.demodulize.sub(/Test$/, '')
|
36
|
+
this_klass = "Fleakr::Objects::#{class_name}".constantize
|
37
|
+
|
38
|
+
options = attributes.extract_options!
|
39
|
+
finder_attribute = options[:using].nil? ? "#{class_name.downcase}_id" : options[:using]
|
40
|
+
|
41
|
+
attributes.each do |attribute|
|
42
|
+
target_klass = "Fleakr::Objects::#{attribute.to_s.singularize.classify}".constantize
|
43
|
+
it "should be able to retrieve the #{class_name.downcase}'s #{attribute}" do
|
44
|
+
results = [stub()]
|
45
|
+
object = this_klass.new
|
46
|
+
object.stubs(:id).with().returns('1')
|
47
|
+
|
48
|
+
target_klass.expects("find_all_by_#{finder_attribute}".to_sym).with('1').returns(results)
|
49
|
+
object.send(attribute).should == results
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should memoize the results for the #{class_name.downcase}'s #{attribute}" do
|
53
|
+
object = this_klass.new
|
54
|
+
|
55
|
+
target_klass.expects("find_all_by_#{finder_attribute}".to_sym).once.returns([])
|
56
|
+
2.times { object.send(attribute) }
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.should_find_one(thing, options)
|
63
|
+
class_name = thing.to_s.singularize.camelcase
|
64
|
+
klass = "Fleakr::Objects::#{class_name}".constantize
|
65
|
+
object_type = class_name.downcase
|
66
|
+
|
67
|
+
options[:with] = options[:by] if options[:with].nil?
|
68
|
+
|
69
|
+
it "should be able to find a #{thing} by #{options[:by]}" do
|
70
|
+
condition_value = '1'
|
71
|
+
stub = stub()
|
72
|
+
response = mock_request_cycle :for => options[:call], :with => {options[:with] => condition_value}
|
73
|
+
|
74
|
+
klass.expects(:new).with(response.body).returns(stub)
|
75
|
+
klass.send("find_by_#{options[:by]}".to_sym, condition_value).should == stub
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def self.should_find_all(thing, options)
|
80
|
+
class_name = thing.to_s.singularize.camelcase
|
81
|
+
klass = "Fleakr::Objects::#{class_name}".constantize
|
82
|
+
object_type = class_name.downcase
|
83
|
+
|
84
|
+
it "should be able to find all #{thing} by #{options[:by]}" do
|
85
|
+
condition_value = '1'
|
86
|
+
response = mock_request_cycle :for => options[:call], :with => {options[:by] => condition_value}
|
87
|
+
|
88
|
+
stubs = []
|
89
|
+
elements = (response.body/options[:path]).map
|
90
|
+
|
91
|
+
|
92
|
+
elements.each do |element|
|
93
|
+
stub = stub()
|
94
|
+
stubs << stub
|
95
|
+
|
96
|
+
klass.expects(:new).with(element).returns(stub)
|
97
|
+
end
|
98
|
+
|
99
|
+
klass.send("find_all_by_#{options[:by]}".to_sym, condition_value).should == stubs
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
def read_fixture(method_call)
|
105
|
+
fixture_path = File.dirname(__FILE__) + '/fixtures'
|
106
|
+
File.read("#{fixture_path}/#{method_call}.xml")
|
107
|
+
end
|
108
|
+
|
109
|
+
def mock_request_cycle(options)
|
110
|
+
response = stub(:body => Hpricot.XML(read_fixture(options[:for])))
|
111
|
+
Fleakr::Api::Request.expects(:with_response!).with(options[:for], options[:with]).returns(response)
|
112
|
+
|
113
|
+
response
|
114
|
+
end
|
115
|
+
|
116
|
+
def create_temp_directory
|
117
|
+
tmp_dir = File.dirname(__FILE__) + '/tmp'
|
118
|
+
FileUtils.mkdir(tmp_dir)
|
119
|
+
|
120
|
+
tmp_dir
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../test_helper'
|
2
|
+
|
3
|
+
module Fleakr::Api
|
4
|
+
class RequestTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
describe "A Request instance" do
|
7
|
+
|
8
|
+
context "with an API key" do
|
9
|
+
|
10
|
+
before do
|
11
|
+
@api_key = 'f00b4r'
|
12
|
+
Fleakr.stubs(:api_key).with().returns(@api_key)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should know the full query parameters" do
|
16
|
+
request = Request.new('flickr.people.findByUsername', :username => 'foobar')
|
17
|
+
|
18
|
+
expected = [
|
19
|
+
"api_key=#{@api_key}",
|
20
|
+
"method=flickr.people.findByUsername",
|
21
|
+
"username=foobar"
|
22
|
+
]
|
23
|
+
|
24
|
+
request.query_parameters.split('&').sort.should == expected
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should escape the keys and values in the parameter list" do
|
28
|
+
request = Request.new('flickr.people.findByUsername', :username => 'the decapitator')
|
29
|
+
request.query_parameters.split('&').include?("username=#{CGI.escape('the decapitator')}").should be(true)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should translate a shorthand API call" do
|
33
|
+
request = Request.new('people.findByUsername')
|
34
|
+
request.query_parameters.split('&').include?('method=flickr.people.findByUsername').should be(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should know the endpoint with full parameters" do
|
38
|
+
query_parameters = 'foo=bar'
|
39
|
+
|
40
|
+
request = Request.new('people.getInfo')
|
41
|
+
request.stubs(:query_parameters).with().returns(query_parameters)
|
42
|
+
|
43
|
+
uri_mock = mock() {|m| m.expects(:query=).with(query_parameters)}
|
44
|
+
|
45
|
+
URI.expects(:parse).with("http://api.flickr.com/services/rest/").returns(uri_mock)
|
46
|
+
|
47
|
+
request.endpoint_uri.should == uri_mock
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be able to make a request" do
|
51
|
+
endpoint_uri = stub()
|
52
|
+
|
53
|
+
request = Request.new('flickr.people.findByUsername')
|
54
|
+
|
55
|
+
request.stubs(:endpoint_uri).with().returns(endpoint_uri)
|
56
|
+
Net::HTTP.expects(:get).with(endpoint_uri).returns('<xml>')
|
57
|
+
|
58
|
+
request.send
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should create a response from the request" do
|
62
|
+
response_xml = '<xml>'
|
63
|
+
response_stub = stub()
|
64
|
+
|
65
|
+
request = Request.new('flickr.people.findByUsername')
|
66
|
+
|
67
|
+
Net::HTTP.stubs(:get).returns(response_xml)
|
68
|
+
Response.expects(:new).with(response_xml).returns(response_stub)
|
69
|
+
|
70
|
+
request.send.should == response_stub
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should be able to make a full request and response cycle" do
|
74
|
+
response = stub(:error? => false)
|
75
|
+
Response.expects(:new).with(kind_of(String)).returns(response)
|
76
|
+
|
77
|
+
Request.with_response!('flickr.people.findByUsername', :username => 'foobar').should == response
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should raise an exception when the full request / response cycle has errors" do
|
81
|
+
response = stub(:error? => true, :error => stub(:code => '1', :message => 'User not found'))
|
82
|
+
Response.stubs(:new).with(kind_of(String)).returns(response)
|
83
|
+
|
84
|
+
lambda do
|
85
|
+
Request.with_response!('flickr.people.findByUsername', :username => 'foobar')
|
86
|
+
end.should raise_error(Fleakr::Api::Request::ApiError)
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../test_helper'
|
2
|
+
|
3
|
+
module Fleakr::Api
|
4
|
+
class ResponseTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
describe "An instance of Response" do
|
7
|
+
|
8
|
+
it "should provide the response body as an Hpricot element" do
|
9
|
+
response_xml = '<xml>'
|
10
|
+
hpricot_stub = stub()
|
11
|
+
|
12
|
+
Hpricot.expects(:XML).with(response_xml).returns(hpricot_stub)
|
13
|
+
|
14
|
+
response = Response.new(response_xml)
|
15
|
+
response.body.should == hpricot_stub
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should memoize the Hpricot document" do
|
19
|
+
response = Response.new('<xml>')
|
20
|
+
|
21
|
+
Hpricot.expects(:XML).with(kind_of(String)).once.returns(stub())
|
22
|
+
|
23
|
+
2.times { response.body }
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should know if there are errors in the response" do
|
27
|
+
response_xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<rsp stat=\"fail\">\n\t<err code=\"1\" msg=\"User not found\" />\n</rsp>\n"
|
28
|
+
response = Response.new(response_xml)
|
29
|
+
|
30
|
+
response.error?.should be(true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not have an error if there are no errors in the XML" do
|
34
|
+
response = Response.new(read_fixture('people.findByUsername'))
|
35
|
+
response.error.should be(nil)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should have an error if there is an error in the response" do
|
39
|
+
response_xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<rsp stat=\"fail\">\n\t<err code=\"1\" msg=\"User not found\" />\n</rsp>\n"
|
40
|
+
response = Response.new(response_xml)
|
41
|
+
|
42
|
+
response.error.code.should == '1'
|
43
|
+
response.error.message.should == 'User not found'
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../test_helper'
|
2
|
+
|
3
|
+
module Fleakr::Objects
|
4
|
+
class ContactTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
describe "The Contact class" do
|
7
|
+
|
8
|
+
should "return a list of users for a specified user's contacts" do
|
9
|
+
user_1, user_2 = [stub(), stub()]
|
10
|
+
contact_1, contact_2 = [stub(:to_user => user_1), stub(:to_user => user_2)]
|
11
|
+
|
12
|
+
response = mock_request_cycle :for => 'contacts.getPublicList', :with => {:user_id => '1'}
|
13
|
+
|
14
|
+
contact_1_doc, contact_2_doc = (response.body/'rsp/contacts/contact').map
|
15
|
+
|
16
|
+
Contact.stubs(:new).with(contact_1_doc).returns(contact_1)
|
17
|
+
Contact.stubs(:new).with(contact_2_doc).returns(contact_2)
|
18
|
+
|
19
|
+
Contact.find_all_by_user_id('1').should == [user_1, user_2]
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "An instance of the Contact class" do
|
25
|
+
context "when populating from an XML document" do
|
26
|
+
before do
|
27
|
+
@object = Contact.new(Hpricot.XML(read_fixture('contacts.getPublicList')).at('contacts/contact'))
|
28
|
+
end
|
29
|
+
|
30
|
+
should_have_a_value_for :id => '9302864@N42'
|
31
|
+
should_have_a_value_for :username => 'blinky'
|
32
|
+
should_have_a_value_for :icon_server => '2263'
|
33
|
+
should_have_a_value_for :icon_farm => '3'
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
context "in general" do
|
38
|
+
|
39
|
+
should "be able to convert to a user" do
|
40
|
+
contact = Contact.new
|
41
|
+
user = mock()
|
42
|
+
|
43
|
+
User.stubs(:new).returns(user)
|
44
|
+
|
45
|
+
[:id, :username, :icon_server, :icon_farm].each do |method|
|
46
|
+
contact.stubs(method).with().returns(method.to_s)
|
47
|
+
user.expects("#{method}=".to_sym).with(method.to_s)
|
48
|
+
end
|
49
|
+
|
50
|
+
contact.to_user.should == user
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../test_helper'
|
2
|
+
|
3
|
+
module Fleakr::Objects
|
4
|
+
class ErrorTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
describe "An instance of the Error class" do
|
7
|
+
|
8
|
+
it "should have a code and a message" do
|
9
|
+
response_xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n<rsp stat=\"fail\">\n\t<err code=\"1\" msg=\"User not found\" />\n</rsp>\n"
|
10
|
+
|
11
|
+
error = Error.new(Hpricot.XML(response_xml))
|
12
|
+
|
13
|
+
error.code.should == '1'
|
14
|
+
error.message.should == 'User not found'
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../test_helper'
|
2
|
+
|
3
|
+
module Fleakr::Objects
|
4
|
+
class GroupTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
should_have_many :photos
|
7
|
+
|
8
|
+
should_search_by :group_id
|
9
|
+
|
10
|
+
describe "The Group class" do
|
11
|
+
|
12
|
+
should_find_all :groups, :by => :user_id, :call => 'people.getPublicGroups', :path => 'rsp/groups/group'
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "An instance of the Group class" do
|
17
|
+
context "when initializing from an Hpricot document" do
|
18
|
+
|
19
|
+
before do
|
20
|
+
doc = Hpricot.XML(read_fixture('people.getPublicGroups')).at('rsp/groups/group')
|
21
|
+
@object = Group.new(doc)
|
22
|
+
end
|
23
|
+
|
24
|
+
should_have_a_value_for :id => '13378274@N00'
|
25
|
+
should_have_a_value_for :name => 'Group #1'
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|