net-flickr 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +25 -0
- data/lib/net/flickr.rb +218 -0
- data/lib/net/flickr/auth.rb +139 -0
- data/lib/net/flickr/errors.rb +35 -0
- data/lib/net/flickr/list.rb +135 -0
- data/lib/net/flickr/people.rb +65 -0
- data/lib/net/flickr/person.rb +251 -0
- data/lib/net/flickr/photo.rb +335 -0
- data/lib/net/flickr/photolist.rb +53 -0
- data/lib/net/flickr/photos.rb +189 -0
- data/lib/net/flickr/tag.rb +55 -0
- metadata +77 -0
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2007-2008 Ryan Grove <ryan@wonko.com>
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without
|
5
|
+
modification, are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name of this project nor the names of its contributors may be
|
13
|
+
used to endorse or promote products derived from this software without
|
14
|
+
specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
17
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
20
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
23
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/lib/net/flickr.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007-2008 Ryan Grove <ryan@wonko.com>
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# * Neither the name of this project nor the names of its contributors may be
|
14
|
+
# used to endorse or promote products derived from this software without
|
15
|
+
# specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
#++
|
28
|
+
|
29
|
+
# Append this file's directory to the include path if it's not there already.
|
30
|
+
$:.unshift(File.dirname(__FILE__))
|
31
|
+
$:.uniq!
|
32
|
+
|
33
|
+
# stdlib includes
|
34
|
+
require 'digest/md5'
|
35
|
+
require 'net/http'
|
36
|
+
require 'uri'
|
37
|
+
|
38
|
+
# RubyGems includes
|
39
|
+
require 'rubygems'
|
40
|
+
require 'hpricot'
|
41
|
+
|
42
|
+
# Net::Flickr includes
|
43
|
+
require 'flickr/auth'
|
44
|
+
require 'flickr/errors'
|
45
|
+
require 'flickr/list'
|
46
|
+
require 'flickr/people'
|
47
|
+
require 'flickr/person'
|
48
|
+
require 'flickr/photo'
|
49
|
+
require 'flickr/photolist'
|
50
|
+
require 'flickr/photos'
|
51
|
+
require 'flickr/tag'
|
52
|
+
|
53
|
+
module Net
|
54
|
+
|
55
|
+
# = Net::Flickr
|
56
|
+
#
|
57
|
+
# This library implements Flickr's REST API. Its usage should be pretty
|
58
|
+
# straightforward. See below for examples.
|
59
|
+
#
|
60
|
+
# Author:: Ryan Grove (mailto:ryan@wonko.com)
|
61
|
+
# Version:: 0.0.1
|
62
|
+
# Copyright:: Copyright (c) 2007-2008 Ryan Grove. All rights reserved.
|
63
|
+
# License:: New BSD License (http://opensource.org/licenses/bsd-license.php)
|
64
|
+
# Website:: http://code.google.com/p/net-flickr/
|
65
|
+
#
|
66
|
+
# == APIs not yet implemented
|
67
|
+
#
|
68
|
+
# * activity
|
69
|
+
# * blogs
|
70
|
+
# * contacts
|
71
|
+
# * favorites
|
72
|
+
# * groups
|
73
|
+
# * groups.pools
|
74
|
+
# * interestingness
|
75
|
+
# * photos.comments
|
76
|
+
# * photos.geo
|
77
|
+
# * photos.licenses
|
78
|
+
# * photos.notes
|
79
|
+
# * photos.transform
|
80
|
+
# * photos.upload
|
81
|
+
# * photosets
|
82
|
+
# * photosets.comments
|
83
|
+
# * reflection
|
84
|
+
# * tags
|
85
|
+
# * test
|
86
|
+
# * urls
|
87
|
+
#
|
88
|
+
class Flickr
|
89
|
+
AUTH_URL = 'http://flickr.com/services/auth/'.freeze
|
90
|
+
REST_ENDPOINT = 'http://api.flickr.com/services/rest/'.freeze
|
91
|
+
VERSION = '0.0.1'.freeze
|
92
|
+
|
93
|
+
attr_accessor :timeout
|
94
|
+
attr_reader :api_key, :api_secret
|
95
|
+
|
96
|
+
# Creates a new Net::Flickr object that will use the specified _api_key_ and
|
97
|
+
# _api_secret_ to connect to Flickr. If you don't already have a Flickr API
|
98
|
+
# key, you can get one at http://flickr.com/services/api/keys.
|
99
|
+
#
|
100
|
+
# If you don't provide an _api_secret_, you won't be able to make API calls
|
101
|
+
# requiring authentication.
|
102
|
+
def initialize(api_key, api_secret = nil)
|
103
|
+
@api_key = api_key
|
104
|
+
@api_secret = api_secret
|
105
|
+
|
106
|
+
# Initialize dependent classes.
|
107
|
+
@auth = Auth.new(self)
|
108
|
+
@people = People.new(self)
|
109
|
+
@photos = Photos.new(self)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns a Net::Flickr::Auth instance.
|
113
|
+
def auth
|
114
|
+
@auth
|
115
|
+
end
|
116
|
+
|
117
|
+
# Parses the specified Flickr REST response. If the response indicates a
|
118
|
+
# successful request, the response block will be returned as an Hpricot
|
119
|
+
# element. Otherwise, an error will be raised.
|
120
|
+
def parse_response(response_xml)
|
121
|
+
begin
|
122
|
+
xml = Hpricot::XML(response_xml)
|
123
|
+
rescue => e
|
124
|
+
raise InvalidResponse, 'Invalid Flickr API response'
|
125
|
+
end
|
126
|
+
|
127
|
+
unless rsp = xml.at('/rsp')
|
128
|
+
raise InvalidResponse, 'Invalid Flickr API response'
|
129
|
+
end
|
130
|
+
|
131
|
+
if rsp['stat'] == 'ok'
|
132
|
+
return rsp
|
133
|
+
elsif rsp['stat'] == 'fail'
|
134
|
+
raise APIError, rsp.at('/err')['msg']
|
135
|
+
else
|
136
|
+
raise InvalidResponse, 'Invalid Flickr API response'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Returns a Net::Flickr::People instance.
|
141
|
+
def people
|
142
|
+
@people
|
143
|
+
end
|
144
|
+
|
145
|
+
# Returns a Net::Flickr::Photos instance.
|
146
|
+
def photos
|
147
|
+
@photos
|
148
|
+
end
|
149
|
+
|
150
|
+
# Calls the specified Flickr REST API _method_ with the supplied arguments
|
151
|
+
# and returns a Flickr REST response in XML format. If an API secret is set,
|
152
|
+
# the request will be properly signed.
|
153
|
+
def request(method, args = {})
|
154
|
+
params = args.merge({'method' => method, 'api_key' => @api_key})
|
155
|
+
url = URI.parse(REST_ENDPOINT)
|
156
|
+
http = Net::HTTP.new(url.host, url.port)
|
157
|
+
request = sign_request(Net::HTTP::Post.new(url.path), params)
|
158
|
+
|
159
|
+
http.start do |http|
|
160
|
+
if block_given?
|
161
|
+
http.request(request) {|response| yield response }
|
162
|
+
else
|
163
|
+
response = http.request(request)
|
164
|
+
|
165
|
+
# Raise a Net::HTTP error if the HTTP request failed.
|
166
|
+
unless response.is_a?(Net::HTTPSuccess) ||
|
167
|
+
response.is_a?(Net::HTTPRedirection)
|
168
|
+
response.error!
|
169
|
+
end
|
170
|
+
|
171
|
+
# Return the parsed response.
|
172
|
+
return parse_response(response.body)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
# Signs a Flickr API request with the API secret if set.
|
178
|
+
def sign_request(request, params)
|
179
|
+
# If the secret isn't set, we can't sign anything.
|
180
|
+
if @api_secret.nil?
|
181
|
+
request.set_form_data(params)
|
182
|
+
return request
|
183
|
+
end
|
184
|
+
|
185
|
+
# Add auth_token to the param list if we're already authenticated.
|
186
|
+
params['auth_token'] = @auth.token unless @auth.token.nil?
|
187
|
+
|
188
|
+
# Build a sorted, concatenated parameter list as described at
|
189
|
+
# http://flickr.com/services/api/auth.spec.html
|
190
|
+
paramlist = ''
|
191
|
+
params.keys.sort.each {|key| paramlist << key <<
|
192
|
+
URI.escape(params[key].to_s) }
|
193
|
+
|
194
|
+
# Sign the request with a hash of the secret key and the concatenated
|
195
|
+
# parameter list.
|
196
|
+
params['api_sig'] = Digest::MD5.hexdigest(@api_secret + paramlist)
|
197
|
+
request.set_form_data(params)
|
198
|
+
|
199
|
+
return request
|
200
|
+
end
|
201
|
+
|
202
|
+
# Signs a Flickr URL with the API secret if set.
|
203
|
+
def sign_url(url)
|
204
|
+
return url if @api_secret.nil?
|
205
|
+
|
206
|
+
uri = URI.parse(url)
|
207
|
+
|
208
|
+
params = uri.query.split('&')
|
209
|
+
params << 'api_sig=' + Digest::MD5.hexdigest(@api_secret +
|
210
|
+
params.sort.join('').gsub('=', ''))
|
211
|
+
|
212
|
+
uri.query = params.join('&')
|
213
|
+
|
214
|
+
return uri.to_s
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007-2008 Ryan Grove <ryan@wonko.com>
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# * Neither the name of this project nor the names of its contributors may be
|
14
|
+
# used to endorse or promote products derived from this software without
|
15
|
+
# specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
#++
|
28
|
+
|
29
|
+
module Net; class Flickr
|
30
|
+
|
31
|
+
# Implements the Flickr authentication API. Please see
|
32
|
+
# http://flickr.com/services/api/auth.spec.html for details on how to use this
|
33
|
+
# API in your application.
|
34
|
+
#
|
35
|
+
# Don't instantiate this class yourself. Instead, create an instance of the
|
36
|
+
# +Flickr+ class and then user <tt>Flickr.auth</tt> to access this class,
|
37
|
+
# like so:
|
38
|
+
#
|
39
|
+
# require 'net/flickr'
|
40
|
+
#
|
41
|
+
# flickr = Net::Flickr.new('524266cbd9d3c2xa2679fee8b337fip2',
|
42
|
+
# '835hae5d6j0sd47a')
|
43
|
+
#
|
44
|
+
# puts flickr.auth.url_desktop
|
45
|
+
#
|
46
|
+
class Auth
|
47
|
+
PERM_NONE = :none
|
48
|
+
PERM_READ = :read
|
49
|
+
PERM_WRITE = :write
|
50
|
+
PERM_DELETE = :delete
|
51
|
+
|
52
|
+
attr_reader :frob, :perms, :token, :user_id, :user_name, :user_fullname
|
53
|
+
|
54
|
+
def initialize(flickr)
|
55
|
+
@flickr = flickr
|
56
|
+
|
57
|
+
@frob = nil
|
58
|
+
@perms = PERM_NONE
|
59
|
+
@token = nil
|
60
|
+
@user_id = nil
|
61
|
+
@user_name = nil
|
62
|
+
@user_fullname = nil
|
63
|
+
end
|
64
|
+
|
65
|
+
#--
|
66
|
+
# Public Instance Methods
|
67
|
+
#++
|
68
|
+
|
69
|
+
# Updates this Auth object with the credentials attached to the specified
|
70
|
+
# authentication _token_. If the _token_ is not valid, an APIError will be
|
71
|
+
# raised.
|
72
|
+
def check_token(token = @token)
|
73
|
+
update_auth(@flickr.request('flickr.auth.checkToken',
|
74
|
+
'auth_token' => token))
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
|
78
|
+
# Gets the full authentication token for the specified _mini_token_.
|
79
|
+
def full_token(mini_token)
|
80
|
+
update_auth(@flickr.request('flickr.auth.getFullToken',
|
81
|
+
'mini_token' => mini_token))
|
82
|
+
return @token
|
83
|
+
end
|
84
|
+
|
85
|
+
# Gets a frob to be used during authentication.
|
86
|
+
def get_frob
|
87
|
+
response = @flickr.request('flickr.auth.getFrob').at('frob')
|
88
|
+
return @frob = response.inner_text
|
89
|
+
end
|
90
|
+
|
91
|
+
# Updates this Auth object with the credentials for the specified _frob_ and
|
92
|
+
# returns an auth token. If the _frob_ is not valid, an APIError will be
|
93
|
+
# raised.
|
94
|
+
def get_token(frob = @frob)
|
95
|
+
update_auth(@flickr.request('flickr.auth.getToken', 'frob' => frob))
|
96
|
+
return @token
|
97
|
+
end
|
98
|
+
|
99
|
+
# Gets a signed URL that can by used by a desktop application to show the
|
100
|
+
# user a Flickr authentication screen. Once the user has visited this URL
|
101
|
+
# and authorized your application, you can call get_token to authenticate.
|
102
|
+
def url_desktop(perms)
|
103
|
+
get_frob if @frob.nil?
|
104
|
+
url = Flickr::AUTH_URL +
|
105
|
+
"?api_key=#{@flickr.api_key}&perms=#{perms}&frob=#{@frob}"
|
106
|
+
|
107
|
+
return @flickr.sign_url(url)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Gets a signed URL that can be used by a web application to show the user a
|
111
|
+
# Flickr authentication screen. Once the user has visited this URL and
|
112
|
+
# authorized your application, you can call get_token with the frob provided
|
113
|
+
# by Flickr to authenticate.
|
114
|
+
def url_webapp(perms)
|
115
|
+
return @flickr.sign_url(Flickr::AUTH_URL +
|
116
|
+
"?api_key=#{@flickr.api_key}&perms=#{perms}")
|
117
|
+
end
|
118
|
+
|
119
|
+
#--
|
120
|
+
# Private Instance Methods
|
121
|
+
#++
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# Updates this Auth object with the credentials in the specified XML
|
126
|
+
# _response_.
|
127
|
+
def update_auth(response)
|
128
|
+
auth = response.at('auth')
|
129
|
+
user = auth.at('user')
|
130
|
+
|
131
|
+
@perms = auth.at('perms').inner_text.to_sym
|
132
|
+
@token = auth.at('token').inner_text
|
133
|
+
@user_id = user['nsid']
|
134
|
+
@user_name = user['username']
|
135
|
+
@user_fullname = user['fullname']
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
end; end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007-2008 Ryan Grove <ryan@wonko.com>
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# * Neither the name of this project nor the names of its contributors may be
|
14
|
+
# used to endorse or promote products derived from this software without
|
15
|
+
# specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
#++
|
28
|
+
|
29
|
+
module Net; class Flickr
|
30
|
+
|
31
|
+
class APIError < StandardError; end
|
32
|
+
class InvalidResponse < StandardError; end
|
33
|
+
class ListError < StandardError; end
|
34
|
+
|
35
|
+
end; end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2007-2008 Ryan Grove <ryan@wonko.com>
|
3
|
+
# All rights reserved.
|
4
|
+
#
|
5
|
+
# Redistribution and use in source and binary forms, with or without
|
6
|
+
# modification, are permitted provided that the following conditions are met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright notice,
|
9
|
+
# this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
11
|
+
# this list of conditions and the following disclaimer in the documentation
|
12
|
+
# and/or other materials provided with the distribution.
|
13
|
+
# * Neither the name of this project nor the names of its contributors may be
|
14
|
+
# used to endorse or promote products derived from this software without
|
15
|
+
# specific prior written permission.
|
16
|
+
#
|
17
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
18
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
19
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
20
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
21
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
22
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
23
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
24
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
25
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
26
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
#++
|
28
|
+
|
29
|
+
module Net; class Flickr
|
30
|
+
|
31
|
+
# Base class for paginated lists.
|
32
|
+
#
|
33
|
+
# Don't instantiate this class yourself. It's a base class extended by
|
34
|
+
# +PhotoList+ and others.
|
35
|
+
class List
|
36
|
+
include Enumerable
|
37
|
+
|
38
|
+
attr_reader :page, :pages, :per_page, :total
|
39
|
+
|
40
|
+
def initialize(flickr, load_method, load_args)
|
41
|
+
@flickr = flickr
|
42
|
+
@load_method = load_method
|
43
|
+
@load_args = load_args
|
44
|
+
|
45
|
+
update_list
|
46
|
+
end
|
47
|
+
|
48
|
+
#--
|
49
|
+
# Public Instance Methods
|
50
|
+
#++
|
51
|
+
|
52
|
+
def [](index)
|
53
|
+
return @items[index]
|
54
|
+
end
|
55
|
+
|
56
|
+
def each
|
57
|
+
@items.each {|item| yield item }
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns +true+ if the current page is the first page of the list, +false+
|
61
|
+
# otherwise.
|
62
|
+
def first_page?
|
63
|
+
return @page == 1
|
64
|
+
end
|
65
|
+
|
66
|
+
# Returns +true+ if the current page is the last page of the list, +false+
|
67
|
+
# otherwise.
|
68
|
+
def last_page?
|
69
|
+
return @page == @pages
|
70
|
+
end
|
71
|
+
|
72
|
+
# Loads the next page in the list.
|
73
|
+
def next
|
74
|
+
if last_page?
|
75
|
+
raise ListError, 'Already on the last page of the list'
|
76
|
+
end
|
77
|
+
|
78
|
+
@load_args['page'] = @page + 1
|
79
|
+
update_list
|
80
|
+
end
|
81
|
+
|
82
|
+
# Loads the specified page in the list.
|
83
|
+
def page=(page)
|
84
|
+
if page < 1 || page > @pages
|
85
|
+
raise ArgumentError, 'Page number out of bounds'
|
86
|
+
end
|
87
|
+
|
88
|
+
@load_args['page'] = page
|
89
|
+
update_list
|
90
|
+
end
|
91
|
+
|
92
|
+
# Sets the number of items loaded per page. Must be between 1 and 500
|
93
|
+
# inclusive.
|
94
|
+
def per_page=(per_page)
|
95
|
+
if per_page < 1 || per_page > 500
|
96
|
+
raise ArgumentError, 'per_page must be between 1 and 500 inclusive'
|
97
|
+
end
|
98
|
+
|
99
|
+
@per_page = per_page
|
100
|
+
@load_args['per_page'] = @per_page
|
101
|
+
end
|
102
|
+
|
103
|
+
# Loads the previous page in the list.
|
104
|
+
def previous
|
105
|
+
if first_page?
|
106
|
+
raise ListError, 'Already on the first page of the list'
|
107
|
+
end
|
108
|
+
|
109
|
+
@load_args['page'] = @page - 1
|
110
|
+
update_list
|
111
|
+
end
|
112
|
+
|
113
|
+
alias prev previous
|
114
|
+
|
115
|
+
#--
|
116
|
+
# Private Instance Methods
|
117
|
+
#++
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def update_list
|
122
|
+
@items = []
|
123
|
+
|
124
|
+
@response = @flickr.request(@load_method, @load_args).
|
125
|
+
at('/*[@page]:first')
|
126
|
+
|
127
|
+
@per_page = @response['perpage'].to_i
|
128
|
+
@page = @response['page'].to_i
|
129
|
+
@pages = @response['pages'].to_i
|
130
|
+
@total = @response['total'].to_i
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end; end
|