reagent-fleakr 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -169,7 +169,33 @@ Searches can also be scoped to other entities in the system (namely Users and Gr
169
169
  => [#<Fleakr::Objects::Photo:0x18a6960 @server_id="41", @id="81370156",
170
170
  @farm_id="1", @title="Clear and Serpent Danger", @secret="013091582a">]
171
171
 
172
- === Authenticated Calls & Uploads
172
+ === Uploading Files
173
+
174
+ Before you can upload files, you need to be able to make authenticated calls to the Flickr
175
+ API. Skip to the next section (Authenticated Calls) for details on how to make this work.
176
+
177
+ Uploading single files is simple:
178
+
179
+ >> Fleakr.upload('/path/to/image.jpg')
180
+ => [#<Fleakr::Objects::Photo:0x217fb54 @updated="1236133594", @server_id="3266", ...>]
181
+
182
+ Notice that the newly-uploaded image is returned. You can further inspect / modify this as
183
+ necessary. The real magic is in uploading multiple files - the upload method takes a file
184
+ glob:
185
+
186
+ >> Fleakr.upload('/path/to/images/*.jpg')
187
+ => [#<Fleakr::Objects::Photo:0x217faa0 ...>,
188
+ #<Fleakr::Objects::Photo:0x212fb18 ...>,
189
+ #<Fleakr::Objects::Photo:0x20e09c8 ...>]
190
+
191
+ You can also set options on the file(s) that you're uploading:
192
+
193
+ >> Fleakr.upload('/path/to/party/images/*.jpg', :viewable_by => :everyone,
194
+ :title => 'Party Pics')
195
+
196
+ The full list of options can be found in the Fleakr::Objects::Photo documentation.
197
+
198
+ === Authenticated Calls
173
199
 
174
200
  While read-only access to the API gets you quite a bit of data, you'll need to generate an
175
201
  authentication token if you want access to the more powerful features (like uploading your
@@ -197,7 +223,9 @@ confirm access to get your mini-token. Now you're ready to make authenticated re
197
223
  Fleakr.token.value # => "34132412341235-12341234ef34"
198
224
 
199
225
  Once you use the mini-token once, it is no longer available. To use the generated auth_token
200
- for future requests, just set Fleakr.auth_token to the generated value.
226
+ for future requests, just set Fleakr.auth_token to the generated value. Similarly, if you have
227
+ an authenticated frob from Flickr (using authentication for desktop applications, for example)
228
+ you can also set <tt>Fleakr.frob</tt> to the frob value returned from the API.
201
229
 
202
230
  === What Went Wrong?
203
231
 
@@ -223,20 +251,19 @@ API requests.
223
251
 
224
252
  === 0.4.x
225
253
 
226
- * Allow passing of parameters to file uploads to allow for access control / naming
227
254
  * Implement remaining bits of person and photo-related API calls (read-only)
228
- * Automatically sign all calls (if we have a secret), authenticate all calls (if we have a token)
229
255
 
230
256
  === 0.5.x
231
257
 
232
258
  * Implement asynchronous file upload / replacement w/ ticket checking
233
- * Provide a better searching interface
259
+ * Provide a better searching interface with ruby-like option syntax
234
260
 
235
261
  === Future
236
262
 
237
263
  * Implement save-able search results (e.g. Fleakr.search('ponies').save_to('/path', :medium))
238
264
  * Implement deeper associations for core elements (e.g. tags / etc..)
239
265
  * Implement write methods for photos & photosets
266
+ * Implement flickr.places.* portion of API
240
267
 
241
268
  == License
242
269
 
data/Rakefile CHANGED
@@ -19,7 +19,7 @@ spec = Gem::Specification.new do |s|
19
19
  s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib,test}/**/*")
20
20
 
21
21
  s.add_dependency('hpricot', '~> 0.6.0')
22
- s.add_dependency('activesupport', '~> 2.2.0')
22
+ s.add_dependency('activesupport', '~> 2.0')
23
23
  s.add_dependency('loggable', '~> 0.2.0')
24
24
  end
25
25
 
@@ -1,12 +1,17 @@
1
1
  module Fleakr
2
2
  module Api # :nodoc:
3
3
 
4
+ # = MethodRequest
5
+ #
6
+ # Handles all API requests that are non-upload related. For upload requests see the
7
+ # UploadRequest class.
8
+ #
4
9
  class MethodRequest
5
10
  attr_reader :parameters, :method
6
11
 
7
12
  # Makes a request to the Flickr API and returns a valid Response object. If
8
13
  # there are errors on the response it will raise an ApiError exception. See
9
- # #Fleakr::Api::MethodRequest.new for details about the additional parameters
14
+ # MethodRequest#new for details about the additional parameters
10
15
  #
11
16
  def self.with_response!(method, additional_parameters = {})
12
17
  request = self.new(method, additional_parameters)
@@ -25,9 +30,9 @@ module Fleakr
25
30
  # see (#Fleakr.api_key=)
26
31
  #
27
32
  # The <tt>additional_parameters</tt> is a list of parameters to pass directly to
28
- # the Flickr API call. Exceptions to this are the <tt>:sign?</tt> and
29
- # <tt>:authenticate?</tt> options that determine if the call should be signed or
30
- # authenticated.
33
+ # the Flickr API call. The exception to this is the <tt>:authenticate?</tt> option
34
+ # that will force the call to not be authenticated if it is set to false (The default
35
+ # behavior is to authenticate all calls when we have a token).
31
36
  #
32
37
  def initialize(method, additional_parameters = {})
33
38
  @parameters = ParameterList.new(additional_parameters)
@@ -0,0 +1,175 @@
1
+ module Fleakr
2
+ module Api # :nodoc:
3
+
4
+ # = Option
5
+ #
6
+ # Top-level class for creating specific option instances based on type
7
+ #
8
+ class Option
9
+
10
+ MAPPING = {
11
+ :tags => 'TagOption',
12
+ :viewable_by => 'ViewOption',
13
+ :level => 'LevelOption',
14
+ :type => 'TypeOption',
15
+ :hide? => 'HiddenOption'
16
+ }
17
+
18
+ # Initialize a new option for the specified type and value
19
+ #
20
+ def self.for(type, value)
21
+ class_for(type).new(type, value)
22
+ end
23
+
24
+ def self.class_for(type) # :nodoc:
25
+ class_name = MAPPING[type] || 'SimpleOption'
26
+ "Fleakr::Api::#{class_name}".constantize
27
+ end
28
+
29
+ end
30
+
31
+ # = SimpleOption
32
+ #
33
+ # Simple name / value option pair
34
+ #
35
+ class SimpleOption
36
+
37
+ attr_reader :type, :value
38
+
39
+ # Create an option of the specified type and value
40
+ #
41
+ def initialize(type, value)
42
+ @type = type
43
+ @value = value
44
+ end
45
+
46
+ # Generate hash representation of this option
47
+ #
48
+ def to_hash
49
+ {type => value}
50
+ end
51
+
52
+ end
53
+
54
+ # = TagOption
55
+ #
56
+ # Represents values for tags
57
+ #
58
+ class TagOption < SimpleOption
59
+
60
+ # Tag with specified values. Value passed will be converted to an array if it isn't
61
+ # already
62
+ #
63
+ def initialize(type, value)
64
+ super type, value
65
+ @value = Array(self.value)
66
+ end
67
+
68
+ # Hash representation of tag values (separated by spaces). Handles multi-word tags
69
+ # by enclosing each tag in double quotes.
70
+ #
71
+ def to_hash
72
+ tags = value.map {|tag| "\"#{tag}\"" }
73
+ {type => tags.join(' ')}
74
+ end
75
+
76
+ end
77
+
78
+ # = ViewOption
79
+ #
80
+ # Specify who is able to view the photo.
81
+ #
82
+ class ViewOption < SimpleOption
83
+
84
+ # Specify who this is viewable by (e.g. everyone / friends / family).
85
+ #
86
+ def initialize(type, value)
87
+ super type, Array(value)
88
+ end
89
+
90
+ # Is this publicly viewable? (i.e. :everyone)
91
+ #
92
+ def public?
93
+ value == [:everyone]
94
+ end
95
+
96
+ # Is this viewable by friends? (i.e. :friends)
97
+ #
98
+ def friends?
99
+ value.include?(:friends)
100
+ end
101
+
102
+ # Is this viewable by family? (i.e. :family)
103
+ #
104
+ def family?
105
+ value.include?(:family)
106
+ end
107
+
108
+ # Hash representation of photo permissions
109
+ #
110
+ def to_hash
111
+ {:is_public => public?.to_i, :is_friend => friends?.to_i, :is_family => family?.to_i}
112
+ end
113
+
114
+ end
115
+
116
+ # = LevelOption
117
+ #
118
+ # Specify the "safety level" of this photo (e.g. safe / moderate / restricted)
119
+ #
120
+ class LevelOption < SimpleOption
121
+
122
+ def value # :nodoc:
123
+ case @value
124
+ when :safe: 1
125
+ when :moderate: 2
126
+ when :restricted: 3
127
+ end
128
+ end
129
+
130
+ # Hash representation of the safety_level for this photo
131
+ #
132
+ def to_hash
133
+ {:safety_level => value}
134
+ end
135
+
136
+ end
137
+
138
+ # = TypeOption
139
+ #
140
+ # Specify the type of this photo (e.g. photo / screenshot / other)
141
+ #
142
+ class TypeOption < SimpleOption
143
+
144
+ def value # :nodoc:
145
+ case @value
146
+ when :photo: 1
147
+ when :screenshot: 2
148
+ when :other: 3
149
+ end
150
+ end
151
+
152
+ # Hash representation of this type
153
+ #
154
+ def to_hash
155
+ {:content_type => value}
156
+ end
157
+
158
+ end
159
+
160
+ # = HiddenOption
161
+ #
162
+ # Specify whether this photo should be hidden from search
163
+ #
164
+ class HiddenOption < SimpleOption
165
+
166
+ # Hash representation of whether to hide this photo
167
+ #
168
+ def to_hash
169
+ {:hidden => (value ? 2 : 1)}
170
+ end
171
+
172
+ end
173
+
174
+ end
175
+ end
@@ -10,8 +10,8 @@ module Fleakr
10
10
  class ParameterList
11
11
 
12
12
  # Create a new parameter list with optional parameters:
13
- # [:sign?] Will these parameters be used to sign the request?
14
- # [:authenticate?] Will the request need to be authenticated?
13
+ # [:authenticate?] Request will automatically be authenticated if Fleakr.token is available
14
+ # set this to false to force it not to authenticate
15
15
  #
16
16
  # Any additional name / value pairs will be created as individual
17
17
  # ValueParameters as part of the list. Example:
@@ -22,7 +22,8 @@ module Fleakr
22
22
  # => #<Fleakr::Api::ValueParameter:0x1656da4 @include_in_signature=true, @name="foo", @value="bar">
23
23
  #
24
24
  def initialize(options = {})
25
- @api_options = options.extract!(:sign?, :authenticate?)
25
+ # TODO: need to find a way to move the unexpected behavior in Fleakr.token elsewhere
26
+ @api_options = options.extract!(:authenticate?)
26
27
 
27
28
  @list = Hash.new
28
29
 
@@ -41,13 +42,13 @@ module Fleakr
41
42
  # Should this parameter list be signed?
42
43
  #
43
44
  def sign?
44
- (@api_options[:sign?] == true || authenticate?) ? true : false
45
+ !Fleakr.shared_secret.blank?
45
46
  end
46
47
 
47
48
  # Should we send the auth_token with the request?
48
49
  #
49
50
  def authenticate?
50
- (@api_options[:authenticate?] == true) ? true : false
51
+ @api_options.has_key?(:authenticate?) ? @api_options[:authenticate?] : !Fleakr.token.blank?
51
52
  end
52
53
 
53
54
  # Access an individual parameter by key (symbol or string)
@@ -64,7 +65,7 @@ module Fleakr
64
65
  # list - e.g. <tt>foo=bar&blee=baz</tt>
65
66
  #
66
67
  def to_query
67
- list.values.map(&:to_query).join('&')
68
+ list.values.map {|element| element.to_query }.join('&')
68
69
  end
69
70
 
70
71
  # Generate the form representation of this parameter list including the
@@ -19,8 +19,8 @@ module Fleakr
19
19
  # a Fleakr::ApiError with the reason for the error. See UploadRequest#new for more
20
20
  # details.
21
21
  #
22
- def self.with_response!(filename, options = {})
23
- request = self.new(filename, options)
22
+ def self.with_response!(filename, type = :create, options = {})
23
+ request = self.new(filename, type, options)
24
24
  response = request.send
25
25
 
26
26
  raise(Fleakr::ApiError, "Code: #{response.error.code} - #{response.error.message}") if response.error?
@@ -28,21 +28,27 @@ module Fleakr
28
28
  response
29
29
  end
30
30
 
31
- # Create a new UploadRequest with the specified filename and options:
31
+ # Create a new UploadRequest with the specified filename, type, and options. Type
32
+ # is one of <tt>:create</tt> or <tt>:update</tt> to specify whether we are saving a new
33
+ # image or replacing an existing one.
32
34
  #
33
- # [:type] Valid values are :create and :update and are used when uploading new
34
- # photos or replacing existing ones
35
+ # For a list of available options, see the documentation in Fleakr::Objects::Photo
35
36
  #
36
- def initialize(filename, options = {})
37
- type_options = options.extract!(:type)
38
- options.merge!(:authenticate? => true)
37
+ def initialize(filename, type = :create, options = {})
38
+ @type = type
39
+ @options = options
39
40
 
40
- @type = type_options[:type] || :create
41
-
42
- @parameters = ParameterList.new(options)
41
+ @parameters = ParameterList.new(upload_options)
43
42
  @parameters << FileParameter.new('photo', filename)
44
43
  end
45
44
 
45
+ # A list of upload options for this upload request (see Fleakr::Api::Option)
46
+ #
47
+ def upload_options
48
+ option_list = @options.map {|key, value| Option.for(key, value) }
49
+ option_list.inject({}) {|hash, option| hash.merge(option.to_hash)}
50
+ end
51
+
46
52
  def headers # :nodoc:
47
53
  {'Content-Type' => "multipart/form-data; boundary=#{self.parameters.boundary}"}
48
54
  end
data/lib/fleakr/api.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require "fleakr/api/response"
2
2
  require "fleakr/api/method_request"
3
+ require "fleakr/api/option"
3
4
  require "fleakr/api/upload_request"
4
5
  require "fleakr/api/parameter_list"
5
6
  require "fleakr/api/parameter"
@@ -0,0 +1,7 @@
1
+ class FalseClass # :nodoc:
2
+
3
+ def to_i
4
+ 0
5
+ end
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+ class TrueClass # :nodoc:
2
+
3
+ def to_i
4
+ 1
5
+ end
6
+
7
+ end
@@ -1 +1,3 @@
1
- require 'fleakr/core_ext/hash'
1
+ require 'fleakr/core_ext/hash'
2
+ require 'fleakr/core_ext/false_class'
3
+ require 'fleakr/core_ext/true_class'
@@ -17,22 +17,39 @@ module Fleakr
17
17
 
18
18
  flickr_attribute :value, :from => 'auth/token'
19
19
  flickr_attribute :permissions, :from => 'auth/perms'
20
+ flickr_attribute :user_id, :from => 'auth/user@nsid'
21
+ flickr_attribute :user_name, :from => 'auth/user@username'
22
+ flickr_attribute :full_name, :from => 'auth/user@fullname'
20
23
 
21
24
  # Retrieve a full authentication token from the supplied mini-token (e.g. 123-456-789)
22
25
  #
23
- def self.from_mini_token(token)
24
- parameters = {:mini_token => token, :sign? => true}
25
- response = Fleakr::Api::MethodRequest.with_response!('auth.getFullToken', parameters)
26
-
27
- self.new(response.body)
26
+ def self.from_mini_token(mini_token)
27
+ from :mini_token, mini_token
28
28
  end
29
29
 
30
30
  # Retrieve a full authentication token from the supplied auth_token string
31
31
  # (e.g. 45-76598454353455)
32
32
  #
33
- def self.from_auth_token(token)
34
- parameters = {:auth_token => token, :sign? => true}
35
- response = Fleakr::Api::MethodRequest.with_response!('auth.checkToken', parameters)
33
+ def self.from_auth_token(auth_token)
34
+ from :auth_token, auth_token
35
+ end
36
+
37
+ # Retrieve a full authentication token from the supplied frob
38
+ def self.from_frob(frob)
39
+ from :frob, frob
40
+ end
41
+
42
+ def self.from(thing, value) # :nodoc:
43
+ api_methods = {
44
+ :mini_token => 'getFullToken',
45
+ :auth_token => 'checkToken',
46
+ :frob => 'getToken'
47
+ }
48
+
49
+ method = "auth.#{api_methods[thing]}"
50
+
51
+ parameters = {thing => value, :authenticate? => false}
52
+ response = Fleakr::Api::MethodRequest.with_response!(method, parameters)
36
53
 
37
54
  self.new(response.body)
38
55
  end
@@ -3,6 +3,9 @@ module Fleakr
3
3
 
4
4
  # = Photo
5
5
  #
6
+ # Handles both the retrieval of Photo objects from various associations (e.g. User / Set) as
7
+ # well as the ability to upload images to the Flickr site.
8
+ #
6
9
  # == Attributes
7
10
  #
8
11
  # [id] The ID for this photo
@@ -59,20 +62,32 @@ module Fleakr
59
62
 
60
63
  has_many :images
61
64
 
62
- # Upload the photo specified by <tt>filename</tt> to the user's Flickr account. This
63
- # call requires authentication.
65
+ # Upload the photo specified by <tt>filename</tt> to the user's Flickr account. When uploading,
66
+ # there are several options available (none are required):
67
+ #
68
+ # [:title] The title for this photo. Any string is allowed.
69
+ # [:description] The description for this photo. Any string is allowed.
70
+ # [:tags] A collection of tags for this photo. This can be a string or array of strings.
71
+ # [:viewable_by] Who can view this photo? Acceptable values are one of <tt>:everyone</tt>,
72
+ # <tt>:friends</tt> or <tt>:family</tt>. This can also take an array of values
73
+ # (e.g. <tt>[:friends, :family]</tt>) to make it viewable by friends and family.
74
+ # [:level] The safety level of this photo. Acceptable values are one of <tt>:safe</tt>,
75
+ # <tt>:moderate</tt>, or <tt>:restricted</tt>.
76
+ # [:type] The type of image this is. Acceptable values are one of <tt>:photo</tt>,
77
+ # <tt>:screenshot</tt>, or <tt>:other</tt>.
78
+ # [:hide?] Should this photo be hidden from public searches? Takes a boolean.
64
79
  #
65
- def self.upload(filename)
66
- response = Fleakr::Api::UploadRequest.with_response!(filename)
80
+ def self.upload(filename, options = {})
81
+ response = Fleakr::Api::UploadRequest.with_response!(filename, :create, options)
67
82
  photo = Photo.new(response.body)
68
- Photo.find_by_id(photo.id, :authenticate? => true)
83
+ Photo.find_by_id(photo.id)
69
84
  end
70
85
 
71
86
  # Replace the current photo's image with the one specified by filename. This
72
87
  # call requires authentication.
73
88
  #
74
89
  def replace_with(filename)
75
- response = Fleakr::Api::UploadRequest.with_response!(filename, :photo_id => self.id, :type => :update)
90
+ response = Fleakr::Api::UploadRequest.with_response!(filename, :update, :photo_id => self.id)
76
91
  self.populate_from(response.body)
77
92
  self
78
93
  end
@@ -33,8 +33,10 @@ module Fleakr
33
33
  target_class = options[:class_name].nil? ? self.name : "Fleakr::Objects::#{options[:class_name]}"
34
34
 
35
35
  class_eval <<-CODE
36
- def self.find_all_#{condition}(value)
37
- response = Fleakr::Api::MethodRequest.with_response!('#{options[:call]}', :#{attribute} => value)
36
+ def self.find_all_#{condition}(value, options = {})
37
+ options.merge!(:#{attribute} => value)
38
+
39
+ response = Fleakr::Api::MethodRequest.with_response!('#{options[:call]}', options)
38
40
  (response.body/'rsp/#{options[:path]}').map {|e| #{target_class}.new(e) }
39
41
  end
40
42
  CODE
@@ -3,7 +3,7 @@ module Fleakr
3
3
 
4
4
  MAJOR = 0
5
5
  MINOR = 4
6
- TINY = 1
6
+ TINY = 2
7
7
 
8
8
  def self.to_s
9
9
  [MAJOR, MINOR, TINY].join('.')
data/lib/fleakr.rb CHANGED
@@ -5,7 +5,15 @@ require 'uri'
5
5
  require 'cgi'
6
6
  require 'net/http'
7
7
  require 'hpricot'
8
- require 'activesupport'
8
+
9
+ # Require only what we need from ActiveSupport
10
+ require 'active_support/core_ext/array'
11
+ require 'active_support/core_ext/module'
12
+ require 'active_support/core_ext/blank'
13
+ require 'active_support/core_ext/time'
14
+ require 'active_support/inflector'
15
+ require 'active_support/core_ext/string'
16
+
9
17
  require 'md5'
10
18
  require 'loggable'
11
19
 
@@ -75,7 +83,7 @@ module Fleakr
75
83
  # Generic catch-all exception for any API errors
76
84
  class ApiError < StandardError; end
77
85
 
78
- mattr_accessor :api_key, :shared_secret, :mini_token, :auth_token
86
+ mattr_accessor :api_key, :shared_secret, :mini_token, :auth_token, :frob
79
87
 
80
88
  # Find a user based on some unique user data. This method will try to find
81
89
  # the user based on username and will fall back to email if that fails. Example:
@@ -113,8 +121,12 @@ module Fleakr
113
121
  # Fleakr.upload('/path/to/my/mug.jpg')
114
122
  # Fleakr.upload('/User/Pictures/Party/*.jpg')
115
123
  #
116
- def self.upload(glob)
117
- Dir[glob].each {|file| Fleakr::Objects::Photo.upload(file) }
124
+ # Additionally, options can be supplied as part of the upload that will apply to all files
125
+ # that are matched by the pattern passed to <tt>glob</tt>. For a full list, see
126
+ # Fleakr::Objects::Photo.
127
+ #
128
+ def self.upload(glob, options = {})
129
+ Dir[glob].map {|file| Fleakr::Objects::Photo.upload(file, options) }
118
130
  end
119
131
 
120
132
  # Get the authentication token needed for authenticated requests. Will either use
@@ -122,13 +134,29 @@ module Fleakr
122
134
  #
123
135
  def self.token
124
136
  @token ||= begin
125
- if !Fleakr.auth_token.nil?
137
+ if Fleakr.auth_token
126
138
  Fleakr::Objects::AuthenticationToken.from_auth_token(Fleakr.auth_token)
127
- else
139
+ elsif Fleakr.frob
140
+ Fleakr::Objects::AuthenticationToken.from_frob(Fleakr.frob)
141
+ elsif Fleakr.mini_token
128
142
  Fleakr::Objects::AuthenticationToken.from_mini_token(Fleakr.mini_token)
129
143
  end
130
144
  end
131
145
  end
146
+
147
+ # Reset the cached token whenever setting a new value for the mini_token, auth_token, or frob
148
+ #
149
+ [:mini_token, :auth_token, :frob].each do |attribute|
150
+ class_eval <<-ACCESSOR
151
+ def self.#{attribute}=(#{attribute})
152
+ reset_token
153
+ @@#{attribute} = #{attribute}
154
+ end
155
+ ACCESSOR
156
+ end
132
157
 
158
+ def self.reset_token # :nodoc: #
159
+ @token = nil
160
+ end
133
161
 
134
162
  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>
@@ -26,16 +26,6 @@ module Fleakr::Api
26
26
  request.parameters[:method].value.should == 'flickr.people.findByUsername'
27
27
  end
28
28
 
29
- it "should know that it needs to sign the request" do
30
- ParameterList.expects(:new).with(:sign? => true).returns(stub(:<< => nil))
31
- request = MethodRequest.new('people.findByUsername', :sign? => true)
32
- end
33
-
34
- it "should know that it needs to authenticate the request" do
35
- ParameterList.expects(:new).with(:authenticate? => true).returns(stub(:<< => nil))
36
- request = MethodRequest.new('activity.userPhotos', :authenticate? => true)
37
- end
38
-
39
29
  it "should know the endpoint with full parameters" do
40
30
  query_parameters = 'foo=bar'
41
31