fleakr 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/README.rdoc +88 -57
  2. data/Rakefile +28 -9
  3. data/lib/fleakr.rb +25 -31
  4. data/lib/fleakr/api/option.rb +34 -34
  5. data/lib/fleakr/api/parameter_list.rb +23 -23
  6. data/lib/fleakr/objects.rb +4 -1
  7. data/lib/fleakr/objects/metadata.rb +35 -0
  8. data/lib/fleakr/objects/metadata_collection.rb +36 -0
  9. data/lib/fleakr/objects/photo.rb +15 -11
  10. data/lib/fleakr/objects/set.rb +17 -13
  11. data/lib/fleakr/objects/url.rb +83 -0
  12. data/lib/fleakr/objects/user.rb +8 -0
  13. data/lib/fleakr/support.rb +3 -1
  14. data/lib/fleakr/support/attribute.rb +2 -2
  15. data/lib/fleakr/support/object.rb +44 -29
  16. data/lib/fleakr/support/url_expander.rb +37 -0
  17. data/lib/fleakr/support/utility.rb +66 -0
  18. data/lib/fleakr/version.rb +5 -5
  19. data/test/fixtures/photos.getExif.xml +362 -0
  20. data/test/test_helper.rb +44 -47
  21. data/test/unit/fleakr/api/authentication_request_test.rb +12 -12
  22. data/test/unit/fleakr/api/file_parameter_test.rb +15 -15
  23. data/test/unit/fleakr/api/method_request_test.rb +1 -1
  24. data/test/unit/fleakr/api/option_test.rb +44 -44
  25. data/test/unit/fleakr/api/parameter_list_test.rb +40 -40
  26. data/test/unit/fleakr/api/response_test.rb +10 -10
  27. data/test/unit/fleakr/api/upload_request_test.rb +28 -28
  28. data/test/unit/fleakr/api/value_parameter_test.rb +10 -10
  29. data/test/unit/fleakr/core_ext/false_class_test.rb +5 -5
  30. data/test/unit/fleakr/core_ext/hash_test.rb +9 -9
  31. data/test/unit/fleakr/core_ext/true_class_test.rb +5 -5
  32. data/test/unit/fleakr/objects/authentication_token_test.rb +23 -23
  33. data/test/unit/fleakr/objects/collection_test.rb +23 -23
  34. data/test/unit/fleakr/objects/comment_test.rb +15 -15
  35. data/test/unit/fleakr/objects/contact_test.rb +11 -11
  36. data/test/unit/fleakr/objects/error_test.rb +8 -8
  37. data/test/unit/fleakr/objects/group_test.rb +13 -13
  38. data/test/unit/fleakr/objects/image_test.rb +4 -4
  39. data/test/unit/fleakr/objects/metadata_collection_test.rb +55 -0
  40. data/test/unit/fleakr/objects/metadata_test.rb +27 -0
  41. data/test/unit/fleakr/objects/photo_context_test.rb +23 -23
  42. data/test/unit/fleakr/objects/photo_test.rb +71 -64
  43. data/test/unit/fleakr/objects/search_test.rb +22 -22
  44. data/test/unit/fleakr/objects/set_test.rb +62 -40
  45. data/test/unit/fleakr/objects/tag_test.rb +32 -31
  46. data/test/unit/fleakr/objects/url_test.rb +185 -0
  47. data/test/unit/fleakr/objects/user_test.rb +43 -16
  48. data/test/unit/fleakr/support/attribute_test.rb +15 -15
  49. data/test/unit/fleakr/support/object_test.rb +77 -33
  50. data/test/unit/fleakr/support/request_test.rb +12 -12
  51. data/test/unit/fleakr/support/url_expander_test.rb +44 -0
  52. data/test/unit/fleakr/support/utility_test.rb +70 -0
  53. data/test/unit/fleakr_test.rb +48 -41
  54. metadata +43 -23
@@ -6,7 +6,7 @@ module Fleakr
6
6
  # Top-level class for creating specific option instances based on type
7
7
  #
