flickraw 0.3.2 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,8 +8,8 @@ require 'open-uri'
8
8
  DESKTOP=1
9
9
 
10
10
  list = flickr.interestingness.getList
11
- photo = list[rand( 100)]
12
- sizes = flickr.photos.getSizes( :photo_id => photo.id)
11
+ photo = list[rand(100)]
12
+ sizes = flickr.photos.getSizes(:photo_id => photo.id)
13
13
  original = sizes.find {|s| s.label == 'Original' }
14
14
 
15
15
  url = original.source
data/flickraw_rdoc.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  require "rdoc/parsers/parserfactory"
2
2
  require "rdoc/parsers/parse_rb"
3
- require "cgi"
4
3
 
5
4
  FLICKR_API_URL='http://www.flickr.com/services/api'
6
5
 
@@ -56,14 +55,12 @@ module RDoc
56
55
  m.singleton = false
57
56
 
58
57
  m.start_collecting_tokens
59
- m.add_token FakedToken.new( <<END
60
- # Generated automatically from the flickr api
58
+ m.add_token FakedToken.new( %{
59
+ # Generated automatically from flickr api
61
60
  def #{name}(*args)
62
- Request.call '#{flickr_method}', *args
61
+ @flickr.call '#{flickr_method}', *args
63
62
  end
64
- END
65
- )
66
-
63
+ } )
67
64
  doc.add_method m
68
65
  progress(".")
69
66
  @stats.num_methods += 1
@@ -86,7 +83,7 @@ END
86
83
  arguments << "[#{arg.name} "
87
84
  arguments << "<em>(required)</em> " if arg.optional == '0'
88
85
  arguments << "] "
89
- arguments << "#{CGI.unescapeHTML(arg.to_s)}\n"
86
+ arguments << "#{unescapeHTML(arg.to_s)}\n"
90
87
  }
91
88
  end
92
89
  end
@@ -95,13 +92,13 @@ END
95
92
  errors = "<b>Error codes</b>\n"
96
93
  info.errors.each {|e|
97
94
  errors << "* #{e.code}: <em>#{e.message}</em>\n\n"
98
- errors << " #{e.to_s}\n"
95
+ errors << " #{unescapeHTML e.to_s}\n"
99
96
  }
100
97
  end
101
98
 
102
99
  if info.method.respond_to? :response
103
100
  response = "<b>Returns</b>\n"
104
- raw = CGI.unescapeHTML(info.method.response.to_s)
101
+ raw = unescapeHTML(info.method.response.to_s)
105
102
  response << raw.collect { |line| line.insert(0, ' ') }.join
106
103
  else
107
104
  response = ''
@@ -133,14 +130,16 @@ END
133
130
  end
134
131
 
135
132
  def unescapeHTML(string)
133
+ string.gsub!('\/', '/')
136
134
  string.gsub(/&(.*?);/n) do
137
135
  match = $1.dup
138
136
  case match
139
- when /\Aamp\z/ni then '&'
140
- when /\Aquot\z/ni then '"'
141
- when /\Agt\z/ni then '>'
142
- when /\Alt\z/ni then '<'
143
- else "&#{match};"
137
+ when /\Aamp\z/ni then '&'
138
+ when /\Aquot\z/ni then '"'
139
+ when /\Agt\z/ni then '>'
140
+ when /\Alt\z/ni then '<'
141
+ when /\Anbsp\z/ni then ' '
142
+ else "&#{match};"
144
143
  end
145
144
  end
146
145
  end
data/lib/flickraw.rb CHANGED
@@ -20,12 +20,12 @@
20
20
  # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
 
23
- require 'rexml/document'
24
23
  require 'net/http'
25
24
  require 'md5'
25
+ require 'yaml'
26
26
 
27
27
  module FlickRaw
28
- VERSION='0.3.2'
28
+ VERSION='0.4'
29
29
 
30
30
  FLICKR_HOST='api.flickr.com'.freeze
31
31
 
@@ -40,67 +40,45 @@ module FlickRaw
40
40
 
41
41
  @api_key = '7b124df89b638e545e3165293883ef62'
42
42
 
