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.
- data/README.rdoc +88 -57
- data/Rakefile +28 -9
- data/lib/fleakr.rb +25 -31
- data/lib/fleakr/api/option.rb +34 -34
- data/lib/fleakr/api/parameter_list.rb +23 -23
- data/lib/fleakr/objects.rb +4 -1
- data/lib/fleakr/objects/metadata.rb +35 -0
- data/lib/fleakr/objects/metadata_collection.rb +36 -0
- data/lib/fleakr/objects/photo.rb +15 -11
- data/lib/fleakr/objects/set.rb +17 -13
- data/lib/fleakr/objects/url.rb +83 -0
- data/lib/fleakr/objects/user.rb +8 -0
- data/lib/fleakr/support.rb +3 -1
- data/lib/fleakr/support/attribute.rb +2 -2
- data/lib/fleakr/support/object.rb +44 -29
- data/lib/fleakr/support/url_expander.rb +37 -0
- data/lib/fleakr/support/utility.rb +66 -0
- data/lib/fleakr/version.rb +5 -5
- data/test/fixtures/photos.getExif.xml +362 -0
- data/test/test_helper.rb +44 -47
- data/test/unit/fleakr/api/authentication_request_test.rb +12 -12
- data/test/unit/fleakr/api/file_parameter_test.rb +15 -15
- data/test/unit/fleakr/api/method_request_test.rb +1 -1
- data/test/unit/fleakr/api/option_test.rb +44 -44
- data/test/unit/fleakr/api/parameter_list_test.rb +40 -40
- data/test/unit/fleakr/api/response_test.rb +10 -10
- data/test/unit/fleakr/api/upload_request_test.rb +28 -28
- data/test/unit/fleakr/api/value_parameter_test.rb +10 -10
- data/test/unit/fleakr/core_ext/false_class_test.rb +5 -5
- data/test/unit/fleakr/core_ext/hash_test.rb +9 -9
- data/test/unit/fleakr/core_ext/true_class_test.rb +5 -5
- data/test/unit/fleakr/objects/authentication_token_test.rb +23 -23
- data/test/unit/fleakr/objects/collection_test.rb +23 -23
- data/test/unit/fleakr/objects/comment_test.rb +15 -15
- data/test/unit/fleakr/objects/contact_test.rb +11 -11
- data/test/unit/fleakr/objects/error_test.rb +8 -8
- data/test/unit/fleakr/objects/group_test.rb +13 -13
- data/test/unit/fleakr/objects/image_test.rb +4 -4
- data/test/unit/fleakr/objects/metadata_collection_test.rb +55 -0
- data/test/unit/fleakr/objects/metadata_test.rb +27 -0
- data/test/unit/fleakr/objects/photo_context_test.rb +23 -23
- data/test/unit/fleakr/objects/photo_test.rb +71 -64
- data/test/unit/fleakr/objects/search_test.rb +22 -22
- data/test/unit/fleakr/objects/set_test.rb +62 -40
- data/test/unit/fleakr/objects/tag_test.rb +32 -31
- data/test/unit/fleakr/objects/url_test.rb +185 -0
- data/test/unit/fleakr/objects/user_test.rb +43 -16
- data/test/unit/fleakr/support/attribute_test.rb +15 -15
- data/test/unit/fleakr/support/object_test.rb +77 -33
- data/test/unit/fleakr/support/request_test.rb +12 -12
- data/test/unit/fleakr/support/url_expander_test.rb +44 -0
- data/test/unit/fleakr/support/utility_test.rb +70 -0
- data/test/unit/fleakr_test.rb +48 -41
- metadata +43 -23
data/lib/fleakr/api/option.rb
CHANGED
@@ -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
|
-
|
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.
|
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
|
|
data/lib/fleakr/objects.rb
CHANGED
@@ -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
|
data/lib/fleakr/objects/photo.rb
CHANGED
@@ -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
|