tumblr_client 0.6.11 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -1
- data/.travis.yml +10 -0
- data/README.md +30 -11
- data/lib/tumblr/blog.rb +50 -64
- data/lib/tumblr/client.rb +8 -6
- data/lib/tumblr/config.rb +7 -9
- data/lib/tumblr/connection.rb +12 -7
- data/lib/tumblr/helpers.rb +14 -9
- data/lib/tumblr/post.rb +96 -99
- data/lib/tumblr/request.rb +13 -0
- data/lib/tumblr/request/oauth.rb +21 -21
- data/lib/tumblr/tagged.rb +9 -14
- data/lib/tumblr/user.rb +37 -36
- data/lib/tumblr/version.rb +5 -0
- data/lib/tumblr_client.rb +7 -2
- data/spec/examples/blog_spec.rb +185 -0
- data/spec/examples/client_spec.rb +46 -0
- data/spec/examples/post_spec.rb +186 -0
- data/spec/examples/tagged_spec.rb +31 -0
- data/spec/examples/user_spec.rb +114 -0
- data/spec/spec_helper.rb +7 -0
- data/{tumblr.gemspec → tumblr_client.gemspec} +4 -2
- metadata +34 -10
- data/.path +0 -1
- data/Gemfile.lock +0 -43
data/lib/tumblr/request.rb
CHANGED
@@ -11,6 +11,16 @@ module Tumblr
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
# get a redirect url
|
15
|
+
def get_redirect_url(path, params = {})
|
16
|
+
response = get_response path, params
|
17
|
+
if response.status == 301
|
18
|
+
response.headers['Location']
|
19
|
+
else
|
20
|
+
response.body['meta']
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
14
24
|
# Performs a get request
|
15
25
|
def get(path, params={})
|
16
26
|
respond get_response(path, params)
|
@@ -18,6 +28,9 @@ module Tumblr
|
|
18
28
|
|
19
29
|
# Performs post request
|
20
30
|
def post(path, params={})
|
31
|
+
if Array === params[:tags]
|
32
|
+
params[:tags] = params[:tags].join(',')
|
33
|
+
end
|
21
34
|
response = connection.post do |req|
|
22
35
|
req.url path
|
23
36
|
req.body = params unless params.empty?
|
data/lib/tumblr/request/oauth.rb
CHANGED
@@ -7,22 +7,22 @@ require 'base64'
|
|
7
7
|
module Tumblr
|
8
8
|
module Request
|
9
9
|
class TumblrOAuth < Faraday::Middleware
|
10
|
+
|
10
11
|
def call(env)
|
11
|
-
if env[:method].to_s ==
|
12
|
-
|
13
|
-
|
12
|
+
if env[:method].to_s == 'get'
|
13
|
+
params = Faraday::Utils.parse_query(env[:url].query) || {}
|
14
|
+
url = "#{env[:url].scheme}://#{env[:url].host}#{env[:url].path}"
|
14
15
|
else
|
15
|
-
|
16
|
-
|
16
|
+
params = env[:body] || {}
|
17
|
+
url = env[:url]
|
17
18
|
end
|
18
19
|
signature_params = params
|
19
20
|
params.each do |key, value|
|
20
21
|
signature_params = {} if value.respond_to?(:content_type)
|
21
22
|
end
|
22
|
-
env[:request_headers][
|
23
|
-
env[:request_headers][
|
24
|
-
env[:request_headers][
|
25
|
-
|
23
|
+
env[:request_headers]['Authorization'] = self.oauth_gen(env[:method], url, signature_params)
|
24
|
+
env[:request_headers]['Content-type'] = 'application/x-www-form-urlencoded'
|
25
|
+
env[:request_headers]['Host'] = @options[:api_host]
|
26
26
|
|
27
27
|
@app.call(env)
|
28
28
|
end
|
@@ -37,36 +37,36 @@ module Tumblr
|
|
37
37
|
params[:oauth_signature_method] = 'HMAC-SHA1'
|
38
38
|
params[:oauth_timestamp] = Time.now.to_i
|
39
39
|
params[:oauth_token] = @options[:token]
|
40
|
-
params[:oauth_version] =
|
40
|
+
params[:oauth_version] = '1.0'
|
41
41
|
params[:oauth_signature] = self.oauth_sig(method, url, params)
|
42
|
-
|
42
|
+
|
43
43
|
header = []
|
44
44
|
params.each do |key, value|
|
45
|
-
|
46
|
-
|
47
|
-
|
45
|
+
if key.to_s.include?('oauth')
|
46
|
+
header << "#{key.to_s}=#{value}"
|
47
|
+
end
|
48
48
|
end
|
49
49
|
|
50
50
|
"OAuth #{header.join(", ")}"
|
51
|
-
|
52
51
|
end
|
53
|
-
|
52
|
+
|
54
53
|
def oauth_sig(method, url, params)
|
55
54
|
parts = [method.upcase, URI.encode(url.to_s, /[^a-z0-9\-\.\_\~]/i)]
|
56
|
-
|
55
|
+
|
57
56
|
#sort the parameters
|
58
57
|
params = Hash[params.sort_by{ |key, value| key.to_s}]
|
59
|
-
|
58
|
+
|
60
59
|
encoded = []
|
61
60
|
params.each do |key, value|
|
62
|
-
|
61
|
+
encoded << "#{key.to_s}=#{URI.encode(value.to_s, /[^a-z0-9\-\.\_\~]/i)}"
|
63
62
|
end
|
64
63
|
|
65
|
-
parts << URI.encode(encoded.join(
|
66
|
-
signature_base = parts.join(
|
64
|
+
parts << URI.encode(encoded.join('&'), /[^a-z0-9\-\.\_\~]/i)
|
65
|
+
signature_base = parts.join('&')
|
67
66
|
secret = "#{@options[:consumer_secret]}&#{@options[:token_secret]}"
|
68
67
|
Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, secret, signature_base)).chomp.gsub(/\n/, '')
|
69
68
|
end
|
69
|
+
|
70
70
|
end
|
71
71
|
end
|
72
72
|
end
|
data/lib/tumblr/tagged.rb
CHANGED
@@ -1,18 +1,13 @@
|
|
1
1
|
module Tumblr
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
params.merge!(options)
|
11
|
-
end
|
12
|
-
if valid_options(@@standard_options, options)
|
13
|
-
get("v2/tagged", params)
|
14
|
-
end
|
15
|
-
end
|
2
|
+
module Tagged
|
3
|
+
|
4
|
+
def tagged(tag, options={})
|
5
|
+
validate_options([:before, :limit, :filter], options)
|
6
|
+
|
7
|
+
params = { :tag => tag, :api_key => @consumer_key }
|
8
|
+
params.merge!(options)
|
9
|
+
get("v2/tagged", params)
|
16
10
|
end
|
11
|
+
|
17
12
|
end
|
18
13
|
end
|
data/lib/tumblr/user.rb
CHANGED
@@ -1,40 +1,41 @@
|
|
1
1
|
module Tumblr
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
2
|
+
module User
|
3
|
+
|
4
|
+
def info
|
5
|
+
get('v2/user/info')
|
6
|
+
end
|
7
|
+
|
8
|
+
def dashboard(options = {})
|
9
|
+
valid_opts = [:limit, :offset, :type, :since_id, :reblog_info, :notes_info]
|
10
|
+
validate_options(valid_opts, options)
|
11
|
+
get('v2/user/dashboard', options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def likes(options = {})
|
15
|
+
validate_options([:limit, :offset], options)
|
16
|
+
get('v2/user/likes', options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def following(options = {})
|
20
|
+
validate_options([:limit, :offset], options)
|
21
|
+
get('v2/user/following', options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def follow(url)
|
25
|
+
post('v2/user/follow', :url => url)
|
26
|
+
end
|
27
|
+
|
28
|
+
def unfollow(url)
|
29
|
+
post('v2/user/unfollow', :url => url)
|
30
|
+
end
|
31
|
+
|
32
|
+
def like(id, reblog_key)
|
33
|
+
post('v2/user/like', :id => id, :reblog_key => reblog_key)
|
34
|
+
end
|
35
|
+
|
36
|
+
def unlike(id, reblog_key)
|
37
|
+
post('v2/user/unlike', :id => id, :reblog_key => reblog_key)
|
38
38
|
end
|
39
|
+
|
39
40
|
end
|
40
41
|
end
|
data/lib/tumblr_client.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'tumblr/client'
|
2
|
+
require 'tumblr/config'
|
3
3
|
|
4
4
|
module Tumblr
|
5
|
+
|
6
|
+
autoload :VERSION, File.join(File.dirname(__FILE__), 'tumblr/version')
|
7
|
+
|
5
8
|
extend Config
|
9
|
+
|
6
10
|
class << self
|
7
11
|
def new(options={})
|
8
12
|
Tumblr::Client.new(options)
|
9
13
|
end
|
10
14
|
end
|
15
|
+
|
11
16
|
end
|
@@ -0,0 +1,185 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tumblr::Blog do
|
4
|
+
|
5
|
+
let(:blog_name) { 'seejohnrun.tumblr.com' }
|
6
|
+
let(:consumer_key) { 'ckey' }
|
7
|
+
let(:client) do
|
8
|
+
Tumblr::Client.new :consumer_key => consumer_key
|
9
|
+
end
|
10
|
+
|
11
|
+
describe :blog_info do
|
12
|
+
|
13
|
+
it 'should make the proper request' do
|
14
|
+
client.should_receive(:get).once.with("v2/blog/#{blog_name}/info", {
|
15
|
+
:api_key => consumer_key
|
16
|
+
}).and_return 'response'
|
17
|
+
r = client.blog_info blog_name
|
18
|
+
r.should == 'response'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
describe :avatar do
|
24
|
+
|
25
|
+
context 'when supplying a size' do
|
26
|
+
|
27
|
+
before do
|
28
|
+
client.should_receive(:get_redirect_url).once.with("v2/blog/#{blog_name}/avatar/128").
|
29
|
+
and_return('url')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should construct the request properly' do
|
33
|
+
r = client.avatar blog_name, 128
|
34
|
+
r.should == 'url'
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when no size is specified' do
|
40
|
+
|
41
|
+
before do
|
42
|
+
client.should_receive(:get_redirect_url).once.with("v2/blog/#{blog_name}/avatar").
|
43
|
+
and_return('url')
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should construct the request properly' do
|
47
|
+
r = client.avatar blog_name
|
48
|
+
r.should == 'url'
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
describe :followers do
|
56
|
+
|
57
|
+
context 'with invalid parameters' do
|
58
|
+
|
59
|
+
it 'should raise an error' do
|
60
|
+
lambda {
|
61
|
+
client.followers blog_name, :not => 'an option'
|
62
|
+
}.should raise_error ArgumentError
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'with valid parameters' do
|
68
|
+
|
69
|
+
before do
|
70
|
+
client.should_receive(:get).once.with("v2/blog/#{blog_name}/followers", {
|
71
|
+
:limit => 1
|
72
|
+
}).and_return('response')
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'should construct the request properly' do
|
76
|
+
r = client.followers blog_name, :limit => 1
|
77
|
+
r.should == 'response'
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
describe :blog_likes do
|
85
|
+
|
86
|
+
context 'with invalid parameters' do
|
87
|
+
|
88
|
+
it 'should raise an error' do
|
89
|
+
lambda {
|
90
|
+
client.blog_likes blog_name, :not => 'an option'
|
91
|
+
}.should raise_error ArgumentError
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
context 'with valid parameters' do
|
97
|
+
|
98
|
+
before do
|
99
|
+
client.should_receive(:get).once.with("v2/blog/#{blog_name}/likes", {
|
100
|
+
:limit => 1,
|
101
|
+
:api_key => consumer_key
|
102
|
+
}).and_return('response')
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should construct the request properly' do
|
106
|
+
r = client.blog_likes blog_name, :limit => 1
|
107
|
+
r.should == 'response'
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
describe :posts do
|
115
|
+
|
116
|
+
context 'without a type supplied' do
|
117
|
+
|
118
|
+
before do
|
119
|
+
client.should_receive(:get).once.with("v2/blog/#{blog_name}/posts", {
|
120
|
+
:limit => 1,
|
121
|
+
:api_key => consumer_key
|
122
|
+
}).and_return('response')
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should construct the request properly' do
|
126
|
+
r = client.posts blog_name, :limit => 1
|
127
|
+
r.should == 'response'
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
context 'when supplying a type' do
|
133
|
+
|
134
|
+
before do
|
135
|
+
client.should_receive(:get).once.with("v2/blog/#{blog_name}/posts/audio", {
|
136
|
+
:limit => 1,
|
137
|
+
:api_key => consumer_key,
|
138
|
+
:type => 'audio'
|
139
|
+
}).and_return('response')
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should construct the request properly' do
|
143
|
+
r = client.posts blog_name, :limit => 1, :type => 'audio'
|
144
|
+
r.should == 'response'
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
# These are all just lists of posts with pagination
|
152
|
+
[:queue, :draft, :submissions].each do |type|
|
153
|
+
|
154
|
+
ext = type == :submissions ? 'submission' : type.to_s # annoying
|
155
|
+
|
156
|
+
describe type do
|
157
|
+
|
158
|
+
context 'when using parameters other than limit & offset' do
|
159
|
+
|
160
|
+
it 'should raise an error' do
|
161
|
+
lambda {
|
162
|
+
client.send type, blog_name, :not => 'an option'
|
163
|
+
}.should raise_error ArgumentError
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
context 'with valid options' do
|
169
|
+
|
170
|
+
it 'should construct the call properly' do
|
171
|
+
limit = 5
|
172
|
+
client.should_receive(:get).once.with("v2/blog/#{blog_name}/posts/#{ext}", {
|
173
|
+
:limit => limit
|
174
|
+
}).and_return('response')
|
175
|
+
r = client.send type, blog_name, :limit => limit
|
176
|
+
r.should == 'response'
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tumblr::Client do
|
4
|
+
|
5
|
+
context 'when using the generic copy' do
|
6
|
+
|
7
|
+
before do
|
8
|
+
@key = 'thekey'
|
9
|
+
Tumblr.configure do |c|
|
10
|
+
c.consumer_key = @key
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should give new clients those credentials' do
|
15
|
+
client = Tumblr::Client.new
|
16
|
+
client.credentials[:consumer_key].should == @key
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should have it\'s own credentials' do
|
20
|
+
Tumblr.credentials[:consumer_key].should == @key
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'should be able to make a new client (using these credentials)' do
|
24
|
+
Tumblr.new.should be_a(Tumblr::Client)
|
25
|
+
Tumblr.new.credentials[:consumer_key].should == @key
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when using custom copies of the client' do
|
31
|
+
|
32
|
+
before do
|
33
|
+
@client1 = Tumblr::Client.new(:consumer_key => 'key1')
|
34
|
+
@client2 = Tumblr::Client.new(:consumer_key => 'key2')
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should keep them separate' do
|
38
|
+
[
|
39
|
+
@client1.credentials[:consumer_key],
|
40
|
+
@client2.credentials[:consumer_key]
|
41
|
+
].uniq.count.should == 2
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|