rest-core 3.6.0 → 4.0.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 +4 -4
- data/.gitmodules +3 -0
- data/.travis.yml +0 -1
- data/CHANGES.md +28 -0
- data/Gemfile +0 -2
- data/README.md +14 -95
- data/Rakefile +16 -3
- data/example/simple.rb +1 -0
- data/example/use-cases.rb +15 -3
- data/lib/rest-core.rb +38 -75
- data/lib/rest-core/client/universal.rb +3 -1
- data/lib/rest-core/client_oauth1.rb +64 -59
- data/lib/rest-core/event.rb +9 -11
- data/lib/rest-core/middleware/auth_basic.rb +21 -21
- data/lib/rest-core/middleware/bypass.rb +8 -8
- data/lib/rest-core/middleware/cache.rb +94 -90
- data/lib/rest-core/middleware/clash_response.rb +15 -14
- data/lib/rest-core/middleware/common_logger.rb +27 -26
- data/lib/rest-core/middleware/default_headers.rb +8 -8
- data/lib/rest-core/middleware/default_payload.rb +8 -8
- data/lib/rest-core/middleware/default_query.rb +8 -8
- data/lib/rest-core/middleware/default_site.rb +12 -12
- data/lib/rest-core/middleware/defaults.rb +38 -38
- data/lib/rest-core/middleware/error_detector.rb +10 -10
- data/lib/rest-core/middleware/error_detector_http.rb +6 -4
- data/lib/rest-core/middleware/error_handler.rb +14 -14
- data/lib/rest-core/middleware/follow_redirect.rb +28 -27
- data/lib/rest-core/middleware/json_request.rb +13 -11
- data/lib/rest-core/middleware/json_response.rb +29 -28
- data/lib/rest-core/middleware/oauth1_header.rb +84 -83
- data/lib/rest-core/middleware/oauth2_header.rb +27 -25
- data/lib/rest-core/middleware/oauth2_query.rb +15 -15
- data/lib/rest-core/middleware/query_response.rb +14 -14
- data/lib/rest-core/middleware/retry.rb +25 -23
- data/lib/rest-core/middleware/smash_response.rb +15 -14
- data/lib/rest-core/middleware/timeout.rb +18 -19
- data/lib/rest-core/test.rb +1 -18
- data/lib/rest-core/util/clash.rb +38 -37
- data/lib/rest-core/util/config.rb +40 -39
- data/lib/rest-core/util/dalli_extension.rb +11 -10
- data/lib/rest-core/util/hmac.rb +9 -8
- data/lib/rest-core/util/json.rb +55 -54
- data/lib/rest-core/util/parse_link.rb +13 -12
- data/lib/rest-core/util/parse_query.rb +24 -22
- data/lib/rest-core/version.rb +1 -1
- data/rest-core.gemspec +121 -158
- data/test/test_cache.rb +2 -0
- data/test/test_default_payload.rb +1 -1
- data/test/test_error_handler.rb +5 -4
- data/test/test_timeout.rb +9 -8
- data/test/test_universal.rb +8 -0
- metadata +9 -73
- data/lib/rest-core/builder.rb +0 -162
- data/lib/rest-core/client.rb +0 -277
- data/lib/rest-core/client/simple.rb +0 -2
- data/lib/rest-core/engine.rb +0 -36
- data/lib/rest-core/engine/dry.rb +0 -9
- data/lib/rest-core/engine/http-client.rb +0 -41
- data/lib/rest-core/error.rb +0 -5
- data/lib/rest-core/event_source.rb +0 -137
- data/lib/rest-core/middleware.rb +0 -151
- data/lib/rest-core/promise.rb +0 -249
- data/lib/rest-core/thread_pool.rb +0 -131
- data/lib/rest-core/timer.rb +0 -58
- data/lib/rest-core/util/payload.rb +0 -173
- data/test/test_builder.rb +0 -40
- data/test/test_client.rb +0 -177
- data/test/test_event_source.rb +0 -159
- data/test/test_future.rb +0 -16
- data/test/test_httpclient.rb +0 -118
- data/test/test_payload.rb +0 -204
- data/test/test_promise.rb +0 -146
- data/test/test_simple.rb +0 -38
- data/test/test_thread_pool.rb +0 -10
data/test/test_universal.rb
CHANGED
@@ -8,6 +8,7 @@ describe RC::Universal do
|
|
8
8
|
WebMock.reset!
|
9
9
|
end
|
10
10
|
|
11
|
+
# TODO: RuntimeError: The request GET http://localhost:1/ with body nil was expected to execute 1 time but it executed 2 times
|
11
12
|
would 'only send payload for post, put, patch' do
|
12
13
|
c = RC::Universal.new(:log_method => false, :payload => '$payload')
|
13
14
|
[:get, :delete, :head, :options].each do |method|
|
@@ -69,4 +70,11 @@ describe RC::Universal do
|
|
69
70
|
errors.map(&:class).should.eq [Errno::ECONNREFUSED]*2
|
70
71
|
called.map(&:class).should.eq [Errno::ECONNREFUSED]
|
71
72
|
end
|
73
|
+
|
74
|
+
would 'not deadlock with ErrorHandler' do
|
75
|
+
c = RC::Universal.new(:log_method => false).
|
76
|
+
event_source('http://localhost:1')
|
77
|
+
c.onerror{ |e| e.should.kind_of?(Errno::ECONNREFUSED) }
|
78
|
+
c.start.wait
|
79
|
+
end
|
72
80
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rest-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.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: 2016-
|
11
|
+
date: 2016-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: rest-builder
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
@@ -24,45 +24,12 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: mime-types
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - ">="
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: timers
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 4.0.1
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 4.0.1
|
55
27
|
description: |-
|
56
|
-
|
57
|
-
|
58
|
-
There has been an explosion in the number of REST APIs available today.
|
59
|
-
To address the need for a way to access these APIs easily and elegantly,
|
60
|
-
we have developed rest-core, which consists of composable middleware
|
61
|
-
that allows you to build a REST client for any REST API. Or in the case of
|
62
|
-
common APIs such as Facebook, Github, and Twitter, you can simply use the
|
63
|
-
dedicated clients provided by [rest-more][].
|
28
|
+
Various [rest-builder](https://github.com/godfat/rest-builder) middleware
|
29
|
+
for building REST clients.
|
64
30
|
|
65
|
-
[rest-more]
|
31
|
+
Checkout [rest-more](https://github.com/godfat/rest-more) for pre-built
|
32
|
+
clients.
|
66
33
|
email:
|
67
34
|
- godfat (XD) godfat.org
|
68
35
|
executables: []
|
@@ -82,18 +49,9 @@ files:
|
|
82
49
|
- example/simple.rb
|
83
50
|
- example/use-cases.rb
|
84
51
|
- lib/rest-core.rb
|
85
|
-
- lib/rest-core/builder.rb
|
86
|
-
- lib/rest-core/client.rb
|
87
|
-
- lib/rest-core/client/simple.rb
|
88
52
|
- lib/rest-core/client/universal.rb
|
89
53
|
- lib/rest-core/client_oauth1.rb
|
90
|
-
- lib/rest-core/engine.rb
|
91
|
-
- lib/rest-core/engine/dry.rb
|
92
|
-
- lib/rest-core/engine/http-client.rb
|
93
|
-
- lib/rest-core/error.rb
|
94
54
|
- lib/rest-core/event.rb
|
95
|
-
- lib/rest-core/event_source.rb
|
96
|
-
- lib/rest-core/middleware.rb
|
97
55
|
- lib/rest-core/middleware/auth_basic.rb
|
98
56
|
- lib/rest-core/middleware/bypass.rb
|
99
57
|
- lib/rest-core/middleware/cache.rb
|
@@ -117,10 +75,7 @@ files:
|
|
117
75
|
- lib/rest-core/middleware/retry.rb
|
118
76
|
- lib/rest-core/middleware/smash_response.rb
|
119
77
|
- lib/rest-core/middleware/timeout.rb
|
120
|
-
- lib/rest-core/promise.rb
|
121
78
|
- lib/rest-core/test.rb
|
122
|
-
- lib/rest-core/thread_pool.rb
|
123
|
-
- lib/rest-core/timer.rb
|
124
79
|
- lib/rest-core/util/clash.rb
|
125
80
|
- lib/rest-core/util/config.rb
|
126
81
|
- lib/rest-core/util/dalli_extension.rb
|
@@ -128,7 +83,6 @@ files:
|
|
128
83
|
- lib/rest-core/util/json.rb
|
129
84
|
- lib/rest-core/util/parse_link.rb
|
130
85
|
- lib/rest-core/util/parse_query.rb
|
131
|
-
- lib/rest-core/util/payload.rb
|
132
86
|
- lib/rest-core/util/smash.rb
|
133
87
|
- lib/rest-core/version.rb
|
134
88
|
- rest-core.gemspec
|
@@ -136,11 +90,9 @@ files:
|
|
136
90
|
- task/gemgem.rb
|
137
91
|
- test/config/rest-core.yaml
|
138
92
|
- test/test_auth_basic.rb
|
139
|
-
- test/test_builder.rb
|
140
93
|
- test/test_cache.rb
|
141
94
|
- test/test_clash.rb
|
142
95
|
- test/test_clash_response.rb
|
143
|
-
- test/test_client.rb
|
144
96
|
- test/test_client_oauth1.rb
|
145
97
|
- test/test_config.rb
|
146
98
|
- test/test_dalli_extension.rb
|
@@ -151,23 +103,16 @@ files:
|
|
151
103
|
- test/test_error_detector.rb
|
152
104
|
- test/test_error_detector_http.rb
|
153
105
|
- test/test_error_handler.rb
|
154
|
-
- test/test_event_source.rb
|
155
106
|
- test/test_follow_redirect.rb
|
156
|
-
- test/test_future.rb
|
157
|
-
- test/test_httpclient.rb
|
158
107
|
- test/test_json_request.rb
|
159
108
|
- test/test_json_response.rb
|
160
109
|
- test/test_oauth1_header.rb
|
161
110
|
- test/test_oauth2_header.rb
|
162
111
|
- test/test_parse_link.rb
|
163
|
-
- test/test_payload.rb
|
164
|
-
- test/test_promise.rb
|
165
112
|
- test/test_query_response.rb
|
166
113
|
- test/test_retry.rb
|
167
|
-
- test/test_simple.rb
|
168
114
|
- test/test_smash.rb
|
169
115
|
- test/test_smash_response.rb
|
170
|
-
- test/test_thread_pool.rb
|
171
116
|
- test/test_timeout.rb
|
172
117
|
- test/test_universal.rb
|
173
118
|
homepage: https://github.com/godfat/rest-core
|
@@ -190,17 +135,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
190
135
|
version: '0'
|
191
136
|
requirements: []
|
192
137
|
rubyforge_project:
|
193
|
-
rubygems_version: 2.5.
|
138
|
+
rubygems_version: 2.5.2
|
194
139
|
signing_key:
|
195
140
|
specification_version: 4
|
196
|
-
summary:
|
141
|
+
summary: Various [rest-builder](https://github.com/godfat/rest-builder) middleware
|
197
142
|
test_files:
|
198
143
|
- test/test_auth_basic.rb
|
199
|
-
- test/test_builder.rb
|
200
144
|
- test/test_cache.rb
|
201
145
|
- test/test_clash.rb
|
202
146
|
- test/test_clash_response.rb
|
203
|
-
- test/test_client.rb
|
204
147
|
- test/test_client_oauth1.rb
|
205
148
|
- test/test_config.rb
|
206
149
|
- test/test_dalli_extension.rb
|
@@ -211,22 +154,15 @@ test_files:
|
|
211
154
|
- test/test_error_detector.rb
|
212
155
|
- test/test_error_detector_http.rb
|
213
156
|
- test/test_error_handler.rb
|
214
|
-
- test/test_event_source.rb
|
215
157
|
- test/test_follow_redirect.rb
|
216
|
-
- test/test_future.rb
|
217
|
-
- test/test_httpclient.rb
|
218
158
|
- test/test_json_request.rb
|
219
159
|
- test/test_json_response.rb
|
220
160
|
- test/test_oauth1_header.rb
|
221
161
|
- test/test_oauth2_header.rb
|
222
162
|
- test/test_parse_link.rb
|
223
|
-
- test/test_payload.rb
|
224
|
-
- test/test_promise.rb
|
225
163
|
- test/test_query_response.rb
|
226
164
|
- test/test_retry.rb
|
227
|
-
- test/test_simple.rb
|
228
165
|
- test/test_smash.rb
|
229
166
|
- test/test_smash_response.rb
|
230
|
-
- test/test_thread_pool.rb
|
231
167
|
- test/test_timeout.rb
|
232
168
|
- test/test_universal.rb
|
data/lib/rest-core/builder.rb
DELETED
@@ -1,162 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'thread'
|
3
|
-
require 'weakref'
|
4
|
-
require 'rest-core/client'
|
5
|
-
|
6
|
-
class RestCore::Builder
|
7
|
-
include RestCore
|
8
|
-
|
9
|
-
singleton_class.module_eval do
|
10
|
-
attr_writer :default_engine
|
11
|
-
def default_engine
|
12
|
-
@default_engine ||= RestCore::HttpClient
|
13
|
-
end
|
14
|
-
|
15
|
-
def client *attrs, &block
|
16
|
-
new(&block).to_client(*attrs)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize &block
|
21
|
-
@engine = nil
|
22
|
-
@middles ||= []
|
23
|
-
instance_eval(&block) if block_given?
|
24
|
-
end
|
25
|
-
|
26
|
-
attr_reader :middles
|
27
|
-
attr_writer :default_engine
|
28
|
-
def default_engine
|
29
|
-
@default_engine ||= self.class.default_engine
|
30
|
-
end
|
31
|
-
|
32
|
-
def use middle, *args, &block
|
33
|
-
middles << [middle, args, block]
|
34
|
-
end
|
35
|
-
|
36
|
-
def run engine
|
37
|
-
@engine = engine
|
38
|
-
end
|
39
|
-
|
40
|
-
def members
|
41
|
-
middles.map{ |(middle, _, _)|
|
42
|
-
middle.members if middle.respond_to?(:members)
|
43
|
-
}.flatten.compact
|
44
|
-
end
|
45
|
-
|
46
|
-
def to_app engine=@engine || default_engine
|
47
|
-
# === foldr m.new app middles
|
48
|
-
middles.reverse.inject(engine.new){ |app, (middle, args, block)|
|
49
|
-
begin
|
50
|
-
middle.new(app, *partial_deep_copy(args), &block)
|
51
|
-
rescue ArgumentError => e
|
52
|
-
raise ArgumentError.new("#{middle}: #{e}")
|
53
|
-
end
|
54
|
-
}
|
55
|
-
end
|
56
|
-
|
57
|
-
def to_client *attrs
|
58
|
-
fields = (members + attrs + [:config_engine]).uniq
|
59
|
-
struct = build_struct(fields)
|
60
|
-
client = Class.new(struct)
|
61
|
-
client.const_set('Struct', struct)
|
62
|
-
class_methods = build_class_methods
|
63
|
-
client.const_set('ClassMethods', class_methods)
|
64
|
-
client.singleton_class.send(:include, class_methods)
|
65
|
-
client.send(:include, Client)
|
66
|
-
client.builder = self
|
67
|
-
client.pool_size = 0 # default to no pool
|
68
|
-
client.pool_idle_time = 60 # default to 60 seconds
|
69
|
-
client.event_source_class = EventSource
|
70
|
-
client.promises = []
|
71
|
-
client.mutex = Mutex.new
|
72
|
-
client
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
def partial_deep_copy obj
|
77
|
-
case obj
|
78
|
-
when Array; obj.map{ |o| partial_deep_copy(o) }
|
79
|
-
when Hash ; obj.inject({}){ |r, (k, v)| r[k] = partial_deep_copy(v); r }
|
80
|
-
else ; obj
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def build_struct fields
|
85
|
-
if fields.empty?
|
86
|
-
Struct.new(nil)
|
87
|
-
else
|
88
|
-
Struct.new(*fields.uniq)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def build_class_methods
|
93
|
-
Module.new do
|
94
|
-
attr_accessor :builder, :pool_size, :pool_idle_time,
|
95
|
-
:event_source_class, :promises, :mutex
|
96
|
-
|
97
|
-
def inherited sub
|
98
|
-
sub.builder = builder
|
99
|
-
sub.pool_size = pool_size
|
100
|
-
sub.pool_idle_time = pool_idle_time
|
101
|
-
sub.event_source_class = event_source_class
|
102
|
-
sub.promises = []
|
103
|
-
sub.mutex = Mutex.new
|
104
|
-
end
|
105
|
-
|
106
|
-
def thread_pool; RestCore::ThreadPool[self]; end
|
107
|
-
|
108
|
-
def defer returns=:future_body
|
109
|
-
raise ArgumentError.new('no block given') unless block_given?
|
110
|
-
promise = RestCore::Promise.new({RestCore::CLIENT => self},
|
111
|
-
lambda{ |res|
|
112
|
-
if err = res[FAIL].find{ |f| f.kind_of?(Exception) }
|
113
|
-
Promise.set_backtrace(err) unless err.backtrace
|
114
|
-
raise err
|
115
|
-
else
|
116
|
-
res
|
117
|
-
end
|
118
|
-
})
|
119
|
-
give_promise(WeakRef.new(promise))
|
120
|
-
promise.defer do
|
121
|
-
begin
|
122
|
-
promise.done(yield)
|
123
|
-
rescue => e
|
124
|
-
promise.reject(e)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
promise.send(returns)
|
128
|
-
end
|
129
|
-
|
130
|
-
def give_promise weak_promise, ps=promises, m=mutex
|
131
|
-
m.synchronize do
|
132
|
-
ps << weak_promise
|
133
|
-
ps.keep_if(&:weakref_alive?)
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
# Shutdown the thread pool for this client and wait for all requests
|
138
|
-
def shutdown
|
139
|
-
thread_pool.shutdown
|
140
|
-
wait
|
141
|
-
end
|
142
|
-
|
143
|
-
# Wait for all the requests to be done for this client
|
144
|
-
def wait ps=promises, m=mutex
|
145
|
-
return self if ps.empty?
|
146
|
-
current_promises = nil
|
147
|
-
m.synchronize do
|
148
|
-
current_promises = ps.dup
|
149
|
-
ps.clear
|
150
|
-
end
|
151
|
-
current_promises.each do |p|
|
152
|
-
next unless p.weakref_alive?
|
153
|
-
begin
|
154
|
-
p.wait
|
155
|
-
rescue WeakRef::RefError # it's gc'ed after we think it's alive
|
156
|
-
end
|
157
|
-
end
|
158
|
-
wait(ps, m)
|
159
|
-
end
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
data/lib/rest-core/client.rb
DELETED
@@ -1,277 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'thread'
|
3
|
-
require 'weakref'
|
4
|
-
require 'rest-core'
|
5
|
-
|
6
|
-
module RestCore::Client
|
7
|
-
include RestCore
|
8
|
-
|
9
|
-
Unserializable = [Proc, Method, IO]
|
10
|
-
|
11
|
-
def self.included mod
|
12
|
-
# honor default attributes
|
13
|
-
src = mod.members.map{ |name|
|
14
|
-
<<-RUBY
|
15
|
-
def #{name}
|
16
|
-
if (r = super).nil?
|
17
|
-
self.#{name} = default_#{name}
|
18
|
-
else
|
19
|
-
r
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def default_#{name} a=app
|
24
|
-
if self.class.respond_to?("default_#{name}")
|
25
|
-
self.class.default_#{name} # old class default style
|
26
|
-
elsif a.respond_to?(:#{name})
|
27
|
-
a.#{name}({}) # middleware instance value
|
28
|
-
elsif a.respond_to?(:app)
|
29
|
-
default_#{name}(a.app) # walk into next app
|
30
|
-
else
|
31
|
-
nil
|
32
|
-
end
|
33
|
-
end
|
34
|
-
private :default_#{name}
|
35
|
-
RUBY
|
36
|
-
}
|
37
|
-
accessor = Module.new
|
38
|
-
accessor.module_eval(src.join("\n"), __FILE__, __LINE__)
|
39
|
-
mod.const_set('Accessor', accessor)
|
40
|
-
mod.send(:include, accessor)
|
41
|
-
end
|
42
|
-
|
43
|
-
attr_reader :app, :dry, :promises
|
44
|
-
attr_accessor :error_callback
|
45
|
-
def initialize o={}
|
46
|
-
@app ||= self.class.builder.to_app # lighten! would reinitialize anyway
|
47
|
-
@dry ||= self.class.builder.to_app(Dry)
|
48
|
-
@promises = [] # don't record any promises in lighten!
|
49
|
-
@mutex = nil # for locking promises, lazily initialized
|
50
|
-
# for serialization
|
51
|
-
@error_callback = nil
|
52
|
-
o.each{ |key, value| send("#{key}=", value) if respond_to?("#{key}=") }
|
53
|
-
end
|
54
|
-
|
55
|
-
def attributes
|
56
|
-
Hash[each_pair.map{ |k, v| [k, send(k)] }]
|
57
|
-
end
|
58
|
-
|
59
|
-
def inspect
|
60
|
-
fields = if size > 0
|
61
|
-
' ' + attributes.map{ |k, v|
|
62
|
-
"#{k}=#{v.inspect.sub(/(?<=.{12}).{4,}/, '...')}"
|
63
|
-
}.join(', ')
|
64
|
-
else
|
65
|
-
''
|
66
|
-
end
|
67
|
-
"#<struct #{self.class.name}#{fields}>"
|
68
|
-
end
|
69
|
-
|
70
|
-
def lighten! o={}
|
71
|
-
attributes.each{ |k, v| vv = case v;
|
72
|
-
when Hash; lighten_hash(v)
|
73
|
-
when Array; lighten_array(v)
|
74
|
-
when *Unserializable; nil
|
75
|
-
else v
|
76
|
-
end
|
77
|
-
send("#{k}=", vv)}
|
78
|
-
initialize(o)
|
79
|
-
@app, @dry = lighten_app(app), lighten_app(dry)
|
80
|
-
self
|
81
|
-
end
|
82
|
-
|
83
|
-
def lighten o={}
|
84
|
-
dup.lighten!(o)
|
85
|
-
end
|
86
|
-
|
87
|
-
def wait
|
88
|
-
self.class.wait(promises, mutex)
|
89
|
-
self
|
90
|
-
end
|
91
|
-
|
92
|
-
def url path, query={}, opts={}
|
93
|
-
dry.call(build_env({
|
94
|
-
REQUEST_PATH => path,
|
95
|
-
REQUEST_QUERY => query,
|
96
|
-
DRY => true}.merge(opts)), &Middleware.method(:request_uri))
|
97
|
-
end
|
98
|
-
|
99
|
-
def get path, query={}, opts={}, &cb
|
100
|
-
request(
|
101
|
-
{REQUEST_METHOD => :get ,
|
102
|
-
REQUEST_PATH => path ,
|
103
|
-
REQUEST_QUERY => query }.merge(opts), &cb)
|
104
|
-
end
|
105
|
-
|
106
|
-
def delete path, query={}, opts={}, &cb
|
107
|
-
request(
|
108
|
-
{REQUEST_METHOD => :delete,
|
109
|
-
REQUEST_PATH => path ,
|
110
|
-
REQUEST_QUERY => query }.merge(opts), &cb)
|
111
|
-
end
|
112
|
-
|
113
|
-
def head path, query={}, opts={}, &cb
|
114
|
-
request(
|
115
|
-
{REQUEST_METHOD => :head ,
|
116
|
-
REQUEST_PATH => path ,
|
117
|
-
REQUEST_QUERY => query ,
|
118
|
-
RESPONSE_KEY => RESPONSE_HEADERS}.merge(opts), &cb)
|
119
|
-
end
|
120
|
-
|
121
|
-
def options path, query={}, opts={}, &cb
|
122
|
-
request(
|
123
|
-
{REQUEST_METHOD => :options,
|
124
|
-
REQUEST_PATH => path ,
|
125
|
-
REQUEST_QUERY => query ,
|
126
|
-
RESPONSE_KEY => RESPONSE_HEADERS}.merge(opts), &cb)
|
127
|
-
end
|
128
|
-
|
129
|
-
def post path, payload={}, query={}, opts={}, &cb
|
130
|
-
request(
|
131
|
-
{REQUEST_METHOD => :post ,
|
132
|
-
REQUEST_PATH => path ,
|
133
|
-
REQUEST_QUERY => query ,
|
134
|
-
REQUEST_PAYLOAD => payload}.merge(opts), &cb)
|
135
|
-
end
|
136
|
-
|
137
|
-
def put path, payload={}, query={}, opts={}, &cb
|
138
|
-
request(
|
139
|
-
{REQUEST_METHOD => :put ,
|
140
|
-
REQUEST_PATH => path ,
|
141
|
-
REQUEST_QUERY => query ,
|
142
|
-
REQUEST_PAYLOAD => payload}.merge(opts), &cb)
|
143
|
-
end
|
144
|
-
|
145
|
-
def patch path, payload={}, query={}, opts={}, &cb
|
146
|
-
request(
|
147
|
-
{REQUEST_METHOD => :patch ,
|
148
|
-
REQUEST_PATH => path ,
|
149
|
-
REQUEST_QUERY => query ,
|
150
|
-
REQUEST_PAYLOAD => payload}.merge(opts), &cb)
|
151
|
-
end
|
152
|
-
|
153
|
-
def event_source path, query={}, opts={}
|
154
|
-
self.class.event_source_class.new(self, path, query, opts)
|
155
|
-
end
|
156
|
-
|
157
|
-
def request env, a=app
|
158
|
-
if block_given?
|
159
|
-
request_full(env, a){ |response| yield(response[response_key(env)]) }
|
160
|
-
else
|
161
|
-
request_full(env, a)[response_key(env)]
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
def request_full env, a=app, &k
|
166
|
-
response = a.call(build_env({ASYNC => !!k}.merge(env))) do |res|
|
167
|
-
(k || RC.id).call(request_complete(res))
|
168
|
-
end
|
169
|
-
|
170
|
-
give_promise(response)
|
171
|
-
|
172
|
-
if block_given?
|
173
|
-
self
|
174
|
-
else
|
175
|
-
response
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
def give_promise response
|
180
|
-
# under ASYNC callback, response might not be a response hash
|
181
|
-
# in that case (maybe in a user created engine), Client#wait
|
182
|
-
# won't work because we have no way to track the promise.
|
183
|
-
if response.kind_of?(Hash) && response[PROMISE].kind_of?(Promise)
|
184
|
-
weak_promise = WeakRef.new(response[PROMISE])
|
185
|
-
self.class.give_promise(weak_promise)
|
186
|
-
self.class.give_promise(weak_promise, promises, mutex)
|
187
|
-
end
|
188
|
-
|
189
|
-
response
|
190
|
-
end
|
191
|
-
|
192
|
-
def build_env env={}
|
193
|
-
default_env.merge(
|
194
|
-
Middleware.string_keys(attributes).merge(Middleware.string_keys(env)))
|
195
|
-
end
|
196
|
-
|
197
|
-
def default_env
|
198
|
-
{REQUEST_METHOD => :get,
|
199
|
-
REQUEST_PATH => '/' ,
|
200
|
-
REQUEST_QUERY => {} ,
|
201
|
-
REQUEST_PAYLOAD => {} ,
|
202
|
-
REQUEST_HEADERS => {} ,
|
203
|
-
FAIL => [] ,
|
204
|
-
LOG => [] ,
|
205
|
-
CLIENT => self}
|
206
|
-
end
|
207
|
-
# ------------------------ instance ---------------------
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
private
|
212
|
-
def request_complete res
|
213
|
-
if err = res[FAIL].find{ |f| f.kind_of?(Exception) }
|
214
|
-
Promise.set_backtrace(err) unless err.backtrace
|
215
|
-
error_callback.call(err) if error_callback
|
216
|
-
if res[ASYNC]
|
217
|
-
res.merge(response_key(res) => err)
|
218
|
-
else
|
219
|
-
raise err
|
220
|
-
end
|
221
|
-
else
|
222
|
-
res
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def mutex
|
227
|
-
@mutex ||= Mutex.new
|
228
|
-
end
|
229
|
-
|
230
|
-
def response_key opts
|
231
|
-
opts[RESPONSE_KEY] ||
|
232
|
-
if opts[HIJACK] then RESPONSE_SOCKET else RESPONSE_BODY end
|
233
|
-
end
|
234
|
-
|
235
|
-
def lighten_hash hash
|
236
|
-
Hash[hash.map{ |(key, value)|
|
237
|
-
case value
|
238
|
-
when Hash; lighten_hash(value)
|
239
|
-
when Array; lighten_array(value)
|
240
|
-
when *Unserializable; [key, nil]
|
241
|
-
else [key, value]
|
242
|
-
end
|
243
|
-
}]
|
244
|
-
end
|
245
|
-
|
246
|
-
def lighten_array array
|
247
|
-
array.map{ |value|
|
248
|
-
case value
|
249
|
-
when Hash; lighten_hash(value)
|
250
|
-
when Array; lighten_array(value)
|
251
|
-
when *Unserializable; nil
|
252
|
-
else value
|
253
|
-
end
|
254
|
-
}.compact
|
255
|
-
end
|
256
|
-
|
257
|
-
def lighten_app app
|
258
|
-
members = if app.class.respond_to?(:members)
|
259
|
-
app.class.members.map{ |key|
|
260
|
-
case value = app.send(key, {})
|
261
|
-
when Hash; lighten_hash(value)
|
262
|
-
when Array; lighten_array(value)
|
263
|
-
when *Unserializable; nil
|
264
|
-
else value
|
265
|
-
end
|
266
|
-
}
|
267
|
-
else
|
268
|
-
[]
|
269
|
-
end
|
270
|
-
|
271
|
-
if app.respond_to?(:app) && app.app
|
272
|
-
app.class.new(lighten_app(app.app), *members)
|
273
|
-
else
|
274
|
-
app.class.new(*members)
|
275
|
-
end
|
276
|
-
end
|
277
|
-
end
|