43
- # This is a wrapper around the xml response which provides an easy interface.
44
- class Xml
45
- include Enumerable
46
- # Returns the text content of the response
47
- attr_reader :to_s
48
-
49
- # Returns the raw xml of the response
50
- attr_reader :to_xml
51
-
52
- def initialize(xml) # :nodoc:
53
- @to_s = xml.texts.join(' ')
54
- @to_xml = xml.to_s
55
-
56
- xml.attributes.each {|a, v| attribute a, v }
57
-
58
- if xml.name =~ /s\z/
59
- elements = REXML::XPath.match( xml, xml.name.sub(/s\z/, ''))
60
- @list = elements.collect { |e| Xml.new e }
61
- else
62
- @list = [self]
63
- xml.elements.each {|e|
64
- if instance_variable_get "@#{e.name}"
65
- send(e.name) << Xml.new(e)
66
- else
67
- attribute e.name, Xml.new(e)
68
- end
69
- }
70
- end
71
- end
72
-
73
- def [](index); @list[index]; end
74
- def each; @list.each { |el| yield el }; end
75
- def length; @list.length; end
76
-
77
- protected
78
- def << el; @list << el; end
79
-
80
- private
81
- def attribute(sym, value)
82
- instance_variable_set "@#{sym}", value
43
+ module SimpleOStruct # :nodoc:
44
+ def __attr_define(k,v)
45
+ instance_variable_set "@#{k}", v
83
46
  meta = class << self; self; end
84
- meta.class_eval { attr_reader sym.to_s }
47
+ meta.class_eval { attr_reader k.to_s }
85
48
  end
86
49
  end
87
50
 
88
- # This is what you get in response to an API call.
89
- class Response < Xml
90
- # This is called internally. It builds the response object according to xml response from the server.
91
- def initialize(raw_xml)
92
- doc = REXML::Document.new raw_xml
93
- super doc.root
94
- super doc.root.elements[1] if doc.root.elements.size == 1
51
+ class Response # :nodoc:
52
+ include SimpleOStruct
53
+ def initialize(h); h.each {|k, v| __attr_define k, Response.structify(v, k) } end
54
+ def self.structify(obj, name = '')
55
+ if obj.is_a? Hash
56
+ if name =~ /s$/ and obj[$`].is_a? Array
57
+ list = structify obj[$`]
58
+ list.extend SimpleOStruct
59
+ list.instance_eval { obj.each {|kv, vv| __attr_define kv, vv } }
60
+ list
61
+ elsif content = obj['_content']
62
+ content.extend SimpleOStruct
63
+ content.instance_eval { obj.each {|kv, vv| __attr_define kv, vv } }
64
+ content
65
+ else
66
+ blank = Response.new(obj)
67
+ end
68
+ elsif obj.is_a? Array
69
+ obj.collect {|e| structify e}
70
+ else
71
+ obj
72
+ end
95
73
  end
96
74
  end
97
75
 
98
76
  class FailedResponse < StandardError
99
77
  attr_reader :code
100
78
  alias :msg :message
101
- def initialize(msg, code)
79
+ def initialize(msg, code, req)
102
80
  @code = code
103
- super( msg)
81
+ super("'#{req}' - #{msg}")
104
82
  end
105
83
  end
106
84
 
@@ -142,20 +120,13 @@ module FlickRaw
142
120
  end
143
121
 
144
122
  # List of the flickr subobjects of this object
145
- def self.flickr_objects
146
- @flickr_objects ||= []
147
- end
123
+ def self.flickr_objects; @flickr_objects ||= [] end
148
124
 
149
125
  # List of the flickr methods of this object
150
- def self.flickr_methods
151
- @flickr_methods ||= []
152
- end
126
+ def self.flickr_methods; @flickr_methods ||= [] end
153
127
 
154
128
  # Returns the prefix of the request corresponding to this class.
155
- def self.request_name
156
- class_req = name.downcase.gsub( /::/, '.')
157
- class_req.sub( /[^\.]+\./, '') # Removes RawFlickr at the beginning
158
- end
129
+ def self.request_name; name.downcase.gsub(/::/, '.').sub(/[^\.]+\./, '') end
159
130
  end
160
131
 
161
132
  # Root class of the flickr api hierarchy.
@@ -170,14 +141,8 @@ module FlickRaw
170
141
  # Raises FailedResponse if the response status is _failed_.
171
142
  def call(req, args={})
172
143
  path = REST_PATH + build_args(args, req).collect { |a, v| "#{a}=#{v}" }.join('&')
