rest-core 3.3.2 → 3.3.3
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/.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
|