fleakr 0.6.3 → 0.7.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 (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