173
-
174
- http_response = Net::HTTP.start(FLICKR_HOST) { |http|
175
- http.get(path, 'User-Agent' => "Flickraw/#{VERSION}")
176
- }
177
- res = Response.new http_response.body
178
- raise FailedResponse.new(res.msg, res.code) if res.stat == 'fail'
179
- lookup_token(req, res)
180
- res
144
+ http_response = Net::HTTP.start(FLICKR_HOST) { |http| http.get(path, 'User-Agent' => "Flickraw/#{VERSION}") }
145
+ parse_response(http_response, req)
181
146
  end
182
147
 
183
148
  # Use this to upload the photo in _file_.
@@ -190,30 +155,45 @@ module FlickRaw
190
155
  boundary = MD5.md5(photo).to_s
191
156
 
192
157
  header = {'Content-type' => "multipart/form-data, boundary=#{boundary} ", 'User-Agent' => "Flickraw/#{VERSION}"}
193
- query = build_args(args).collect { |a, v|
194
- "--#{boundary}\r\n" <<
195
- "Content-Disposition: form-data; name=\"#{a}\"\r\n\r\n" <<
196
- "#{v}\r\n"
197
- }.join('')
198
- query << "--#{boundary}\r\n" <<
199
- "Content-Disposition: form-data; name=\"photo\"; filename=\"#{file}\"\r\n" <<
200
- "Content-Transfer-Encoding: binary\r\n" <<
201
- "Content-Type: image/jpeg\r\n\r\n" <<
202
- photo <<
203
- "\r\n" <<
204
- "--#{boundary}--"
205
-
206
- http_response = Net::HTTP.start(FLICKR_HOST) { |http|
207
- http.post(UPLOAD_PATH, query, header)
158
+ query = ''
159
+ build_args(args).each { |a, v|
160
+ query <<
161
+ "--#{boundary}\r\n" <<
162
+ "Content-Disposition: form-data; name=\"#{a}\"\r\n\r\n" <<
163
+ "#{v}\r\n"
208
164
  }
209
- res = Response.new http_response.body
210
- raise FailedResponse.new(res.msg, res.code) if res.stat == 'fail'
211
- res
165
+ query <<
166
+ "--#{boundary}\r\n" <<
167
+ "Content-Disposition: form-data; name=\"photo\"; filename=\"#{file}\"\r\n" <<
168
+ "Content-Transfer-Encoding: binary\r\n" <<
169
+ "Content-Type: image/jpeg\r\n\r\n" <<
170
+ photo <<
171
+ "\r\n" <<
172
+ "--#{boundary}--"
173
+
174
+ http_response = Net::HTTP.start(FLICKR_HOST) { |http| http.post(UPLOAD_PATH, query, header) }
175
+ xml = http_response.body
176
+ if xml[/stat="(\w+)"/, 1] == 'fail'
177
+ msg = xml[/msg="([^"]+)"/, 1]
178
+ code = xml[/code="([^"]+)"/, 1]
179
+ raise FailedResponse.new(msg, code, 'flickr.upload')
180
+ end
181
+ Response.structify( {:stat => 'ok', :photoid => xml[/<photoid>(\w+)<\/photoid>/, 1], :ticketid => xml[/<ticketid>(\w+)<\/ticketid>/, 1]})
212
182
  end
213
183
 
214
184
  private
185
+ def parse_response(response, req = nil)
186
+ yaml = YAML.load(response.body.gsub(/:([^\s])/, ': \1'))
187
+ raise FailedResponse.new(yaml['message'], yaml['code'], req) if yaml.delete('stat') == 'fail'
188
+ name, yaml = yaml.to_a.first if yaml.size == 1
189
+
190
+ res = Response.structify yaml, name
191
+ lookup_token(req, res)
192
+ res
193
+ end
194
+
215
195
  def build_args(args={}, req = nil)
216
- full_args = {:api_key => FlickRaw.api_key}
196
+ full_args = {:api_key => FlickRaw.api_key, :format => 'json', :nojsoncallback => 1}
217
197
  full_args[:method] = req if req
218
198
  full_args[:auth_token] = @token if @token
219
199
  args.each {|k, v| full_args[k.to_sym] = v }
@@ -223,7 +203,7 @@ module FlickRaw
223
203
 
224
204
  def lookup_token(req, res)
