simple-flickr 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,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 Errno::ETIMEDOUT, 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,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,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
+ [Errno::ETIMEDOUT,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,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: simple-flickr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
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/client.rb
45
+ - lib/simple-flickr/person.rb
46
+ - lib/simple-flickr/photo.rb
47
+ - lib/simple-flickr/photo_set.rb
48
+ - lib/simple-flickr/photos.rb
49
+ - lib/simple-flickr/proxy.rb
50
+ - lib/simple-flickr.rb
51
+ has_rdoc: true
52
+ homepage: http://github.com/jerrett/simple-flickr
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.8.6
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.5
76
+ signing_key:
77
+ specification_version: 2
78
+ summary: A wrapper for Flickrs REST API
79
+ test_files: []
80
+