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 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