fleakr 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README.rdoc +114 -19
  2. data/Rakefile +1 -1
  3. data/lib/fleakr/api/file_parameter.rb +47 -0
  4. data/lib/fleakr/api/method_request.rb +57 -0
  5. data/lib/fleakr/api/parameter.rb +35 -0
  6. data/lib/fleakr/api/parameter_list.rb +96 -0
  7. data/lib/fleakr/api/response.rb +2 -2
  8. data/lib/fleakr/api/upload_request.rb +64 -0
  9. data/lib/fleakr/api/value_parameter.rb +36 -0
  10. data/lib/fleakr/api.rb +7 -0
  11. data/lib/fleakr/core_ext/hash.rb +22 -0
  12. data/lib/fleakr/core_ext.rb +1 -0
  13. data/lib/fleakr/objects/authentication_token.rb +43 -0
  14. data/lib/fleakr/objects/contact.rb +5 -5
  15. data/lib/fleakr/objects/error.rb +2 -2
  16. data/lib/fleakr/objects/group.rb +2 -2
  17. data/lib/fleakr/objects/image.rb +7 -7
  18. data/lib/fleakr/objects/photo.rb +69 -5
  19. data/lib/fleakr/objects/search.rb +3 -6
  20. data/lib/fleakr/objects/set.rb +11 -5
  21. data/lib/fleakr/objects/user.rb +14 -26
  22. data/lib/fleakr/objects.rb +9 -0
  23. data/lib/fleakr/support/attribute.rb +30 -12
  24. data/lib/fleakr/support/object.rb +20 -4
  25. data/lib/fleakr/support.rb +2 -0
  26. data/lib/fleakr/version.rb +1 -1
  27. data/lib/fleakr.rb +66 -7
  28. data/test/fixtures/auth.checkToken.xml +8 -0
  29. data/test/fixtures/auth.getFullToken.xml +8 -0
  30. data/test/fixtures/people.getInfo.xml +1 -1
  31. data/test/fixtures/photos.getInfo.xml +20 -0
  32. data/test/test_helper.rb +18 -3
  33. data/test/unit/fleakr/api/file_parameter_test.rb +63 -0
  34. data/test/unit/fleakr/api/method_request_test.rb +103 -0
  35. data/test/unit/fleakr/api/parameter_list_test.rb +161 -0
  36. data/test/unit/fleakr/api/parameter_test.rb +34 -0
  37. data/test/unit/fleakr/api/upload_request_test.rb +133 -0
  38. data/test/unit/fleakr/api/value_parameter_test.rb +41 -0
  39. data/test/unit/fleakr/core_ext/hash_test.rb +32 -0
  40. data/test/unit/fleakr/objects/authentication_token_test.rb +47 -0
  41. data/test/unit/fleakr/objects/image_test.rb +10 -5
  42. data/test/unit/fleakr/objects/photo_test.rb +96 -36
  43. data/test/unit/fleakr/objects/search_test.rb +1 -1
  44. data/test/unit/fleakr/objects/set_test.rb +12 -1
  45. data/test/unit/fleakr/objects/user_test.rb +2 -16
  46. data/test/unit/fleakr/support/attribute_test.rb +82 -24
  47. data/test/unit/fleakr/support/object_test.rb +26 -3
  48. data/test/unit/fleakr_test.rb +65 -6
  49. metadata +28 -5
  50. data/lib/fleakr/api/request.rb +0 -58
  51. data/test/unit/fleakr/api/request_test.rb +0 -93
@@ -24,11 +24,11 @@ module Fleakr
24
24
 
25
25
  include Fleakr::Support::Object
26
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
27
+ flickr_attribute :size, :from => '@label'
28
+ flickr_attribute :width
29
+ flickr_attribute :height
30
+ flickr_attribute :url, :from => '@source'
31
+ flickr_attribute :page, :from => '@url'
32
32
 
33
33
  find_all :by_photo_id, :call => 'photos.getSizes', :path => 'sizes/size'
34
34
 
@@ -41,8 +41,8 @@ module Fleakr
41
41
  # directory, the file will be created with the original filename from Flickr.
42
42
  # If the target is a file, it will be saved with the specified name. In the