8
8
  class Option
9
-
9
+
10
10
  MAPPING = {
11
11
  :tags => 'TagOption',
12
12
  :viewable_by => 'ViewOption',
@@ -14,85 +14,85 @@ module Fleakr
14
14
  :type => 'TypeOption',
15
15
  :hide? => 'HiddenOption'
16
16
  }
17
-
17
+
18
18
  # Initialize a new option for the specified type and value
19
19
  #
20
20
  def self.for(type, value)
21
21
  class_for(type).new(type, value)
22
22
  end
23
-
23
+
24
24
  def self.class_for(type) # :nodoc:
25
25
  class_name = MAPPING[type] || 'SimpleOption'
26
- "Fleakr::Api::#{class_name}".constantize
26
+ Fleakr::Api.const_get(class_name)
27
27
  end
28
-
28
+
29
29
  end
30
-
30
+
31
31
  # = SimpleOption
32
- #
32
+ #
33
33
  # Simple name / value option pair
34
34
  #
35
35
  class SimpleOption
36
36
 
37
37
  attr_reader :type, :value
38
-
38
+
39
39
  # Create an option of the specified type and value
40
40
  #
41
41
  def initialize(type, value)
42
42
  @type = type
43
43
  @value = value
44
44
  end
45
-
45
+
46
46
  # Generate hash representation of this option
47
47
  #
48
48
  def to_hash
49
49
  {type => value}
50
50
  end
51
-
51
+
52
52
  end
53
-
53
+
54
54
  # = TagOption
55
55
  #
56
56
  # Represents values for tags
57
57
  #
58
58
  class TagOption < SimpleOption
59
-
59
+
60
60
  # Tag with specified values. Value passed will be converted to an array if it isn't
61
61
  # already
62
- #
62
+ #
63
63
  def initialize(type, value)
64
64
  super type, value
65
65
  @value = Array(self.value)
66
66
  end
67
-
68
- # Hash representation of tag values (separated by spaces). Handles multi-word tags
67
+
68
+ # Hash representation of tag values (separated by spaces). Handles multi-word tags
69
69
  # by enclosing each tag in double quotes.
70
70
  #
71
71
  def to_hash
72
72
  tags = value.map {|tag| "\"#{tag}\"" }
73
73
  {type => tags.join(' ')}
74
74
  end
75
-
75
+
76
76
  end
77
-
77
+
78
78
  # = ViewOption
79
79
  #
80
80
  # Specify who is able to view the photo.
81
81
  #
82
82
  class ViewOption < SimpleOption
83
-
83
+
84
84
  # Specify who this is viewable by (e.g. everyone / friends / family).
85
85
  #
86
86
  def initialize(type, value)
87
87
  super type, Array(value)
88
88
  end
89
-
89
+
90
90
  # Is this publicly viewable? (i.e. :everyone)
91
91
  #
92
92
  def public?
93
93
  value == [:everyone]
94
94
  end
95
-
95
+
96
96
  # Is this viewable by friends? (i.e. :friends)
97
97
  #
98
98
  def friends?
@@ -104,43 +104,43 @@ module Fleakr
104
104
  def family?
105
105
  value.include?(:family)
106
106
  end
107
-
107
+
108
108
  # Hash representation of photo permissions
109
109
  #
110
110
  def to_hash
111
111
  {:is_public => public?.to_i, :is_friend => friends?.to_i, :is_family => family?.to_i}
112
112
  end
113
-
113
+
114
114
  end
115
-
115
+
116
116
  # = LevelOption
117
117
  #
118
118
  # Specify the "safety level" of this photo (e.g. safe / moderate / restricted)
119
119
  #
120
120
  class LevelOption < SimpleOption
121
-
122
- def value # :nodoc:
121
+
122
+ def value # :nodoc:
123
123
  case @value
124
124
  when :safe then 1
125
125
  when :moderate then 2
126
126
  when :restricted then 3
127
127
  end
128
128
  end
129
-
129
+
130
130
  # Hash representation of the safety_level for this photo
