rest-core 2.1.0 → 2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +13 -0
- data/Rakefile +1 -1
- data/lib/rest-core/engine/em-http-request.rb +34 -24
- data/lib/rest-core/engine/rest-client.rb +23 -23
- data/lib/rest-core/util/payload.rb +34 -27
- data/lib/rest-core/version.rb +1 -1
- data/rest-core.gemspec +3 -3
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5cc0c6118d2d5169988871b31d9b5544e2f28f60
|
4
|
+
data.tar.gz: c73e366ba7c4cdbdec4a5a76528ed5d8df21aed4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c175b2f84c14257fe189ae82bee8f1d3a2bd205ac4da36ab8b0b596ccfdf47253d05b8cb4940c4ebe47e770385ed282b6dfadf53db04a1fba67adc4975ae177e
|
7
|
+
data.tar.gz: 53cd1bed753213a3a27637ceb85acf9577504aaa48cf0b760c48c20a6cd35c87f96f8b8c2dc438b568adc8404d1b4c19066dbb5efc6c40871d5ea91e78cd43e5
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,18 @@
|
|
1
1
|
# CHANGES
|
2
2
|
|
3
|
+
## rest-core 2.1.1 -- 2013-05-21
|
4
|
+
|
5
|
+
### Bugs fixes
|
6
|
+
|
7
|
+
* Fixed em-http-request support.
|
8
|
+
|
9
|
+
### Enhancement
|
10
|
+
|
11
|
+
* [`Payload`] Now it is a class rather than a module.
|
12
|
+
* [`Paylaod`] Introduced `Payload.generate_with_headers`.
|
13
|
+
* [`Paylaod`] Give a `nil` if payload passing to `Payload.generate` should
|
14
|
+
not have any payload at all.
|
15
|
+
|
3
16
|
## rest-core 2.1.0 -- 2013-05-08
|
4
17
|
|
5
18
|
### Incompatible changes
|
data/Rakefile
CHANGED
@@ -24,7 +24,7 @@ task 'gem:spec' do
|
|
24
24
|
s.email = ['dev (XD) cardinalblue.com']
|
25
25
|
|
26
26
|
s.post_install_message = <<-MARKDOWN
|
27
|
-
# [rest-core] Incompatible changes for POST requests:
|
27
|
+
# [rest-core] Since 2.1.0, Incompatible changes for POST requests:
|
28
28
|
|
29
29
|
* We no longer support Rails-like POST payload, like translating
|
30
30
|
`{:foo => [1, 2]}` to `'foo[]=1&foo[]=2'`. It would now be translated to
|
@@ -20,41 +20,37 @@ class RestCore::EmHttpRequest
|
|
20
20
|
FUTURE => future)
|
21
21
|
end
|
22
22
|
|
23
|
-
def close client, tmpfile
|
24
|
-
(client.instance_variable_get(:@callbacks)||[]).clear
|
25
|
-
(client.instance_variable_get(:@errbacks )||[]).clear
|
26
|
-
client.close
|
27
|
-
if tmpfile.respond_to?(:close!) # tempfile
|
28
|
-
tmpfile.close!
|
29
|
-
elsif tmpfile.respond_to?(:close) # regular IO
|
30
|
-
tmpfile.close
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
23
|
def request future, env
|
35
|
-
payload = Payload.
|
36
|
-
|
37
|
-
args
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
24
|
+
payload, headers = Payload.generate_with_headers(env[REQUEST_PAYLOAD],
|
25
|
+
env[REQUEST_HEADERS])
|
26
|
+
args = if payload.nil?
|
27
|
+
{}
|
28
|
+
else
|
29
|
+
tmpfile = payload2file(payload)
|
30
|
+
if tmpfile.respond_to?(:path)
|
31
|
+
{:file => tmpfile.path}
|
32
|
+
else
|
33
|
+
{:body => tmpfile}
|
34
|
+
end
|
35
|
+
end.merge(:head => headers)
|
36
|
+
|
37
|
+
client = ::EventMachine::HttpRequest.new(request_uri(env)).
|
38
|
+
send(env[REQUEST_METHOD], args)
|
45
39
|
|
46
40
|
client.callback{
|
47
|
-
|
41
|
+
close_tmpfile(tmpfile)
|
48
42
|
future.on_load(client.response,
|
49
43
|
client.response_header.status,
|
50
44
|
client.response_header)}
|
51
45
|
|
52
46
|
client.errback{
|
53
|
-
|
47
|
+
close_client(client)
|
48
|
+
close_tmpfile(tmpfile)
|
54
49
|
future.on_error(client.error)}
|
55
50
|
|
56
51
|
env[TIMER].on_timeout{
|
57
|
-
|
52
|
+
close_client(client)
|
53
|
+
close_tmpfile(tmpfile)
|
58
54
|
future.on_error(env[TIMER].error)
|
59
55
|
} if env[TIMER]
|
60
56
|
end
|
@@ -77,4 +73,18 @@ class RestCore::EmHttpRequest
|
|
77
73
|
IO.copy_stream(io, tempfile)
|
78
74
|
tempfile
|
79
75
|
end
|
76
|
+
|
77
|
+
def close_client client
|
78
|
+
(client.instance_variable_get(:@callbacks)||[]).clear
|
79
|
+
(client.instance_variable_get(:@errbacks )||[]).clear
|
80
|
+
client.close
|
81
|
+
end
|
82
|
+
|
83
|
+
def close_tmpfile tmpfile
|
84
|
+
if tmpfile.respond_to?(:close!) # tempfile
|
85
|
+
tmpfile.close!
|
86
|
+
elsif tmpfile.respond_to?(:close) # regular IO
|
87
|
+
tmpfile.close
|
88
|
+
end
|
89
|
+
end
|
80
90
|
end
|
@@ -10,29 +10,8 @@ class RestCore::RestClient
|
|
10
10
|
def call env, &k
|
11
11
|
future = Future::FutureThread.new(env, k, env[ASYNC])
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
payload = Payload.generate(env[REQUEST_PAYLOAD])
|
16
|
-
headers = env[REQUEST_HEADERS].merge(payload.headers)
|
17
|
-
res = ::RestClient::Request.execute(:method => env[REQUEST_METHOD],
|
18
|
-
:url => request_uri(env) ,
|
19
|
-
:payload => payload ,
|
20
|
-
:headers => headers ,
|
21
|
-
:max_redirects => 0)
|
22
|
-
future.on_load(res.body, res.code, normalize_headers(res.raw_headers))
|
23
|
-
|
24
|
-
rescue ::RestClient::Exception => e
|
25
|
-
if res = e.response
|
26
|
-
# we don't want to raise an exception for 404 requests
|
27
|
-
future.on_load(res.body, res.code,
|
28
|
-
normalize_headers(res.raw_headers))
|
29
|
-
else
|
30
|
-
future.on_error(e)
|
31
|
-
end
|
32
|
-
rescue Exception => e
|
33
|
-
future.on_error(e)
|
34
|
-
end
|
35
|
-
}
|
13
|
+
# we can implement thread pool in the future
|
14
|
+
t = future.wrap{ request(future, env) }
|
36
15
|
|
37
16
|
env[TIMER].on_timeout{
|
38
17
|
t.kill
|
@@ -45,6 +24,27 @@ class RestCore::RestClient
|
|
45
24
|
FUTURE => future)
|
46
25
|
end
|
47
26
|
|
27
|
+
def request future, env
|
28
|
+
payload, headers = Payload.generate_with_headers(env[REQUEST_PAYLOAD],
|
29
|
+
env[REQUEST_HEADERS])
|
30
|
+
res = ::RestClient::Request.execute(:method => env[REQUEST_METHOD],
|
31
|
+
:url => request_uri(env) ,
|
32
|
+
:payload => payload ,
|
33
|
+
:headers => headers ,
|
34
|
+
:max_redirects => 0)
|
35
|
+
future.on_load(res.body, res.code, normalize_headers(res.raw_headers))
|
36
|
+
|
37
|
+
rescue ::RestClient::Exception => e
|
38
|
+
if res = e.response
|
39
|
+
# we don't want to raise an exception for 404 requests
|
40
|
+
future.on_load(res.body, res.code, normalize_headers(res.raw_headers))
|
41
|
+
else
|
42
|
+
future.on_error(e)
|
43
|
+
end
|
44
|
+
rescue Exception => e
|
45
|
+
future.on_error(e)
|
46
|
+
end
|
47
|
+
|
48
48
|
def normalize_headers raw_headers
|
49
49
|
raw_headers.inject({}){ |r, (k, v)|
|
50
50
|
r[k.to_s.upcase.tr('-', '_')] = if v.kind_of?(Array) && v.size == 1
|
@@ -9,11 +9,19 @@ require 'stringio'
|
|
9
9
|
require 'tempfile'
|
10
10
|
|
11
11
|
module RestCore; end
|
12
|
-
|
12
|
+
class RestCore::Payload
|
13
13
|
include RestCore
|
14
|
-
module_function
|
15
14
|
|
16
|
-
def
|
15
|
+
def self.generate_with_headers payload, headers
|
16
|
+
h = if p = generate(payload)
|
17
|
+
p.headers.merge(headers)
|
18
|
+
else
|
19
|
+
headers
|
20
|
+
end
|
21
|
+
[p, h]
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.generate payload
|
17
25
|
if payload.respond_to?(:read)
|
18
26
|
Streamed.new(payload)
|
19
27
|
|
@@ -21,7 +29,10 @@ module RestCore::Payload
|
|
21
29
|
StreamedString.new(payload)
|
22
30
|
|
23
31
|
elsif payload.kind_of?(Hash)
|
24
|
-
if
|
32
|
+
if payload.empty?
|
33
|
+
nil
|
34
|
+
|
35
|
+
elsif Middleware.contain_binary?(payload)
|
25
36
|
Multipart.new(payload)
|
26
37
|
|
27
38
|
else
|
@@ -34,34 +45,30 @@ module RestCore::Payload
|
|
34
45
|
end
|
35
46
|
end
|
36
47
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
48
|
+
# Payload API
|
49
|
+
attr_reader :io
|
50
|
+
alias_method :to_io, :io
|
51
|
+
|
52
|
+
def initialize payload; @io = payload ; end
|
53
|
+
def read bytes=nil; io.read(bytes) ; end
|
54
|
+
def close ; io.close unless closed?; end
|
55
|
+
def closed? ; io.closed? ; end
|
56
|
+
def headers ; {} ; end
|
57
|
+
|
58
|
+
def size
|
59
|
+
if io.respond_to?(:size)
|
60
|
+
io.size
|
61
|
+
elsif io.respond_to?(:stat)
|
62
|
+
io.stat.size
|
63
|
+
else
|
64
|
+
0
|
47
65
|
end
|
66
|
+
end
|
48
67
|
|
68
|
+
class Streamed < Payload
|
49
69
|
def headers
|
50
70
|
{'Content-Length' => size.to_s}
|
51
71
|
end
|
52
|
-
|
53
|
-
def size
|
54
|
-
if io.respond_to?(:size)
|
55
|
-
io.size
|
56
|
-
elsif io.respond_to?(:stat)
|
57
|
-
io.stat.size
|
58
|
-
else
|
59
|
-
0
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def close ; io.close unless closed?; end
|
64
|
-
def closed?; io.closed? ; end
|
65
72
|
end
|
66
73
|
|
67
74
|
class StreamedString < Streamed
|
data/lib/rest-core/version.rb
CHANGED
data/rest-core.gemspec
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "rest-core"
|
5
|
-
s.version = "2.1.
|
5
|
+
s.version = "2.1.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = [
|
9
9
|
"Cardinal Blue",
|
10
10
|
"Lin Jen-Shin (godfat)"]
|
11
|
-
s.date = "2013-05-
|
11
|
+
s.date = "2013-05-21"
|
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/cardinalblue/rest-more"
|
13
13
|
s.email = ["dev (XD) cardinalblue.com"]
|
14
14
|
s.files = [
|
@@ -97,7 +97,7 @@ Gem::Specification.new do |s|
|
|
97
97
|
"test/test_wrapper.rb"]
|
98
98
|
s.homepage = "https://github.com/cardinalblue/rest-core"
|
99
99
|
s.licenses = ["Apache License 2.0"]
|
100
|
-
s.post_install_message = "# [rest-core] Incompatible changes for POST requests:\n\n* We no longer support Rails-like POST payload, like translating\n `{:foo => [1, 2]}` to `'foo[]=1&foo[]=2'`. It would now be translated to\n `'foo=1&foo=2'`. If you like `'foo[]'` as the key, simply pass it as\n `{'foo[]' => [1, 2]}`.\n\n* This also applies to nested hashes like `{:foo => {:bar => 1}`. If you\n want that behaviour, just pass `{'foo[bar]' => 1}` which would then be\n translated to `'foo[bar]=1'`.\n"
|
100
|
+
s.post_install_message = "# [rest-core] Since 2.1.0, Incompatible changes for POST requests:\n\n* We no longer support Rails-like POST payload, like translating\n `{:foo => [1, 2]}` to `'foo[]=1&foo[]=2'`. It would now be translated to\n `'foo=1&foo=2'`. If you like `'foo[]'` as the key, simply pass it as\n `{'foo[]' => [1, 2]}`.\n\n* This also applies to nested hashes like `{:foo => {:bar => 1}`. If you\n want that behaviour, just pass `{'foo[bar]' => 1}` which would then be\n translated to `'foo[bar]=1'`.\n"
|
101
101
|
s.require_paths = ["lib"]
|
102
102
|
s.rubygems_version = "2.0.3"
|
103
103
|
s.summary = "Modular Ruby clients interface for REST APIs."
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cardinal Blue
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rest-client
|
@@ -130,7 +130,7 @@ licenses:
|
|
130
130
|
- Apache License 2.0
|
131
131
|
metadata: {}
|
132
132
|
post_install_message: |
|
133
|
-
# [rest-core] Incompatible changes for POST requests:
|
133
|
+
# [rest-core] Since 2.1.0, Incompatible changes for POST requests:
|
134
134
|
|
135
135
|
* We no longer support Rails-like POST payload, like translating
|
136
136
|
`{:foo => [1, 2]}` to `'foo[]=1&foo[]=2'`. It would now be translated to
|