43
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}"
44
+ def save_to(target, prefix = nil)
45
+ destination = File.directory?(target) ? "#{target}/#{prefix}#{self.filename}" : "#{target}"
46
46
  File.open(destination, 'w') {|f| f << Net::HTTP.get(URI.parse(self.url)) }
47
47
  end
48
48
 
@@ -7,6 +7,10 @@ module Fleakr
7
7
  #
8
8
  # [id] The ID for this photo
9
9
  # [title] The title of this photo
10
+ # [description] The description of this photo
11
+ # [secret] This photo's secret (used for sharing photo without permissions checking)
12
+ # [comment_count] Count of the comments attached to this photo
13
+ # [url] This photo's page on Flickr
10
14
  # [square] The tiny square representation of this photo
11
15
  # [thumbnail] The thumbnail for this photo
12
16
  # [small] The small representation of this photo
@@ -25,18 +29,78 @@ module Fleakr
25
29
 
26
30
  include Fleakr::Support::Object
27
31
 
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'
32
+ flickr_attribute :id, :from => ['@id', 'photoid']
33
+ flickr_attribute :title
34
+ flickr_attribute :description
35
+ flickr_attribute :farm_id, :from => '@farm'
36
+ flickr_attribute :server_id, :from => '@server'
37
+ flickr_attribute :secret
38
+ flickr_attribute :posted
39
+ flickr_attribute :taken
40
+ flickr_attribute :updated, :from => '@lastupdate'
41
+ flickr_attribute :comment_count, :from => 'comments'
42
+ flickr_attribute :url
43
+
44
+ # TODO:
45
+ # * owner (user)
46
+ # * visibility
47
+ # * editability
48
+ # * usage
49
+ # * notes
50
+ # * tags
33
51
 
34
52
  find_all :by_photoset_id, :call => 'photosets.getPhotos', :path => 'photoset/photo'
35
53
  find_all :by_user_id, :call => 'people.getPublicPhotos', :path => 'photos/photo'
36
54
  find_all :by_group_id, :call => 'groups.pools.getPhotos', :path => 'photos/photo'
37
55
 
56
+ find_one :by_id, :using => :photo_id, :call => 'photos.getInfo', :authenticate? => true
57
+
58
+ lazily_load :posted, :taken, :updated, :comment_count, :url, :description, :with => :load_info
59
+
38
60
  has_many :images
39
61
 
62
+ # Upload the photo specified by <tt>filename</tt> to the user's Flickr account. This
63
+ # call requires authentication.
64
+ #
65
+ def self.upload(filename)
66
+ response = Fleakr::Api::UploadRequest.with_response!(filename)
67
+ photo = Photo.new(response.body)
68
+ Photo.find_by_id(photo.id, :authenticate? => true)
69
+ end
70
+
71
+ # Replace the current photo's image with the one specified by filename. This
72
+ # call requires authentication.
73
+ #
74
+ def replace_with(filename)
75
+ response = Fleakr::Api::UploadRequest.with_response!(filename, :photo_id => self.id, :type => :update)
76
+ self.populate_from(response.body)
77
+ self
78
+ end
79
+
80
+ # TODO: Refactor this to remove duplication w/ User#load_info - possibly in the lazily_load class method
81
+ def load_info # :nodoc:
82
+ response = Fleakr::Api::MethodRequest.with_response!('photos.getInfo', :photo_id => self.id)
83
+ self.populate_from(response.body)
84
+ end
85
+
86
+ # When was this photo posted?
87
+ #
88
+ def posted_at
89
+ Time.at(posted.to_i)
90
+ end
91
+
92
+ # When was this photo taken?
93
+ #
94
+ def taken_at
95
+ Time.parse(taken)
96
+ end
97
+
98
+ # When was this photo last updated? This includes addition of tags and other metadata.
99
+ #
100
+ def updated_at
101
+ Time.at(updated.to_i)
102
+ end
103
+
40
104
  # Create methods to access image sizes by name
41
105
  SIZES.each do |size|
42
106
  define_method(size) do
@@ -9,13 +9,10 @@ module Fleakr
9
9
 
10
10
  # Retrieve search results from the API
