rest-core 3.3.2 → 3.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -3
- data/CHANGES.md +22 -0
- data/README.md +4 -7
- data/lib/rest-core/engine/http-client.rb +0 -2
- data/lib/rest-core/event_source.rb +1 -1
- data/lib/rest-core/middleware/auth_basic.rb +1 -1
- data/lib/rest-core/middleware/error_handler.rb +1 -0
- data/lib/rest-core/middleware/oauth1_header.rb +2 -2
- data/lib/rest-core/promise.rb +20 -17
- data/lib/rest-core/version.rb +1 -1
- data/rest-core.gemspec +3 -3
- data/test/test_client.rb +41 -0
- data/test/test_error_handler.rb +15 -0
- data/test/test_simple.rb +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07acac398a096c63464e9dca43b964dbe0d6359a
|
4
|
+
data.tar.gz: 887c818f4a83591b316511c709fbbf10e2d45c35
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24e9ebd41021150461013695d6e7cf4d2e6c628ea5156787c7dd957d4cd72e9df3452529518cfc9a48d1c837379aebee3cc6485bbe6422ba196fb3951f02da19
|
7
|
+
data.tar.gz: 6a0da34cf3b1221b9b791fb63eee8419c2ce93b6766e395019453f5dc65a8859f24a73a48ef46728ef7e9262186ff0d032334d82ddb777cfcad4b08ec920e4ad
|
data/.travis.yml
CHANGED
data/CHANGES.md
CHANGED
@@ -1,5 +1,27 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## rest-core 3.3.3 -- 2014-11-07
|
4
|
+
|
5
|
+
### Bugs fixed
|
6
|
+
|
7
|
+
* `RC::EventSource` would now properly reconnect for SystemCallError such as
|
8
|
+
`Errno::ECONNRESET`.
|
9
|
+
|
10
|
+
* It would now always emit a warning whenever there's an exception raised
|
11
|
+
asynchronously.
|
12
|
+
|
13
|
+
* All exceptions raised from a thread or thread pool would now have a
|
14
|
+
proper backtrace. This was fixed by introducing `RC::Promise.backtrace`
|
15
|
+
|
16
|
+
### Enhancements
|
17
|
+
|
18
|
+
* Introduced `RC::Promise.backtrace`. Using this in a callback could give you
|
19
|
+
proper backtrace, comparing to `caller` would only give you the backtrace
|
20
|
+
for current thread.
|
21
|
+
|
22
|
+
* Introduced `RC::Promise.set_backtrace`. Using this we could set exceptions
|
23
|
+
with proper backtrace.
|
24
|
+
|
3
25
|
## rest-core 3.3.2 -- 2014-10-11
|
4
26
|
|
5
27
|
* Just use `File.join` for `RC::DefaultSite` as `File::SEPARATOR` is
|
data/README.md
CHANGED
@@ -14,6 +14,9 @@ talk is in Mandarin.
|
|
14
14
|
* [github](https://github.com/godfat/rest-core)
|
15
15
|
* [rubygems](https://rubygems.org/gems/rest-core)
|
16
16
|
* [rdoc](http://rdoc.info/projects/godfat/rest-core)
|
17
|
+
* [mailing list](http://www.freelists.org/list/rest-core)
|
18
|
+
Send your questions to: <rest-core@freelists.org> and you could read
|
19
|
+
through [archives](http://www.freelists.org/archives/rest-core)
|
17
20
|
|
18
21
|
## DESCRIPTION:
|
19
22
|
|
@@ -73,8 +76,6 @@ gem 'rest-core', :git => 'git://github.com/godfat/rest-core.git',
|
|
73
76
|
If you just want to use Facebook or Twitter clients, please take a look at
|
74
77
|
[rest-more][] which has a lot of clients built with rest-core.
|
75
78
|
|
76
|
-
[rest-more]: http://github.com/godfat/rest-more
|
77
|
-
|
78
79
|
## Build Your Own Clients:
|
79
80
|
|
80
81
|
You can use `RestCore::Builder` to build your own dedicated clients.
|
@@ -374,12 +375,10 @@ client.request_full(RC::REQUEST_PATH => 'godfat',
|
|
374
375
|
|
375
376
|
Runnable example is at: [example/simple.rb][]. Please see [rest-more][]
|
376
377
|
for more complex examples to build clients, and [slides][] from
|
377
|
-
[rubyconf.tw/2011][
|
378
|
+
[rubyconf.tw/2011][talk] for concepts.
|
378
379
|
|
379
380
|
[example/simple.rb]: example/simple.rb
|
380
|
-
[rest-more]: https://github.com/godfat/rest-more
|
381
381
|
[slides]: http://www.godfat.org/slide/2011-08-27-rest-core.html
|
382
|
-
[rubyconf.tw]: http://rubyconf.tw/2011/#6
|
383
382
|
|
384
383
|
## Playing Around:
|
385
384
|
|
@@ -452,7 +451,6 @@ This is mostly for fun and experimenting, so it's only included in
|
|
452
451
|
installed before trying this.
|
453
452
|
|
454
453
|
[rib]: https://github.com/godfat/rib
|
455
|
-
[rest-more]: https://github.com/godfat/rest-more
|
456
454
|
|
457
455
|
## List of built-in Middleware:
|
458
456
|
|
@@ -683,7 +681,6 @@ all the possible use cases, you can also see: [example/use-cases.rb][]. It's
|
|
683
681
|
also served as a test for each possible combinations, so it's quite complex
|
684
682
|
and complete.
|
685
683
|
|
686
|
-
[example/simple.rb]: example/simple.rb
|
687
684
|
[example/use-cases.rb]: example/use-cases.rb
|
688
685
|
|
689
686
|
## rest-core users:
|
@@ -47,7 +47,7 @@ class RestCore::Oauth1Header
|
|
47
47
|
|
48
48
|
def signature env, params
|
49
49
|
[Hmac.sha1("#{consumer_secret(env)}&#{oauth_token_secret(env)}",
|
50
|
-
base_string(env, params))].pack('
|
50
|
+
base_string(env, params))].pack('m0')
|
51
51
|
end
|
52
52
|
|
53
53
|
def base_string env, oauth_params
|
@@ -63,7 +63,7 @@ class RestCore::Oauth1Header
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def nonce
|
66
|
-
[OpenSSL::Random.random_bytes(32)].pack('
|
66
|
+
[OpenSSL::Random.random_bytes(32)].pack('m0').tr("+/=", '')
|
67
67
|
end
|
68
68
|
|
69
69
|
# according to OAuth 1.0a spec, only:
|
data/lib/rest-core/promise.rb
CHANGED
@@ -21,6 +21,14 @@ class RestCore::Promise
|
|
21
21
|
promise
|
22
22
|
end
|
23
23
|
|
24
|
+
def self.backtrace
|
25
|
+
Thread.current[:backtrace] || []
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.set_backtrace e
|
29
|
+
e.set_backtrace((e.backtrace || caller) + backtrace)
|
30
|
+
end
|
31
|
+
|
24
32
|
def initialize env, k=RC.id, immediate=false, &job
|
25
33
|
self.env = env
|
26
34
|
self.k = [k]
|
@@ -58,11 +66,13 @@ class RestCore::Promise
|
|
58
66
|
if pool_size < 0 # negative number for blocking call
|
59
67
|
job.call
|
60
68
|
elsif pool_size > 0
|
69
|
+
backtrace = caller + self.class.backtrace
|
61
70
|
self.task = client_class.thread_pool.defer do
|
62
|
-
synchronized_yield{ job.call }
|
71
|
+
synchronized_yield(backtrace){ job.call }
|
63
72
|
end
|
64
73
|
else
|
65
|
-
|
74
|
+
backtrace = caller + self.class.backtrace
|
75
|
+
Thread.new{ synchronized_yield(backtrace){ job.call } }
|
66
76
|
end
|
67
77
|
env[TIMER].on_timeout{ reject(env[TIMER].error) } if env[TIMER]
|
68
78
|
end
|
@@ -85,7 +95,8 @@ class RestCore::Promise
|
|
85
95
|
self.body, self.status, self.headers, self.socket =
|
86
96
|
body, status, headers, socket
|
87
97
|
# under ASYNC callback, should call immediately
|
88
|
-
|
98
|
+
callback if immediate
|
99
|
+
ensure
|
89
100
|
condv.broadcast # client or response might be waiting
|
90
101
|
end
|
91
102
|
|
@@ -112,7 +123,7 @@ class RestCore::Promise
|
|
112
123
|
# For synchronous mode, since we're waiting for the callback anyway,
|
113
124
|
# we don't really have to check if it's called.
|
114
125
|
def done?
|
115
|
-
!!status && !
|
126
|
+
!!status && (!immediate || called)
|
116
127
|
end
|
117
128
|
|
118
129
|
protected
|
@@ -124,14 +135,16 @@ class RestCore::Promise
|
|
124
135
|
private
|
125
136
|
# called in a new thread if pool_size == 0, otherwise from the pool
|
126
137
|
# i.e. requesting thread
|
127
|
-
def synchronized_yield
|
138
|
+
def synchronized_yield backtrace
|
139
|
+
Thread.current[:backtrace] = backtrace
|
128
140
|
mutex.synchronize{ yield }
|
129
141
|
rescue Exception => e
|
142
|
+
self.class.set_backtrace(e)
|
130
143
|
# nothing we can do here for an asynchronous exception,
|
131
144
|
# so we just log the error
|
132
145
|
# TODO: add error_log_method
|
133
146
|
warn "RestCore: ERROR: #{e}\n from #{e.backtrace.inspect}"
|
134
|
-
reject(e)
|
147
|
+
reject(e) unless done? # not done: i/o error; done: callback error
|
135
148
|
end
|
136
149
|
|
137
150
|
# called in client thread, when yield is called
|
@@ -144,18 +157,8 @@ class RestCore::Promise
|
|
144
157
|
RESPONSE_SOCKET => socket,
|
145
158
|
FAIL => ((env[FAIL]||[]) + [error]).compact,
|
146
159
|
LOG => env[LOG] ||[])){ |r, i| i.call(r) }
|
160
|
+
ensure
|
147
161
|
self.called = true
|
148
|
-
response
|
149
|
-
end
|
150
|
-
|
151
|
-
# called in requesting thread, whenever the request is done
|
152
|
-
def callback_in_async
|
153
|
-
callback
|
154
|
-
rescue Exception => e
|
155
|
-
# nothing we can do here for an asynchronous exception,
|
156
|
-
# so we just log the error
|
157
|
-
# TODO: add error_log_method
|
158
|
-
warn "RestCore: ERROR: #{e}\n from #{e.backtrace.inspect}"
|
159
162
|
end
|
160
163
|
|
161
164
|
def client_class; env[CLIENT].class; end
|
data/lib/rest-core/version.rb
CHANGED
data/rest-core.gemspec
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: rest-core 3.3.
|
2
|
+
# stub: rest-core 3.3.3 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "rest-core"
|
6
|
-
s.version = "3.3.
|
6
|
+
s.version = "3.3.3"
|
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-11-07"
|
12
12
|
s.description = "Modular Ruby clients interface for REST APIs.\n\nThere has been an explosion in the number of REST APIs available today.\nTo address the need for a way to access these APIs easily and elegantly,\nwe have developed rest-core, which consists of composable middleware\nthat allows you to build a REST client for any REST API. Or in the case of\ncommon APIs such as Facebook, Github, and Twitter, you can simply use the\ndedicated clients provided by [rest-more][].\n\n[rest-more]: https://github.com/godfat/rest-more"
|
13
13
|
s.email = ["godfat (XD) godfat.org"]
|
14
14
|
s.files = [
|
data/test/test_client.rb
CHANGED
@@ -49,6 +49,7 @@ describe RC::Simple do
|
|
49
49
|
stub_request(:get, url).to_return do
|
50
50
|
m.synchronize{ i += 1 }
|
51
51
|
Thread.pass
|
52
|
+
{}
|
52
53
|
end
|
53
54
|
|
54
55
|
client = RC::Builder.client
|
@@ -131,4 +132,44 @@ describe RC::Simple do
|
|
131
132
|
stub_request(:get, url).to_return(:body => '123')
|
132
133
|
Class.new(RC::Simple).new.get(url).should.eq '123'
|
133
134
|
end
|
135
|
+
|
136
|
+
would 'not deadlock when exception was raised in the callback' do
|
137
|
+
client = Class.new(RC::Simple).new
|
138
|
+
stub_request(:get, url).to_return(:body => 'nnf')
|
139
|
+
|
140
|
+
(0..1).each do |size|
|
141
|
+
mock(any_instance_of(RC::Promise)).warn(is_a(String)) do |msg|
|
142
|
+
msg.should.include?('nnf')
|
143
|
+
end
|
144
|
+
client.class.pool_size = size
|
145
|
+
client.get(url) do |body|
|
146
|
+
raise body
|
147
|
+
end
|
148
|
+
client.class.shutdown
|
149
|
+
end
|
150
|
+
|
151
|
+
client.class.pool_size = -1
|
152
|
+
should.raise do
|
153
|
+
client.get(url) do |body|
|
154
|
+
raise body
|
155
|
+
end
|
156
|
+
end.message.should.eq 'nnf'
|
157
|
+
client.class.shutdown
|
158
|
+
end
|
159
|
+
|
160
|
+
would 'be able to access caller outside the callback' do
|
161
|
+
client = RC::Simple.new
|
162
|
+
stub_request(:get, url).to_return(:body => 'nnf')
|
163
|
+
client.get(url) do
|
164
|
+
current_file = /^#{__FILE__}/
|
165
|
+
caller.grep(current_file).should.empty?
|
166
|
+
RC::Promise.backtrace.grep(current_file).should.not.empty?
|
167
|
+
client.get(url) do
|
168
|
+
RC::Promise.backtrace.last.should.not =~ /promise\.rb:\d+:in/
|
169
|
+
client = nil
|
170
|
+
end
|
171
|
+
end
|
172
|
+
client.wait
|
173
|
+
client.should.nil? # to make sure the inner most block did run
|
174
|
+
end
|
134
175
|
end
|
data/test/test_error_handler.rb
CHANGED
@@ -41,4 +41,19 @@ describe RC::ErrorHandler do
|
|
41
41
|
client.new(:error_handler => lambda{ |res| 1 }).
|
42
42
|
request(RC::FAIL => [0], RC::RESPONSE_KEY => RC::FAIL).should.eq [0, 1]
|
43
43
|
end
|
44
|
+
|
45
|
+
would 'set full backtrace' do
|
46
|
+
url = 'http://example.com/'
|
47
|
+
client = RC::Builder.client do
|
48
|
+
use RC::ErrorHandler, lambda{ |env|
|
49
|
+
RuntimeError.new(env[RC::RESPONSE_BODY]) }
|
50
|
+
use RC::ErrorDetectorHttp
|
51
|
+
end.new
|
52
|
+
stub_request(:get, url).to_return(:status => 404, :body => 'nnf')
|
53
|
+
client.get(url) do |error|
|
54
|
+
error.message.should.eq 'nnf'
|
55
|
+
error.backtrace.grep(/^#{__FILE__}/).should.not.empty?
|
56
|
+
end
|
57
|
+
client.wait
|
58
|
+
end
|
44
59
|
end
|
data/test/test_simple.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.3
|
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-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httpclient
|