infomeme_client 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +8 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/infomeme_client/base.rb +77 -0
- data/lib/infomeme_client/communication.rb +75 -0
- data/lib/infomeme_client/entity_hash/comment.rb +2 -0
- data/lib/infomeme_client/entity_hash/meme.rb +45 -0
- data/lib/infomeme_client/entity_hash/meme_type.rb +2 -0
- data/lib/infomeme_client/entity_hash/transaction.rb +3 -0
- data/lib/infomeme_client/entity_hash/user.rb +2 -0
- data/lib/infomeme_client/entity_hash.rb +65 -0
- data/lib/infomeme_client/errors.rb +22 -0
- data/lib/infomeme_client/functions/meme.rb +23 -0
- data/lib/infomeme_client/functions/user.rb +55 -0
- data/lib/infomeme_client/functions/user_meme.rb +94 -0
- data/lib/infomeme_client/functions/user_transaction.rb +21 -0
- data/lib/infomeme_client/functions.rb +16 -0
- data/lib/infomeme_client/meme_application.rb +18 -0
- data/lib/infomeme_client/permissions.rb +22 -0
- data/lib/infomeme_client/response.rb +51 -0
- data/lib/infomeme_client.rb +21 -0
- data/test/fixtures/memes/comments.json +1 -0
- data/test/fixtures/memes/meme.json +1 -0
- data/test/fixtures/memes/memes.json +1 -0
- data/test/fixtures/memes/types.json +1 -0
- data/test/fixtures/oauth/access_token.json +1 -0
- data/test/fixtures/oauth/authorize.json +1 -0
- data/test/fixtures/oauth/permissions.json +1 -0
- data/test/fixtures/oauth/request_token.json +1 -0
- data/test/fixtures/oauth/verify_access.json +1 -0
- data/test/fixtures/response/error.json +1 -0
- data/test/fixtures/response/ok.json +1 -0
- data/test/fixtures/response/test.json +1 -0
- data/test/fixtures/response/test_extract.json +1 -0
- data/test/fixtures/users/memes.json +1 -0
- data/test/fixtures/users/permissions.json +1 -0
- data/test/fixtures/users/user.json +1 -0
- data/test/fixtures/users/user_public.json +1 -0
- data/test/helper.rb +69 -0
- data/test/test_authorization.rb +56 -0
- data/test/test_communication.rb +46 -0
- data/test/test_entity_hash.rb +15 -0
- data/test/test_meme_functions.rb +46 -0
- data/test/test_permissions.rb +25 -0
- data/test/test_user_functions.rb +15 -0
- data/test/test_user_meme_functions.rb +47 -0
- metadata +164 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Infomeme Ltd.
|
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
|
12
|
+
included in all 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
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "infomeme_client"
|
8
|
+
gem.summary = "A RubyGem for implementing both Infomeme client and meme applications."
|
9
|
+
gem.description = gem.summary
|
10
|
+
gem.email = "infomeme@infomeme.com"
|
11
|
+
gem.homepage = "https://api.infomeme.com"
|
12
|
+
gem.authors = ["Infomeme Ltd."]
|
13
|
+
gem.add_dependency "oauth"
|
14
|
+
gem.add_dependency "json"
|
15
|
+
gem.add_dependency "multipart-post"
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/test_*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "infomeme_client #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module InfomemeClient::Base
|
2
|
+
def initialize(options = {})
|
3
|
+
self.consumer = OAuth::Consumer.new(options[:api_key] || ::INFOMEME_API_KEY, options[:api_secret] || ::INFOMEME_API_SECRET, :site => options[:site] || ::INFOMEME_API_SITE)
|
4
|
+
self.default_language = options[:language] || "en"
|
5
|
+
self.default_currency = options[:currency] || "usd"
|
6
|
+
case
|
7
|
+
when options.key?(:token) && options.key?(:secret) then authorize_with_token(options[:token], options[:secret])
|
8
|
+
when options.key?(:login) && options.key?(:password) then authorize_with_credentials(options[:login], options[:password])
|
9
|
+
else deauthorize
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def request_authorization
|
14
|
+
response = handle_response :get, consumer.request_token_url
|
15
|
+
response.request_token
|
16
|
+
end
|
17
|
+
|
18
|
+
def authorize_url(token, permissions = [])
|
19
|
+
"https://infomeme.com/authorize?token=#{token}&permissions=#{permissions.join(',')}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def authorize_with_verifier(token, secret, verifier)
|
23
|
+
req_token = OAuth::RequestToken.new(consumer, token, secret)
|
24
|
+
response = token_request(req_token, :get, finalize_get_url(consumer.access_token_url, {:oauth_verifier => verifier})) #do request with request_token
|
25
|
+
return false if response.error?
|
26
|
+
authorize_with_token(response.access_token.token, response.access_token.secret)
|
27
|
+
end
|
28
|
+
|
29
|
+
def authorize_with_token(token, secret)
|
30
|
+
access_token = OAuth::AccessToken.new(consumer, token, secret)
|
31
|
+
response = token_request(access_token, :get, "/oauth/verify_access")
|
32
|
+
return false if response.error?
|
33
|
+
self.verified_user = response.user_id
|
34
|
+
self.token = access_token
|
35
|
+
refresh_user_data
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def authorize_with_credentials(login, password, permissions = nil)
|
40
|
+
req_token = request_authorization
|
41
|
+
response = put(consumer.authorize_url, {:oauth_token => req_token.token, :login => login, :password => password, :permissions => permissions || all_permissions.collect {|perm| perm.id}})
|
42
|
+
return false if response.error?
|
43
|
+
authorize_with_verifier(req_token.token, req_token.secret, response.verifier)
|
44
|
+
end
|
45
|
+
|
46
|
+
def deauthorize
|
47
|
+
self.verified_user = nil
|
48
|
+
self.token = OAuth::AccessToken.new(consumer)
|
49
|
+
refresh_user_data
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def authorized?
|
54
|
+
! verified_user.nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
def credentials(just = nil)
|
58
|
+
creds = {
|
59
|
+
:login => verified_user,
|
60
|
+
:token => token.token,
|
61
|
+
:secret => token.secret,
|
62
|
+
}
|
63
|
+
creds.key?(just) ? creds[just] : creds
|
64
|
+
end
|
65
|
+
|
66
|
+
def inspect
|
67
|
+
"#<#{self.class.name}: #{authorized? ? credentials.merge({:permissions => (all_permissions || []).select {|perm| has_permission?(perm.id)}.collect {|perm| perm.name}}).inspect : 'not authorized'}>"
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
attr_accessor :consumer, :token, :verified_user
|
72
|
+
|
73
|
+
def refresh_user_data
|
74
|
+
refresh_settings
|
75
|
+
refresh_permissions
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module InfomemeClient::Communication
|
2
|
+
def get(path, headers = {})
|
3
|
+
request(:get, path, headers)
|
4
|
+
end
|
5
|
+
|
6
|
+
def post(path, body = "", headers = {})
|
7
|
+
request(:post, path, body, headers)
|
8
|
+
end
|
9
|
+
|
10
|
+
def put(path, body = "", headers = {})
|
11
|
+
request(:put, path, body, headers)
|
12
|
+
end
|
13
|
+
|
14
|
+
def request(method, path, *args)
|
15
|
+
token_request(token, method, path, *args)
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle_response(method, path, *args, &block)
|
19
|
+
response = request(method, path, *args)
|
20
|
+
response.raise_error
|
21
|
+
if block_given?
|
22
|
+
if block.arity == 1
|
23
|
+
yield response
|
24
|
+
else
|
25
|
+
yield unless response.error?
|
26
|
+
end
|
27
|
+
else
|
28
|
+
response
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def extract_from_response(extract, method, path, *args)
|
33
|
+
handle_response(method, path, *args) do |resp|
|
34
|
+
resp.extract(extract) unless resp.error?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def extract_or_response(extract, method, path, options, headers = {})
|
39
|
+
no_extract = options[:no_extract] || false
|
40
|
+
options.delete(:no_extract)
|
41
|
+
if [:put, :post].include?(method.to_sym)
|
42
|
+
args = [method, path, options, headers]
|
43
|
+
else
|
44
|
+
args = [method, finalize_get_url(path, options), headers]
|
45
|
+
end
|
46
|
+
if no_extract
|
47
|
+
handle_response *args
|
48
|
+
else
|
49
|
+
extract_from_response *args.unshift(extract)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
def token_request(token, method, path, *args)
|
55
|
+
body = [:post, :put].include?(method.to_sym) ? (args.shift || {}) : {}
|
56
|
+
headers = args.shift || {}
|
57
|
+
headers.store("Accept", "application/json") #override to use json
|
58
|
+
if [:post, :put].include?(method.to_sym) && (! headers.key?("Content-Type") || headers["Content-Type"] == "application/json")
|
59
|
+
body = JSON.generate(body) unless body.is_a?(String)
|
60
|
+
headers.store("Content-Type", "application/json")
|
61
|
+
end
|
62
|
+
args.unshift headers
|
63
|
+
args.unshift body if [:post, :put].include?(method.to_sym)
|
64
|
+
begin
|
65
|
+
resp = token.request(method, path, *args).body
|
66
|
+
InfomemeClient::Response.new JSON.parse(resp)
|
67
|
+
rescue => e
|
68
|
+
InfomemeClient::Response.new e
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def finalize_get_url(url, params)
|
73
|
+
url + (url.include?("?") ? "&" : "?") + params.collect {|key, val| "#{key.to_s}=#{val.to_s}"}.join("&")
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class InfomemeClient::EntityHash::Meme < InfomemeClient::EntityHash
|
2
|
+
def initialize(meme, client)
|
3
|
+
super(meme, true)
|
4
|
+
@client = client
|
5
|
+
freeze
|
6
|
+
end
|
7
|
+
|
8
|
+
#todo: have_access?, published_by_me?, confirmed?, inactive?, incomplete?, has_upload?, etc.
|
9
|
+
|
10
|
+
def update(options = {})
|
11
|
+
@client.update_meme(id, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def delete
|
15
|
+
@client.delete_meme(id)
|
16
|
+
end
|
17
|
+
|
18
|
+
def confirm
|
19
|
+
@client.confirm_meme(id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def activate
|
23
|
+
@client.activate_meme(id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def deactivate
|
27
|
+
@client.deactivate_meme(id)
|
28
|
+
end
|
29
|
+
|
30
|
+
def upload_url(raw = false)
|
31
|
+
@client.upload_for_meme(id, raw)
|
32
|
+
end
|
33
|
+
|
34
|
+
def upload(file)
|
35
|
+
@client.upload(id, file)
|
36
|
+
end
|
37
|
+
|
38
|
+
def rate(rating)
|
39
|
+
@client.rate(id, rating)
|
40
|
+
end
|
41
|
+
|
42
|
+
def comment(comment)
|
43
|
+
@client.comment(id, comment)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class InfomemeClient::EntityHash
|
2
|
+
autoload :Comment, "infomeme_client/entity_hash/comment"
|
3
|
+
autoload :Meme, "infomeme_client/entity_hash/meme"
|
4
|
+
autoload :MemeType, "infomeme_client/entity_hash/meme_type"
|
5
|
+
autoload :Transaction, "infomeme_client/entity_hash/transaction"
|
6
|
+
autoload :User, "infomeme_client/entity_hash/user"
|
7
|
+
|
8
|
+
def initialize(hsh, no_freeze = false)
|
9
|
+
@hsh = hsh.inject({}) {|memo, keyvalue| #ripped from ActiveSupport, http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Hash/Keys.html#M000904
|
10
|
+
key, value = keyvalue
|
11
|
+
memo[(key.to_sym rescue key) || key] = map_values(value)
|
12
|
+
memo
|
13
|
+
}
|
14
|
+
freeze unless no_freeze
|
15
|
+
end
|
16
|
+
|
17
|
+
def method_missing(sym)
|
18
|
+
@hsh.key?(sym) ? @hsh[sym] : super
|
19
|
+
end
|
20
|
+
|
21
|
+
def respond_to?(sym, include_private = false)
|
22
|
+
@hsh.key?(sym) ? true : super
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_hash
|
26
|
+
@hsh.inject({}) do |memo, (key, value)|
|
27
|
+
memo[key] = extract_values(value)
|
28
|
+
memo
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def freeze
|
33
|
+
@hsh.each do |key, val|
|
34
|
+
deep_freeze(val)
|
35
|
+
end
|
36
|
+
@hsh.freeze
|
37
|
+
super
|
38
|
+
end
|
39
|
+
|
40
|
+
def id
|
41
|
+
@hsh.key?(:id) ? @hsh[:id] : super
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def map_values(val)
|
46
|
+
case
|
47
|
+
when val.is_a?(Hash) then InfomemeClient::EntityHash.new(val)
|
48
|
+
when val.is_a?(Array) then val.collect {|obj| map_values(obj)}
|
49
|
+
else val
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def extract_values(val)
|
54
|
+
case
|
55
|
+
when val.is_a?(InfomemeClient::EntityHash) then val.to_hash
|
56
|
+
when val.is_a?(Array) then val.collect {|obj| extract_values(obj)}
|
57
|
+
else val
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def deep_freeze(val)
|
62
|
+
val.each {|obj| deep_freeze(obj)} if val.is_a?(Array)
|
63
|
+
val.freeze
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class InfomemeClient::Error < StandardError
|
2
|
+
class RequestFailed < self ; end
|
3
|
+
class InternalError < self ; end
|
4
|
+
class NoAccess < self ; end
|
5
|
+
class NotFound < self ; end
|
6
|
+
|
7
|
+
attr_reader :errors
|
8
|
+
|
9
|
+
def initialize(args)
|
10
|
+
@errors = args.shift
|
11
|
+
msg = args.shift
|
12
|
+
super(msg)
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
"#{super} Errors: #{errors.inspect}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def inspect
|
20
|
+
"<#{self.class.inspect} #{self.message}>"
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module InfomemeClient::Functions::Meme
|
2
|
+
def browse(options = {})
|
3
|
+
get_memes "/memes", options
|
4
|
+
end
|
5
|
+
|
6
|
+
def search(search_token, options = {})
|
7
|
+
get_memes "/memes/search", options.merge({:search_token => search_token})
|
8
|
+
end
|
9
|
+
|
10
|
+
def meme_types
|
11
|
+
extract_from_response :meme_types, :get, "/memes/types"
|
12
|
+
end
|
13
|
+
|
14
|
+
def meme(meme_id)
|
15
|
+
handle_response :get, "/memes/#{meme_id}" do |resp|
|
16
|
+
resp.extract(:meme, self) unless resp.error?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def meme_comments(meme_id, options = {})
|
21
|
+
extract_or_response :comments, :get, "/memes/#{meme_id}/comments", options
|
22
|
+
end
|
23
|
+
end
|