131
131
  #
132
132
  def to_hash
133
133
  {:safety_level => value}
134
134
  end
135
-
135
+
136
136
  end
137
-
137
+
138
138
  # = TypeOption
139
139
  #
140
140
  # Specify the type of this photo (e.g. photo / screenshot / other)
141
141
  #
142
142
  class TypeOption < SimpleOption
143
-
143
+
144
144
  def value # :nodoc:
145
145
  case @value
146
146
  when :photo then 1
@@ -148,27 +148,27 @@ module Fleakr
148
148
  when :other then 3
149
149
  end
150
150
  end
151
-
151
+
152
152
  # Hash representation of this type
153
153
  #
154
154
  def to_hash
155
155
  {:content_type => value}
156
156
  end
157
-
157
+
158
158
  end
159
-
159
+
160
160
  # = HiddenOption
161
161
  #
162
162
  # Specify whether this photo should be hidden from search
163
163
  #
164
164
  class HiddenOption < SimpleOption
165
-
165
+
166
166
  # Hash representation of whether to hide this photo
167
167
  #
168
168
  def to_hash
169
169
  {:hidden => (value ? 2 : 1)}
170
170
  end
171
-
171
+
172
172
  end
173
173
 
174
174
  end
@@ -1,6 +1,6 @@
1
1
  module Fleakr
2
2
  module Api # :nodoc:
3
-
3
+
4
4
  # = ParameterList
5
5
  #
6
6
  # Represents a list of parameters that get passed as part of a
@@ -8,13 +8,13 @@ module Fleakr
8
8
  # into query strings (using #to_query) or form data (using #to_form)
9
9
  #
10
10
  class ParameterList
11
-
11
+
12
12
  attr_reader :upload_options # :nodoc:
13
-
13
+
14
14
  # Create a new parameter list with optional parameters:
15
15
  #
16
16
  # list = Fleakr::Api::ParameterList.new(:username => 'reagent')
17
- #
17
+ #
18
18
  # You can also disable the sending of the authentication token using
19
19
  # the second parameter:
20
20
  #
@@ -27,35 +27,35 @@ module Fleakr
27
27
  end
28
28
 
29
29
  # Should we send an authentication token as part of this list of parameters?
30
- # By default this is true if the token is available as a global value or if
30
+ # By default this is true if the token is available as a global value or if
31
31
  # the :auth_token key/value is part of the initial list. You can override this
32
32
  # in the constructor.
33
- #
33
+ #
34
34
  def send_authentication_token?
35
35
  @send_authentication_token && !authentication_token.nil?
36
36
  end
37
-
37
+
38
38
  # The default options to send as part of the parameter list, defaults to
39
39
  # sending the API key
40
40
  #
41
41
  def default_options
42
42
  {:api_key => Fleakr.api_key}
43
43
  end
44
-
44
+
45
45
  # Should this parameter list be signed? This will be true if Fleakr.shared_secret
46
46
  # is set, false if not.
47
47
  #
48
48
  def sign?
49
- !Fleakr.shared_secret.blank?
49
+ !Fleakr::Support::Utility.blank?(Fleakr.shared_secret)
50
50
  end
51
-
52
- # Generate the query string representation of this parameter
51
+
52
+ # Generate the query string representation of this parameter
53
53
  # list - e.g. <tt>foo=bar&blee=baz</tt>
54
54
  #
55
55
  def to_query
56
56
  list.map {|element| element.to_query }.join('&')
57
57
  end
58
-
58
+
59
59
  # Generate the form representation of this parameter list including the
60
60
  # boundary
61
61
  #
@@ -65,54 +65,54 @@ module Fleakr
65
65
 
66
66
  form
67
67
  end
68
-
68
+
69
69
  # Retrieve the authentication token from either the list of parameters
70
70
  # or the global value (e.g. Fleakr.auth_token)
71
71
  #
72
72
  def authentication_token
73
73
  Fleakr.auth_token.nil? ? @options[:auth_token] : Fleakr.auth_token
