jerrett-simple-flickr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,34 @@
1
+ Simple-Flickr
2
+ Jerrett Taylor (jerrett@gmail.com)
3
+
4
+ DESCRIPTION:
5
+
6
+ This is an interface into the Flickr REST API. There are a bunch of various libraries that do this,
7
+ but most of the ones I found are out of date and no longer work with the new(ish) Flickr API,
8
+ partially work, or resulted in general funkyness.
9
+
10
+ At the moment, this does what I need. Feel free to do what you want with it, and let me know if
11
+ you make changes, fix bugs, or add any features - i'd be more than happy to accept any patches!
12
+
13
+ FEATURES/PROBLEMS:
14
+
15
+ This currently only provides a wrapper around public data (non-authenticated stuff), but it would not be
16
+ too tricky to add authenticated stuff in at a later date, should it be needed.
17
+
18
+ This currently provides wrapping for people, photos, and photosets. For anything else, you can use the
19
+ Flickr::Client#request and get hpricot documents back, which are easy to parse... or, submit a patch with the missing
20
+ wrappers!
21
+
22
+ SYNOPSIS:
23
+
24
+ client = Flickr::Client.new( 'apikey' )
25
+ person = client.person( 'jerrett taylor' )
26
+ => #<Flickr::Person:0x11e5e14 ...>>
27
+ person.photosets.first.title
28
+ => "Macro"
29
+ person.photosets.first.photos
30
+ => [#<Flickr::Photo:0x116ab10 ...>
31
+
32
+ REQUIREMENTS:
33
+ - Hpricot
34
+
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'rake'
2
+ require 'rake/gempackagetask'
3
+
4
+ Dir[ "tasks/**/*.rake" ].each { | tasks | load tasks }
5
+
6
+ desc "Run specs"
7
+ task :default => :spec
8
+
9
+ spec = Gem::Specification.new do |s|
10
+ s.name = 'simple-flickr'
11
+ s.version = '0.1.0'
12
+ s.summary = "A wrapper for Flickrs REST API"
13
+ s.description = "A wrapper for Flickrs REST API."
14
+
15
+ s.author = "Jerrett Taylor"
16
+ s.email = "jerrett@gmail.com"
17
+ s.homepage = "http://github.com/jerrett/simple-flickr"
18
+
19
+ # code
20
+ s.require_path = "lib"
21
+ s.files = %w( README Rakefile ) + Dir["{spec,lib}/**/*"]
22
+
23
+ # rdoc
24
+ s.has_rdoc = false
25
+
26
+ # Dependencies
27
+ s.add_dependency "hpricot", [">= 0.6.0"]
28
+
29
+ # Requirements
30
+ s.required_ruby_version = ">= 1.8.6"
31
+
32
+ s.platform = Gem::Platform::RUBY
33
+ end
34
+
35
+ desc "create .gemspec file (useful for github)"
36
+ task :gemspec do
37
+ filename = "#{spec.name}.gemspec"
38
+ File.open(filename, "w") do |f|
39
+ f.puts spec.to_ruby
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ # A good starting point is Flickr::Client. Quick and simple example usage:
4
+ #
5
+ # client = Flickr::Client.new( 'apikey' )
6
+ # person = client.person( 'jerrett taylor' )
7
+ # => #<Flickr::Person:0x11e5e14 ...>>
8
+ # person.photosets.first.title
9
+ # => "Macro"
10
+ # person.photosets.first.photos
11
+ # => [#<Flickr::Photo:0x116ab10 ...>]
12
+ #
13
+ # There is some basic caching, so the above example while making two calls
14
+ # to person.photosets, would only contact flickr once.
15
+ #
16
+ # All Proxy classes include Flickr::Proxy which grants them Flickr::Proxy#api_query. This
17
+ # allows you to retreive a collection directly, for example if you want to get a list
18
+ # of photosets and you know the internal flickr user id (or 'nsid'), you
19
+ # can do the following:
20
+ #
21
+ # client = Flickr::Client.new( 'yourapikey' )
22
+ # PhotoSet.api_query( 'photosets.getPhotos', client, :photoset_id => 1234 )
23
+ #
24
+ # Similarly, you could get a list of all of a people photos or favorites:
25
+ #
26
+ # client = Flickr::Client.new( 'yourapikey' )
27
+ # Photo.api_query( 'favorites.getPublicList', client, :user_id => 'flickruserid' )
28
+ # Photo.api_query( 'people.getPublicPhotos', client, :user_id => 'flickruserid' )
29
+ #
30
+ # The benifit of this is that it will only do a single request, since you don't
31
+ # need to lookup the ID's if you have them already.
32
+ module Flickr
33
+ class RequestError < StandardError
34
+ attr_accessor :status, :message
35
+ def initialize( status, message )
36
+ @status, @message = status.to_i, message
37
+ end
38
+
39
+ def to_s
40
+ "#{message} (#{status})"
41
+ end
42
+ end
43
+ end
44
+
45
+ # Dependencies
46
+ require 'rubygems'
47
+ require 'hpricot'
48
+ require 'open-uri'
49
+ require 'uri'
50
+
51
+ # Classes
52
+ require 'simple-flickr/proxy'
53
+ require 'simple-flickr/client'
54
+ require 'simple-flickr/person'
55
+ require 'simple-flickr/photos'
56
+ require 'simple-flickr/photo'
57
+ require 'simple-flickr/photo_set'
@@ -0,0 +1,91 @@
1
+ module Flickr
2
+ # This can be used to make any raw request to Flickr,
3
+ # using Flickr::Client#request.
4
+ #
5
+ # You will be greeted with an Hpricot document in return,
6
+ # which you will then have to parse yourself. Lucky for you,
7
+ # Flickr provides pretty clean responses and very nice documentation
8
+ # (at http://www.flickr.com/services/api/), so it should be pretty
9
+ # easy to deal with.
10
+ #
11
+ # Use this if the rest of this library doesn't wrap the calls you
12
+ # need, or if you just want to do it all your way instead.
13
+ class Client
14
+ REST_ENDPOINT = "http://api.flickr.com/services/rest"
15
+
16
+ # Create a new Flickr::Client object.
17
+ #
18
+ # === Parameters
19
+ # api_key<String>:: The API Key provided to you by flickr.
20
+ #
21
+ # Please see http://www.flickr.com/services/api/
22
+ # for more information.
23
+ def initialize( api_key )
24
+ @api_key = api_key
25
+ @cached_requests = {}
26
+ end
27
+
28
+ # This is just to make it nicer to look at. Without this, the @cached_requests pile up and make a mess.
29
+ def inspect # :nodoc:
30
+ "<Flickr::Client api_key=\"#{@api_key}\">"
31
+ end
32
+
33
+ # Locate a person using their username or email address.
34
+ #
35
+ # === Parameters
36
+ # :query<String>:: The flickr username or email address of the person you want to find.
37
+ #
38
+ # === Returns
39
+ # Flickr::Person:: Proxy object representing a Flickr person.
40
+ def person( query )
41
+ Person.find( query, self )
42
+ end
43
+
44
+ # Find a single photo using the Flickr photo ID
45
+ #
46
+ # === Parameters
47
+ # :photo_id<String>:: The flickr photo id (should be a ~10-digit integer)
48
+ def photo( photo_id )
49
+ Photo.find( photo_id, self )
50
+ end
51
+
52
+ # Find a single photoset using the Flickr photoset ID
53
+ #
54
+ # === Parameters
55
+ # :photoset_id<String>:: The flickr photoset id (should be a ~10-digit integer)
56
+ def photoset( photoset_id )
57
+ PhotoSet.find( photoset_id, self )
58
+ end
59
+
60
+ # Make a request to flickr. This will cache (per Flickr::Client instance) requests to avoid uneccesary traffic.
61
+ # This will raise a Flickr::RequestError if something goes wrong.
62
+ #
63
+ # === Parameters
64
+ # :method<String>:: The method to call. This is any method from the Flickr API: http://www.flickr.com/services/api/ (but
65
+ # without the leading 'flickr.' in front of the method call.
66
+ # :arguments<Hash>:: An (optional) hash of key/value arguments. This is whatever arguments the method you are calling expects.
67
+ #
68
+ # === Returns
69
+ # Hpricot::Elem:: An Hpricot Elem object, representing the XML response.
70
+ #
71
+ # flickr = Flickr::Client.new( 'myapikey' )
72
+ # flickr.request( 'favorites.getPublicList', :user_id => '66273938@N00', :per_page => 5 )
73
+ def request( method, arguments = {} )
74
+ url = REST_ENDPOINT + "?" + arguments.merge(
75
+ :api_key => @api_key,
76
+ :method => "flickr.#{method}"
77
+ ).collect { | key, value | "#{key}=#{URI.encode(value.to_s)}" }.sort.join( '&' )
78
+
79
+ return @cached_requests[ url ] if @cached_requests.has_key? url
80
+
81
+ begin
82
+ response = Hpricot.XML( open(url).read ).at('rsp')
83
+ rescue Timeout::Error, OpenURI::HTTPError, Errno::ECONNRESET, SocketError, Errno::ECONNREFUSED => e
84
+ raise RequestError.new(0, e)
85
+ end
86
+ raise RequestError.new(response.at('err')['code'], response.at('err')['msg']) unless response['stat'] == 'ok'
87
+
88
+ @cached_requests[ url ] = response
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,103 @@
1
+ module Flickr
2
+
3
+ # Represents a Flickr Person.
4
+ #
5
+ # You can find a Flickr::Person by email or by username,
6
+ # using Flickr::Person#find.
7
+ class Person
8
+ include Proxy
9
+
10
+ def initialize( xml, client ) # :nodoc:
11
+ super( xml, client )
12
+
13
+ @attributes.merge!(
14
+ 'id' => xml[ 'nsid' ],
15
+ 'profileurl' => xml.search('profileurl').text,
16
+ 'photosurl' => xml.search('photosurl').text,
17
+ 'location' => xml.search('location').text,
18
+ 'realname' => xml.search('realname').text,
19
+ 'username' => xml.search('username').text
20
+ )
21
+ end
22
+
23
+ # Return the most recent photos from a persons photostream.
24
+ #
25
+ # === Arguments
26
+ # :options<Hash>:: This is a hash of options that will be passed to flickr. For more details
27
+ # on what you can pass, please check out http://www.flickr.com/services/api/flickr.people.getPublicPhotos.html
28
+ #
29
+ # === Returns
30
+ # [Flickr::Photo]:: An array of Flickr::Photo objects.
31
+ def photos( options = {} )
32
+ Photo.api_query( 'people.getPublicPhotos', @client, options.merge(:user_id => id) )
33
+ end
34
+
35
+ # Return the persons photosets.
36
+ #
37
+ # === Returns
38
+ # [Flickr::PhotoSet]:: An array of Flickr::PhotoSet objects.
39
+ def photosets
40
+ PhotoSet.api_query( 'photosets.getList', @client, :user_id => id )
41
+ end
42
+
43
+ # Return the most recent photos from a persons favorites.
44
+ #
45
+ # === Arguments
46
+ # :options<Hash>:: This is a hash of options that will be passed to flickr. For more details
47
+ # on what you can pass, please check out http://www.flickr.com/services/api/flickr.favorites.getPublicList.html
48
+ #
49
+ # === Returns
50
+ # [Flickr::Photo]:: An array of Flickr::Photo objects.
51
+ def favorites( options )
52
+ Photo.api_query( 'favorites.getPublicList', @client, options.merge(:user_id => id) )
53
+ end
54
+
55
+ # Find a person on Flickr using their flickr username or email address.
56
+ #
57
+ # === Parameters
58
+ # :query<String>:: The Flickr username or email address of the person.
59
+ # :client<Flickr::Client>:: A Flickr::Client to use for communication with flickr.
60
+ #
61
+ # === Returns
62
+ # Flickr::Person:: An instance of Flickr::Person representing the person, or nil
63
+ # if no people can be found.
64
+ def self.find( query, client )
65
+ return nil unless query.is_a? String
66
+
67
+ begin
68
+ if query.include? '@'
69
+ xml = client.request( 'people.findByEmail', :find_email => query )
70
+ else
71
+ xml = client.request( 'people.findByUsername', :username => query )
72
+ end
73
+ rescue => e
74
+ return nil if e.respond_to? :status and e.status == 1
75
+ raise e
76
+ end
77
+
78
+ find_by_id( xml.at('user')['nsid'], client )
79
+ end
80
+
81
+ # Find a user using their flickr user id. Use this if you already know the NSID
82
+ # of a user, instead of #find.
83
+ #
84
+ # === Parameters
85
+ # :user_id<String>:: The Flickr User id (NSID).
86
+ # :client<Flickr::Client>:: A Flickr::Client to use for communication with flickr.
87
+ #
88
+ # === Returns
89
+ # Flickr::Person:: An instance of Flickr::Person representing the person, or nil
90
+ # if no people can be found.
91
+ def self.find_by_id( user_id, client )
92
+ begin
93
+ userxml = client.request( 'people.getInfo', :user_id => user_id )
94
+ rescue => e
95
+ return nil if e.respond_to? :status and e.status == 1
96
+ raise e
97
+ end
98
+
99
+ new( userxml.at('person'), client )
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,71 @@
1
+ module Flickr
2
+ # Represents a Flickr Photo.
3
+ class Photo
4
+ include Proxy
5
+ include Comparable
6
+
7
+ # http://www.flickr.com/services/api/misc.urls.html
8
+ PHOTO_SIZES = { 'square' => '_s', 'thumbnail' => '_t', 'small' => '_m', 'medium' => '', 'large' => '_b' }
9
+
10
+ # Initialize the photo with an extra hack to ensure that various attributes are
11
+ # present, no matter whether flicker provides them as attributes or as seperate
12
+ # nodes (or by several different names, occasionally)
13
+ #
14
+ # === Parameters
15
+ # See Flickr::Proxy#initialize
16
+ def initialize( xml, client )
17
+ super( xml, client )
18
+ @attributes['title'] ||= xml.search('title').text
19
+ @attributes['description'] = xml.search('description').text
20
+ @attributes['uploaded_at'] = Time.at((@attributes.delete('dateuploaded') or @attributes.delete('dateupload')).to_i)
21
+ @attributes['owner'] ||= xml.at('owner').attributes['nsid'] if xml.at('owner')
22
+ end
23
+
24
+ # Get the person associated with this photo
25
+ #
26
+ # === Returns
27
+ # Flickr::Person: The associated person object
28
+ def person
29
+ Person.find_by_id( owner, @client )
30
+ end
31
+
32
+ # Comparison with another Flickr::PHoto.
33
+ #
34
+ # === Parameters
35
+ # :other<Flickr::Photo>: The other photo to compare to.
36
+ #
37
+ # === Returns
38
+ # Integer: -1, 0, 1 if the id of this Photo is less than, equal to, or greater than the +other+ Photo.
39
+ def <=>( other )
40
+ return 0 if self.id == other.id
41
+ self.id < other.id ? -1 : 1
42
+ end
43
+
44
+ # Return the url to an image for the specified size. This does not currently support 'original'.
45
+ #
46
+ # === Parameters
47
+ # :size<String>:: The desired size of the image. Can be +square+, +thumbnail+, +small+, +medium+, or +large+.
48
+ #
49
+ # === Returns
50
+ # String:: The url to the image.
51
+ def url( size = 'medium' )
52
+ "http://farm#{farm}.static.flickr.com/#{server}/#{id}_#{secret}#{PHOTO_SIZES[size]}.jpg"
53
+ end
54
+
55
+ # Find Photos using a Flickr API method, a Flickr::Client and a hash of options.
56
+ #
57
+ # This works the same as Flickr::Proxy#api_query, only it returns a Flickr::Photos object instead of an Array.
58
+ def self.api_query( api_method, client, options )
59
+ Flickr::Photos.new( client.request(api_method, options).at('photos|photoset'), client ) # Photosets, unlike every other photos result, returns in a <photosets> node instead of <photos>.
60
+ end
61
+
62
+ # Find a single photo using the Flickr photo ID and a Flickr::Client
63
+ #
64
+ # === Parameters
65
+ # :photo_id<String>:: The flickr photo id (should be a ~10-digit integer)
66
+ # :client<Flickr::Client>:: The flickr client object to use
67
+ def self.find( photo_id, client )
68
+ Photo.new( client.request('photos.getInfo', :photo_id => photo_id).at('photo'), client )
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,42 @@
1
+ module Flickr
2
+
3
+ # Represents a Flickr Photo Set.
4
+ class PhotoSet
5
+ include Proxy
6
+
7
+ def initialize( xml, client ) # :nodoc:
8
+ super( xml, client )
9
+ @attributes[ 'title' ] = xml.at('title').inner_text
10
+ @attributes[ 'description' ] = xml.at('description').inner_text
11
+ end
12
+
13
+ # Return the most recent photos for this photoset.
14
+ #
15
+ # === Arguments
16
+ # :options<Hash>:: This is a hash of options that will be passed to flickr. For more details
17
+ # on what you can pass, please check out http://www.flickr.com/services/api/flickr.photosets.getPhotos.html
18
+ #
19
+ # === Returns
20
+ # [Flickr::Photo]:: An array of Flickr::Photo objects.
21
+ def photos( options = {} )
22
+ Photo.api_query( 'photosets.getPhotos', @client, options.merge(:photoset_id => id) )
23
+ end
24
+
25
+ # Get the person associated with this photoset
26
+ #
27
+ # === Returns
28
+ # Flickr::Person: The associated person object
29
+ def person
30
+ Person.find_by_id( owner, @client )
31
+ end
32
+
33
+ # Find a single photo using the Flickr photo ID and a Flickr::Client
34
+ #
35
+ # === Parameters
36
+ # :photoset_id<String>:: The flickr photoset id (should be a ~10-digit integer)
37
+ # :client<Flickr::Client>:: The flickr client object to use
38
+ def self.find( photoset_id, client )
39
+ PhotoSet.new( client.request('photosets.getInfo', :photoset_id => photoset_id).at('photoset'), client )
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,62 @@
1
+ module Flickr
2
+ # A collection of Photos.
3
+ class Photos
4
+ include Enumerable
5
+
6
+ def offset
7
+ (current_page-1) * per_page
8
+ end
9
+
10
+ def current_page
11
+ @attributes['page'].to_i
12
+ end
13
+
14
+ def per_page
15
+ (@attributes['perpage'] || @attributes['per_page']).to_i
16
+ end
17
+
18
+ def total_entries
19
+ @attributes['total'].to_i
20
+ end
21
+
22
+ def total_pages
23
+ (total_entries.to_f / per_page).ceil
24
+ end
25
+
26
+ def next_page
27
+ total_pages > current_page ? current_page+1 : nil
28
+ end
29
+
30
+ def previous_page
31
+ current_page > 1 ? current_page-1 : nil
32
+ end
33
+
34
+ # Create a new Flickr::Photos collection using the provided Hpricot::Elem object, which should
35
+ # contain an appropriate Photo response in XML from Flickr.
36
+ def initialize( result_xml, client )
37
+ @photos = result_xml.search( 'photo' ).collect { |xml| Flickr::Photo.new( xml, client ) }
38
+ @attributes = result_xml.attributes
39
+ end
40
+
41
+ # Iterate through all the Flickr::Photo objects.
42
+ def each
43
+ @photos.each { |photo| yield photo }
44
+ end
45
+
46
+ # Is this collection of photos empty?
47
+ def empty?
48
+ to_a.empty?
49
+ end
50
+
51
+ # How big is this collection?
52
+ def size
53
+ to_a.size
54
+ end
55
+ alias_method :length, :size
56
+
57
+ # Allow Photos to be accessed as an Array
58
+ def [](n)
59
+ to_a[n]
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,72 @@
1
+ module Flickr
2
+ # Flickr Proxy
3
+ #
4
+ # This contains shared functionality for Flickr Proxy classes.
5
+ #
6
+ # Any class that includes this should call super on initialize to pass
7
+ # in the XML and Flickr::Client instance, if they overide initialize.
8
+ #
9
+ # All attributes from the Hpricto::Elem passed in to initialize will be grabbed
10
+ # and mapped to method calls, for example:
11
+ #
12
+ # xml => #<Hpricot::Doc {emptyelem <foo id="3" foo="bar">}>
13
+ #
14
+ # test = Myclass.new( xml, client )
15
+ # test.id => "3"
16
+ # test.foo => "bar"
17
+ module Proxy
18
+ attr_accessor :attributes
19
+
20
+ # Create a new proxy class. This needs an Hpricot::Elem
21
+ # of the XML returned from Flickr, from Flickr::Client#request.
22
+ #
23
+ # Typically you don't want to call this directly, and should be using
24
+ # the +find+ method of the class instead.
25
+ #
26
+ # === Parameters
27
+ # :xml<Hpricot::Elem>:: XML from Flickr, in Hpricot form.
28
+ # :client<Flickr::Client>:: A Flickr::Client to use for communication with flickr.
29
+ def initialize( xml, client )
30
+ @attributes = xml.attributes
31
+ @client = client
32
+ end
33
+
34
+ # Return the id, instead of the object_id
35
+ def id # :nodoc:
36
+ @attributes[ 'id' ]
37
+ end
38
+
39
+ # This maps method calls to attributes.
40
+ def method_missing( method, *args ) # :nodoc:
41
+ return @attributes[method.to_s] if @attributes[method.to_s]
42
+ super
43
+ end
44
+
45
+ # Class methods.
46
+ module ClassMethods
47
+ # Find objects using a Flickr API method, a Flickr::Client and a hash of options.
48
+ #
49
+ # this is mostly intended for internal use, but can also be used to directly call
50
+ # specific api methods.
51
+ #
52
+ # === Parameters
53
+ # :client<Flickr::Client>:: Instance of a Flickr::Client to use to make the request.
54
+ # :api_method<String>:: The Flickr API method to use. Must return nodes matching the class this is called on. (example, 'photosets' for Flickr::PhotoSet)
55
+ # :options<Hash>:: Options to be passed along to the Flickr API Method.
56
+ #
57
+ # === Returns
58
+ # Array[Flickr::Photo]:: An Array of Flickr::Photo objects.
59
+ def api_query(api_method, client, options = {} )
60
+ client.request( api_method, options ).search( self.to_s.gsub('Flickr::','').downcase ).collect { |xml| new( xml, client ) }
61
+ end
62
+ end
63
+
64
+ def self.included(klass) # :nodoc:
65
+ klass.extend(ClassMethods)
66
+ end
67
+ end
68
+ end
69
+
70
+
71
+
72
+
@@ -0,0 +1,51 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Flickr::Client do
4
+ before( :each ) do
5
+ @flickr = Flickr::Client.new( 'my-api-key' )
6
+ end
7
+
8
+ it 'should make a request to a flickr method with no arguments' do
9
+ @flickr.should_receive( :open ).with( Flickr::Client::REST_ENDPOINT + '?api_key=my-api-key&method=flickr.test.echo' ).and_return( VALID_FLICKR_RESPONSE )
10
+ @flickr.request( 'test.echo' )
11
+ end
12
+
13
+ it 'should make a request to a flickr method with arguments passed' do
14
+ @flickr.should_receive( :open ).with( Flickr::Client::REST_ENDPOINT + '?api_key=my-api-key&method=flickr.favorites.getList&per_page=4&user_id=123456789N00' ).and_return( VALID_FLICKR_RESPONSE )
15
+ @flickr.request( 'favorites.getList', :user_id => '123456789N00', :per_page => 4 )
16
+ end
17
+
18
+ [Timeout::Error.new(nil), OpenURI::HTTPError.new(nil,nil), Errno::ECONNRESET, SocketError, Errno::ECONNREFUSED].each do |e|
19
+ it "should raise an appropriate error if open-uri raises #{e}" do
20
+ @flickr.should_receive( :open ).and_raise( e )
21
+ proc { @flickr.request( 'test.echo' ) }.should raise_error( Flickr::RequestError )
22
+ end
23
+ end
24
+
25
+ it 'should raise an appropriate error if something goes wrong with the request' do
26
+ @flickr.should_receive( :open ).and_return( INVALID_FLICKR_RESPONSE )
27
+ proc { @flickr.request( 'test.echo' ) }.should raise_error( Flickr::RequestError )
28
+ end
29
+
30
+ it 'should cache requests returning the correct result and not make uneccesary calls to flickr' do
31
+ @flickr.should_receive( :open ).once.and_return( VALID_FLICKR_RESPONSE )
32
+
33
+ response = Hpricot.XML( VALID_FLICKR_RESPONSE.read ).at( 'rsp' )
34
+ @flickr.request( 'favorites.getList', :user_id => '123456789N00', :per_page => 4 ).to_s.should == response.to_s
35
+ @flickr.request( 'favorites.getList', :user_id => '123456789N00', :per_page => 4 ).to_s.should == response.to_s
36
+ end
37
+
38
+ it 'should request a user passing self in as the client' do
39
+ user = mock('flickr user')
40
+ Flickr::Person.should_receive( :find ).with( 'ennoia', @flickr ).and_return( user )
41
+ @flickr.person( 'ennoia' ).should == user
42
+ end
43
+
44
+ it 'should request a photo passing self in as the client' do
45
+ photo = mock('flickr photo')
46
+ Flickr::Photo.should_receive( :find ).with( 'myphoto', @flickr ).and_return( photo )
47
+ @flickr.photo( 'myphoto' ).should == photo
48
+ end
49
+ end
50
+
51
+
@@ -0,0 +1,98 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Flickr::Person do
4
+ before( :each ) do
5
+ @client = mock( 'Flickr::Client' )
6
+ end
7
+
8
+ describe 'when finding a person' do
9
+ before( :each ) do
10
+ @find_user_xml = Hpricot.parse( '<rsp stat="ok"><user nsid="66273938@N00" id="66273938@N00"><username>Ennoia</username></user></rsp>' )
11
+ @person_xml = Hpricot.parse( '<rsp stat="ok"><person nsid="12037949754@N01" isadmin="0" ispro="0" iconserver="122" iconfarm="1">
12
+ <username>bees</username><realname>Cal Henderson</realname><mbox_sha1sum>eea6cd28e3d0003ab51b0058a684d94980b727ac</mbox_sha1sum>
13
+ <location>Vancouver, Canada</location><photosurl>http://www.flickr.com/photos/bees/</photosurl><profileurl>http://www.flickr.com/people/bees/</profileurl>
14
+ <photos><firstdate>1071510391</firstdate><firstdatetaken>1900-09-02 09:11:24</firstdatetaken><count>449</count></photos></person></rsp>')
15
+
16
+ @person = mock( 'Flickr::Person' )
17
+ end
18
+
19
+ it 'should find a person by email address' do
20
+ @client.should_receive( :request ).with( 'people.findByEmail' , :find_email => 'foo@bar.com' ).and_return( @find_user_xml )
21
+ Flickr::Person.should_receive( :find_by_id ).with( '66273938@N00', @client ).and_return( @person )
22
+ Flickr::Person.find( 'foo@bar.com' , @client ).should == @person
23
+ end
24
+
25
+ it 'should find a person by username' do
26
+ @client.should_receive( :request ).with( 'people.findByUsername' , :username => 'ennoia' ).and_return( @find_user_xml )
27
+ Flickr::Person.should_receive( :find_by_id ).with( '66273938@N00', @client ).and_return( @person )
28
+ Flickr::Person.find( 'ennoia' , @client ).should == @person
29
+ end
30
+
31
+ it 'should return nil if no person was found' do
32
+ @client.should_receive( :request ).and_raise( Flickr::RequestError.new( '1', 'Not found') )
33
+ Flickr::Person.find( 'sdfsdfsd', @client ).should == nil
34
+ end
35
+
36
+ it 'should raise an exception if any other error is encountered' do
37
+ @client.should_receive( :request ).and_raise( Flickr::RequestError.new( '101', 'Not found') )
38
+ proc { Flickr::Person.find( 'sdfsdfsd', @client ) }.should raise_error( Flickr::RequestError )
39
+ end
40
+
41
+ it 'should return nil if something invalid is passed in (non string)' do
42
+ Flickr::Person.find(nil, @client).should == nil
43
+ end
44
+
45
+ it 'should find a user by the flickr userid' do
46
+ @client.should_receive( :request ).with( 'people.getInfo', :user_id => '66273938@N00' ).and_return( @person_xml )
47
+ Flickr::Person.should_receive( :new ).with( @person_xml.at('person'), @client ).and_return( @person )
48
+ Flickr::Person.find_by_id( '66273938@N00' , @client ).should == @person
49
+ end
50
+
51
+ it 'should return nil if no person was found by id' do
52
+ @client.should_receive( :request ).and_raise( Flickr::RequestError.new( '1', 'Not found') )
53
+ Flickr::Person.find_by_id( 'sdfsdfsd', @client ).should == nil
54
+ end
55
+ end
56
+ end
57
+
58
+ describe Flickr::Person do
59
+ before( :each ) do
60
+ @client = mock( 'Flickr::Client' )
61
+ user_xml = Hpricot.parse( '<rsp stat="ok"><person nsid="12037949754@N01" isadmin="0" ispro="0" iconserver="122" iconfarm="1">
62
+ <username>bees</username><realname>Cal Henderson</realname><mbox_sha1sum>eea6cd28e3d0003ab51b0058a684d94980b727ac</mbox_sha1sum>
63
+ <location>Vancouver, Canada</location><photosurl>http://www.flickr.com/photos/bees/</photosurl><profileurl>http://www.flickr.com/people/bees/</profileurl>
64
+ <photos><firstdate>1071510391</firstdate><firstdatetaken>1900-09-02 09:11:24</firstdatetaken><count>449</count></photos></person></rsp>')
65
+ @person = Flickr::Person.new( user_xml.at('person'), @client )
66
+ end
67
+
68
+ it 'should include proxy' do
69
+ Flickr::Photo.included_modules.include?( Flickr::Proxy ).should == true
70
+ end
71
+
72
+ it 'should set the id' do
73
+ @person.id.should == '12037949754@N01'
74
+ end
75
+
76
+ it 'should use the passed in client' do
77
+ @person.instance_variable_get( :'@client' ).should == @client
78
+ end
79
+
80
+ it 'should return the users photos' do
81
+ photos = mock( 'photos' )
82
+ Flickr::Photo.should_receive( :api_query ).with( 'people.getPublicPhotos', @client, :user_id => '12037949754@N01', :per_page => 2 ).and_return( photos )
83
+ @person.photos( :per_page => 2).should == photos
84
+ end
85
+
86
+ it 'should return the users favorites' do
87
+ photos = mock( 'photos' )
88
+ Flickr::Photo.should_receive( :api_query ).with( 'favorites.getPublicList', @client, :user_id => '12037949754@N01', :per_page => 2 ).and_return( photos )
89
+ @person.favorites( :per_page => 2).should == photos
90
+ end
91
+
92
+ it 'should return the users photosets' do
93
+ photosets = mock( 'photosets' )
94
+ Flickr::PhotoSet.should_receive( :api_query ).with( 'photosets.getList', @client, :user_id => '12037949754@N01' ).and_return( photosets )
95
+ @person.photosets.should == photosets
96
+ end
97
+ end
98
+
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Flickr::PhotoSet do
4
+ before( :each ) do
5
+ @client = mock( 'Flickr::Client' )
6
+ user_xml = Hpricot.parse( '<photos page="2" pages="89" perpage="10" total="881"><photoset id="5" primary="2483" secret="abcdef" server="8" photos="4" farm="1"><title>Test</title><description>foo</description></photoset></photosets>' )
7
+ @photoset = Flickr::PhotoSet.new( user_xml.at('photoset'), @client )
8
+ end
9
+
10
+ it 'should include proxy' do
11
+ Flickr::PhotoSet.included_modules.include?( Flickr::Proxy ).should == true
12
+ end
13
+
14
+ it 'should grab the title and description from the xml' do
15
+ @photoset.title.should == 'Test'
16
+ @photoset.description.should == 'foo'
17
+ end
18
+
19
+ it 'should use the passed in client' do
20
+ @photoset.instance_variable_get( :'@client' ).should == @client
21
+ end
22
+
23
+ it 'should return photos for the current photoset' do
24
+ set = mock('photo set')
25
+ Flickr::Photo.should_receive( :api_query ).with( 'photosets.getPhotos', @client, :photoset_id => '5').and_return( set )
26
+ @photoset.photos.should == set
27
+ end
28
+ end
@@ -0,0 +1,64 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Flickr::Photo do
4
+ before( :each ) do
5
+ @client = mock( 'Flickr::Client' )
6
+ @xml = Hpricot.parse( '<photos page="2" pages="89" perpage="10" total="881"><photo id="2636" owner="47058503995@N01" farm="1" secret="a123456" server="2" title="test_04" ispublic="1" isfriend="0" isfamily="0" /></photos>' )
7
+ @photo = Flickr::Photo.new( @xml.at('photo'), @client )
8
+ end
9
+
10
+ it 'should include proxy' do
11
+ Flickr::Photo.included_modules.include?( Flickr::Proxy ).should == true
12
+ end
13
+
14
+ it 'should use the passed in client' do
15
+ @photo.instance_variable_get( :'@client' ).should == @client
16
+ end
17
+
18
+ it 'should fetch "person" when it is requested' do
19
+ @photo.should_receive(:owner).and_return('owner_id')
20
+ Flickr::Person.should_receive(:find_by_id).with('owner_id', @client).and_return('person')
21
+ @photo.person.should == 'person'
22
+ end
23
+
24
+ it 'should fetch a single photo on a call to Photo.find' do
25
+ @photo_data = mock('photo', :at => 'photodata')
26
+ @client.should_receive(:request).with('photos.getInfo', :photo_id => 'myphoto').and_return(@photo_data)
27
+ Flickr::Photo.should_receive(:new).with('photodata', @client).and_return('my photo object')
28
+ Flickr::Photo.find('myphoto', @client)
29
+ end
30
+
31
+ it 'should return the url of the image for the requested size' do
32
+ @photo.url.should == 'http://farm1.static.flickr.com/2/2636_a123456.jpg'
33
+ @photo.url( 'small' ).should == 'http://farm1.static.flickr.com/2/2636_a123456_m.jpg'
34
+ end
35
+
36
+ it 'should implement <=> based on id' do
37
+ @photo
38
+ photo2 = mock( 'photo', :id => '2636' )
39
+ photo3 = mock( 'photo', :id => '2637' )
40
+ photo4 = mock( 'photo', :id => '2635' )
41
+
42
+ (@photo <=> photo2).should == 0
43
+ (@photo <=> photo3).should == -1
44
+ (@photo <=> photo4).should == 1
45
+ end
46
+
47
+ it 'should include comparable' do
48
+ Flickr::Photo.included_modules.include?( Comparable ).should == true
49
+ end
50
+
51
+ it 'should create a new Photos collection with the results of the photos node in the returned xml' do
52
+ @client.should_receive( :request ).with( 'person.listPhotos', :foo => 'bar' ).and_return( @xml )
53
+ Flickr::Photos.should_receive( :new ).with( @xml.at('photos'), @client )
54
+ Flickr::Photo.api_query( 'person.listPhotos', @client, :foo => 'bar')
55
+ end
56
+
57
+ it 'should create a new Photos collection with the results of the photosets node in the returned xml' do
58
+ photosets_xml = Hpricot.parse( '<photosets page="2" pages="89" perpage="10" total="881"><photo id="2636" owner="47058503995@N01" farm="1" secret="a123456" server="2" title="test_04" ispublic="1" isfriend="0" isfamily="0" /></photosets>' )
59
+
60
+ @client.should_receive( :request ).with( 'person.listPhotos', :foo => 'bar' ).and_return( photosets_xml )
61
+ Flickr::Photos.should_receive( :new ).with( photosets_xml.at('photoset'), @client )
62
+ Flickr::Photo.api_query( 'person.listPhotos', @client, :foo => 'bar')
63
+ end
64
+ end
@@ -0,0 +1,47 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Flickr::Photos do
4
+ before( :each ) do
5
+ @client = mock( 'Flickr::Client' )
6
+ @photos_xml = Hpricot.parse( '<photos page="2" pages="89" perpage="10" total="881"><photo id="2636" owner="47058503995@N01" farm="1" secret="a123456" server="2" title="test_04" ispublic="1" isfriend="0" isfamily="0" /></photos>' )
7
+ @photo = mock( 'photo' )
8
+ Flickr::Photo.stub!( :new ).and_return( @photo )
9
+
10
+ @photos = Flickr::Photos.new( @photos_xml.at('photos'), @client )
11
+ end
12
+
13
+ it 'should implement size' do
14
+ @photos.size.should == 1
15
+ end
16
+
17
+ it 'should implement each' do
18
+ @photos.each { |photo| photo }.should == [@photo]
19
+ end
20
+
21
+ it 'should implement empty?' do
22
+ @photos.empty?.should == false
23
+ end
24
+
25
+ it 'should implement pagination methods' do
26
+ @photos.offset.should == 10
27
+ @photos.current_page.should == 2
28
+ @photos.previous_page.should == 1
29
+ @photos.next_page.should == 3
30
+ @photos.total_entries.should == 881
31
+ @photos.total_pages.should == 89
32
+ end
33
+ end
34
+
35
+ describe Flickr::Photos do
36
+ it 'should create a collection of photos from passed in xml' do
37
+ client = mock( 'Flickr::Client' )
38
+ photos_xml = Hpricot.parse( '<photos page="2" pages="89" perpage="10" total="881"><photo id="2636" owner="47058503995@N01" farm="1" secret="a123456" server="2" title="test_04" ispublic="1" isfriend="0" isfamily="0" /><photo id="2637" owner="47058503995@N01" farm="1" secret="a123456" server="2" title="test_05" ispublic="1" isfriend="0" isfamily="0" /></photos>' )
39
+ photos = Flickr::Photos.new( photos_xml.at('photos'), client )
40
+
41
+ photos[0].id.should == '2636'
42
+ photos[0].title.should == 'test_04'
43
+ photos[0].should be_kind_of(Flickr::Photo)
44
+
45
+ photos[1].id.should == '2637'
46
+ end
47
+ end
@@ -0,0 +1,48 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ class Flickr::ProxyTest
4
+ include Flickr::Proxy
5
+ end
6
+
7
+ describe Flickr::ProxyTest do
8
+
9
+ describe 'when dealing with attributes' do
10
+ before( :each ) do
11
+ @client = mock( 'Flickr::Client' )
12
+ @xml = Hpricot.parse( '<doc><proxytest id="2636" var1="test" foo="bar" /></doc>' ).at( 'proxytest' )
13
+ end
14
+
15
+ it 'should set the attributes' do
16
+ proxy = Flickr::ProxyTest.new( @xml, @client )
17
+ proxy.id.should == "2636"
18
+ proxy.var1.should == "test"
19
+ proxy.foo.should == "bar"
20
+ end
21
+
22
+ it 'should set the client' do
23
+ proxy = Flickr::ProxyTest.new( @xml, @client )
24
+ proxy.instance_variable_get( :'@client' ).should == @client
25
+ end
26
+ end
27
+
28
+ describe 'when calling api_query' do
29
+ it 'should make a request to get photosets for the current user id' do
30
+ @client.should_receive( :request ).with( 'photosets.getList', { :user_id => '66273938@N00' } ).and_return( stub('hpricot result', :search => [] ) )
31
+ Flickr::ProxyTest.api_query( 'photosets.getList', @client, :user_id => '66273938@N00' )
32
+ end
33
+
34
+ it 'should return PhotoSet objects created with the returned xml for each photo' do
35
+ result = mock( 'Hpricot XML Result')
36
+ test1_xml,test2_xml = mock('hpricot xml'), mock('hpricot xml')
37
+ test1, test2 = mock('test'), mock('photo')
38
+
39
+ @client.should_receive( :request ).and_return( result )
40
+ result.should_receive( :search ).with( 'proxytest' ).and_return( [test1_xml, test2_xml] )
41
+
42
+ Flickr::ProxyTest.should_receive( :new ).with( test1_xml, @client ).and_return( test1 )
43
+ Flickr::ProxyTest.should_receive( :new ).with( test2_xml, @client ).and_return( test2 )
44
+
45
+ Flickr::ProxyTest.api_query( 'proxytest.getList', @client ).should == [test1,test2]
46
+ end
47
+ end
48
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ specdoc
4
+ --loadby
5
+ mtime
6
+ --reverse
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/../lib/simple-flickr'
2
+ require 'ruby-debug'
3
+
4
+ # Let's make sure we don't contact flickr during specs.
5
+ # Overide open (open-uri) to just return flickr-xmli
6
+
7
+ class MockFlickrResponse
8
+ def initialize(xml); @xml = xml; end
9
+ def read; @xml; end
10
+ end
11
+
12
+ VALID_FLICKR_RESPONSE = MockFlickrResponse.new( '<?xml version="1.0" encoding="utf-8" ?><rsp stat="ok"></rsp>' )
13
+ INVALID_FLICKR_RESPONSE = MockFlickrResponse.new( '<?xml version="1.0" encoding="utf-8" ?><rsp stat="fail"><err code="101" msg="Something went wrong" /></rsp>' )
14
+
15
+ class Flickr::Base
16
+ def open( url )
17
+ VALID_FLICKR_RESPONSE
18
+ end
19
+ end
20
+
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jerrett-simple-flickr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jerrett Taylor
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-22 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.6.0
24
+ version:
25
+ description: A wrapper for Flickrs REST API.
26
+ email: jerrett@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - README
35
+ - Rakefile
36
+ - spec/client_spec.rb
37
+ - spec/person_spec.rb
38
+ - spec/photo_set_spec.rb
39
+ - spec/photo_spec.rb
40
+ - spec/photos_spec.rb
41
+ - spec/proxy_spec.rb
42
+ - spec/spec.opts
43
+ - spec/spec_helper.rb
44
+ - lib/simple-flickr
45
+ - lib/simple-flickr/client.rb
46
+ - lib/simple-flickr/person.rb
47
+ - lib/simple-flickr/photo.rb
48
+ - lib/simple-flickr/photo_set.rb
49
+ - lib/simple-flickr/photos.rb
50
+ - lib/simple-flickr/proxy.rb
51
+ - lib/simple-flickr.rb
52
+ has_rdoc: false
53
+ homepage: http://github.com/jerrett/simple-flickr
54
+ post_install_message:
55
+ rdoc_options: []
56
+
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.8.6
64
+ version:
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ version:
71
+ requirements: []
72
+
73
+ rubyforge_project:
74
+ rubygems_version: 1.2.0
75
+ signing_key:
76
+ specification_version: 2
77
+ summary: A wrapper for Flickrs REST API
78
+ test_files: []
79
+