rest-more 3.1.0 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e31b7b448ea1e4dce6284fb2a7ecbacb506d759
4
- data.tar.gz: 212fdd5674abee559e5c29e55dd4f696dc71c2f0
3
+ metadata.gz: 5444cce199f7ad6519edbcbfa1db1a2ee7d1b143
4
+ data.tar.gz: 2e7c6a0750501114f7bdd7f631827f5acacf08ea
5
5
  SHA512:
6
- metadata.gz: 02fb9f18f3d7a0ce0eac2d2030ceb2a21b9f45b50a13816ce35ec3227d38fae60041f12a577de54ac7035698361ea10997f362eca66cbbfbe5b26f63b10c009f
7
- data.tar.gz: d80cb820e5c77553e2a61ea6b61a05d56c2fe0552ba7a3af81af5a828897b3f97e2b0d7f3cec60669f25144a16db052f1b3dad79f36557e40a05c751455b7290
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::Firebase][]
32
- * [RC::Github][]
33
- * [RC::Instagram][]
34
- * [RC::Linkedin][]
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.0.0') }
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
- get("1/metadata/#{root}/#{path}", query, opts)['contents'].
91
- map{ |c| c['path'] }
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(:data, :app_id, :secret, :old_site) do
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
- authorize!(:code => old_data['code'], :redirect_uri => '')
181
- self.data = old_data.merge(data)
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
- self.data = ParseQuery.parse_query(
222
- post('oauth/access_token', payload, {},
223
- {:json_response => false}.merge(opts)))
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
- def me query={}, opts={}
27
- get('user', query, opts)
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
 
@@ -23,8 +23,8 @@ end
23
23
  module RestCore::Instagram::Client
24
24
  include RestCore
25
25
 
26
- def me query={}, opts={}
27
- get('v1/users/self', query, opts)
26
+ def me query={}, opts={}, &cb
27
+ get('v1/users/self', query, opts, &cb)
28
28
  end
29
29
 
30
30
  def access_token
@@ -27,8 +27,14 @@ end
27
27
  module RestCore::Linkedin::Client
28
28
  include RestCore
29
29
 
30
- def me query={}, opts={}
31
- get('v1/people/~', query, opts)
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', {:id => user}.merge(query), opts)
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 , '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 :Twitter , 'rest-core/client/twitter'
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
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestMore
3
- VERSION = '3.1.0'
3
+ VERSION = '3.2.0'
4
4
  end
data/rest-more.gemspec CHANGED
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rest-more 3.1.0 ruby lib
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.1.0"
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-05-09"
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/firebase/test_firebase.rb",
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/firebase/test_firebase.rb",
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.0.0"])
110
+ s.add_runtime_dependency(%q<rest-core>, [">= 3.2.0"])
109
111
  else
110
- s.add_dependency(%q<rest-core>, [">= 3.0.0"])
112
+ s.add_dependency(%q<rest-core>, [">= 3.2.0"])
111
113
  end
112
114
  else
113
- s.add_dependency(%q<rest-core>, [">= 3.0.0"])
115
+ s.add_dependency(%q<rest-core>, [">= 3.2.0"])
114
116
  end
115
117
  end
@@ -4,7 +4,6 @@ require 'rest-more/test'
4
4
  describe RC::Dropbox do
5
5
  after do
6
6
  WebMock.reset!
7
- Muack.verify
8
7
  end
9
8
 
10
9
  should 'get right' do
@@ -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
- stub(o = Object.new).to_s{ 'i am mock' }
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).
@@ -4,7 +4,6 @@ require 'rest-more/test'
4
4
  describe RC::Facebook::Error do
5
5
  after do
6
6
  WebMock.reset!
7
- Muack.verify
8
7
  end
9
8
 
10
9
  should 'have the right ancestors' do
@@ -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
  describe 'log method' do
@@ -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 'return true in authorized? if there is an access_token' do
@@ -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 'do fql query with/without access_token' do
@@ -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 'get the next/prev page' do
@@ -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
- mock(rg).authorize!(:code => code, :redirect_uri => ''){
117
- rg.data = {'access_token' => access_token}
118
- }.times(2)
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
@@ -2,11 +2,6 @@
2
2
  require 'rest-more/test'
3
3
 
4
4
  describe RC::Facebook do
5
- after do
6
- WebMock.reset!
7
- Muack.verify
8
- end
9
-
10
5
  should 'be serialized with lighten' do
11
6
  require 'yaml'
12
7
  [YAML, Marshal].each{ |engine|
@@ -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
@@ -4,7 +4,6 @@ require 'rest-more/test'
4
4
  describe RC::Twitter do
5
5
  after do
6
6
  WebMock.reset!
7
- Muack.verify
8
7
  end
9
8
 
10
9
  should 'get right' do
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.1.0
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-05-09 00:00:00.000000000 Z
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.0.0
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.0.0
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/firebase/test_firebase.rb
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/firebase/test_firebase.rb
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