11
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
12
+ @results ||= begin
13
+ response = Fleakr::Api::MethodRequest.with_response!('photos.search', parameters)
14
+ (response.body/'rsp/photos/photo').map {|p| Photo.new(p) }
17
15
  end
18
- @results
19
16
  end
20
17
 
21
18
  private
@@ -8,6 +8,7 @@ module Fleakr
8
8
  # [id] The ID for this photoset
9
9
  # [title] The title of this photoset
10
10
  # [description] The description of this set
11
+ # [count] Count of photos in this set
11
12
  #
12
13
  # == Associations
13
14
  #
@@ -19,26 +20,31 @@ module Fleakr
19
20
 
20
21
  has_many :photos, :using => :photoset_id
21
22
 
22
- flickr_attribute :id, :attribute => 'id'
23
+ flickr_attribute :id
23
24
  flickr_attribute :title
24
25
  flickr_attribute :description
26
+ flickr_attribute :count, :from => '@photos'
25
27
 
26
28
  find_all :by_user_id, :call => 'photosets.getList', :path => 'photosets/photoset'
27
29
 
28
- # Save all photos in this set to the specified directory using the specified size. Allowed
30
+ # Save all photos in this set to the specified directory for the specified size. Allowed
29
31
  # 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
32
+ # <tt>:large</tt>, and <tt>:original</tt>. When saving the set, this method will create
31
33
  # a subdirectory based on the set's title.
32
34
  #
33
35
  def save_to(path, size)
34
36
  target = "#{path}/#{self.title}"
35
37
  FileUtils.mkdir(target) unless File.exist?(target)
36
38
 
37
- self.photos.each do |photo|
39
+ self.photos.each_with_index do |photo, index|
38
40
  image = photo.send(size)
39
- image.save_to(target) unless image.nil?
41
+ image.save_to(target, file_prefix(index)) unless image.nil?
40
42
  end
41
43
  end
44
+
45
+ def file_prefix(index) # :nodoc:
46
+ sprintf("%0#{self.count.length}d_", (index + 1))
47
+ end
42
48
 
43
49
  end
44
50
  end
@@ -11,6 +11,7 @@ module Fleakr
11
11
  # [id] The ID for this user (also referred to as the NSID in the API docs)
12
12
  # [username] This user's username
13
13
  # [name] This user's full name (if entered)
14
+ # [location] This user's location (if entered)
14
15
  # [photos_url] The direct URL to this user's photostream
15
16
  # [profile_url] The direct URL to this user's profile
16
17
  # [photos_count] The number of photos that this user has uploaded
@@ -42,37 +43,24 @@ module Fleakr
42
43
 
43
44
  include Fleakr::Support::Object
44
45
 
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'
46
+ flickr_attribute :id, :from => 'user@nsid'
47
+ flickr_attribute :username
48
+ flickr_attribute :name, :from => 'person/realname'
49
+ flickr_attribute :location
50
+ flickr_attribute :photos_url, :from => 'person/photosurl'
51
+ flickr_attribute :profile_url, :from => 'person/profileurl'
52
+ flickr_attribute :photos_count, :from => 'person/photos/count'
53
+ flickr_attribute :icon_server, :from => 'person@iconserver'
54
+ flickr_attribute :icon_farm, :from => 'person@iconfarm'
55
+ flickr_attribute :pro, :from => 'person@ispro'
56
+ flickr_attribute :admin, :from => 'person@isadmin'
69
57
 
70
58
  has_many :sets, :groups, :photos, :contacts
71
59
 
72
60
  find_one :by_username, :call => 'people.findByUsername'
73
61
  find_one :by_email, :using => :find_email, :call => 'people.findByEmail'
74
62
 
75
- lazily_load :name, :photos_url, :profile_url, :photos_count, :with => :load_info
63
+ lazily_load :name, :photos_url, :profile_url, :photos_count, :location, :with => :load_info
76
64
  lazily_load :icon_server, :icon_farm, :pro, :admin, :with => :load_info
77
65
 
78
66
  scoped_search
@@ -97,7 +85,7 @@ module Fleakr
97
85
  end
98
86
 
99
87
  def load_info # :nodoc:
