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.
Files changed (42) hide show
  1. data/README.rdoc +149 -0
  2. data/Rakefile +40 -0
  3. data/lib/fleakr/api/request.rb +58 -0
  4. data/lib/fleakr/api/response.rb +35 -0
  5. data/lib/fleakr/objects/contact.rb +31 -0
  6. data/lib/fleakr/objects/error.rb +22 -0
  7. data/lib/fleakr/objects/group.rb +26 -0
  8. data/lib/fleakr/objects/image.rb +51 -0
  9. data/lib/fleakr/objects/photo.rb +55 -0
  10. data/lib/fleakr/objects/search.rb +33 -0
  11. data/lib/fleakr/objects/set.rb +45 -0
  12. data/lib/fleakr/objects/user.rb +106 -0
  13. data/lib/fleakr/support/attribute.rb +28 -0
  14. data/lib/fleakr/support/object.rb +88 -0
  15. data/lib/fleakr/version.rb +13 -0
  16. data/lib/fleakr.rb +74 -0
  17. data/test/fixtures/contacts.getPublicList.xml +7 -0
  18. data/test/fixtures/groups.pools.getPhotos.xml +7 -0
  19. data/test/fixtures/people.findByEmail.xml +6 -0
  20. data/test/fixtures/people.findByUsername.xml +6 -0
  21. data/test/fixtures/people.getInfo.xml +18 -0
  22. data/test/fixtures/people.getPublicGroups.xml +7 -0
  23. data/test/fixtures/people.getPublicPhotos.xml +7 -0
  24. data/test/fixtures/photos.getSizes.xml +10 -0
  25. data/test/fixtures/photos.search.xml +7 -0
  26. data/test/fixtures/photosets.getList.xml +13 -0
  27. data/test/fixtures/photosets.getPhotos.xml +7 -0
  28. data/test/test_helper.rb +123 -0
  29. data/test/unit/fleakr/api/request_test.rb +93 -0
  30. data/test/unit/fleakr/api/response_test.rb +49 -0
  31. data/test/unit/fleakr/objects/contact_test.rb +58 -0
  32. data/test/unit/fleakr/objects/error_test.rb +21 -0
  33. data/test/unit/fleakr/objects/group_test.rb +31 -0
  34. data/test/unit/fleakr/objects/image_test.rb +76 -0
  35. data/test/unit/fleakr/objects/photo_test.rb +101 -0
  36. data/test/unit/fleakr/objects/search_test.rb +74 -0
  37. data/test/unit/fleakr/objects/set_test.rb +71 -0
  38. data/test/unit/fleakr/objects/user_test.rb +104 -0
  39. data/test/unit/fleakr/support/attribute_test.rb +68 -0
  40. data/test/unit/fleakr/support/object_test.rb +95 -0
  41. data/test/unit/fleakr_test.rb +44 -0
  42. 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