rubytter 0.11.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +18 -46
- data/VERSION +1 -1
- data/examples/use_oauth.rb +28 -0
- data/lib/rubytter/core_ext.rb +26 -0
- data/lib/rubytter/oauth_rubytter.rb +6 -16
- data/lib/rubytter.rb +15 -31
- data/spec/rubytter_spec.rb +14 -15
- metadata +5 -4
- data/examples/home_timeline.rb +0 -14
data/README.rdoc
CHANGED
@@ -13,66 +13,38 @@ Rubytter is simple twitter library.
|
|
13
13
|
=== implemented API methods:
|
14
14
|
|
15
15
|
- /statuses/update
|
16
|
-
- /statuses/destroy
|
16
|
+
- /statuses/destroy/id
|
17
17
|
- /statuses/public_timeline
|
18
|
-
- /statuses/home_timeline
|
19
18
|
- /statuses/friends_timeline
|
20
19
|
- /statuses/replies
|
21
|
-
- /statuses/
|
22
|
-
- /statuses/
|
23
|
-
- /statuses/
|
24
|
-
- /statuses/
|
25
|
-
- /
|
26
|
-
- /statuses/retweet/%s
|
27
|
-
- /statuses/retweets/%s
|
28
|
-
- /statuses/retweeted_by_me
|
29
|
-
- /statuses/retweeted_to_me
|
30
|
-
- /statuses/retweets_of_me
|
31
|
-
- /users/show/%s
|
20
|
+
- /statuses/user_timeline/id
|
21
|
+
- /statuses/show/id
|
22
|
+
- /statuses/friends/id
|
23
|
+
- /statuses/followers/id
|
24
|
+
- /users/show/id
|
32
25
|
- /direct_messages
|
33
26
|
- /direct_messages/sent
|
34
27
|
- /direct_messages/new
|
35
|
-
- /direct_messages/destroy
|
36
|
-
- /friendships/create
|
37
|
-
- /friendships/destroy
|
28
|
+
- /direct_messages/destroy/id
|
29
|
+
- /friendships/create/id
|
30
|
+
- /friendships/destroy/id
|
38
31
|
- /friendships/exists
|
39
|
-
- /followers/ids
|
40
|
-
- /friends/ids
|
41
|
-
- /favorites
|
42
|
-
- /favorites/create
|
43
|
-
- /favorites/destroy
|
32
|
+
- /followers/ids/id
|
33
|
+
- /friends/ids/id
|
34
|
+
- /favorites
|
35
|
+
- /favorites/create/id
|
36
|
+
- /favorites/destroy/id
|
44
37
|
- /account/verify_credentials
|
45
38
|
- /account/end_session
|
46
39
|
- /account/update_delivery_device
|
47
40
|
- /account/update_profile_colors
|
48
41
|
- /account/rate_limit_status
|
49
42
|
- /account/update_profile
|
50
|
-
- /notifications/follow
|
51
|
-
- /notifications/leave
|
52
|
-
- /blocks/create
|
53
|
-
- /blocks/destroy
|
54
|
-
- /blocks/exists/%s
|
55
|
-
- /blocks/blocking
|
56
|
-
- /blocks/blocking/ids
|
57
|
-
- /saved_searches
|
58
|
-
- /saved_searches/show/%s
|
59
|
-
- /saved_searches/create
|
60
|
-
- /saved_searches/destroy/%s
|
61
|
-
- /:user/lists (create)
|
62
|
-
- /:user/lists/%s (update)
|
63
|
-
- /:user/lists/%s (delete)
|
64
|
-
- /:user/lists
|
65
|
-
- /:user/lists/memberships
|
66
|
-
- /:user/lists/%s/statuses
|
67
|
-
- /:user/lists/%s
|
68
|
-
- /%s/%s/members
|
69
|
-
- /:user/%s/members
|
70
|
-
- /:user/%s/members
|
71
|
-
- /%s/%s/subscribers
|
72
|
-
- /%s/%s/subscribers
|
73
|
-
- /%s/%s/subscribers
|
43
|
+
- /notifications/follow/id
|
44
|
+
- /notifications/leave/id
|
45
|
+
- /blocks/create/id
|
46
|
+
- /blocks/destroy/id
|
74
47
|
- (search.twitter.com)/search
|
75
|
-
- (api.twitter.com)/1/users/search
|
76
48
|
|
77
49
|
== SYNOPSIS:
|
78
50
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
1.0.0
|
@@ -0,0 +1,28 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__), '../lib')
|
2
|
+
require 'rubygems'
|
3
|
+
require 'rubytter'
|
4
|
+
require 'oauth'
|
5
|
+
|
6
|
+
key = "httN2PgAfeEuOywgw4m2g"
|
7
|
+
secret = "qunvnx27QC98380PUHQ0YUhSoMFMA2HJQZisWKDOgI"
|
8
|
+
|
9
|
+
consumer = OAuth::Consumer.new(key, secret, :site => "http://twitter.com")
|
10
|
+
|
11
|
+
request_token = consumer.get_request_token
|
12
|
+
system('open', request_token.authorize_url) || puts("Access here: #{request_token.authorize_url}\nand...")
|
13
|
+
|
14
|
+
print "Enter PIN: "
|
15
|
+
pin = gets.strip
|
16
|
+
|
17
|
+
access_token = request_token.get_access_token(
|
18
|
+
:oauth_token => request_token.token,
|
19
|
+
:oauth_verifier => pin
|
20
|
+
)
|
21
|
+
|
22
|
+
client = OAuthRubytter.new(access_token)
|
23
|
+
client.friends_timeline.each do |status|
|
24
|
+
puts "#{status.user.screen_name}: #{status.text}"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'irby'
|
28
|
+
client.irb
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Hash
|
2
|
+
def stringify_keys
|
3
|
+
inject({}) do |options, (key, value)|
|
4
|
+
options[key.to_s] = value
|
5
|
+
options
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def stringify_keys!
|
10
|
+
keys.each do |key|
|
11
|
+
self[key.to_s] = delete(key)
|
12
|
+
end
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
def symbolize_keys
|
17
|
+
inject({}) do |options, (key, value)|
|
18
|
+
options[(key.to_sym rescue key) || key] = value
|
19
|
+
options
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def symbolize_keys!
|
24
|
+
self.replace(self.symbolize_keys)
|
25
|
+
end
|
26
|
+
end
|
@@ -9,33 +9,23 @@ class OAuthRubytter < Rubytter
|
|
9
9
|
|
10
10
|
def get(path, params = {})
|
11
11
|
path += '.json'
|
12
|
-
param_str =
|
12
|
+
param_str = to_param_str(params)
|
13
13
|
path = path + '?' + param_str unless param_str.empty?
|
14
|
-
|
14
|
+
parse_response(@access_token.get(path, @header))
|
15
15
|
end
|
16
16
|
|
17
17
|
def post(path, params = {})
|
18
18
|
path += '.json'
|
19
|
-
|
19
|
+
parse_response(@access_token.post(path, params.stringify_keys, @header))
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
path += '.json'
|
24
|
-
structize(@access_token.put(path, params, @header))
|
25
|
-
end
|
26
|
-
|
27
|
-
def delete(path, params = {})
|
28
|
-
path += '.json'
|
29
|
-
param_str = self.class.to_param_str(params)
|
30
|
-
path = path + '?' + param_str unless param_str.empty?
|
31
|
-
structize(@access_token.delete(path, @header))
|
32
|
-
end
|
22
|
+
private
|
33
23
|
|
34
|
-
def
|
24
|
+
def parse_response(res)
|
35
25
|
json_data = JSON.parse(res.body)
|
36
26
|
case res.code
|
37
27
|
when "200"
|
38
|
-
|
28
|
+
structize(json_data)
|
39
29
|
else
|
40
30
|
raise APIError.new(json_data['error'], res)
|
41
31
|
end
|
data/lib/rubytter.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
|
2
1
|
# -*- coding: utf-8 -*-
|
3
2
|
require 'rubygems'
|
4
3
|
require 'json'
|
@@ -7,6 +6,7 @@ require 'cgi'
|
|
7
6
|
|
8
7
|
require 'rubytter/connection'
|
9
8
|
require 'rubytter/oauth_rubytter'
|
9
|
+
require 'rubytter/core_ext'
|
10
10
|
|
11
11
|
class Rubytter
|
12
12
|
VERSION = File.read(File.join(File.dirname(__FILE__), '../VERSION')).strip
|
@@ -39,7 +39,6 @@ class Rubytter
|
|
39
39
|
update_status /statuses/update post
|
40
40
|
remove_status /statuses/destroy/%s delete
|
41
41
|
public_timeline /statuses/public_timeline
|
42
|
-
home_timeline /statuses/home_timeline
|
43
42
|
friends_timeline /statuses/friends_timeline
|
44
43
|
replies /statuses/replies
|
45
44
|
mentions /statuses/mentions
|
@@ -47,11 +46,6 @@ class Rubytter
|
|
47
46
|
show /statuses/show/%s
|
48
47
|
friends /statuses/friends/%s
|
49
48
|
followers /statuses/followers/%s
|
50
|
-
retweet /statuses/retweet/%s post
|
51
|
-
retweets /statuses/retweets/%s
|
52
|
-
retweeted_by_me /statuses/retweeted_by_me
|
53
|
-
retweeted_to_me /statuses/retweeted_to_me
|
54
|
-
retweets_of_me /statuses/retweets_of_me
|
55
49
|
user /users/show/%s
|
56
50
|
direct_messages /direct_messages
|
57
51
|
sent_direct_messages /direct_messages/sent
|
@@ -62,7 +56,7 @@ class Rubytter
|
|
62
56
|
friendship_exists /friendships/exists
|
63
57
|
followers_ids /followers/ids/%s
|
64
58
|
friends_ids /friends/ids/%s
|
65
|
-
favorites /favorites
|
59
|
+
favorites /favorites
|
66
60
|
favorite /favorites/create/%s post
|
67
61
|
remove_favorite /favorites/destroy/%s delete
|
68
62
|
verify_credentials /account/verify_credentials get
|
@@ -106,9 +100,7 @@ class Rubytter
|
|
106
100
|
def #{method}(*args)
|
107
101
|
path = login ? '#{path}'.gsub(':user', login) :'#{path}'
|
108
102
|
params = args.last.kind_of?(Hash) ? args.pop : {}
|
109
|
-
path
|
110
|
-
path.sub!(/\\/\\z/, '')
|
111
|
-
#{http_method}(path, params)
|
103
|
+
#{http_method}(path % args, params)
|
112
104
|
end
|
113
105
|
EOS
|
114
106
|
else
|
@@ -158,49 +150,41 @@ class Rubytter
|
|
158
150
|
|
159
151
|
def get(path, params = {})
|
160
152
|
path += '.json'
|
161
|
-
param_str = '?' +
|
153
|
+
param_str = '?' + to_param_str(params)
|
162
154
|
path = path + param_str unless param_str.empty?
|
163
155
|
req = create_request(Net::HTTP::Get.new(path))
|
164
|
-
|
156
|
+
structize(http_request(@host, req))
|
165
157
|
end
|
166
158
|
|
167
159
|
def post(path, params = {})
|
168
160
|
path += '.json'
|
169
|
-
param_str =
|
161
|
+
param_str = to_param_str(params)
|
170
162
|
req = create_request(Net::HTTP::Post.new(path))
|
171
|
-
|
163
|
+
structize(http_request(@host, req, param_str))
|
172
164
|
end
|
173
165
|
|
174
166
|
def delete(path, params = {})
|
175
167
|
path += '.json'
|
176
|
-
param_str =
|
168
|
+
param_str = to_param_str(params)
|
177
169
|
req = create_request(Net::HTTP::Delete.new(path))
|
178
|
-
|
170
|
+
structize(http_request(@host, req, param_str))
|
179
171
|
end
|
180
172
|
|
181
173
|
def search(query, params = {})
|
182
174
|
path = '/search.json'
|
183
|
-
param_str = '?' +
|
175
|
+
param_str = '?' + to_param_str(params.merge({:q => query}))
|
184
176
|
path = path + param_str unless param_str.empty?
|
185
177
|
req = create_request(Net::HTTP::Get.new(path), false)
|
186
178
|
|
187
179
|
json_data = http_request("search.#{@host}", req, nil, @connection_for_search)
|
188
|
-
|
180
|
+
structize(
|
189
181
|
json_data['results'].map do |result|
|
190
|
-
|
182
|
+
search_result_to_hash(result)
|
191
183
|
end
|
192
184
|
)
|
193
185
|
end
|
194
186
|
|
195
|
-
def
|
196
|
-
path = '/1/users/search.json'
|
197
|
-
param_str = '?' + self.class.to_param_str(params.merge({:q => query}))
|
198
|
-
path = path + param_str unless param_str.empty?
|
199
|
-
req = create_request(Net::HTTP::Get.new(path))
|
200
|
-
self.class.structize(http_request("api.#{@host}", req))
|
201
|
-
end
|
202
|
-
|
203
|
-
def self.search_result_to_hash(json)
|
187
|
+
def search_result_to_hash(json)
|
204
188
|
{
|
205
189
|
'id' => json['id'],
|
206
190
|
'text' => json['text'],
|
@@ -242,7 +226,7 @@ class Rubytter
|
|
242
226
|
req
|
243
227
|
end
|
244
228
|
|
245
|
-
def
|
229
|
+
def structize(data)
|
246
230
|
case data
|
247
231
|
when Array
|
248
232
|
data.map{|i| structize(i)}
|
@@ -283,7 +267,7 @@ class Rubytter
|
|
283
267
|
end
|
284
268
|
end
|
285
269
|
|
286
|
-
def
|
270
|
+
def to_param_str(hash)
|
287
271
|
raise ArgumentError, 'Argument must be a Hash object' unless hash.is_a?(Hash)
|
288
272
|
hash.to_a.map{|i| i[0].to_s + '=' + CGI.escape(i[1].to_s) }.join('&')
|
289
273
|
end
|
data/spec/rubytter_spec.rb
CHANGED
@@ -129,16 +129,16 @@ class Rubytter
|
|
129
129
|
end
|
130
130
|
|
131
131
|
it 'should respond to to_param_str' do
|
132
|
-
param_str =
|
132
|
+
param_str = @rubytter.to_param_str(:page => 2, :foo => 'bar')
|
133
133
|
param_str.should =~ /^.+?=.+?&.+?=.+?$/
|
134
134
|
param_str.should =~ /page=2/
|
135
135
|
param_str.should =~ /foo=bar/
|
136
136
|
end
|
137
137
|
|
138
138
|
it 'should raise when call to_param_str with invalid arg' do
|
139
|
-
lambda {
|
140
|
-
lambda {
|
141
|
-
lambda {
|
139
|
+
lambda { @rubytter.to_param_str(nil) }.should raise_error(ArgumentError)
|
140
|
+
lambda { @rubytter.to_param_str('foo') }.should raise_error(ArgumentError)
|
141
|
+
lambda { @rubytter.to_param_str(:bar) }.should raise_error(ArgumentError)
|
142
142
|
end
|
143
143
|
|
144
144
|
it 'should set default header' do
|
@@ -180,7 +180,7 @@ class Rubytter
|
|
180
180
|
:d => {:a => {:a => 1, :b => 2}, :b => 1},
|
181
181
|
:e => [{:a => 1, :b => 2}, {:c => '"<>&'}]
|
182
182
|
}
|
183
|
-
struct =
|
183
|
+
struct = @rubytter.structize(hash)
|
184
184
|
struct.a.should == 'a'
|
185
185
|
struct.b.should == 1
|
186
186
|
struct.c.a.should == 1
|
@@ -198,7 +198,7 @@ class Rubytter
|
|
198
198
|
{"status" => {"text" => "foo", "user" => {"screen_name" => "jugyo_foo"}}},
|
199
199
|
{"status" => {"text" => "bar", "user" => {"screen_name" => "jugyo_bar"}}},
|
200
200
|
]
|
201
|
-
struct =
|
201
|
+
struct = @rubytter.structize(data)
|
202
202
|
struct[0].status.text.should == 'foo'
|
203
203
|
struct[0].status.user.screen_name.should == 'jugyo_foo'
|
204
204
|
struct[1].status.text.should == 'bar'
|
@@ -216,7 +216,7 @@ class Rubytter
|
|
216
216
|
:d => {:a => {:a => 1, :b => 2}, :b => 1},
|
217
217
|
:e => [{:a => 1, :b => 2}, {:c => '"<>&'}]
|
218
218
|
}
|
219
|
-
struct =
|
219
|
+
struct = @rubytter.structize(hash)
|
220
220
|
struct.to_hash.should == {
|
221
221
|
:a => "a",
|
222
222
|
"b" => 1,
|
@@ -232,7 +232,7 @@ class Rubytter
|
|
232
232
|
hash = {
|
233
233
|
:e => [{:a => 1, :b => 2}, {:c => '"<>&'}]
|
234
234
|
}
|
235
|
-
struct =
|
235
|
+
struct = @rubytter.structize(hash)
|
236
236
|
struct.to_hash(true).should == {"e"=>[{"a"=>1, "b"=>2}, {"c"=>""<>&"}]}
|
237
237
|
end
|
238
238
|
|
@@ -248,7 +248,7 @@ class Rubytter
|
|
248
248
|
:d => {:a => {:a => 1, :b => 2}, :b => 1},
|
249
249
|
:e => [{:a => 1, :b => 2}, {:c => '"<>&'}]
|
250
250
|
}
|
251
|
-
struct =
|
251
|
+
struct = @rubytter.structize(hash)
|
252
252
|
struct.to_json.should == '{"a":"a","b":1,"c":{"a":1,"b":2},"d":{"a":{"a":1,"b":2},"b":1},"e":[{"a":1,"b":2},{"c":"\"<>&"}]}'
|
253
253
|
end
|
254
254
|
|
@@ -262,9 +262,9 @@ class Rubytter
|
|
262
262
|
end
|
263
263
|
|
264
264
|
it 'should create same structs from same datas' do
|
265
|
-
|
266
|
-
|
267
|
-
|
265
|
+
@rubytter.structize({:a => 'a'}).should == @rubytter.structize({:a => 'a'})
|
266
|
+
@rubytter.structize({:a => 'a', :b => {:c => 'c'}}).should ==
|
267
|
+
@rubytter.structize({:a => 'a', :b => {:c => 'c'}})
|
268
268
|
end
|
269
269
|
|
270
270
|
it 'should be set app_name' do
|
@@ -285,8 +285,7 @@ class Rubytter
|
|
285
285
|
'from_user' => 'jugyo',
|
286
286
|
'profile_image_url' => 'http://s3.amazonaws.com/twitter_production/profile_images/63467667/megane2_normal.png'
|
287
287
|
}
|
288
|
-
|
289
|
-
result = Rubytter.search_result_to_hash(json_data)
|
288
|
+
result = @rubytter.search_result_to_hash(json_data)
|
290
289
|
result['id'].should == '123'
|
291
290
|
result['text'].should == 'foo foo bar bar'
|
292
291
|
result['created_at'].should == 'Sat, 21 Mar 2009 09:48:20 +0000'
|
@@ -355,7 +354,7 @@ class Rubytter
|
|
355
354
|
response = simple_mock(:body => '{}', :code => '200')
|
356
355
|
access_token.should_receive(:post).with(
|
357
356
|
"/statuses/update.json",
|
358
|
-
{
|
357
|
+
{'status' => 'test'},
|
359
358
|
{"User-Agent"=>"Rubytter/#{Rubytter::VERSION} (http://github.com/jugyo/rubytter)"}
|
360
359
|
).and_return(response)
|
361
360
|
rubytter.update('test')
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubytter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jugyo
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2010-01-31 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -49,15 +49,16 @@ files:
|
|
49
49
|
- examples/favorite.rb
|
50
50
|
- examples/follow.rb
|
51
51
|
- examples/friends_timeline.rb
|
52
|
-
- examples/home_timeline.rb
|
53
52
|
- examples/limit.rb
|
54
53
|
- examples/lists.rb
|
55
54
|
- examples/replies.rb
|
56
55
|
- examples/search.rb
|
57
56
|
- examples/update_status.rb
|
57
|
+
- examples/use_oauth.rb
|
58
58
|
- examples/user.rb
|
59
59
|
- lib/rubytter.rb
|
60
60
|
- lib/rubytter/connection.rb
|
61
|
+
- lib/rubytter/core_ext.rb
|
61
62
|
- lib/rubytter/oauth_rubytter.rb
|
62
63
|
- spec/rubytter_spec.rb
|
63
64
|
- spec/search.json
|
@@ -97,10 +98,10 @@ test_files:
|
|
97
98
|
- examples/favorite.rb
|
98
99
|
- examples/follow.rb
|
99
100
|
- examples/friends_timeline.rb
|
100
|
-
- examples/home_timeline.rb
|
101
101
|
- examples/limit.rb
|
102
102
|
- examples/lists.rb
|
103
103
|
- examples/replies.rb
|
104
104
|
- examples/search.rb
|
105
105
|
- examples/update_status.rb
|
106
|
+
- examples/use_oauth.rb
|
106
107
|
- examples/user.rb
|
data/examples/home_timeline.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
require 'rubygems'
|
4
|
-
require 'rubytter'
|
5
|
-
|
6
|
-
if ARGV.size < 2
|
7
|
-
puts "Usage: ruby #{File.basename(__FILE__)} user_id password"
|
8
|
-
exit
|
9
|
-
end
|
10
|
-
|
11
|
-
client = Rubytter.new(ARGV[0], ARGV[1])
|
12
|
-
client.home_timeline.each do |status|
|
13
|
-
puts "#{status.user.screen_name}: #{status.text}"
|
14
|
-
end
|