rest-more 3.1.0 → 3.2.0
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.
- checksums.yaml +4 -4
- data/CHANGES.md +18 -0
- data/README.md +21 -57
- data/Rakefile +1 -1
- data/lib/rest-core/client/dropbox.rb +12 -8
- data/lib/rest-core/client/facebook.rb +16 -6
- data/lib/rest-core/client/github.rb +44 -2
- data/lib/rest-core/client/instagram.rb +2 -2
- data/lib/rest-core/client/linkedin.rb +8 -2
- data/lib/rest-core/client/stackexchange.rb +67 -0
- data/lib/rest-core/client/twitter.rb +10 -9
- data/lib/rest-more.rb +8 -7
- data/lib/rest-more/version.rb +1 -1
- data/rest-more.gemspec +11 -9
- data/test/dropbox/test_dropbox.rb +0 -1
- data/test/facebook/test_api.rb +2 -2
- data/test/facebook/test_error.rb +0 -1
- data/test/facebook/test_handler.rb +0 -1
- data/test/facebook/test_misc.rb +0 -1
- data/test/facebook/test_old.rb +0 -1
- data/test/facebook/test_page.rb +0 -1
- data/test/facebook/test_parse.rb +5 -4
- data/test/facebook/test_serialize.rb +0 -5
- data/test/github/test_github.rb +31 -0
- data/test/stackexchange/test_stackexchange.rb +16 -0
- data/test/twitter/test_twitter.rb +0 -1
- metadata +9 -7
- data/lib/rest-core/client/firebase.rb +0 -105
- data/test/firebase/test_firebase.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5444cce199f7ad6519edbcbfa1db1a2ee7d1b143
|
4
|
+
data.tar.gz: 2e7c6a0750501114f7bdd7f631827f5acacf08ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73043581c21ef0dad61cba002fff199a754c96b6290ee49d44da0a78f43a3d8ea79534d239ed695b12e6c66ad1a8ad5bf91b349c0ffabb4cd86d439c87d03ca3
|
7
|
+
data.tar.gz: 9f2a1b3582b0006f88ad2b1b2619fa7c7a13a539fcf827d71f94758cf4bdc01488e89f3768a4e23e5ce0aa8a02c61be64e82ddf9be11fe8438d90186a5a40876
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## rest-more 3.2.0 -- 2014-06-27
|
4
|
+
|
5
|
+
* Removed RC::Firebase because it's extracted into [rest-firebase][]
|
6
|
+
* A lot of methods now accept callback properly.
|
7
|
+
|
8
|
+
[rest-firebase]: https://github.com/CodementorIO/rest-firebase
|
9
|
+
|
10
|
+
### Changes for RC::Github
|
11
|
+
|
12
|
+
* Added `RC::Github#all` to grab resources through all pages automatically
|
13
|
+
and concurrently. e.g. `RC::Github.new.all('users/godfat/repos')`
|
14
|
+
|
15
|
+
### Changes for RC::Linkedin
|
16
|
+
|
17
|
+
* Added `RC::Linkedin#profile` to access someone's profile easier.
|
18
|
+
|
19
|
+
### Added RC::StackExchange
|
20
|
+
|
3
21
|
## rest-more 3.1.0 -- 2014-05-09
|
4
22
|
|
5
23
|
### Changes for RC::Firebase
|
data/README.md
CHANGED
@@ -26,24 +26,34 @@ Various REST clients such as Facebook and Twitter built with [rest-core][].
|
|
26
26
|
|
27
27
|
Out-of-box REST clients built with rest-core for:
|
28
28
|
|
29
|
-
* [RC::Dropbox][]
|
30
|
-
* [RC::Facebook][] (most completed)
|
31
|
-
* [RC::
|
32
|
-
* [RC::
|
33
|
-
* [RC::
|
34
|
-
* [RC::
|
35
|
-
* [RC::Twitter][]
|
29
|
+
* [RC::Dropbox][] (via OAuth 1.0a)
|
30
|
+
* [RC::Facebook][] (via OAuth 2, most completed)
|
31
|
+
* [RC::Github][] (via OAuth 2)
|
32
|
+
* [RC::Instagram][] (via OAuth 2)
|
33
|
+
* [RC::Linkedin][] (via OAuth 1.0a)
|
34
|
+
* [RC::StackExchange][] (via OAuth 2)
|
35
|
+
* [RC::Twitter][] (via OAuth 1.0a)
|
36
36
|
|
37
37
|
[RC::Dropbox]: lib/rest-core/client/dropbox.rb
|
38
38
|
[RC::Facebook]: lib/rest-core/client/facebook.rb
|
39
|
-
[RC::Firebase]: lib/rest-core/client/firebase.rb
|
40
39
|
[RC::Github]: lib/rest-core/client/github.rb
|
41
40
|
[RC::Instagram]: lib/rest-core/client/instagram.rb
|
42
41
|
[RC::Linkedin]: lib/rest-core/client/linkedin.rb
|
42
|
+
[RC::StackExchange]: lib/rest-core/client/stackexchange.rb
|
43
43
|
[RC::Twitter]: lib/rest-core/client/twitter.rb
|
44
44
|
|
45
45
|
Rails utilities are also included for some clients.
|
46
46
|
|
47
|
+
Other clients in other gems:
|
48
|
+
|
49
|
+
* Firebase: [rest-firebase][]
|
50
|
+
* TopCoder: [topcoder][]
|
51
|
+
* YahooBuy: [rest-more-yahoo_buy][]
|
52
|
+
|
53
|
+
[rest-firebase]: https://github.com/CodementorIO/rest-firebase
|
54
|
+
[topcoder]: https://github.com/miaout17/topcoder
|
55
|
+
[rest-more-yahoo_buy]: https://github.com/GoodLife/rest-more-yahoo_buy
|
56
|
+
|
47
57
|
## REQUIREMENTS:
|
48
58
|
|
49
59
|
### Mandatory:
|
@@ -132,55 +142,6 @@ f.authorize!(:redirect_uri => redirect_uri, :code => 'code')
|
|
132
142
|
p [f.me, f.get('me/posts')]
|
133
143
|
```
|
134
144
|
|
135
|
-
### Firebase example:
|
136
|
-
|
137
|
-
Check out their
|
138
|
-
[REST API documentation](https://www.firebase.com/docs/rest-api.html)
|
139
|
-
for a complete reference, and [RC::Firebase][] for built-in APIs.
|
140
|
-
|
141
|
-
``` ruby
|
142
|
-
require 'rest-more'
|
143
|
-
|
144
|
-
f = RC::Firebase.new :site => 'https://SampleChat.firebaseIO-demo.com/',
|
145
|
-
:secret => 'secret',
|
146
|
-
:d => {:auth_data => 'something'},
|
147
|
-
:log_method => method(:puts),
|
148
|
-
:auth => false # Ignore auth for this example!
|
149
|
-
|
150
|
-
@reconnect = true
|
151
|
-
|
152
|
-
# Streaming over 'users/tom'
|
153
|
-
es = f.event_source('users/tom')
|
154
|
-
es.onopen { |sock| p sock } # Called when connected
|
155
|
-
es.onmessage{ |event, data, sock| p event, data } # Called for each message
|
156
|
-
es.onerror { |error, sock| p error } # Called whenever there's an error
|
157
|
-
# Extra: If we return true in onreconnect callback, it would automatically
|
158
|
-
# reconnect the node for us if disconnected.
|
159
|
-
es.onreconnect{ |error, sock| p error; @reconnect }
|
160
|
-
|
161
|
-
# Start making the request
|
162
|
-
es.start
|
163
|
-
|
164
|
-
# Try to close the connection and see it reconnects automatically
|
165
|
-
es.close
|
166
|
-
|
167
|
-
# Update users/tom.json
|
168
|
-
p f.put('users/tom', :some => 'data')
|
169
|
-
p f.post('users/tom', :some => 'other')
|
170
|
-
p f.get('users/tom')
|
171
|
-
p f.delete('users/tom')
|
172
|
-
|
173
|
-
# Need to tell onreconnect stops reconnecting, or even if we close
|
174
|
-
# the connection manually, it would still try to reconnect again.
|
175
|
-
@reconnect = false
|
176
|
-
|
177
|
-
# Close the connection to gracefully shut it down.
|
178
|
-
es.close
|
179
|
-
|
180
|
-
# Refresh the auth by resetting it
|
181
|
-
f.auth = nil
|
182
|
-
```
|
183
|
-
|
184
145
|
### Github example:
|
185
146
|
|
186
147
|
Check out their
|
@@ -194,6 +155,8 @@ g = RC::Github.new :access_token => 'if you have the token',
|
|
194
155
|
:log_method => method(:puts)
|
195
156
|
|
196
157
|
p [g.me, g.get('users/godfat')]
|
158
|
+
p g.all('users/godfat/repos').size # get all repositories across all pages
|
159
|
+
|
197
160
|
```
|
198
161
|
|
199
162
|
### Instagram example:
|
@@ -342,6 +305,7 @@ Which is using `RestCore::Universal` for accessing arbitrary websites.
|
|
342
305
|
|
343
306
|
## Powered sites:
|
344
307
|
|
308
|
+
* [Codementor](https://www.codementor.io/)
|
345
309
|
* [PicCollage](http://pic-collage.com/)
|
346
310
|
|
347
311
|
## CHANGES:
|
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ Gemgem.init(dir) do |s|
|
|
14
14
|
s.version = RestMore::VERSION
|
15
15
|
s.homepage = 'https://github.com/godfat/rest-more'
|
16
16
|
|
17
|
-
%w[rest-core].each{ |g| s.add_runtime_dependency(g, '>=3.
|
17
|
+
%w[rest-core].each{ |g| s.add_runtime_dependency(g, '>=3.2.0') }
|
18
18
|
|
19
19
|
# exclude rest-core
|
20
20
|
s.files.reject!{ |f| f.start_with?('rest-core/') }
|
@@ -68,27 +68,31 @@ end
|
|
68
68
|
module RestCore::Dropbox::Client
|
69
69
|
include RestCore
|
70
70
|
|
71
|
-
def me query={}, opts={}
|
72
|
-
get('1/account/info', query, opts)
|
71
|
+
def me query={}, opts={}, &cb
|
72
|
+
get('1/account/info', query, opts, &cb)
|
73
73
|
end
|
74
74
|
|
75
75
|
def default_root
|
76
76
|
'sandbox'
|
77
77
|
end
|
78
78
|
|
79
|
-
def download path, query={}, opts={}
|
79
|
+
def download path, query={}, opts={}, &cb
|
80
80
|
get("https://api-content.dropbox.com/1/files/#{root}/#{path}",
|
81
|
-
query, {:json_response => false}.merge(opts))
|
81
|
+
query, {:json_response => false}.merge(opts), &cb)
|
82
82
|
end
|
83
83
|
|
84
|
-
def upload path, file, query={}, opts={}
|
84
|
+
def upload path, file, query={}, opts={}, &cb
|
85
85
|
put("https://api-content.dropbox.com/1/files_put/#{root}/#{path}",
|
86
|
-
file, query, opts)
|
86
|
+
file, query, opts, &cb)
|
87
87
|
end
|
88
88
|
|
89
89
|
def ls path='', query={}, opts={}
|
90
|
-
|
91
|
-
|
90
|
+
args = ["1/metadata/#{root}/#{path}", query, opts]
|
91
|
+
if block_given?
|
92
|
+
get(*args){ |r| yield(r['contents'].map{ |c| c['path'] }) }
|
93
|
+
else
|
94
|
+
get(*args)['contents'].map{ |c| c['path'] }
|
95
|
+
end
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
@@ -5,7 +5,7 @@ require 'rest-core/util/hmac'
|
|
5
5
|
# https://developers.facebook.com/docs/reference/api
|
6
6
|
# https://developers.facebook.com/tools/explorer
|
7
7
|
module RestCore
|
8
|
-
Facebook = Builder.client(:
|
8
|
+
Facebook = Builder.client(:app_id, :secret, :data, :old_site) do
|
9
9
|
use Timeout , 10
|
10
10
|
|
11
11
|
use DefaultSite , 'https://graph.facebook.com/'
|
@@ -177,8 +177,13 @@ module RestCore::Facebook::Client
|
|
177
177
|
# beware! maybe facebook would take out the code someday
|
178
178
|
return self.data = old_data unless old_data && old_data['code']
|
179
179
|
# passing empty redirect_uri is needed!
|
180
|
-
|
181
|
-
|
180
|
+
arg = {:code => old_data['code'], :redirect_uri => ''}
|
181
|
+
|
182
|
+
if block_given?
|
183
|
+
authorize!(arg){ |r| self.data = old_data.merge(r) }
|
184
|
+
else
|
185
|
+
self.data = old_data.merge(authorize!(arg))
|
186
|
+
end
|
182
187
|
end
|
183
188
|
|
184
189
|
def parse_json! json
|
@@ -218,9 +223,14 @@ module RestCore::Facebook::Client
|
|
218
223
|
|
219
224
|
def authorize! opts={}
|
220
225
|
payload = {:client_id => app_id, :client_secret => secret}.merge(opts)
|
221
|
-
|
222
|
-
|
223
|
-
|
226
|
+
args = ['oauth/access_token', payload, {},
|
227
|
+
{:json_response => false}.merge(opts)]
|
228
|
+
|
229
|
+
if block_given?
|
230
|
+
post(*args){ |r| yield(self.data = ParseQuery.parse_query(r)) }
|
231
|
+
else
|
232
|
+
self.data = ParseQuery.parse_query(post(*args))
|
233
|
+
end
|
224
234
|
end
|
225
235
|
|
226
236
|
# old rest facebook api, i will definitely love to remove them someday
|
@@ -23,8 +23,50 @@ end
|
|
23
23
|
module RestCore::Github::Client
|
24
24
|
include RestCore
|
25
25
|
|
26
|
-
|
27
|
-
|
26
|
+
MAX_PER_PAGE = 100
|
27
|
+
|
28
|
+
def me query={}, opts={}, &cb
|
29
|
+
get('user', query, opts, &cb)
|
30
|
+
end
|
31
|
+
|
32
|
+
def all path, query={}, opts={}
|
33
|
+
q = {:per_page => MAX_PER_PAGE}.merge(query)
|
34
|
+
r = get(path, q, opts.merge(RESPONSE_KEY => PROMISE)).then{ |response|
|
35
|
+
body = response[RESPONSE_BODY] + (page_range(response).map{ |page|
|
36
|
+
get(path, q.merge(:page => page),
|
37
|
+
opts.merge(RESPONSE_KEY => RESPONSE_BODY))
|
38
|
+
}.inject([], &:+))
|
39
|
+
response.merge(RESPONSE_BODY => body)
|
40
|
+
}.future_response
|
41
|
+
|
42
|
+
if block_given?
|
43
|
+
yield(r[response_key(opts)])
|
44
|
+
self
|
45
|
+
else
|
46
|
+
r[response_key(opts)]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def page_range response
|
52
|
+
from = (parse_current_page(response) || 1).to_i + 1
|
53
|
+
to = (parse_last_page(response) || from - 1).to_i
|
54
|
+
if from <= to
|
55
|
+
from..to
|
56
|
+
else
|
57
|
+
[]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_current_page response
|
62
|
+
RC::ParseQuery.parse_query(URI.parse(response[REQUEST_URI]).query)['page']
|
63
|
+
end
|
64
|
+
|
65
|
+
def parse_last_page response
|
66
|
+
return unless link = response[RESPONSE_HEADERS]['LINK']
|
67
|
+
ls = RC::ParseLink.parse_link(link)
|
68
|
+
return unless last_link = ls['last']
|
69
|
+
RC::ParseQuery.parse_query(URI.parse(last_link['uri']).query)['page']
|
28
70
|
end
|
29
71
|
end
|
30
72
|
|
@@ -27,8 +27,14 @@ end
|
|
27
27
|
module RestCore::Linkedin::Client
|
28
28
|
include RestCore
|
29
29
|
|
30
|
-
def me query={}, opts={}
|
31
|
-
|
30
|
+
def me query={}, opts={}, &cb
|
31
|
+
profile('~', nil, query, opts, &cb)
|
32
|
+
end
|
33
|
+
|
34
|
+
def profile name, value=nil, fields=[], query={}, opts={}, &cb
|
35
|
+
path = if value then "#{name}=#{CGI.escape(value)}" else name end
|
36
|
+
info = if fields.empty? then '' else ":(#{fields.join(',')})" end
|
37
|
+
get("v1/people/#{path}#{info}", query, opts, &cb)
|
32
38
|
end
|
33
39
|
end
|
34
40
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
|
2
|
+
require 'rest-core'
|
3
|
+
|
4
|
+
# http://api.stackexchange.com/docs
|
5
|
+
module RestCore
|
6
|
+
StackExchange = Builder.client(:client_id, :client_secret, :key, :data) do
|
7
|
+
use Timeout , 10
|
8
|
+
|
9
|
+
use DefaultSite , 'https://api.stackexchange.com/'
|
10
|
+
use DefaultHeaders, {'Accept' => 'application/json'}
|
11
|
+
use DefaultQuery , nil
|
12
|
+
use Oauth2Query , nil
|
13
|
+
|
14
|
+
use CommonLogger , nil
|
15
|
+
use Cache , nil, 600 do
|
16
|
+
use ErrorHandler, lambda{ |env|
|
17
|
+
RuntimeError.new(env[RESPONSE_BODY]['error_message'])}
|
18
|
+
use ErrorDetectorHttp
|
19
|
+
use JsonResponse, true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module RestCore::StackExchange::Client
|
25
|
+
include RestCore
|
26
|
+
|
27
|
+
def me query={}, opts={}, &cb
|
28
|
+
get('me', query, opts, &cb)
|
29
|
+
end
|
30
|
+
|
31
|
+
def access_token
|
32
|
+
data['access_token']
|
33
|
+
end
|
34
|
+
|
35
|
+
def access_token= token
|
36
|
+
data['access_token'] = token
|
37
|
+
end
|
38
|
+
|
39
|
+
def authorize_url query={}, opts={}
|
40
|
+
url('https://stackexchange.com/oauth',
|
41
|
+
{:access_token => false, :key => false, :site => false,
|
42
|
+
:client_id => client_id}.merge(query), opts)
|
43
|
+
end
|
44
|
+
|
45
|
+
def authorize! payload={}, opts={}, &cb
|
46
|
+
p = {:client_id => client_id, :client_secret => client_secret}.
|
47
|
+
merge(payload)
|
48
|
+
|
49
|
+
args = ['https://stackexchange.com/oauth/access_token', p,
|
50
|
+
{:access_token => false, :key => false, :site => false},
|
51
|
+
{:json_response => false}.merge(opts)]
|
52
|
+
|
53
|
+
if block_given?
|
54
|
+
post(*args){ |r| yield(self.data = ParseQuery.parse_query(r)) }
|
55
|
+
else
|
56
|
+
self.data = ParseQuery.parse_query(post(*args))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
def default_data ; {}; end
|
62
|
+
def default_query; {:key => key, :site => 'stackoverflow'}; end
|
63
|
+
end
|
64
|
+
|
65
|
+
class RestCore::StackExchange
|
66
|
+
include RestCore::StackExchange::Client
|
67
|
+
end
|
@@ -65,28 +65,29 @@ end
|
|
65
65
|
module RestCore::Twitter::Client
|
66
66
|
include RestCore
|
67
67
|
|
68
|
-
def me query={}, opts={}
|
69
|
-
get('1.1/account/verify_credentials.json', query, opts)
|
68
|
+
def me query={}, opts={}, &cb
|
69
|
+
get('1.1/account/verify_credentials.json', query, opts, &cb)
|
70
70
|
end
|
71
71
|
|
72
|
-
def tweet status, media=nil, payload={}, query={}, opts={}
|
72
|
+
def tweet status, media=nil, payload={}, query={}, opts={}, &cb
|
73
73
|
if media
|
74
74
|
post('1.1/statuses/update_with_media.json',
|
75
75
|
{:status => status, 'media[]' => media}.merge(payload),
|
76
|
-
query, opts)
|
76
|
+
query, opts, &cb)
|
77
77
|
else
|
78
78
|
post('1.1/statuses/update.json',
|
79
79
|
{:status => status}.merge(payload),
|
80
|
-
query, opts)
|
80
|
+
query, opts, &cb)
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
-
def search q, query={}, opts={}
|
85
|
-
get('1.1/search/tweets.json', {q: q}.merge(query), opts)
|
84
|
+
def search q, query={}, opts={}, &cb
|
85
|
+
get('1.1/search/tweets.json', {q: q}.merge(query), opts, &cb)
|
86
86
|
end
|
87
87
|
|
88
|
-
def statuses user, query={}, opts={}
|
89
|
-
get('1.1/statuses/user_timeline.json',
|
88
|
+
def statuses user, query={}, opts={}, &cb
|
89
|
+
get('1.1/statuses/user_timeline.json',
|
90
|
+
{:id => user}.merge(query), opts, &cb)
|
90
91
|
end
|
91
92
|
end
|
92
93
|
|
data/lib/rest-more.rb
CHANGED
@@ -2,11 +2,12 @@
|
|
2
2
|
require 'rest-core'
|
3
3
|
|
4
4
|
module RestCore
|
5
|
-
autoload :Dropbox
|
6
|
-
autoload :Facebook
|
7
|
-
autoload :Firebase
|
8
|
-
autoload :Github
|
9
|
-
autoload :Instagram, 'rest-core/client/instagram'
|
10
|
-
autoload :Linkedin
|
11
|
-
autoload :
|
5
|
+
autoload :Dropbox , 'rest-core/client/dropbox'
|
6
|
+
autoload :Facebook , 'rest-core/client/facebook'
|
7
|
+
autoload :Firebase , 'rest-core/client/firebase'
|
8
|
+
autoload :Github , 'rest-core/client/github'
|
9
|
+
autoload :Instagram , 'rest-core/client/instagram'
|
10
|
+
autoload :Linkedin , 'rest-core/client/linkedin'
|
11
|
+
autoload :StackExchange, 'rest-core/client/stackexchange'
|
12
|
+
autoload :Twitter , 'rest-core/client/twitter'
|
12
13
|
end
|
data/lib/rest-more/version.rb
CHANGED
data/rest-more.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: rest-more 3.
|
2
|
+
# stub: rest-more 3.2.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "rest-more"
|
6
|
-
s.version = "3.
|
6
|
+
s.version = "3.2.0"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib"]
|
10
10
|
s.authors = ["Lin Jen-Shin (godfat)"]
|
11
|
-
s.date = "2014-
|
11
|
+
s.date = "2014-06-27"
|
12
12
|
s.description = "Various REST clients such as Facebook and Twitter built with [rest-core][].\n\n[rest-core]: https://github.com/godfat/rest-core"
|
13
13
|
s.email = ["godfat (XD) godfat.org"]
|
14
14
|
s.executables = ["rib-rest-core"]
|
@@ -49,12 +49,12 @@ Gem::Specification.new do |s|
|
|
49
49
|
"lib/rest-core/client/dropbox.rb",
|
50
50
|
"lib/rest-core/client/facebook.rb",
|
51
51
|
"lib/rest-core/client/facebook/rails_util.rb",
|
52
|
-
"lib/rest-core/client/firebase.rb",
|
53
52
|
"lib/rest-core/client/github.rb",
|
54
53
|
"lib/rest-core/client/github/rails_util.rb",
|
55
54
|
"lib/rest-core/client/instagram.rb",
|
56
55
|
"lib/rest-core/client/linkedin.rb",
|
57
56
|
"lib/rest-core/client/linkedin/rails_util.rb",
|
57
|
+
"lib/rest-core/client/stackexchange.rb",
|
58
58
|
"lib/rest-core/client/twitter.rb",
|
59
59
|
"lib/rest-core/client/twitter/rails_util.rb",
|
60
60
|
"lib/rest-core/util/rails_util_util.rb",
|
@@ -77,8 +77,9 @@ Gem::Specification.new do |s|
|
|
77
77
|
"test/facebook/test_parse.rb",
|
78
78
|
"test/facebook/test_serialize.rb",
|
79
79
|
"test/facebook/test_timeout.rb",
|
80
|
-
"test/
|
80
|
+
"test/github/test_github.rb",
|
81
81
|
"test/instagram/test_instagram.rb",
|
82
|
+
"test/stackexchange/test_stackexchange.rb",
|
82
83
|
"test/twitter/test_twitter.rb"]
|
83
84
|
s.homepage = "https://github.com/godfat/rest-more"
|
84
85
|
s.licenses = ["Apache License 2.0"]
|
@@ -97,19 +98,20 @@ Gem::Specification.new do |s|
|
|
97
98
|
"test/facebook/test_parse.rb",
|
98
99
|
"test/facebook/test_serialize.rb",
|
99
100
|
"test/facebook/test_timeout.rb",
|
100
|
-
"test/
|
101
|
+
"test/github/test_github.rb",
|
101
102
|
"test/instagram/test_instagram.rb",
|
103
|
+
"test/stackexchange/test_stackexchange.rb",
|
102
104
|
"test/twitter/test_twitter.rb"]
|
103
105
|
|
104
106
|
if s.respond_to? :specification_version then
|
105
107
|
s.specification_version = 4
|
106
108
|
|
107
109
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
108
|
-
s.add_runtime_dependency(%q<rest-core>, [">= 3.
|
110
|
+
s.add_runtime_dependency(%q<rest-core>, [">= 3.2.0"])
|
109
111
|
else
|
110
|
-
s.add_dependency(%q<rest-core>, [">= 3.
|
112
|
+
s.add_dependency(%q<rest-core>, [">= 3.2.0"])
|
111
113
|
end
|
112
114
|
else
|
113
|
-
s.add_dependency(%q<rest-core>, [">= 3.
|
115
|
+
s.add_dependency(%q<rest-core>, [">= 3.2.0"])
|
114
116
|
end
|
115
117
|
end
|
data/test/facebook/test_api.rb
CHANGED
@@ -4,7 +4,6 @@ require 'rest-more/test'
|
|
4
4
|
describe RC::Facebook do
|
5
5
|
after do
|
6
6
|
WebMock.reset!
|
7
|
-
Muack.verify
|
8
7
|
end
|
9
8
|
|
10
9
|
should 'generate correct url' do
|
@@ -83,7 +82,8 @@ describe RC::Facebook do
|
|
83
82
|
end
|
84
83
|
|
85
84
|
should 'convert query to string' do
|
86
|
-
|
85
|
+
o = Object.new
|
86
|
+
def o.to_s; 'i am mock'; end
|
87
87
|
stub_request(:get, "https://graph.facebook.com/search?q=i%20am%20mock").
|
88
88
|
to_return(:body => 'ok')
|
89
89
|
RC::Facebook.new(:json_response => false).
|
data/test/facebook/test_error.rb
CHANGED
data/test/facebook/test_misc.rb
CHANGED
data/test/facebook/test_old.rb
CHANGED
data/test/facebook/test_page.rb
CHANGED
data/test/facebook/test_parse.rb
CHANGED
@@ -113,9 +113,11 @@ describe RC::Facebook do
|
|
113
113
|
app_id = 456
|
114
114
|
rg = RC::Facebook.new(:secret => secret,
|
115
115
|
:app_id => app_id)
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
|
117
|
+
stub_request(:post, 'https://graph.facebook.com/oauth/access_token').
|
118
|
+
with(:body => {'client_id' => '456', 'client_secret' => 'lulala',
|
119
|
+
'code' => 'lalalu', 'redirect_uri' => ''}).
|
120
|
+
to_return(:body => 'access_token=lololo').times(2)
|
119
121
|
|
120
122
|
check = lambda{
|
121
123
|
rg.data['code'] .should.eq code
|
@@ -155,5 +157,4 @@ describe RC::Facebook do
|
|
155
157
|
rg.access_token .should.eq 'a'
|
156
158
|
rg.data['expires'] .should.eq '1234'
|
157
159
|
end
|
158
|
-
|
159
160
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
require 'rest-more/test'
|
3
|
+
|
4
|
+
describe RC::Github do
|
5
|
+
after do
|
6
|
+
WebMock.reset!
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'get all' do
|
10
|
+
link = '</users/godfat/repos?type=o&per_page=100&page=3>; rel="last"'
|
11
|
+
headers = {'Link' => link}
|
12
|
+
stub_request(:get,
|
13
|
+
'https://api.github.com/users/godfat/repos?type=o&per_page=100').
|
14
|
+
to_return(:body => [0], :headers => headers).times(2)
|
15
|
+
stub_request(:get,
|
16
|
+
'https://api.github.com/users/godfat/repos?type=o&per_page=100&page=2').
|
17
|
+
to_return(:body => [1], :headers => headers).times(2)
|
18
|
+
stub_request(:get,
|
19
|
+
'https://api.github.com/users/godfat/repos?type=o&per_page=100&page=3').
|
20
|
+
to_return(:body => [2], :headers => headers).times(2)
|
21
|
+
|
22
|
+
args = ['users/godfat/repos', {:type => 'o'}]
|
23
|
+
exps = [0, 1, 2]
|
24
|
+
g = RC::Github.new
|
25
|
+
g.all(*args) do |res|
|
26
|
+
res.should.eq exps
|
27
|
+
g.all(*args).should.eq exps
|
28
|
+
end
|
29
|
+
g.wait
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
require 'rest-more/test'
|
3
|
+
|
4
|
+
describe RC::StackExchange do
|
5
|
+
after do
|
6
|
+
WebMock.reset!
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'me' do
|
10
|
+
stub_request(:get,
|
11
|
+
'https://api.stackexchange.com/me?key=yek&site=stackoverflow').
|
12
|
+
to_return(:body => '{"name":"meme"}')
|
13
|
+
|
14
|
+
RC::StackExchange.new(:key => 'yek').me.should.eq 'name' => 'meme'
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-more
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lin Jen-Shin (godfat)
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-core
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 3.
|
19
|
+
version: 3.2.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 3.
|
26
|
+
version: 3.2.0
|
27
27
|
description: |-
|
28
28
|
Various REST clients such as Facebook and Twitter built with [rest-core][].
|
29
29
|
|
@@ -71,12 +71,12 @@ files:
|
|
71
71
|
- lib/rest-core/client/dropbox.rb
|
72
72
|
- lib/rest-core/client/facebook.rb
|
73
73
|
- lib/rest-core/client/facebook/rails_util.rb
|
74
|
-
- lib/rest-core/client/firebase.rb
|
75
74
|
- lib/rest-core/client/github.rb
|
76
75
|
- lib/rest-core/client/github/rails_util.rb
|
77
76
|
- lib/rest-core/client/instagram.rb
|
78
77
|
- lib/rest-core/client/linkedin.rb
|
79
78
|
- lib/rest-core/client/linkedin/rails_util.rb
|
79
|
+
- lib/rest-core/client/stackexchange.rb
|
80
80
|
- lib/rest-core/client/twitter.rb
|
81
81
|
- lib/rest-core/client/twitter/rails_util.rb
|
82
82
|
- lib/rest-core/util/rails_util_util.rb
|
@@ -99,8 +99,9 @@ files:
|
|
99
99
|
- test/facebook/test_parse.rb
|
100
100
|
- test/facebook/test_serialize.rb
|
101
101
|
- test/facebook/test_timeout.rb
|
102
|
-
- test/
|
102
|
+
- test/github/test_github.rb
|
103
103
|
- test/instagram/test_instagram.rb
|
104
|
+
- test/stackexchange/test_stackexchange.rb
|
104
105
|
- test/twitter/test_twitter.rb
|
105
106
|
homepage: https://github.com/godfat/rest-more
|
106
107
|
licenses:
|
@@ -139,6 +140,7 @@ test_files:
|
|
139
140
|
- test/facebook/test_parse.rb
|
140
141
|
- test/facebook/test_serialize.rb
|
141
142
|
- test/facebook/test_timeout.rb
|
142
|
-
- test/
|
143
|
+
- test/github/test_github.rb
|
143
144
|
- test/instagram/test_instagram.rb
|
145
|
+
- test/stackexchange/test_stackexchange.rb
|
144
146
|
- test/twitter/test_twitter.rb
|
@@ -1,105 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rest-core'
|
3
|
-
|
4
|
-
# https://www.firebase.com/docs/security/custom-login.html
|
5
|
-
# https://www.firebase.com/docs/rest-api.html
|
6
|
-
module RestCore
|
7
|
-
Firebase = Builder.client(:d, :secret, :auth) do
|
8
|
-
use Timeout , 10
|
9
|
-
|
10
|
-
use DefaultSite , 'https://SampleChat.firebaseIO-demo.com/'
|
11
|
-
use DefaultHeaders, {'Accept' => 'application/json'}
|
12
|
-
use DefaultQuery , nil
|
13
|
-
|
14
|
-
use FollowRedirect, 1
|
15
|
-
use CommonLogger , nil
|
16
|
-
use Cache , nil, 600 do
|
17
|
-
use ErrorHandler, lambda{ |env| Firebase::Error.call(env) }
|
18
|
-
use ErrorDetectorHttp
|
19
|
-
use JsonResponse, true
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class RestCore::Firebase::Error < RestCore::Error
|
25
|
-
include RestCore
|
26
|
-
class ServerError < Firebase::Error; end
|
27
|
-
class ClientError < RestCore::Error; end
|
28
|
-
|
29
|
-
class BadRequest < Firebase::Error; end
|
30
|
-
class Unauthorized < Firebase::Error; end
|
31
|
-
class Forbidden < Firebase::Error; end
|
32
|
-
class NotFound < Firebase::Error; end
|
33
|
-
class NotAcceptable < Firebase::Error; end
|
34
|
-
class ExpectationFailed < Firebase::Error; end
|
35
|
-
|
36
|
-
class InternalServerError < Firebase::Error::ServerError; end
|
37
|
-
class BadGateway < Firebase::Error::ServerError; end
|
38
|
-
class ServiceUnavailable < Firebase::Error::ServerError; end
|
39
|
-
|
40
|
-
attr_reader :error, :code, :url
|
41
|
-
def initialize error, code, url=''
|
42
|
-
@error, @code, @url = error, code, url
|
43
|
-
super("[#{code}] #{error.inspect} from #{url}")
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.call env
|
47
|
-
error, code, url = env[RESPONSE_BODY], env[RESPONSE_STATUS],
|
48
|
-
env[REQUEST_URI]
|
49
|
-
return new(error, code, url) unless error.kind_of?(Hash)
|
50
|
-
case code
|
51
|
-
when 400; BadRequest
|
52
|
-
when 401; Unauthorized
|
53
|
-
when 403; Forbidden
|
54
|
-
when 404; NotFound
|
55
|
-
when 406; NotAcceptable
|
56
|
-
when 417; ExpectationFailed
|
57
|
-
when 500; InternalServerError
|
58
|
-
when 502; BadGateway
|
59
|
-
when 503; ServiceUnavailable
|
60
|
-
else ; self
|
61
|
-
end.new(error, code, url)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
module RestCore::Firebase::Client
|
66
|
-
include RestCore
|
67
|
-
|
68
|
-
class EventSource < RestCore::EventSource
|
69
|
-
def onmessage event=nil, data=nil, sock=nil
|
70
|
-
if event
|
71
|
-
super(event, Json.decode(data), sock)
|
72
|
-
else
|
73
|
-
super
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def request env, app=app
|
79
|
-
super(env.merge(REQUEST_PATH => "#{env[REQUEST_PATH]}.json",
|
80
|
-
REQUEST_PAYLOAD => Json.encode(env[REQUEST_PAYLOAD])),
|
81
|
-
app)
|
82
|
-
end
|
83
|
-
|
84
|
-
def generate_auth opts={}
|
85
|
-
raise Firebase::Error::ClientError.new(
|
86
|
-
"Please set your secret") unless secret
|
87
|
-
|
88
|
-
header = {:typ => 'JWT', :alg => 'HS256'}
|
89
|
-
claims = {:v => 0, :iat => Time.now.to_i, :d => d}.merge(opts)
|
90
|
-
# http://tools.ietf.org/html/draft-ietf-jose-json-web-signature-26
|
91
|
-
input = [header, claims].map{ |d| base64url(Json.encode(d)) }.join('.')
|
92
|
-
# http://tools.ietf.org/html/draft-ietf-oauth-json-web-token-20
|
93
|
-
"#{input}.#{base64url(Hmac.sha256(secret, input))}"
|
94
|
-
end
|
95
|
-
|
96
|
-
private
|
97
|
-
def base64url str; [str].pack('m').tr('+/', '-_'); end
|
98
|
-
def default_query; {:auth => auth}; end
|
99
|
-
def default_auth ; generate_auth ; end
|
100
|
-
end
|
101
|
-
|
102
|
-
class RestCore::Firebase
|
103
|
-
include RestCore::Firebase::Client
|
104
|
-
self.event_source_class = EventSource
|
105
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'rest-more/test'
|
3
|
-
|
4
|
-
describe RC::Firebase do
|
5
|
-
before do
|
6
|
-
stub(Time).now{ Time.at(0) }
|
7
|
-
end
|
8
|
-
|
9
|
-
after do
|
10
|
-
WebMock.reset!
|
11
|
-
Muack.verify
|
12
|
-
end
|
13
|
-
|
14
|
-
path = 'https://a.json?auth=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9%0A.eyJ2IjowLCJpYXQiOjAsImQiOm51bGx9%0A.C9JtzZhiCrsClNdAQcE7Irngr2BZJCH4x1p-IHxfrAo%3D%0A'
|
15
|
-
|
16
|
-
def firebase
|
17
|
-
RC::Firebase.new(:secret => 'nnf')
|
18
|
-
end
|
19
|
-
|
20
|
-
should 'get true' do
|
21
|
-
stub_request(:get, path).to_return(:body => 'true')
|
22
|
-
firebase.get('https://a').should.eq true
|
23
|
-
end
|
24
|
-
|
25
|
-
should 'put {"status":"ok"}' do
|
26
|
-
json = '{"status":"ok"}'
|
27
|
-
rbon = {'status' => 'ok'}
|
28
|
-
stub_request(:put, path).with(:body => json).to_return(:body => json)
|
29
|
-
firebase.put('https://a', rbon).should.eq rbon
|
30
|
-
end
|
31
|
-
|
32
|
-
should 'parse event source' do
|
33
|
-
stub_request(:get, path).to_return(:body => <<-SSE)
|
34
|
-
event: put
|
35
|
-
data: {}
|
36
|
-
|
37
|
-
event: keep-alive
|
38
|
-
data: null
|
39
|
-
|
40
|
-
event: invalid
|
41
|
-
data: invalid
|
42
|
-
SSE
|
43
|
-
m = [{'event' => 'put' , 'data' => {}},
|
44
|
-
{'event' => 'keep-alive', 'data' => nil}]
|
45
|
-
es = firebase.event_source('https://a')
|
46
|
-
es.should.kind_of RC::Firebase::Client::EventSource
|
47
|
-
es.onmessage do |event, data|
|
48
|
-
{'event' => event, 'data' => data}.should.eq m.shift
|
49
|
-
end.onerror do |error|
|
50
|
-
error.should.kind_of RC::Json::ParseError
|
51
|
-
end.start.wait
|
52
|
-
m.should.empty
|
53
|
-
end
|
54
|
-
|
55
|
-
check = lambda do |status, klass|
|
56
|
-
stub_request(:delete, path).to_return(
|
57
|
-
:body => '{}', :status => status)
|
58
|
-
|
59
|
-
lambda{ firebase.delete('https://a').tap{} }.should.raise(klass)
|
60
|
-
|
61
|
-
WebMock.reset!
|
62
|
-
end
|
63
|
-
|
64
|
-
should 'raise exception when encountering error' do
|
65
|
-
[400, 401, 402, 403, 404, 406, 417].each do |status|
|
66
|
-
check[status, RC::Firebase::Error]
|
67
|
-
end
|
68
|
-
[500, 502, 503].each do |status|
|
69
|
-
check[status, RC::Firebase::Error::ServerError]
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|