100
- response = Fleakr::Api::Request.with_response!('people.getInfo', :user_id => self.id)
88
+ response = Fleakr::Api::MethodRequest.with_response!('people.getInfo', :user_id => self.id)
101
89
  self.populate_from(response.body)
102
90
  end
103
91
 
@@ -0,0 +1,9 @@
1
+ require 'fleakr/objects/authentication_token'
2
+ require 'fleakr/objects/contact'
3
+ require 'fleakr/objects/error'
4
+ require 'fleakr/objects/group'
5
+ require 'fleakr/objects/image'
6
+ require 'fleakr/objects/photo'
7
+ require 'fleakr/objects/search'
8
+ require 'fleakr/objects/set'
9
+ require 'fleakr/objects/user'
@@ -2,25 +2,43 @@ module Fleakr
2
2
  module Support # :nodoc:all
3
3
  class Attribute
4
4
 
5
- attr_reader :name, :xpath, :attribute
5
+ # TODO: Refactor the location / attribute logic into a Source class
6
6
 
7
- def initialize(name, options = {})
7
+ attr_reader :name, :sources
8
+
9
+ def initialize(name, sources = nil)
8
10
  @name = name.to_sym
9
- @attribute = options[:attribute]
11
+
12
+ @sources = Array(sources)
13
+ @sources << @name.to_s if @sources.empty?
14
+ end
15
+
16
+ def split(source)
17
+ location, attribute = source.split('@')
18
+ location = self.name.to_s if location.blank?
19
+
20
+ [location, attribute]
21
+ end
22
+
23
+ def node_for(document, source)
24
+ document.at(location(source)) || document.search("//[@#{attribute(source)}]").first
25
+ end
10
26
 
11
- @xpath = options[:xpath]
12
- @xpath ||= @name.to_s unless @attribute
27
+ def attribute(source)
28
+ location, attribute = source.split('@')
29
+ attribute || location
30
+ end
31
+
32
+ def location(source)
33
+ split(source).first
13
34
  end
14
35
 
15
36
  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
37
+ values = sources.map do |source|
38
+ node = node_for(document, source)
39
+ (node.attributes[attribute(source)] || node.inner_text) unless node.nil?
23
40
  end
41
+ values.compact.first
24
42
  end
25
43
 
26
44
  end
@@ -9,7 +9,7 @@ module Fleakr
9
9
  end
10
10
 
11
11
  def flickr_attribute(name, options = {})
12
- self.attributes << Attribute.new(name, options)
12
+ self.attributes << Attribute.new(name, options[:from])
13
13
  class_eval "attr_accessor :#{name}"
14
14
  end
15
15
 
@@ -34,7 +34,7 @@ module Fleakr
34
34
 
35
35
  class_eval <<-CODE
36
36
  def self.find_all_#{condition}(value)
