fleakr 0.3.0
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.rdoc +149 -0
- data/Rakefile +40 -0
- data/lib/fleakr/api/request.rb +58 -0
- data/lib/fleakr/api/response.rb +35 -0
- data/lib/fleakr/objects/contact.rb +31 -0
- data/lib/fleakr/objects/error.rb +22 -0
- data/lib/fleakr/objects/group.rb +26 -0
- data/lib/fleakr/objects/image.rb +51 -0
- data/lib/fleakr/objects/photo.rb +55 -0
- data/lib/fleakr/objects/search.rb +33 -0
- data/lib/fleakr/objects/set.rb +45 -0
- data/lib/fleakr/objects/user.rb +106 -0
- data/lib/fleakr/support/attribute.rb +28 -0
- data/lib/fleakr/support/object.rb +88 -0
- data/lib/fleakr/version.rb +13 -0
- data/lib/fleakr.rb +74 -0
- data/test/fixtures/contacts.getPublicList.xml +7 -0
- data/test/fixtures/groups.pools.getPhotos.xml +7 -0
- data/test/fixtures/people.findByEmail.xml +6 -0
- data/test/fixtures/people.findByUsername.xml +6 -0
- data/test/fixtures/people.getInfo.xml +18 -0
- data/test/fixtures/people.getPublicGroups.xml +7 -0
- data/test/fixtures/people.getPublicPhotos.xml +7 -0
- data/test/fixtures/photos.getSizes.xml +10 -0
- data/test/fixtures/photos.search.xml +7 -0
- data/test/fixtures/photosets.getList.xml +13 -0
- data/test/fixtures/photosets.getPhotos.xml +7 -0
- data/test/test_helper.rb +123 -0
- data/test/unit/fleakr/api/request_test.rb +93 -0
- data/test/unit/fleakr/api/response_test.rb +49 -0
- data/test/unit/fleakr/objects/contact_test.rb +58 -0
- data/test/unit/fleakr/objects/error_test.rb +21 -0
- data/test/unit/fleakr/objects/group_test.rb +31 -0
- data/test/unit/fleakr/objects/image_test.rb +76 -0
- data/test/unit/fleakr/objects/photo_test.rb +101 -0
- data/test/unit/fleakr/objects/search_test.rb +74 -0
- data/test/unit/fleakr/objects/set_test.rb +71 -0
- data/test/unit/fleakr/objects/user_test.rb +104 -0
- data/test/unit/fleakr/support/attribute_test.rb +68 -0
- data/test/unit/fleakr/support/object_test.rb +95 -0
- data/test/unit/fleakr_test.rb +44 -0
- metadata +123 -0
data/README.rdoc
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
= Fleakr
|
2
|
+
|
3
|
+
== Description
|
4
|
+
|
5
|
+
A teeny tiny gem to interface with Flickr photostreams
|
6
|
+
|
7
|
+
== Installation
|
8
|
+
|
9
|
+
=== Stable
|
10
|
+
|
11
|
+
sudo gem install fleakr
|
12
|
+
|
13
|
+
=== Bleeding Edge
|
14
|
+
|
15
|
+
sudo gem install reagent-fleakr --source=http://gems.github.com
|
16
|
+
|
17
|
+
Or ...
|
18
|
+
|
19
|
+
$ git clone git://github.com/reagent/fleakr.git
|
20
|
+
$ cd fleakr
|
21
|
+
$ rake gem && sudo gem install pkg/fleakr-<version>.gem
|
22
|
+
|
23
|
+
== Usage
|
24
|
+
|
25
|
+
Before doing anything, require the library:
|
26
|
+
|
27
|
+
>> require 'rubygems'
|
28
|
+
>> require 'fleakr'
|
29
|
+
|
30
|
+
Then, set your API key (only need to do this once per session):
|
31
|
+
|
32
|
+
>> Fleakr.api_key = '<your api key here>'
|
33
|
+
|
34
|
+
Find a user by username:
|
35
|
+
|
36
|
+
>> user = Fleakr.user('the decapitator')
|
37
|
+
=> #<Fleakr::Objects::User:0x692648 @username="the decapitator", @id="21775151@N06">
|
38
|
+
|
39
|
+
Or by email:
|
40
|
+
|
41
|
+
>> user = Fleakr.user('user@host.com')
|
42
|
+
=> #<Fleakr::Objects::User:0x11f484c @username="bckspcr", @id="84481630@N00">
|
43
|
+
|
44
|
+
Once you have a user, you can find his associated sets:
|
45
|
+
|
46
|
+
>> user.sets
|
47
|
+
=> [#<Fleakr::Objects::Set:0x671358 @title="The Decapitator", @description="">,
|
48
|
+
#<Fleakr::Objects::Set:0x66d898 @title="londonpaper hijack", ...
|
49
|
+
|
50
|
+
Or contacts:
|
51
|
+
|
52
|
+
>> user.contacts.first
|
53
|
+
=> #<Fleakr::Objects::User:0x19039bc @username=".schill",
|
54
|
+
@id="12289718@N00", @icon_farm="1", @icon_server="4">
|
55
|
+
|
56
|
+
Or groups if you would like:
|
57
|
+
|
58
|
+
>> user.groups
|
59
|
+
=> [#<Fleakr::Objects::Group:0x11f2330 ...,
|
60
|
+
#<Fleakr::Objects::Group:0x11f2308 ...
|
61
|
+
>> user.groups.first.name
|
62
|
+
=> "Rural Decay"
|
63
|
+
>> user.groups.first.id
|
64
|
+
=> "14581414@N00"
|
65
|
+
|
66
|
+
Groups also contain photos:
|
67
|
+
|
68
|
+
>> user.groups.last.photos.first.title
|
69
|
+
=> "Welcome To The Machine"
|
70
|
+
|
71
|
+
When accessing a set, you can also grab all the photos that are in that set:
|
72
|
+
|
73
|
+
>> user.sets.first
|
74
|
+
=> #<Fleakr::Objects::Set:0x1195bbc @title="The Decapitator", @id="72157603480986566", @description="">
|
75
|
+
>> user.sets.first.photos.first
|
76
|
+
=> #<Fleakr::Objects::Photo:0x1140108 ... >
|
77
|
+
>> user.sets.first.photos.first.title
|
78
|
+
=> "Untitled1"
|
79
|
+
|
80
|
+
If a photo interests you, save it down to a directory of your choosing:
|
81
|
+
|
82
|
+
>> user.sets.first.photos.first.small.save_to('/tmp')
|
83
|
+
=> #<File:/tmp/2117922283_715587b2cb_m.jpg (closed)>
|
84
|
+
|
85
|
+
If you can't decide on a photo and would rather just save the whole set, specify the target directory
|
86
|
+
and the size of the images you're interested in:
|
87
|
+
|
88
|
+
>> user.sets.first.save_to('/tmp', :square)
|
89
|
+
=> [#<Fleakr::Objects::Photo:0x1187a1c @secret="715587b2cb" ...
|
90
|
+
>> Dir["/tmp/#{user.sets.first.title}/*.jpg"].map
|
91
|
+
=> ["/tmp/The Decapitator/2117919621_8b2d601bff_s.jpg",
|
92
|
+
"/tmp/The Decapitator/2117921045_5fb15eff90_s.jpg",
|
93
|
+
"/tmp/The Decapitator/2117922283_715587b2cb_s.jpg", ...
|
94
|
+
|
95
|
+
If you would prefer to just search photos, you can do that with search text:
|
96
|
+
|
97
|
+
>> photos = Fleakr.search('ponies!!')
|
98
|
+
=> [#<Fleakr::Objects::Photo:0x11f4e64 @title="hiroshima atomic garden", @id="3078234390">,
|
99
|
+
#<Fleakr::Objects::Photo:0x11f4928 @title="PONYLOV", @id="3077360853">, ...
|
100
|
+
>> photos.first.title
|
101
|
+
=> "hiroshima atomic garden"
|
102
|
+
|
103
|
+
You can also search based on tags:
|
104
|
+
|
105
|
+
>> photos = Fleakr.search(:tags => 'macro')
|
106
|
+
>> photos.first.title
|
107
|
+
=> "Demure"
|
108
|
+
>> photos.first.id
|
109
|
+
=> "3076049945"
|
110
|
+
|
111
|
+
Searches can also be scoped to other entities in the system (namely Users and Groups):
|
112
|
+
|
113
|
+
>> user.groups.first.search('awesome')
|
114
|
+
=> [#<Fleakr::Objects::Photo:0x18cb4cc @server_id="2012", @id="2181921273",
|
115
|
+
@farm_id="3", @title="", @secret="634eda7521">, ...
|
116
|
+
>> user.search('serpent')
|
117
|
+
=> [#<Fleakr::Objects::Photo:0x18a6960 @server_id="41", @id="81370156",
|
118
|
+
@farm_id="1", @title="Clear and Serpent Danger", @secret="013091582a">]
|
119
|
+
|
120
|
+
== TODO
|
121
|
+
|
122
|
+
* Implement remaining bits of person, photoset, and photo-releated APIs
|
123
|
+
* Provide a better searching interface
|
124
|
+
* Lazily load attributes for objects that need to be accessed via secondary API call
|
125
|
+
|
126
|
+
== License
|
127
|
+
|
128
|
+
Copyright (c) 2008 Patrick Reagan (reaganpr@gmail.com)
|
129
|
+
|
130
|
+
Permission is hereby granted, free of charge, to any person
|
131
|
+
obtaining a copy of this software and associated documentation
|
132
|
+
files (the "Software"), to deal in the Software without
|
133
|
+
restriction, including without limitation the rights to use,
|
134
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
135
|
+
copies of the Software, and to permit persons to whom the
|
136
|
+
Software is furnished to do so, subject to the following
|
137
|
+
conditions:
|
138
|
+
|
139
|
+
The above copyright notice and this permission notice shall be
|
140
|
+
included in all copies or substantial portions of the Software.
|
141
|
+
|
142
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
143
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
144
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
145
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
146
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
147
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
148
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
149
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
require 'lib/fleakr/version'
|
6
|
+
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'fleakr'
|
11
|
+
s.version = Fleakr::Version.to_s
|
12
|
+
s.has_rdoc = true
|
13
|
+
s.extra_rdoc_files = %w(README.rdoc)
|
14
|
+
s.rdoc_options = %w(--main README.rdoc)
|
15
|
+
s.summary = "A teeny tiny gem to interface with Flickr photostreams"
|
16
|
+
s.author = 'Patrick Reagan'
|
17
|
+
s.email = 'reaganpr@gmail.com'
|
18
|
+
s.homepage = 'http://sneaq.net'
|
19
|
+
s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib,test}/**/*")
|
20
|
+
|
21
|
+
s.add_dependency('hpricot', '~> 0.6.0')
|
22
|
+
s.add_dependency('activesupport', '~> 2.2.0')
|
23
|
+
end
|
24
|
+
|
25
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
26
|
+
pkg.gem_spec = spec
|
27
|
+
end
|
28
|
+
|
29
|
+
Rake::TestTask.new do |t|
|
30
|
+
t.libs << 'test'
|
31
|
+
t.test_files = FileList["test/**/*_test.rb"]
|
32
|
+
t.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'Generate the gemspec to serve this Gem from Github'
|
36
|
+
task :github do
|
37
|
+
file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
|
38
|
+
File.open(file, 'w') {|f| f << spec.to_ruby }
|
39
|
+
puts "Created gemspec: #{file}"
|
40
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Api # :nodoc:
|
3
|
+
|
4
|
+
# = Request
|
5
|
+
#
|
6
|
+
# Performs requests against the Flickr API and returns response objects (Flickr::Api::Response)
|
7
|
+
# that contain Hpricot documents for further parsing and inspection. This class is used internally
|
8
|
+
# in all the defined model objects.
|
9
|
+
#
|
10
|
+
class Request
|
11
|
+
|
12
|
+
# Generic catch-all exception for any API errors
|
13
|
+
class ApiError < StandardError; end
|
14
|
+
|
15
|
+
# Makes a request to the Flickr API and returns a valid Response object. If
|
16
|
+
# there are errors on the response it will rais an ApiError exception
|
17
|
+
def self.with_response!(method, additional_parameters = {})
|
18
|
+
request = Request.new(method, additional_parameters)
|
19
|
+
response = request.send
|
20
|
+
|
21
|
+
raise(ApiError, "Code: #{response.error.code} - #{response.error.message}") if response.error?
|
22
|
+
|
23
|
+
response
|
24
|
+
end
|
25
|
+
|
26
|
+
# Create a new request for the specified API method and pass along any additional
|
27
|
+
# parameters. The Flickr API uses namespacing for its methods - this is optional
|
28
|
+
# when calling this method.
|
29
|
+
#
|
30
|
+
# This must be called after initializing the library with the required API key
|
31
|
+
# see (#Fleakr.api_key=)
|
32
|
+
def initialize(method, additional_parameters = {})
|
33
|
+
method = method.sub(/^(flickr\.)?/, 'flickr.')
|
34
|
+
|
35
|
+
default_parameters = {:api_key => Fleakr.api_key, :method => method}
|
36
|
+
@parameters = default_parameters.merge(additional_parameters)
|
37
|
+
end
|
38
|
+
|
39
|
+
def send # :nodoc:
|
40
|
+
Response.new(Net::HTTP.get(endpoint_uri))
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def endpoint_uri
|
45
|
+
uri = URI.parse('http://api.flickr.com/services/rest/')
|
46
|
+
uri.query = query_parameters
|
47
|
+
uri
|
48
|
+
end
|
49
|
+
|
50
|
+
def query_parameters
|
51
|
+
@parameters.map {|key,value| "#{key}=#{CGI.escape(value)}" }.join('&')
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Api
|
3
|
+
|
4
|
+
# = Response
|
5
|
+
#
|
6
|
+
# Response objects contain Hpricot documents that are traversed and parsed by
|
7
|
+
# the model objects. This class is never called directly but is instantiated
|
8
|
+
# during the request cycle (see: Fleakr::Api::Request.with_response!)
|
9
|
+
#
|
10
|
+
class Response
|
11
|
+
|
12
|
+
# Creates a new response from a raw XML string returned from a Request
|
13
|
+
def initialize(response_xml)
|
14
|
+
@response_xml = response_xml
|
15
|
+
end
|
16
|
+
|
17
|
+
# Return a document-based representation of the XML contained in the
|
18
|
+
# API response. This is an Hpricot document object
|
19
|
+
def body
|
20
|
+
@body ||= Hpricot.XML(@response_xml)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Did the response from the API contain errors?
|
24
|
+
def error?
|
25
|
+
(self.body/'rsp').attr('stat') != 'ok'
|
26
|
+
end
|
27
|
+
|
28
|
+
# Access the API error if one exists
|
29
|
+
def error
|
30
|
+
Fleakr::Objects::Error.new(self.body) if self.error?
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
class Contact # :nodoc:
|
4
|
+
|
5
|
+
include Fleakr::Support::Object
|
6
|
+
|
7
|
+
flickr_attribute :id, :attribute => 'nsid'
|
8
|
+
flickr_attribute :username, :attribute => 'username'
|
9
|
+
flickr_attribute :icon_server, :attribute => 'iconserver'
|
10
|
+
flickr_attribute :icon_farm, :attribute => 'iconfarm'
|
11
|
+
|
12
|
+
# Retrieve a list of contacts for the specified user ID and return an initialized
|
13
|
+
# collection of #User objects
|
14
|
+
def self.find_all_by_user_id(user_id)
|
15
|
+
response = Fleakr::Api::Request.with_response!('contacts.getPublicList', :user_id => user_id)
|
16
|
+
(response.body/'contacts/contact').map {|c| Contact.new(c).to_user }
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_user
|
20
|
+
user = User.new
|
21
|
+
self.class.attributes.each do |attribute|
|
22
|
+
attribute_name = attribute.name
|
23
|
+
user.send("#{attribute.name}=".to_sym, self.send(attribute.name))
|
24
|
+
end
|
25
|
+
|
26
|
+
user
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
# = Error
|
4
|
+
#
|
5
|
+
# == Accessors
|
6
|
+
#
|
7
|
+
# This class is a simple wrapper for the error response that the API returns. There are
|
8
|
+
# a couple of attributes:
|
9
|
+
#
|
10
|
+
# [code] The error code as described in the documentation
|
11
|
+
# [message] The associated error message
|
12
|
+
#
|
13
|
+
class Error
|
14
|
+
|
15
|
+
include Fleakr::Support::Object
|
16
|
+
|
17
|
+
flickr_attribute :code, :xpath => 'rsp/err', :attribute => 'code'
|
18
|
+
flickr_attribute :message, :xpath => 'rsp/err', :attribute => 'msg'
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
|
4
|
+
# = Group
|
5
|
+
#
|
6
|
+
# == Accessors
|
7
|
+
#
|
8
|
+
# [id] This group's ID
|
9
|
+
# [name] The name of the group
|
10
|
+
#
|
11
|
+
class Group
|
12
|
+
|
13
|
+
include Fleakr::Support::Object
|
14
|
+
|
15
|
+
flickr_attribute :id, :attribute => 'nsid'
|
16
|
+
flickr_attribute :name, :attribute => 'name'
|
17
|
+
|
18
|
+
find_all :by_user_id, :call => 'people.getPublicGroups', :path => 'groups/group'
|
19
|
+
|
20
|
+
has_many :photos
|
21
|
+
|
22
|
+
scoped_search
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects
|
3
|
+
|
4
|
+
# = Image
|
5
|
+
#
|
6
|
+
# This class wraps the functionality for saving remote images to disk. It's called
|
7
|
+
# by the Fleakr::Objects::Photo class to save an image with a specific size and would
|
8
|
+
# typically never be called directly.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# user = Fleakr.user('brownout')
|
13
|
+
# user.photos.first.small.save_to('/tmp')
|
14
|
+
#
|
15
|
+
# == Attributes
|
16
|
+
#
|
17
|
+
# [size] The name of this image's size (e.g. Square, Large, etc...)
|
18
|
+
# [width] The width of this image
|
19
|
+
# [height] The height of this image
|
20
|
+
# [url] The direct URL for this image
|
21
|
+
# [page] The page on Flickr that represents this photo
|
22
|
+
#
|
23
|
+
class Image
|
24
|
+
|
25
|
+
include Fleakr::Support::Object
|
26
|
+
|
27
|
+
flickr_attribute :size, :attribute => :label
|
28
|
+
flickr_attribute :width, :attribute => :width
|
29
|
+
flickr_attribute :height, :attribute => :height
|
30
|
+
flickr_attribute :url, :attribute => :source
|
31
|
+
flickr_attribute :page, :attribute => :url
|
32
|
+
|
33
|
+
find_all :by_photo_id, :call => 'photos.getSizes', :path => 'sizes/size'
|
34
|
+
|
35
|
+
# The filename portion of the image (without the full URL)
|
36
|
+
def filename
|
37
|
+
self.url.match(/([^\/]+)$/)[1]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Save this image to the specified directory or file. If the target is a
|
41
|
+
# directory, the file will be created with the original filename from Flickr.
|
42
|
+
# If the target is a file, it will be saved with the specified name. In the
|
43
|
+
# case that the target file already exists, this method will overwrite it.
|
44
|
+
def save_to(target)
|
45
|
+
destination = File.directory?(target) ? "#{target}/#{self.filename}" : "#{target}"
|
46
|
+
File.open(destination, 'w') {|f| f << Net::HTTP.get(URI.parse(self.url)) }
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
|
4
|
+
# = Photo
|
5
|
+
#
|
6
|
+
# == Attributes
|
7
|
+
#
|
8
|
+
# [id] The ID for this photo
|
9
|
+
# [title] The title of this photo
|
10
|
+
# [square] The tiny square representation of this photo
|
11
|
+
# [thumbnail] The thumbnail for this photo
|
12
|
+
# [small] The small representation of this photo
|
13
|
+
# [medium] The medium representation of this photo
|
14
|
+
# [large] The large representation of this photo
|
15
|
+
# [original] The original photo
|
16
|
+
#
|
17
|
+
# == Associations
|
18
|
+
#
|
19
|
+
# [images] The underlying images for this photo.
|
20
|
+
#
|
21
|
+
class Photo
|
22
|
+
|
23
|
+
# Available sizes for this photo
|
24
|
+
SIZES = [:square, :thumbnail, :small, :medium, :large, :original]
|
25
|
+
|
26
|
+
include Fleakr::Support::Object
|
27
|
+
|
28
|
+
flickr_attribute :title, :attribute => 'title'
|
29
|
+
flickr_attribute :id, :attribute => 'id'
|
30
|
+
flickr_attribute :farm_id, :attribute => 'farm'
|
31
|
+
flickr_attribute :server_id, :attribute => 'server'
|
32
|
+
flickr_attribute :secret, :attribute => 'secret'
|
33
|
+
|
34
|
+
find_all :by_photoset_id, :call => 'photosets.getPhotos', :path => 'photoset/photo'
|
35
|
+
find_all :by_user_id, :call => 'people.getPublicPhotos', :path => 'photos/photo'
|
36
|
+
find_all :by_group_id, :call => 'groups.pools.getPhotos', :path => 'photos/photo'
|
37
|
+
|
38
|
+
has_many :images
|
39
|
+
|
40
|
+
# Create methods to access image sizes by name
|
41
|
+
SIZES.each do |size|
|
42
|
+
define_method(size) do
|
43
|
+
images_by_size[size]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
def images_by_size
|
49
|
+
image_sizes = SIZES.inject({}) {|l,o| l.merge(o => nil)}
|
50
|
+
self.images.inject(image_sizes) {|l,o| l.merge!(o.size.downcase.to_sym => o) }
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
class Search
|
4
|
+
|
5
|
+
# Create a new search
|
6
|
+
def initialize(search_options)
|
7
|
+
@search_options = search_options
|
8
|
+
end
|
9
|
+
|
10
|
+
# Retrieve search results from the API
|
11
|
+
def results
|
12
|
+
if @results.nil?
|
13
|
+
response = Fleakr::Api::Request.with_response!('photos.search', parameters)
|
14
|
+
@results = (response.body/'rsp/photos/photo').map do |flickr_photo|
|
15
|
+
Photo.new(flickr_photo)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
@results
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def tag_list
|
23
|
+
Array(@search_options[:tags]).join(',')
|
24
|
+
end
|
25
|
+
|
26
|
+
def parameters
|
27
|
+
@search_options.merge!(:tags => tag_list) if tag_list.length > 0
|
28
|
+
@search_options
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
|
4
|
+
# = Set
|
5
|
+
#
|
6
|
+
# == Attributes
|
7
|
+
#
|
8
|
+
# [id] The ID for this photoset
|
9
|
+
# [title] The title of this photoset
|
10
|
+
# [description] The description of this set
|
11
|
+
#
|
12
|
+
# == Associations
|
13
|
+
#
|
14
|
+
# [photos] The collection of photos for this set. See Fleakr::Objects::Photo
|
15
|
+
#
|
16
|
+
class Set
|
17
|
+
|
18
|
+
include Fleakr::Support::Object
|
19
|
+
|
20
|
+
has_many :photos, :using => :photoset_id
|
21
|
+
|
22
|
+
flickr_attribute :id, :attribute => 'id'
|
23
|
+
flickr_attribute :title
|
24
|
+
flickr_attribute :description
|
25
|
+
|
26
|
+
find_all :by_user_id, :call => 'photosets.getList', :path => 'photosets/photoset'
|
27
|
+
|
28
|
+
# Save all photos in this set to the specified directory using the specified size. Allowed
|
29
|
+
# Sizes include <tt>:square</tt>, <tt>:small</tt>, <tt>:thumbnail</tt>, <tt>:medium</tt>,
|
30
|
+
# <tt>:large</tt>, and <tt>:original</tt>. When saving the set, this # method will create
|
31
|
+
# a subdirectory based on the set's title.
|
32
|
+
#
|
33
|
+
def save_to(path, size)
|
34
|
+
target = "#{path}/#{self.title}"
|
35
|
+
FileUtils.mkdir(target) unless File.exist?(target)
|
36
|
+
|
37
|
+
self.photos.each do |photo|
|
38
|
+
image = photo.send(size)
|
39
|
+
image.save_to(target) unless image.nil?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Objects # :nodoc:
|
3
|
+
|
4
|
+
# = User
|
5
|
+
#
|
6
|
+
# == Accessors
|
7
|
+
#
|
8
|
+
# This class maps directly onto the flickr.people.* API methods and provides the following attributes
|
9
|
+
# for a user:
|
10
|
+
#
|
11
|
+
# [id] The ID for this user (also referred to as the NSID in the API docs)
|
12
|
+
# [username] This user's username
|
13
|
+
# [name] This user's full name (if entered)
|
14
|
+
# [photos_url] The direct URL to this user's photostream
|
15
|
+
# [profile_url] The direct URL to this user's profile
|
16
|
+
# [photos_count] The number of photos that this user has uploaded
|
17
|
+
# [icon_url] This user's buddy icon (or a default one if an icon wasn't uploaded)
|
18
|
+
# [pro?] Does this user have a pro account?
|
19
|
+
# [admin?] Is this user an admin?
|
20
|
+
#
|
21
|
+
# == Associations
|
22
|
+
#
|
23
|
+
# The User class is pretty central to many of the other data available across the system, so there are a
|
24
|
+
# few associations available to a user:
|
25
|
+
#
|
26
|
+
# [sets] A list of this user's public sets (newest first). See Fleakr::Objects::Set for more information.
|
27
|
+
# [groups] A list of this user's public groups. See Fleakr::Objects::Group.
|
28
|
+
# [photos] A list of this user's public photos (newest first). See Fleakr::Objects::Photo.
|
29
|
+
# [contacts] A list of this user's contacts - these are simply User objects
|
30
|
+
#
|
31
|
+
# == Examples
|
32
|
+
#
|
33
|
+
# Access to a specific user is typically done through the Fleakr.user method:
|
34
|
+
#
|
35
|
+
# user = Fleakr.user('brownout')
|
36
|
+
# user.id
|
37
|
+
# user.username
|
38
|
+
# user.sets
|
39
|
+
# user.contacts
|
40
|
+
#
|
41
|
+
class User
|
42
|
+
|
43
|
+
include Fleakr::Support::Object
|
44
|
+
|
45
|
+
def self.lazily_load(*attributes)
|
46
|
+
options = attributes.extract_options!
|
47
|
+
|
48
|
+
attributes.each do |attribute|
|
49
|
+
class_eval <<-CODE
|
50
|
+
def #{attribute}_with_loading
|
51
|
+
self.send(:#{options[:with]}) if @#{attribute}.nil?
|
52
|
+
#{attribute}_without_loading
|
53
|
+
end
|
54
|
+
alias_method_chain :#{attribute}, :loading
|
55
|
+
CODE
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
flickr_attribute :id, :xpath => 'rsp/user', :attribute => 'nsid'
|
60
|
+
flickr_attribute :username, :xpath => 'rsp/user/username'
|
61
|
+
flickr_attribute :name, :xpath => 'rsp/person/realname'
|
62
|
+
flickr_attribute :photos_url, :xpath => 'rsp/person/photosurl'
|
63
|
+
flickr_attribute :profile_url, :xpath => 'rsp/person/profileurl'
|
64
|
+
flickr_attribute :photos_count, :xpath => 'rsp/person/photos/count'
|
65
|
+
flickr_attribute :icon_server, :xpath => 'rsp/person', :attribute => 'iconserver'
|
66
|
+
flickr_attribute :icon_farm, :xpath => 'rsp/person', :attribute => 'iconfarm'
|
67
|
+
flickr_attribute :pro, :xpath => 'rsp/person', :attribute => 'ispro'
|
68
|
+
flickr_attribute :admin, :xpath => 'rsp/person', :attribute => 'isadmin'
|
69
|
+
|
70
|
+
has_many :sets, :groups, :photos, :contacts
|
71
|
+
|
72
|
+
find_one :by_username, :call => 'people.findByUsername'
|
73
|
+
find_one :by_email, :using => :find_email, :call => 'people.findByEmail'
|
74
|
+
|
75
|
+
lazily_load :name, :photos_url, :profile_url, :photos_count, :with => :load_info
|
76
|
+
lazily_load :icon_server, :icon_farm, :pro, :admin, :with => :load_info
|
77
|
+
|
78
|
+
scoped_search
|
79
|
+
|
80
|
+
# Is this a pro account?
|
81
|
+
def pro?
|
82
|
+
(self.pro.to_i == 0) ? false : true
|
83
|
+
end
|
84
|
+
|
85
|
+
# Is this user an admin?
|
86
|
+
def admin?
|
87
|
+
(self.admin.to_i == 0) ? false : true
|
88
|
+
end
|
89
|
+
|
90
|
+
# This user's buddy icon
|
91
|
+
def icon_url
|
92
|
+
if self.icon_server.to_i > 0
|
93
|
+
"http://farm#{self.icon_farm}.static.flickr.com/#{self.icon_server}/buddyicons/#{self.id}.jpg"
|
94
|
+
else
|
95
|
+
'http://www.flickr.com/images/buddyicon.jpg'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def load_info # :nodoc:
|
100
|
+
response = Fleakr::Api::Request.with_response!('people.getInfo', :user_id => self.id)
|
101
|
+
self.populate_from(response.body)
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Fleakr
|
2
|
+
module Support # :nodoc:all
|
3
|
+
class Attribute
|
4
|
+
|
5
|
+
attr_reader :name, :xpath, :attribute
|
6
|
+
|
7
|
+
def initialize(name, options = {})
|
8
|
+
@name = name.to_sym
|
9
|
+
@attribute = options[:attribute]
|
10
|
+
|
11
|
+
@xpath = options[:xpath]
|
12
|
+
@xpath ||= @name.to_s unless @attribute
|
13
|
+
end
|
14
|
+
|
15
|
+
def value_from(document)
|
16
|
+
node = document
|
17
|
+
|
18
|
+
begin
|
19
|
+
node = document.at(self.xpath) if self.xpath
|
20
|
+
self.attribute.nil? ? node.inner_text : node[self.attribute]
|
21
|
+
rescue NoMethodError
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|