225
205
  token_reqs = ['flickr.auth.getToken', 'flickr.auth.getFullToken', 'flickr.auth.checkToken']
226
- @token = res.token if token_reqs.include?(req) and res.respond_to?( :token)
206
+ @token = res.token if token_reqs.include?(req) and res.respond_to?(:token)
227
207
  end
228
208
  end
229
209
 
@@ -238,7 +218,6 @@ module FlickRaw
238
218
  def auth_url(args={})
239
219
  full_args = {:api_key => FlickRaw.api_key, :perms => 'read'}
240
220
  args.each {|k, v| full_args[k.to_sym] = v }
241
-
242
221
  full_args[:api_sig] = api_sig(full_args) if FlickRaw.shared_secret
243
222
 
244
223
  'http://' + FLICKR_HOST + AUTH_PATH + full_args.collect { |a, v| "#{a}=#{v}" }.join('&')
@@ -251,7 +230,7 @@ module FlickRaw
251
230
  end
252
231
 
253
232
  methods = Flickr.new.call 'flickr.reflection.getMethods'
254
- methods.each { |method| Flickr.build_request method.to_s }
233
+ methods.each { |method| Flickr.build_request method }
255
234
  end
256
235
 
257
236
  class Object
@@ -260,7 +239,5 @@ class Object
260
239
  #
261
240
  # recent_photos = flickr.photos.getRecent
262
241
  # puts recent_photos[0].title
263
- def flickr
264
- @flickr ||= FlickRaw::Flickr.new
265
- end
242
+ def flickr; @flickr ||= FlickRaw::Flickr.new end
266
243
  end
data/rakefile CHANGED
@@ -1,11 +1,12 @@
1
1
  require 'rake/rdoctask'
2
2
  require 'rake/packagetask'
3
3
  require 'rake/gempackagetask'
4
+ require 'rake/testtask'
4
5
 
5
6
  require 'lib/flickraw'
6
7
  require 'flickraw_rdoc'
7
8
 
8
- PKG_FILES = FileList["lib/flickraw.rb", "flickraw_rdoc.rb", "copying.txt", "README", "TODO", "rakefile", "examples/*.rb"].to_a
9
+ PKG_FILES = FileList["lib/flickraw.rb", "flickraw_rdoc.rb", "copying.txt", "README", "TODO", "rakefile", "examples/*.rb", "test/*.rb"].to_a
9
10
 
10
11
  spec = Gem::Specification.new do |s|
11
12
  s.summary = "Flickr library with a syntax close to the syntax described on http://www.flickr.com/services/api"
@@ -29,3 +30,4 @@ Rake::GemPackageTask.new spec do |p|
29
30
  p.need_tar_gz = true
30
31
  end
31
32
 