37
- response = Fleakr::Api::Request.with_response!('#{options[:call]}', :#{attribute} => value)
37
+ response = Fleakr::Api::MethodRequest.with_response!('#{options[:call]}', :#{attribute} => value)
38
38
  (response.body/'rsp/#{options[:path]}').map {|e| #{target_class}.new(e) }
39
39
  end
40
40
  CODE
@@ -44,8 +44,10 @@ module Fleakr
44
44
  attribute = options[:using].nil? ? condition.to_s.sub(/^by_/, '') : options[:using]
45
45
 
46
46
  class_eval <<-CODE
47
- def self.find_#{condition}(value)
48
- response = Fleakr::Api::Request.with_response!('#{options[:call]}', :#{attribute} => value)
47
+ def self.find_#{condition}(value, options = {})
48
+ options.merge!(:#{attribute} => value)
49
+
50
+ response = Fleakr::Api::MethodRequest.with_response!('#{options[:call]}', options)
49
51
  #{self.name}.new(response.body)
50
52
  end
51
53
  CODE
@@ -60,6 +62,20 @@ module Fleakr
60
62
  end
61
63
  CODE
62
64
  end
65
+
66
+ def lazily_load(*attributes)
67
+ options = attributes.extract_options!
68
+
69
+ attributes.each do |attribute|
70
+ class_eval <<-CODE
71
+ def #{attribute}_with_loading
72
+ self.send(:#{options[:with]}) if @#{attribute}.nil?
73
+ #{attribute}_without_loading
74
+ end
75
+ alias_method_chain :#{attribute}, :loading
76
+ CODE
77
+ end
78
+ end
63
79
 
64
80
  end
65
81
 
@@ -0,0 +1,2 @@
1
+ require 'fleakr/support/attribute'
2
+ require 'fleakr/support/object'
@@ -2,7 +2,7 @@ module Fleakr
2
2
  module Version # :nodoc:
3
3
 
4
4
  MAJOR = 0
5
- MINOR = 3
5
+ MINOR = 4
6
6
  TINY = 0
7
7
 
8
8
  def self.to_s
data/lib/fleakr.rb CHANGED
@@ -6,13 +6,16 @@ require 'net/http'
6
6
  require 'rubygems'
7
7
  require 'hpricot'
8
8
  require 'activesupport'
9
+ require 'md5'
9
10
 
10
- %w(support api objects).each do |path|
11
- full_path = File.expand_path(File.dirname(__FILE__)) + "/fleakr/#{path}"
12
- Dir["#{full_path}/*.rb"].each {|f| require f }
13
- end
11
+ require 'fleakr/api'
12
+ require 'fleakr/core_ext'
13
+ require 'fleakr/support'
14
+ require 'fleakr/objects'
14
15
 
15
- # = Fleakr: A teeny tiny gem to interface with Flickr
16
+ # = Fleakr: A small, yet powerful, gem to interface with Flickr photostreams
17
+ #
18
+ # == Quick Start
16
19
  #
17
20
  # Getting started is easy, just make sure you have a valid API key from Flickr and you can
18
21
  # then start making any non-authenticated request to pull back data for yours and others'
@@ -36,10 +39,42 @@ end
36
39
  # user.groups
37
40
  #
38
41
  # To see what other associations and attributes are available, see the Fleakr::Objects::User class
42
+ #
43
+ # == Authentication
44
+ #
45
+ # If you want to do something more than just retrieve public photos (like upload your own),
46
+ # you'll need to generate an authentication token to use across requests and sessions.
47
+ #
48
+ # Assuming you've already applied for a key, go back and make sure you have the right settings
49
+ # to get your auth token. Click on the 'Edit key details' link and ensure that:
50
+ #
51
+ # 1. Your application description and notes are up-to-date
52
+ # 1. The value for 'Authentication Type' is set to 'Mobile Application'
53
+ # 1. The value for 'Mobile Permissions' is set to either 'write' or 'delete'
54
+ #
55
+ # Once this is set, you'll see your Authentication URL on the key details page (it will look
56
+ # something like http://www.flickr.com/auth-534525246245). Paste this URL into your browser and
57
+ # confirm access to get your mini-token. Now you're ready to make authenticated requests:
58
+ #
59
+ # require 'rubygems'
60
+ # require 'fleakr'
61
+ #
62
+ # Fleakr.api_key = 'ABC123'
63
+ # Fleakr.shared_secret = 'sekrit' # Available with your key details on the Flickr site
64
+ # Fleakr.mini_token = '362-133-214'
65
+ #
66
+ # Fleakr.upload('/path/to/my/photo.jpg')
67
+ # Fleakr.token.value # => "34132412341235-12341234ef34"
68
+ #
69
+ # Once you use the mini-token once, it is no longer available. To use the generated auth_token
70
+ # for future requests, just set Fleakr.auth_token to the generated value.
39
71
  #
40
72
  module Fleakr
41
73
 
42
- mattr_accessor :api_key
74
+ # Generic catch-all exception for any API errors
75
+ class ApiError < StandardError; end
76
+
77
+ mattr_accessor :api_key, :shared_secret, :mini_token, :auth_token
43
78
 
44
79
  # Find a user based on some unique user data. This method will try to find
45
80
  # the user based on username and will fall back to email if that fails. Example:
@@ -51,7 +86,7 @@ module Fleakr
51
86
  def self.user(user_data)
52
87
  begin
53
88
  Objects::User.find_by_username(user_data)
54
- rescue Api::Request::ApiError
89
+ rescue ApiError
55
90
  Objects::User.find_by_email(user_data)
56
91
  end
57
92
  end
@@ -71,4 +106,28 @@ module Fleakr
71
106
  Objects::Search.new(params).results
72
107
  end
73
108
 
109
+ # Upload one or more files to your Flickr account (requires authentication). Simply provide
110
+ # a filename or a pattern to upload one or more files:
111
+ #
112
+ # Fleakr.upload('/path/to/my/mug.jpg')
113
+ # Fleakr.upload('/User/Pictures/Party/*.jpg')
114
+ #
115
+ def self.upload(glob)
116
+ Dir[glob].each {|file| Fleakr::Objects::Photo.upload(file) }
117
+ end
118
+
119
+ # Get the authentication token needed for authenticated requests. Will either use
120
+ # a valid auth_token (if available) or a mini-token to generate the auth_token.
121
+ #
122
+ def self.token
123
+ @token ||= begin
124
+ if !Fleakr.auth_token.nil?
125
+ Fleakr::Objects::AuthenticationToken.from_auth_token(Fleakr.auth_token)
126
+ else
127
+ Fleakr::Objects::AuthenticationToken.from_mini_token(Fleakr.mini_token)
128
+ end
129
+ end
130
+ end
131
+
132
+
74
133
  end
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <rsp stat="ok">
3
+ <auth>
4
+ <token>abc-123</token>
5
+ <perms>delete</perms>
6
+ <user nsid="31066442@N69" fullname="Sir Froot Pants" username="frootpantz"></user>
7
+ </auth>
8
+ </rsp>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <rsp stat="ok">
3
+ <auth>
4
+ <token>abc-123</token>
5
+ <perms>delete</perms>
6
+ <user nsid="31066442@N69" fullname="Sir Froot Pants" username="frootpantz"></user>
7
+ </auth>
8
+ </rsp>
@@ -4,7 +4,7 @@
4
4
  <username>frootpantz</username>
5
5
  <realname>Sir Froot Pantz</realname>
6
6
  <mbox_sha1sum>e52ed1e5b91c763694995460e9796fc2adc02019</mbox_sha1sum>
7
- <location />
7
+ <location>The Moon</location>
8
8
  <photosurl>http://www.flickr.com/photos/frootpantz/</photosurl>
9
9
  <profileurl>http://www.flickr.com/people/frootpantz/</profileurl>
10
10
  <mobileurl>http://m.flickr.com/photostream.gne?id=34225</mobileurl>
@@ -0,0 +1,20 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <rsp stat="ok">
3
+ <photo id="1" secret="secret" server="3085" farm="4" dateuploaded="1230274722" isfavorite="0" license="0" rotation="0" originalsecret="sekrit" originalformat="jpg" media="photo">
4
+ <owner nsid="31066442@N69" username="frootpantz" realname="" location="" />
5
+ <title>Tree</title>
6
+ <description>A Tree</description>
7
+ <visibility ispublic="1" isfriend="0" isfamily="0" />
8
+ <dates posted="1230274722" taken="2008-12-25 18:26:55" takengranularity="0" lastupdate="1230276652" />
9
+
10
+ <editability cancomment="0" canaddmeta="0" />
11
+ <usage candownload="1" canblog="0" canprint="0" />
12
+ <comments>0</comments>
13
+ <notes />
14
+ <tags />
15
+ <urls>
16
+ <url type="photopage">http://www.flickr.com/photos/yes/1</url>
17
+ </urls>
18
+
19
+ </photo>
20
+ </rsp>
data/test/test_helper.rb CHANGED
@@ -9,6 +9,19 @@ require File.dirname(__FILE__) + '/../lib/fleakr'
9
9
 
10
10
  class Test::Unit::TestCase
11
11
 
12
+ def self.should_autoload_when_accessing(*attributes)
13
+ options = attributes.extract_options!
14
+ attributes.each do |accessor_name|
15
+ it "should load the additional user information when accessing the :#{accessor_name} attribute" do
16
+ klass = self.class.name.sub(/Test$/, '').constantize
17
+
18
+ object = klass.new
19
+ object.expects(options[:with]).with()
20
+ object.send(accessor_name)
21
+ end
22
+ end
23
+ end
24
+
12
25
  def self.should_have_a_value_for(attribute_test)
13
26
  it "should have a value for :#{attribute_test.keys.first}" do
14
27
  @object.send(attribute_test.keys.first).should == attribute_test.values.first
@@ -64,12 +77,14 @@ class Test::Unit::TestCase
64
77
  klass = "Fleakr::Objects::#{class_name}".constantize
65
78
  object_type = class_name.downcase
66
79
 
80
+ condition_value = '1'
81
+
67
82
  options[:with] = options[:by] if options[:with].nil?
83
+ params = {options[:with] => condition_value}
68
84
 
69
85
  it "should be able to find a #{thing} by #{options[:by]}" do
70
- condition_value = '1'
71
86
  stub = stub()
72
- response = mock_request_cycle :for => options[:call], :with => {options[:with] => condition_value}
87
+ response = mock_request_cycle :for => options[:call], :with => params
73
88
 
74
89
  klass.expects(:new).with(response.body).returns(stub)
75
90
  klass.send("find_by_#{options[:by]}".to_sym, condition_value).should == stub
@@ -108,7 +123,7 @@ class Test::Unit::TestCase
108
123
 
109
124
  def mock_request_cycle(options)
110
125
  response = stub(:body => Hpricot.XML(read_fixture(options[:for])))
111
- Fleakr::Api::Request.expects(:with_response!).with(options[:for], options[:with]).returns(response)
126
+ Fleakr::Api::MethodRequest.expects(:with_response!).with(options[:for], options[:with]).returns(response)
112
127
 
113
128
  response
114
129
  end
@@ -0,0 +1,63 @@
1
+ require File.dirname(__FILE__) + '/../../../test_helper'
2
+
3
+ module Fleakr::Api
4
+ class FileParameterTest < Test::Unit::TestCase
5
+
6
+ describe "An instance of the FileParameter class" do
7
+
8
+ before do
9
+ @temp_dir = File.expand_path(create_temp_directory)
10
+ @filename = "#{@temp_dir}/image.jpg"
11
+ end
12
+
13
+ after do
14
+ FileUtils.rm_rf(@temp_dir)
15
+ end
16
+
17
+ it "should know not to include itself in the parameter signature" do
18
+ parameter = FileParameter.new('photo', @filename)
19
+ parameter.include_in_signature?.should be(false)
20
+ end
21
+
22
+ {'jpg' => 'image/jpeg', 'png' => 'image/png', 'gif' => 'image/gif'}.each do |ext, mime_type|
23
+ it "should know the correct MIME type for an extension of #{ext}" do
24
+ parameter = FileParameter.new('photo', "#{@temp_dir}/image.#{ext}")
25
+ parameter.mime_type.should == mime_type
26
+ end
27
+ end
28
+
29
+ it "should retrieve the contents of the file when accessing the value" do
30
+ File.expects(:read).with(@filename).returns('bopbip')
31
+
32
+ parameter = FileParameter.new('photo', @filename)
33
+ parameter.value.should == 'bopbip'
34
+ end
35
+
36
+ it "should cache the file contents after retrieving them" do
37
+ File.expects(:read).with(@filename).once.returns('bopbip')
38
+
39
+ parameter = FileParameter.new('photo', @filename)
40
+ 2.times { parameter.value }
41
+ end
42
+
43
+ it "should know how to generate a form representation of itself" do
44
+ filename = 'image.jpg'
45
+ mime_type = 'image/jpeg'
46
+
47
+ parameter = FileParameter.new('photo', filename)
48
+ parameter.stubs(:mime_type).with().returns(mime_type)
49
+ parameter.stubs(:value).with().returns('data')
50
+
51
+ expected =
52
+ "Content-Disposition: form-data; name=\"photo\"; filename=\"#{filename}\"\r\n" +
53
+ "Content-Type: image/jpeg\r\n" +
54
+ "\r\n" +
55
+ "data\r\n"
56
+
57
+ parameter.to_form.should == expected
58
+ end
59
+
60
+ end
61
+
62
+ end
63
+ end