flickraw 0.1

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 (4) hide show
  1. data/flickraw_rdoc.rb +136 -0
  2. data/lib/flickraw.rb +225 -0
  3. data/rakefile +30 -0
  4. metadata +48 -0
@@ -0,0 +1,136 @@
1
+ require "rdoc/parsers/parserfactory"
2
+ require "rdoc/parsers/parse_rb"
3
+ #require "flickraw"
4
+ require "cgi"
5
+
6
+ FLICKR_API_URL='http://www.flickr.com/services/api'
7
+
8
+ FakedToken = Struct.new :text
9
+
10
+ module RDoc
11
+ class FlickrawParser < RubyParser
12
+ extend ParserFactory
13
+ parse_files_matching(/flickraw\.rb$/)
14
+
15
+ def scan
16
+ super
17
+
18
+ fr = @top_level.find_module_named 'FlickRaw'
19
+ k = fr.add_class NormalClass, 'Flickr', 'FlickRaw::Request'
20
+ k.record_location @top_level
21
+ @stats.num_classes += 1
22
+
23
+ add_flickr_methods(FlickRaw::Flickr, k)
24
+ @top_level
25
+ end
26
+
27
+ private
28
+ def add_flickr_methods(obj, doc)
29
+ obj.constants.each { |const_name|
30
+ const = obj.const_get const_name
31
+ if const.is_a?(Class) && const < FlickRaw::Request
32
+ name = const.name.sub(/.*::/, '')
33
+ k = doc.add_class NormalClass, name, 'FlickRaw::Request'
34
+ k.record_location @top_level
35
+ @stats.num_classes += 1
36
+
37
+ m = AnyMethod.new nil, name.downcase
38
+ m.comment = "Returns a #{name} object."
39
+ m.params = ''
40
+ m.singleton = false
41
+ doc.add_method m
42
+
43
+ progress("c")
44
+ @stats.num_methods += 1
45
+
46
+ add_flickr_methods(const, k)
47
+ end
48
+ }
49
+
50
+ obj.flickr_methods.each {|name|
51
+ flickr_method = obj.request_name + '.' + name
52
+ info = flickr.reflection.getMethodInfo :method_name => flickr_method
53
+
54
+ m = AnyMethod.new nil, name
55
+ m.comment = flickr_method_comment(info)
56
+ m.params = flickr_method_args(info)
57
+ m.singleton = false
58
+
59
+ m.start_collecting_tokens
60
+ m.add_token FakedToken.new( <<END
61
+ # Generated automatically from the flickr api
62
+ def #{name}(*args)
63
+ Request.call '#{flickr_method}', *args
64
+ end
65
+ END
66
+ )
67
+
68
+ doc.add_method m
69
+ progress(".")
70
+ @stats.num_methods += 1
71
+ }
72
+ end
73
+
74
+ def flickr_method_comment(info)
75
+ description = CGI.unescapeHTML(info.method.description.to_s)
76
+ # description.gsub!( /<\/?(\w+)>/ ) {|b|
77
+ # return b if ['em', 'b', 'tt'].include? $1
78
+ # return ''
79
+ # }
80
+
81
+ if info.respond_to? :arguments
82
+ args = info.arguments.select { |arg| arg.name != 'api_key' }
83
+
84
+ arguments = "<b>Arguments</b>\n"
85
+ if args.size > 0
86
+ args.each {|arg|
87
+ arguments << "[#{arg.name} "
88
+ arguments << "<em>(required)</em> " if arg.optional == '0'
89
+ arguments << "] "
90
+ arguments << "#{CGI.unescapeHTML(arg.to_s)}\n"
91
+ }
92
+ end
93
+ end
94
+
95
+ if info.respond_to? :errors
96
+ errors = "<b>Error codes</b>\n"
97
+ info.errors.each {|e|
98
+ errors << "* #{e.code}: <em>(#{e.message})</em>\n\n"
99
+ errors << " #{e.to_s}\n"
100
+ }
101
+ end
102
+
103
+ if info.method.respond_to? :response
104
+ response = "<b>Output</b>\n"
105
+ raw = CGI.unescapeHTML(info.method.response.to_s)
106
+ response << raw.collect { |line| line.insert(0, ' ') }.join
107
+ else
108
+ response = ''
109
+ end
110
+
111
+ str = "{#{info.method.name}}[#{FLICKR_API_URL}/#{info.method.name}.html] request.\n\n"
112
+ str << description << "\n\n"
113
+ str << arguments << "\n\n"
114
+ str << errors << "\n\n"
115
+ str << response << "\n\n"
116
+ end
117
+
118
+ def flickr_method_args(info)
119
+ str = ''
120
+ if info.respond_to? :arguments
121
+ args = info.arguments.select { |arg| arg.name != 'api_key' }
122
+
123
+ if args.size > 0
124
+ str << '('
125
+ args.each {|arg|
126
+ str << ":#{arg.name} => '#{arg.name}'"
127
+ str << ','
128
+ }
129
+ str.chomp! ','
130
+ str << ')'
131
+ end
132
+ end
133
+ str
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,225 @@
1
+ # Copyright (c) 2006 Hank Lords <hanklords@gmail.com>
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+
23
+ require 'rexml/document'
24
+ require 'open-uri'
25
+ require 'md5'
26
+
27
+ module FlickRaw
28
+ VERSION='0.1'
29
+
30
+ # URL of the flickr REST api
31
+ REST_URL='http://www.flickr.com/services/rest/?'.freeze
32
+
33
+ # URL of the flickr auth page
34
+ AUTH_URL='http://flickr.com/services/auth/?'
35
+
36
+ @api_key = '7b124df89b638e545e3165293883ef62'
37
+
38
+ # This is a wrapper around the xml response which provides an easy interface.
39
+ class Xml
40
+ # Returns the text content of the response
41
+ attr_reader :to_s
42
+
43
+ # Returns the raw xml of the response
44
+ attr_reader :to_xml
45
+
46
+ def initialize(xml) # :nodoc:
47
+ @to_s = xml.texts.join(' ')
48
+ @to_xml = xml.to_s
49
+ @list = nil
50
+
51
+ xml.attributes.each {|a, v| attribute a, v }
52
+
53
+ if xml.name =~ /s\z/
54
+ elements = REXML::XPath.match( xml, xml.name.sub(/s\z/, ''))
55
+ unless elements.empty?
56
+ @list = elements.collect { |e| Xml.new e }
57
+ end
58
+ else
59
+ xml.elements.each {|e| attribute e.name, Xml.new(e) }
60
+ end
61
+ end
62
+
63
+ def respond_to?(m) # :nodoc:
64
+ super || @list.respond_to?(m)
65
+ end
66
+
67
+ private
68
+ def method_missing(sym, *args, &block)
69
+ if @list.respond_to?( sym)
70
+ @list.send sym, *args, &block
71
+ else
72
+ super
73
+ end
74
+ end
75
+
76
+ def attribute(sym, value)
77
+ meta = class << self; self; end
78
+ meta.class_eval { define_method(sym) { value } }
79
+ end
80
+ end
81
+
82
+ # This is what you get in response to an API call.
83
+ class Response < Xml
84
+ # This is called internally. It builds the response object according to xml response from the server.
85
+ def initialize(raw_xml)
86
+ doc = REXML::Document.new raw_xml
87
+ super doc.root
88
+ super doc.root.elements[1] if doc.root.elements.size == 1
89
+ end
90
+ end
91
+
92
+ class FailedResponse < StandardError
93
+ attr_reader :code
94
+ alias :msg :message
95
+ def initialize(msg, code)
96
+ @code = code
97
+ super( msg)
98
+ end
99
+ end
100
+
101
+ class Request
102
+ def initialize(flickr = nil) # :nodoc:
103
+ @flickr = flickr
104
+
105
+ self.class.flickr_objects.each {|name|
106
+ klass = self.class.const_get name.capitalize
107
+ instance_variable_set "@#{name}", klass.new(@flickr)
108
+ }
109
+ end
110
+
111
+ def self.build_request(req) # :nodoc:
112
+ method_nesting = req.split '.'
113
+ raise "'#{@name}' : Method name mismatch" if method_nesting.shift != request_name.split('.').last
114
+
115
+ if method_nesting.size > 1
116
+ name = method_nesting.first
117
+ class_name = name.capitalize
118
+ if const_defined? class_name
119
+ klass = const_get( class_name)
120
+ else
121
+ klass = Class.new Request
122
+ const_set(class_name, klass)
123
+ attr_reader name
124
+ flickr_objects << name
125
+ end
126
+
127
+ klass.build_request method_nesting.join('.')
128
+ else
129
+ req = method_nesting.first
130
+ define_method(req) { |*args|
131
+ class_req = self.class.request_name
132
+ @flickr.call class_req + '.' + req, *args
133
+ }
134
+ flickr_methods << req
135
+ end
136
+ end
137
+
138
+ # List of the flickr subobjects of this object
139
+ def self.flickr_objects
140
+ @flickr_objects ||= []
141
+ end
142
+
143
+ # List of the flickr methods of this object
144
+ def self.flickr_methods
145
+ @flickr_methods ||= []
146
+ end
147
+
148
+ # Returns the prefix of the request corresponding to this class.
149
+ def self.request_name
150
+ class_req = name.downcase.gsub( /::/, '.')
151
+ class_req.sub( /[^\.]+\./, '') # Removes RawFlickr at the beginning
152
+ end
153
+ end
154
+
155
+ # Root class of the flickr api hierarchy.
156
+ class Flickr < Request
157
+ def initialize # :nodoc:
158
+ super self
159
+ @token = nil
160
+ end
161
+
162
+ # This is the central method. It does the actual request to the flickr server.
163
+ #
164
+ # Raises FailedResponse if the response status is _failed_.
165
+ def call(req, args={})
166
+ url = build_call_url(req, args)
167
+ res = Response.new open(url, 'User-Agent' => "Flickraw/#{VERSION}")
168
+ raise FailedResponse.new( res.msg, res.code) if res.stat == 'fail'
169
+ lookup_token( req, res)
170
+ res
171
+ end
172
+
173
+ private
174
+ def build_call_url(req, args={})
175
+ full_args = {:api_key => FlickRaw.api_key, :method => req}
176
+ full_args[:auth_token] = @token if @token
177
+ args.each {|k, v| full_args[k.to_sym] = v }
178
+ full_args[:api_sig] = FlickRaw.api_sig(full_args) if FlickRaw.shared_secret
179
+
180
+ url = REST_URL + full_args.collect { |a, v| "#{a}=#{v}" }.join('&')
181
+ end
182
+
183
+ def lookup_token(req, res)
184
+ token_reqs = ['flickr.auth.getToken', 'flickr.auth.getFullToken']
185
+ @token = res.token if token_reqs.include?(req) and res.respond_to?( :token)
186
+ end
187
+ end
188
+
189
+ class << self
190
+ # Your flickr API key, see http://www.flickr.com/services/api/keys for more information
191
+ attr_accessor :api_key
192
+
193
+ # The shared secret of _api_key_, see http://www.flickr.com/services/api/keys for more information
194
+ attr_accessor :shared_secret
195
+
196
+ # Returns the flickr auth URL.
197
+ def auth_url(args={})
198
+ full_args = {:api_key => FlickRaw.api_key, :perms => 'read'}
199
+ args.each {|k, v| full_args[k.to_sym] = v }
200
+
201
+ full_args[:api_sig] = api_sig(full_args) if FlickRaw.shared_secret
202
+
203
+ url = AUTH_URL + full_args.collect { |a, v| "#{a}=#{v}" }.join('&')
204
+ end
205
+
206
+ # Returns the signature of hsh. This is meant to be passed in the _api_sig_ parameter.
207
+ def api_sig(hsh)
208
+ MD5.md5(FlickRaw.shared_secret + hsh.sort{|a, b| a[0].to_s <=> b[0].to_s }.flatten.join).to_s
209
+ end
210
+ end
211
+
212
+ methods = Flickr.new.call 'flickr.reflection.getMethods'
213
+ methods.each { |method| Flickr.build_request method.to_s }
214
+ end
215
+
216
+ class Object
217
+ # Use this to access the flickr API easily. You can type directly the flickr requests as they are described on the flickr website.
218
+ # require 'flickraw'
219
+ #
220
+ # recent_photos = flickr.photos.getRecent
221
+ # puts recent_photos[0].title
222
+ def flickr
223
+ @flickr ||= FlickRaw::Flickr.new
224
+ end
225
+ end
@@ -0,0 +1,30 @@
1
+ require 'rake/rdoctask'
2
+ require 'rake/packagetask'
3
+ require 'rake/gempackagetask'
4
+
5
+ require 'lib/flickraw'
6
+ require 'flickraw_rdoc'
7
+
8
+ PKG_FILES = FileList["lib/flickraw.rb", "flickraw_rdoc.rb", "rakefile"].to_a
9
+
10
+ spec = Gem::Specification.new do |s|
11
+ s.summary = "Flickr library with a syntax close to the syntax described on http://www.flickr.com/services/api"
12
+ s.name = "flickraw"
13
+ s.author = "Hank Lords"
14
+ s.email = "hanklords@gmail.com"
15
+ s.version = FlickRaw::VERSION
16
+ s.has_rdoc = true
17
+ s.require_path = 'lib'
18
+ s.autorequire = 'rake'
19
+ s.files = PKG_FILES
20
+ s.description = "Flickr library with a syntax close to the syntax described on http://www.flickr.com/services/api"
21
+ end
22
+
23
+ Rake::RDocTask.new do |rd|
24
+ rd.rdoc_files.include "README", "lib/flickraw.rb", "TODO"
25
+ rd.options << "--inline-source"
26
+ end
27
+
28
+ Rake::GemPackageTask.new spec do |p|
29
+ p.need_tar_gz = true
30
+ end
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.0
3
+ specification_version: 1
4
+ name: flickraw
5
+ version: !ruby/object:Gem::Version
6
+ version: "0.1"
7
+ date: 2006-07-11 00:00:00 +02:00
8
+ summary: Flickr library with a syntax close to the syntax described on http://www.flickr.com/services/api
9
+ require_paths:
10
+ - lib
11
+ email: hanklords@gmail.com
12
+ homepage:
13
+ rubyforge_project:
14
+ description: Flickr library with a syntax close to the syntax described on http://www.flickr.com/services/api
15
+ autorequire: rake
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Hank Lords
31
+ files:
32
+ - lib/flickraw.rb
33
+ - flickraw_rdoc.rb
34
+ - rakefile
35
+ test_files: []
36
+
37
+ rdoc_options: []
38
+
39
+ extra_rdoc_files: []
40
+
41
+ executables: []
42
+
43
+ extensions: []
44
+
45
+ requirements: []
46
+
47
+ dependencies: []
48
+