33
+ Rake::TestTask.new
data/test/test.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'test/unit'
2
+ require 'lib/flickraw'
3
+
4
+ class Basic < Test::Unit::TestCase
5
+ def test_known
6
+ known_methods = ["flickr.activity.userComments", "flickr.activity.userPhotos", "flickr.auth.checkToken", "flickr.auth.getFrob", "flickr.auth.getFullToken", "flickr.auth.getToken", "flickr.blogs.getList", "flickr.blogs.postPhoto", "flickr.contacts.getList", "flickr.contacts.getPublicList", "flickr.favorites.add", "flickr.favorites.getList", "flickr.favorites.getPublicList", "flickr.favorites.remove", "flickr.groups.browse", "flickr.groups.getInfo", "flickr.groups.pools.add", "flickr.groups.pools.getContext", "flickr.groups.pools.getGroups", "flickr.groups.pools.getPhotos", "flickr.groups.pools.remove", "flickr.groups.search", "flickr.interestingness.getList", "flickr.people.findByEmail", "flickr.people.findByUsername", "flickr.people.getInfo", "flickr.people.getPublicGroups", "flickr.people.getPublicPhotos", "flickr.people.getUploadStatus", "flickr.photos.addTags", "flickr.photos.comments.addComment", "flickr.photos.comments.deleteComment", "flickr.photos.comments.editComment", "flickr.photos.comments.getList", "flickr.photos.delete", "flickr.photos.geo.getLocation", "flickr.photos.geo.getPerms", "flickr.photos.geo.removeLocation", "flickr.photos.geo.setLocation", "flickr.photos.geo.setPerms", "flickr.photos.getAllContexts", "flickr.photos.getContactsPhotos", "flickr.photos.getContactsPublicPhotos", "flickr.photos.getContext", "flickr.photos.getCounts", "flickr.photos.getExif", "flickr.photos.getFavorites", "flickr.photos.getInfo", "flickr.photos.getNotInSet", "flickr.photos.getPerms", "flickr.photos.getRecent", "flickr.photos.getSizes", "flickr.photos.getUntagged", "flickr.photos.getWithGeoData", "flickr.photos.getWithoutGeoData", "flickr.photos.licenses.getInfo", "flickr.photos.licenses.setLicense", "flickr.photos.notes.add", "flickr.photos.notes.delete", "flickr.photos.notes.edit", "flickr.photos.recentlyUpdated", "flickr.photos.removeTag", "flickr.photos.search", "flickr.photos.setDates", "flickr.photos.setMeta", "flickr.photos.setPerms", "flickr.photos.setTags", "flickr.photos.transform.rotate", "flickr.photos.upload.checkTickets", "flickr.photosets.addPhoto", "flickr.photosets.comments.addComment", "flickr.photosets.comments.deleteComment", "flickr.photosets.comments.editComment", "flickr.photosets.comments.getList", "flickr.photosets.create", "flickr.photosets.delete", "flickr.photosets.editMeta", "flickr.photosets.editPhotos", "flickr.photosets.getContext", "flickr.photosets.getInfo", "flickr.photosets.getList", "flickr.photosets.getPhotos", "flickr.photosets.orderSets", "flickr.photosets.removePhoto", "flickr.reflection.getMethodInfo", "flickr.reflection.getMethods", "flickr.tags.getHotList", "flickr.tags.getListPhoto", "flickr.tags.getListUser", "flickr.tags.getListUserPopular", "flickr.tags.getListUserRaw", "flickr.tags.getRelated", "flickr.test.echo", "flickr.test.login", "flickr.test.null", "flickr.urls.getGroup", "flickr.urls.getUserPhotos", "flickr.urls.getUserProfile", "flickr.urls.lookupGroup", "flickr.urls.lookupUser"]
7
+ found_methods = flickr.reflection.getMethods
8
+ assert_instance_of Array, found_methods
9
+ known_methods.each { |m| assert found_methods.include?(m), m}
10
+ end
11
+
12
+ def test_found
13
+ found_methods = flickr.reflection.getMethods
14
+ found_methods.each { |m|
15
+ assert_nothing_raised {
16
+ begin
17
+ eval m
18
+ rescue FlickRaw::FailedResponse
19
+ end
20
+ }
21
+ }
22
+ end
23
+
24
+ def test_photos
25
+ list = flickr.photos.getRecent :per_page => '10'
26
+ assert_instance_of Array, list
27
+ assert_equal(list.size, 10)
28
+
29
+ id = secret = info = nil
30
+ assert_nothing_raised(NoMethodError) {
31
+ id = list[0].id
32
+ secret = list[0].secret
33
+ }
34
+ assert_nothing_raised(FlickRaw::FailedResponse) {
35
+ info = flickr.photos.getInfo :photo_id => id, :secret => secret
36
+ }
37
+ assert_respond_to info, :id
38
+ assert_respond_to info, :secret
39
+ assert_respond_to info, :title
40
+ assert_respond_to info, :description
41
+ assert_respond_to info, :owner
42
+ assert_respond_to info, :dates
43
+ assert_respond_to info, :comments
44
+ assert_respond_to info, :tags
45
+ end
46
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
3
3
  specification_version: 1
4
4
  name: flickraw
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.2
7
- date: 2006-10-24 00:00:00 +02:00
6
+ version: "0.4"
7
+ date: 2007-01-09 00:00:00 +01:00
8
8
  summary: Flickr library with a syntax close to the syntax described on http://www.flickr.com/services/api
9
9
  require_paths:
10
10
  - lib
@@ -35,10 +35,11 @@ files:
35
35
  - README
36
36
  - TODO
37
37
  - rakefile
38
+ - examples/flickr_KDE.rb
38
39
  - examples/auth.rb
39
40
  - examples/interestingness.rb
40
- - examples/flickr_KDE.rb
41
41
  - examples/upload.rb
42
+ - test/test.rb
42
43
  test_files: []
43
44
 
44
45
  rdoc_options: []