74
74
  end
75
-
75
+
76
76
  # Add an option to the list that should be sent with a request.
77
77
  #
78
78
  def add_option(name, value)
79
79
  @options.merge!(name => value)
80
80
  end
81
-
81
+
82
82
  # Add an option that should be sent with an upload request.
83
83
  #
84
84
  def add_upload_option(name, value)
85
85
  @upload_options.merge!(name => value)
86
86
  end
87
-
87
+
88
88
  def options # :nodoc:
89
89
  options = default_options.merge(@options)
90
90
  options.merge!(:auth_token => authentication_token) if send_authentication_token?
91
-
91
+
92
92
  options
93
93
  end
94
-
94
+
95
95
  def boundary # :nodoc:
96
96
  @boundary ||= Digest::MD5.hexdigest(rand.to_s)
97
97
  end
98
-
98
+
99
99
  def signature # :nodoc:
100
100
  sorted_options = options_without_signature.sort {|a,b| a[0].to_s <=> b[0].to_s }
101
101
  signature_text = sorted_options.map {|o| "#{o[0]}#{o[1]}" }.join
102
102
 
103
103
  Digest::MD5.hexdigest("#{Fleakr.shared_secret}#{signature_text}")
104
104
  end
105
-
105
+
106
106
  def options_without_signature # :nodoc:
107
107
  options.reject {|k,v| k.to_s == 'api_sig'}
108
108
  end
109
-
109
+
110
110
  def options_with_signature # :nodoc:
111
111
  options_without_signature.merge(:api_sig => signature)
112
112
  end
113
-
113
+
114
114
  def list # :nodoc:
115
- options_for_list = sign? ? options_with_signature : options_without_signature
115
+ options_for_list = sign? ? options_with_signature : options_without_signature
116
116
  value_parameters = options_for_list.map {|k,v| ValueParameter.new(k, v) }
117
117
  file_parameters = upload_options.map {|k,v| FileParameter.new(k, v) }
118
118
 
@@ -2,6 +2,8 @@ require 'fleakr/objects/authentication_token'
2
2
  require 'fleakr/objects/collection'
3
3
  require 'fleakr/objects/contact'
4
4
  require 'fleakr/objects/error'
5
+ require 'fleakr/objects/metadata_collection'
6
+ require 'fleakr/objects/metadata'
5
7
  require 'fleakr/objects/group'
6
8
  require 'fleakr/objects/image'
7
9
  require 'fleakr/objects/photo_context'
@@ -10,4 +12,5 @@ require 'fleakr/objects/comment'
10
12
  require 'fleakr/objects/tag'
11
13
  require 'fleakr/objects/search'
12
14
  require 'fleakr/objects/set'
13
- require 'fleakr/objects/user'
15
+ require 'fleakr/objects/user'
16
+ require 'fleakr/objects/url'
@@ -0,0 +1,35 @@
1
+ module Fleakr
2
+ module Objects
3
+
4
+ # = Metadata
5
+ #
6
+ # This class wraps the functionality of EXIF data extraction. It's called
7
+ # by the Fleakr::Objects::Photo class to obtain EXIF values
8
+ #
9
+ # Example:
10
+ #
11
+ # user = Fleakr.user('brownout')
12
+ # user.photos.first.metadata
13
+ #
14
+ # == Attributes
15
+ #
16
+ # [raw] The raw value returned by Flickr (e.g. 1/500 for ExposureTime)
17
+ # [clean] The clean value returned by Flickr for the tag (e.g. 0.0.02 (1/500) for ExposureTime)
18
+ # [tagspace] The tag space of the EXIF data, (e.g. TIFF, ExifIFD, Composite)
19
+ # [tag] The label as a tag, (e.g. ExposureProgram)
20
+ # [label] The label for the tag, (e.g. 'Exposure Program')
21
+ #
22
+
23
+ class Metadata
24
+
25
+ include Fleakr::Support::Object
26
+
27
+ flickr_attribute :tagspace, :tag, :label
28
+ flickr_attribute :raw, :from => 'raw'
29
+ flickr_attribute :clean, :from => 'clean'
30
+
31
+ find_all :by_photo_id, :call => 'photos.getExif', :path => 'photo/exif'
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,36 @@
1
+ module Fleakr
2
+ module Objects
3
+
4
+ class MetadataCollection
5
+
6
+ include Enumerable
7
+
8
+ attr_reader :photo
9
+
10
+ def initialize(photo)
11
+ @photo = photo
12
+ end
13
+
14
+ def data
15
+ @data ||= begin
16
+ elements = Metadata.find_all_by_photo_id(photo.id)
17
+ elements.inject({}) {|c, e| c.merge(e.label => e) }
18
+ end
19
+ end
20
+
21
+ def keys
22
+ data.keys
23
+ end
24
+
25
+ def [](key)
26
+ data[key].raw
27
+ end
28
+
29
+ def each(&block)
30
+ data.each(&block)
31
+ end
32
+
33
+ end
34
+
35
+ end
36
+ end
@@ -1,11 +1,11 @@
1
1
  module Fleakr
2
2
  module Objects # :nodoc:
3
-
3
+
4
4
  # = Photo
5
5
  #
6
- # Handles both the retrieval of Photo objects from various associations (e.g. User / Set) as
6
+ # Handles both the retrieval of Photo objects from various associations (e.g. User / Set) as
7
7
  # well as the ability to upload images to the Flickr site.
8
- #
8
+ #
9
9
  # == Attributes
10
10
  #
11
11
  # [id] The ID for this photo
@@ -22,7 +22,7 @@ module Fleakr
22
22
  # [large] The large representation of this photo
23
23
  # [original] The original photo
24
24
  # [previous] The previous photo based on the current context
25
- # [next] The next photo based on the current context
25
+ # [next] The next photo based on the current context
26
26
  #
27
27
  # == Associations
28
28
  #
@@ -57,13 +57,17 @@ module Fleakr
57
57
  find_all :by_set_id, :using => :photoset_id, :call => 'photosets.getPhotos', :path => 'photoset/photo'
58
58
  find_all :by_user_id, :call => 'people.getPublicPhotos', :path => 'photos/photo'
59
59
  find_all :by_group_id, :call => 'groups.pools.getPhotos', :path => 'photos/photo'
60
-
60
+
61
61
  find_one :by_id, :using => :photo_id, :call => 'photos.getInfo'
62
-
62
+
63
63
  lazily_load :posted, :taken, :updated, :comment_count, :url, :description, :with => :load_info
64
-
64
+
65
65
  has_many :images, :tags, :comments
66
66
 
67
+ def metadata
68
+ @metadata ||= MetadataCollection.new(self)
69
+ end
70
+
67
71
  # Upload the photo specified by <tt>filename</tt> to the user's Flickr account. When uploading,
68
72
  # there are several options available (none are required):
69
73
  #
@@ -85,7 +89,7 @@ module Fleakr
85
89
  Photo.find_by_id(photo.id)
86
90
  end
87
91
 
88
- # Replace the current photo's image with the one specified by filename. This
92
+ # Replace the current photo's image with the one specified by filename. This
89
93
  # call requires authentication.
90
94
  #
91
95
  def replace_with(filename)
@@ -108,7 +112,7 @@ module Fleakr
108
112
  end
109
113
 
110
114
  # The user who uploaded this photo. See Fleakr::Objects::User for additional information.
111
- #
115
+ #
112
116
  def owner
113
117
  @owner ||= User.find_by_id(owner_id)
114
118
  end
@@ -118,13 +122,13 @@ module Fleakr
118
122
  def posted_at
119
123
  Time.at(posted.to_i)
120
124
  end
121
-
125
+
122
126
  # When was this photo taken?
123
127
  #
124
128
  def taken_at
125
129
  Time.parse(taken)
126
130
  end
127
-
131
+
128
132
  # When was this photo last updated? This includes addition of tags and other metadata.
129
133
  #
130
134
  def updated_at