rest-core 3.1.1 → 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: 530a9ed8d2e0b7cc07703113eaf17950cc611d12
4
- data.tar.gz: ad5eb2846acf18bfacdd88fff480e91bccb4f89e
3
+ metadata.gz: fbe0fe23ff10ec39cf8a2b367616b1c332bd0d42
4
+ data.tar.gz: 0a7132a6620ecab1c35fd69fdff24733161aafad
5
5
  SHA512:
6
- metadata.gz: 4e43365d45547c82c1093963a677c34c2f38ab7c637e80c1219462b7a75313aa30ed8ce817ec94d55d9400a1d993b93bf2e4e203b7a6f4334818086dfa5e8ea9
7
- data.tar.gz: a7c962c1876c5b67480708d2dda7e5df1299432cb16aea00afd7173efffc7e22c3596f9d06da640511d2de64df649cc4c927d9bd23e3e1492be502534543f287
6
+ metadata.gz: d59288134f72ed58c335e743e439479d93de99f6c4278d871733ec845790d65cede5986e276f0a8cd0f0aa39f1cf2ee38325ef468e74cbcb4a08bf3cb01ed2cc
7
+ data.tar.gz: 73a39d9b95793cc496d05e6c9370e0da5bd7c3ae22374e3ebe4ebc71d3dfd0d2778f885a9b8395fe1c8d38fd143b767df45d57ccbfcb6ae957116a8139ba2c41
data/CHANGES.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-core 3.2.0 -- 2014-06-27
4
+
5
+ ### Enhancements
6
+
7
+ * Introduced `RC::JsonResponse::ParseError` which would be a subclass of
8
+ `RC::Json::ParseError`, and contain the original text before parsing.
9
+ This should be great for debugging. For example, some servers might
10
+ return HTML instead JSON, and we would like to read the HTML to learn
11
+ more why they are doing this.
12
+
13
+ * Introduced `RC::ParseLink` utility for parsing web links described in
14
+ [RFC5988](http://tools.ietf.org/html/rfc5988)
15
+
16
+ * Introduced `RC::Clash` which is a hash wrapper protecting you from getting
17
+ nils from hashes. This is useful whenever we want to access a value deeply
18
+ inside a hash. For example: `json['a']['b']['c']['d']` would never fail
19
+ due to nils. Note that `RC::Clash` is recursive.
20
+
21
+ * Introduced `RC::Smash` which is a hash wrapper protecting you from getting
22
+ nils from hashes. This is useful whenever we want to access a value deeply
23
+ inside a hash. Instead of using multiple layers of subscript operators,
24
+ we try to use a "path" to specify which value we want. For example:
25
+ `json['a', 'b', 'c', 'd']` is the same as `json['a']['b']['c']['d']` but
26
+ with protection from nils in the middle. Note that `RC:Smash` is *not*
27
+ recursive.
28
+
29
+ * Introduced `RC::ClashResponse` which would wrap the response inside
30
+ `RC::Clash`. This is useful along with `RC::JsonResponse`.
31
+
32
+ * Introduced `RC::SmashResponse` which would wrap the response inside
33
+ `RC::Smash`. This is useful along with `RC::JsonResponse`.
34
+
35
+ * Introduced `RC::Client.shutdown` which is essentially the same as
36
+ `RC::Client.thread_pool.shutdown` and `RC::Client.wait`.
37
+
38
+ * `RC::ClashResponse` and `RC::SmashResponse` is added into `RC::Universal`
39
+ with `{:clash_response => false, :smash_response => false}` by default.
40
+
41
+ * Introduced `RC::Promise#future_response` to allow you customize the
42
+ behaviour of promises more easily.
43
+
44
+ * Introduced `RC::Promise.claim` to allow you pre-fill a promise.
45
+
46
+ * Introduced `RC::Promise#then` to allow you append a callback whenever
47
+ the response is ready. The type should be: `Env -> Response`
48
+
49
+ * Now `RC::Promise#inspect` would show REQUEST_URI instead of REQUEST_PATH,
50
+ which should be easier to debug.
51
+
52
+ * Introduced `RC::ThreadPool#size` which is a short hand for
53
+ `RC::ThreadPool#workers.size`.
54
+
55
+ ### Bugs fixed
56
+
57
+ * Inheritance with `RC::Client` now works properly.
58
+ * Now `RC::Cache` properly return cached headers.
59
+ * Now `RC::Cache` would work more like `RC::Engine`, wrapping responses
60
+ inside futures.
61
+
3
62
  ## rest-core 3.1.1 -- 2014-05-13
4
63
 
5
64
  ### Enhancements
data/README.md CHANGED
@@ -225,6 +225,26 @@ a large number of concurrent calls.
225
225
  Also, setting `pool_size` to `-1` would mean we want to make blocking
226
226
  requests, without spawning any threads. This might be useful for debugging.
227
227
 
228
+ ### Gracefully shutdown
229
+
230
+ To shutdown gracefully, consider shutdown the thread pool (if we're using it),
231
+ and wait for all requests for a given client. For example, suppose we're using
232
+ `RC::Universal`, we'll do this when we're shutting down:
233
+
234
+ ``` ruby
235
+ RC::Universal.shutdown
236
+ ```
237
+
238
+ We could put them in `at_exit` callback like this:
239
+
240
+ ``` ruby
241
+ at_exit do
242
+ RC::Universal.shutdown
243
+ end
244
+ ```
245
+
246
+ If you're using unicorn, you probably want to put that in the config.
247
+
228
248
  ### Persistent connections (keep-alive connections)
229
249
 
230
250
  Since we're using [httpclient][] by default now, we would reuse connections,
@@ -396,7 +416,10 @@ module RestCore
396
416
  # cache {} didn't support it
397
417
  use ErrorHandler, nil
398
418
  use ErrorDetectorHttp
399
- use JsonResponse, false
419
+ use SmashResponse, false
420
+ use ClashResponse, false
421
+ use JsonResponse, false
422
+ use QueryResponse, false
400
423
  end
401
424
  end
402
425
  end
@@ -493,6 +516,7 @@ simply ignore `:expires_in`.
493
516
  [RC::AuthBasic]: lib/rest-core/middleware/auth_basic.rb
494
517
  [RC::Bypass]: lib/rest-core/middleware/bypass.rb
495
518
  [RC::Cache]: lib/rest-core/middleware/cache.rb
519
+ [RC::ClashResponse]: lib/rest-core/middleware/clash_response.rb
496
520
  [RC::CommonLogger]: lib/rest-core/middleware/common_logger.rb
497
521
  [RC::DefaultHeaders]: lib/rest-core/middleware/default_headers.rb
498
522
  [RC::DefaultPayload]: lib/rest-core/middleware/default_payload.rb
@@ -508,6 +532,7 @@ simply ignore `:expires_in`.
508
532
  [RC::Oauth1Header]: lib/rest-core/middleware/oauth1_header.rb
509
533
  [RC::Oauth2Header]: lib/rest-core/middleware/oauth2_header.rb
510
534
  [RC::Oauth2Query]: lib/rest-core/middleware/oauth2_query.rb
535
+ [RC::SmashResponse]: lib/rest-core/middleware/smash_response.rb
511
536
  [RC::Timeout]: lib/rest-core/middleware/timeout.rb
512
537
  [moneta]: https://github.com/minad/moneta#expiration
513
538
 
@@ -663,6 +688,7 @@ and complete.
663
688
 
664
689
  ## rest-core users:
665
690
 
691
+ * [rest-firebase](https://github.com/CodementorIO/rest-firebase)
666
692
  * [rest-more][]
667
693
  * [rest-more-yahoo_buy](https://github.com/GoodLife/rest-more-yahoo_buy)
668
694
  * [s2sync](https://github.com/brucehsu/s2sync)
@@ -671,6 +697,7 @@ and complete.
671
697
 
672
698
  ## Powered sites:
673
699
 
700
+ * [Codementor](https://www.codementor.io/)
674
701
  * [PicCollage](http://pic-collage.com/)
675
702
 
676
703
  ## CHANGES:
data/TODO.md CHANGED
@@ -3,10 +3,6 @@
3
3
  * middleware revisit (how to initialize?)
4
4
  * X-Method-Override
5
5
 
6
- # BUG
7
-
8
- * inheritance should work; assign builder?
9
-
10
6
  # FEATURE
11
7
 
12
8
  * middleware composer
@@ -40,14 +40,19 @@ module RestCore
40
40
  # misc utilities
41
41
  autoload :Hmac , 'rest-core/util/hmac'
42
42
  autoload :Json , 'rest-core/util/json'
43
+ autoload :ParseLink , 'rest-core/util/parse_link'
43
44
  autoload :ParseQuery , 'rest-core/util/parse_query'
44
45
  autoload :Payload , 'rest-core/util/payload'
45
46
  autoload :Config , 'rest-core/util/config'
47
+ autoload :Clash , 'rest-core/util/clash'
48
+ autoload :Smash , 'rest-core/util/smash'
46
49
 
47
50
  # middlewares
48
51
  autoload :AuthBasic , 'rest-core/middleware/auth_basic'
49
52
  autoload :Bypass , 'rest-core/middleware/bypass'
50
53
  autoload :Cache , 'rest-core/middleware/cache'
54
+ autoload :ClashResponse , 'rest-core/middleware/clash_response'
55
+ autoload :SmashResponse , 'rest-core/middleware/smash_response'
51
56
  autoload :CommonLogger , 'rest-core/middleware/common_logger'
52
57
  autoload :DefaultHeaders, 'rest-core/middleware/default_headers'
53
58
  autoload :DefaultQuery , 'rest-core/middleware/default_query'
@@ -45,6 +45,16 @@ class RestCore::Builder
45
45
  Module.new do
46
46
  attr_accessor :builder, :pool_size, :pool_idle_time,
47
47
  :event_source_class, :promises, :mutex
48
+
49
+ def inherited sub
50
+ sub.builder = builder
51
+ sub.pool_size = pool_size
52
+ sub.pool_idle_time = pool_idle_time
53
+ sub.event_source_class = event_source_class
54
+ sub.promises = []
55
+ sub.mutex = Mutex.new
56
+ end
57
+
48
58
  def thread_pool; RestCore::ThreadPool[self]; end
49
59
 
50
60
  def give_promise weak_promise, ps=promises, m=mutex
@@ -54,6 +64,13 @@ class RestCore::Builder
54
64
  end
55
65
  end
56
66
 
67
+ # Shutdown the thread pool for this client and wait for all requests
68
+ def shutdown
69
+ thread_pool.shutdown
70
+ wait
71
+ end
72
+
73
+ # Wait for all the requests to be done for this client
57
74
  def wait ps=promises, m=mutex
58
75
  return self if ps.empty?
59
76
  current_promises = nil
@@ -12,10 +12,13 @@ module RestCore
12
12
 
13
13
  use FollowRedirect, 10
14
14
  use CommonLogger , method(:puts)
15
- use Cache , {}, 600 do
15
+ use Cache , {}, 600 do # default :expires_in 600 but the default
16
+ # cache {} didn't support it
16
17
  use ErrorHandler, nil
17
18
  use ErrorDetectorHttp
18
- use JsonResponse, false
19
+ use SmashResponse, false
20
+ use ClashResponse, false
21
+ use JsonResponse, false
19
22
  use QueryResponse, false
20
23
  end
21
24
  end
@@ -9,12 +9,7 @@ class RestCore::Engine
9
9
  req = env.merge(REQUEST_URI => request_uri(env))
10
10
  promise = Promise.new(req, k, req[ASYNC])
11
11
  promise.defer{ request(promise, req) }
12
- req.merge(RESPONSE_BODY => promise.future_body,
13
- RESPONSE_STATUS => promise.future_status,
14
- RESPONSE_HEADERS => promise.future_headers,
15
- RESPONSE_SOCKET => promise.future_socket,
16
- FAIL => promise.future_failures,
17
- PROMISE => promise)
12
+ promise.future_response
18
13
  end
19
14
 
20
15
  private
@@ -22,18 +22,16 @@ class RestCore::Cache
22
22
  env
23
23
  end
24
24
 
25
- if cached = cache_get(e)
25
+ cache_get(e){ |cached|
26
26
  e[TIMER].cancel if e[TIMER]
27
27
  wrapped.call(cached, &k)
28
- else
29
- app.call(e){ |res|
30
- wrapped.call(res){ |res_wrapped|
31
- k.call(if (res_wrapped[FAIL] || []).empty?
32
- cache_for(res).merge(res_wrapped)
33
- else
34
- res_wrapped
35
- end)}}
36
- end
28
+ } || app.call(e){ |res|
29
+ wrapped.call(res){ |res_wrapped|
30
+ k.call(if (res_wrapped[FAIL] || []).empty?
31
+ cache_for(res).merge(res_wrapped)
32
+ else
33
+ res_wrapped
34
+ end)}}
37
35
  end
38
36
 
39
37
  def cache_key env
@@ -41,14 +39,15 @@ class RestCore::Cache
41
39
  cache_key_raw(env))}"
42
40
  end
43
41
 
44
- def cache_get env
42
+ def cache_get env, &k
45
43
  return unless cache(env)
46
44
  return unless cache_for?(env)
47
45
 
46
+ uri = request_uri(env)
48
47
  start_time = Time.now
49
48
  return unless data = cache(env)[cache_key(env)]
50
- log(env, Event::CacheHit.new(Time.now - start_time, request_uri(env))).
51
- merge(data_extract(data))
49
+ log(env, Event::CacheHit.new(Time.now - start_time, uri)).
50
+ merge(data_extract(data, env.merge(REQUEST_URI => uri), k))
52
51
  end
53
52
 
54
53
  private
@@ -96,13 +95,12 @@ class RestCore::Cache
96
95
  "#{ res[RESPONSE_BODY]}"
97
96
  end
98
97
 
99
- def data_extract data
98
+ def data_extract data, env, k
100
99
  _, status, headers, body =
101
- data.match(/\A(\d+)\n([^\n]+\n)*\n\n(.*)\Z/m).to_a
100
+ data.match(/\A(\d+)\n((?:[^\n]+\n)*)\n\n(.*)\Z/m).to_a
102
101
 
103
- {RESPONSE_BODY => body,
104
- RESPONSE_HEADERS => Hash[(headers||'').scan(/([^:]+): ([^\n]+)\n/)],
105
- RESPONSE_STATUS => status.to_i}
102
+ Promise.claim(env, k, body,status.to_i,
103
+ Hash[(headers||'').scan(/([^:]+): ([^\n]+)\n/)]).future_response
106
104
  end
107
105
 
108
106
  def cache_for? env
@@ -0,0 +1,21 @@
1
+
2
+ require 'rest-core/middleware'
3
+ require 'rest-core/util/clash'
4
+
5
+ class RestCore::ClashResponse
6
+ def self.members; [:clash_response]; end
7
+ include RestCore::Middleware
8
+
9
+ def call env, &k
10
+ return app.call(env, &k) if env[DRY]
11
+ return app.call(env, &k) unless clash_response(env)
12
+
13
+ app.call(env){ |res|
14
+ if res[RESPONSE_BODY].kind_of?(Hash)
15
+ yield(res.merge(RESPONSE_BODY => Clash.new(res[RESPONSE_BODY])))
16
+ else
17
+ yield(res)
18
+ end
19
+ }
20
+ end
21
+ end
@@ -6,6 +6,14 @@ class RestCore::JsonResponse
6
6
  def self.members; [:json_response]; end
7
7
  include RestCore::Middleware
8
8
 
9
+ class ParseError < Json.const_get(:ParseError)
10
+ attr_reader :cause, :body
11
+ def initialize cause, body
12
+ super("#{cause.message}\nOriginal text: #{body}")
13
+ @cause, @body = cause, body
14
+ end
15
+ end
16
+
9
17
  JSON_RESPONSE_HEADER = {'Accept' => 'application/json'}.freeze
10
18
 
11
19
  def call env, &k
@@ -19,10 +27,10 @@ class RestCore::JsonResponse
19
27
  end
20
28
 
21
29
  def process response
22
- response.merge(RESPONSE_BODY =>
23
- Json.decode("[#{response[RESPONSE_BODY]}]").first)
24
- # [this].first is not needed for yajl-ruby
30
+ body = response[RESPONSE_BODY]
31
+ response.merge(RESPONSE_BODY => Json.decode("[#{body}]").first)
32
+ # [this].first is not needed for yajl-ruby
25
33
  rescue Json.const_get(:ParseError) => error
26
- fail(response, error)
34
+ fail(response, ParseError.new(error, body))
27
35
  end
28
36
  end
@@ -0,0 +1,21 @@
1
+
2
+ require 'rest-core/middleware'
3
+ require 'rest-core/util/smash'
4
+
5
+ class RestCore::SmashResponse
6
+ def self.members; [:smash_response]; end
7
+ include RestCore::Middleware
8
+
9
+ def call env, &k
10
+ return app.call(env, &k) if env[DRY]
11
+ return app.call(env, &k) unless smash_response(env)
12
+
13
+ app.call(env){ |res|
14
+ if res[RESPONSE_BODY].kind_of?(Hash)
15
+ yield(res.merge(RESPONSE_BODY => Smash.new(res[RESPONSE_BODY])))
16
+ else
17
+ yield(res)
18
+ end
19
+ }
20
+ end
21
+ end
@@ -15,9 +15,15 @@ class RestCore::Promise
15
15
  end
16
16
  end
17
17
 
18
+ def self.claim env, k=RC.id, body, status, headers
19
+ promise = new(env, k)
20
+ promise.fulfill(body, status, headers)
21
+ promise
22
+ end
23
+
18
24
  def initialize env, k=RC.id, immediate=false, &job
19
25
  self.env = env
20
- self.k = k
26
+ self.k = [k]
21
27
  self.immediate = immediate
22
28
 
23
29
  self.body, self.status, self.headers,
@@ -30,7 +36,7 @@ class RestCore::Promise
30
36
  end
31
37
 
32
38
  def inspect
33
- "<#{self.class.name} for #{env[REQUEST_PATH]}>"
39
+ "<#{self.class.name} for #{env[REQUEST_URI]}>"
34
40
  end
35
41
 
36
42
  def future_body ; Future.new(self, RESPONSE_BODY ); end
@@ -38,6 +44,14 @@ class RestCore::Promise
38
44
  def future_headers ; Future.new(self, RESPONSE_HEADERS); end
39
45
  def future_socket ; Future.new(self, RESPONSE_SOCKET ); end
40
46
  def future_failures; Future.new(self, FAIL) ; end
47
+ def future_response
48
+ env.merge(RESPONSE_BODY => future_body,
49
+ RESPONSE_STATUS => future_status,
50
+ RESPONSE_HEADERS => future_headers,
51
+ RESPONSE_SOCKET => future_socket,
52
+ FAIL => future_failures,
53
+ PROMISE => self)
54
+ end
41
55
 
42
56
  # called in client thread
43
57
  def defer &job
@@ -87,6 +101,12 @@ class RestCore::Promise
87
101
  fulfill('', 0, {})
88
102
  end
89
103
 
104
+ # append your actions, which would be called when we're calling back
105
+ def then &action
106
+ k << action
107
+ self
108
+ end
109
+
90
110
  protected
91
111
  attr_accessor :env, :k, :immediate,
92
112
  :response, :body, :status, :headers, :socket, :error,
@@ -107,13 +127,13 @@ class RestCore::Promise
107
127
 
108
128
  # called in client thread, when yield is called
109
129
  def callback
110
- self.response ||= k.call(
130
+ self.response ||= k.inject(
111
131
  env.merge(RESPONSE_BODY => body ,
112
132
  RESPONSE_STATUS => status,
113
133
  RESPONSE_HEADERS => headers,
114
134
  RESPONSE_SOCKET => socket,
115
135
  FAIL => ((env[FAIL]||[]) + [error]).compact,
116
- LOG => env[LOG] ||[]))
136
+ LOG => env[LOG] ||[])){ |r, i| i.call(r) }
117
137
  end
118
138
 
119
139
  # called in requesting thread, whenever the request is done
@@ -74,6 +74,10 @@ class RestCore::ThreadPool
74
74
  "#<#{self.class.name} client_class=#{client_class}>"
75
75
  end
76
76
 
77
+ def size
78
+ workers.size
79
+ end
80
+
77
81
  def max_size
78
82
  client_class.pool_size
79
83
  end
@@ -2,7 +2,11 @@
2
2
  require 'timers'
3
3
 
4
4
  class RestCore::Timer
5
- TimerGen = Timers.new
5
+ TimerGen = if Timers.respond_to?(:new)
6
+ Timers.new
7
+ else
8
+ Timers::Group.new
9
+ end
6
10
 
7
11
  attr_accessor :timeout, :error
8
12
  def initialize timeout, error, &block
@@ -0,0 +1,50 @@
1
+
2
+ module RestCore; end
3
+ class RestCore::Clash
4
+ Empty = Hash.new(&(l = lambda{|_,_|Hash.new(&l).freeze})).freeze
5
+
6
+ attr_accessor :data
7
+ def initialize data
8
+ self.data = data
9
+ end
10
+
11
+ def [] k
12
+ if data.key?(k)
13
+ convert(data[k])
14
+ else
15
+ Empty
16
+ end
17
+ end
18
+
19
+ def == rhs
20
+ if rhs.kind_of?(RestCore::Clash)
21
+ data == rhs.data
22
+ else
23
+ data == rhs
24
+ end
25
+ end
26
+
27
+ private
28
+ def convert value
29
+ case value
30
+ when Hash
31
+ RestCore::Clash.new(value)
32
+ when Array
33
+ value.map{ |ele| convert(ele) }
34
+ else
35
+ value
36
+ end
37
+ end
38
+
39
+ def respond_to_missing? msg, include_private=false
40
+ data.respond_to?(msg, include_private)
41
+ end
42
+
43
+ def method_missing msg, *args, &block
44
+ if data.respond_to?(msg)
45
+ data.public_send(msg, *args, &block)
46
+ else
47
+ super
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module RestCore; end
3
+ module RestCore::ParseLink
4
+ module_function
5
+ # http://tools.ietf.org/html/rfc5988
6
+ parname = '"?([^"]+)"?'
7
+ LINKPARAM = /#{parname}=#{parname}/
8
+ def parse_link link
9
+ link.split(',').inject({}) do |r, value|
10
+ uri, *pairs = value.split(';')
11
+ params = Hash[pairs.map{ |p| p.strip.match(LINKPARAM)[1..2] }]
12
+ r[params['rel']] = params.merge('uri' => uri[/<([^>]+)>/, 1])
13
+ r
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,41 @@
1
+
2
+ module RestCore; end
3
+ class RestCore::Smash
4
+ attr_accessor :data
5
+ def initialize data
6
+ self.data = data
7
+ end
8
+
9
+ def [] *keys
10
+ keys.inject(data) do |r, k|
11
+ if r.respond_to?(:key) && r.key?(k)
12
+ r[k]
13
+ elsif r.respond_to?(:[])
14
+ r[k]
15
+ else
16
+ return nil # stop here
17
+ end
18
+ end
19
+ end
20
+
21
+ def == rhs
22
+ if rhs.kind_of?(RestCore::Smash)
23
+ data == rhs.data
24
+ else
25
+ data == rhs
26
+ end
27
+ end
28
+
29
+ private
30
+ def respond_to_missing? msg, include_private=false
31
+ data.respond_to?(msg, include_private)
32
+ end
33
+
34
+ def method_missing msg, *args, &block
35
+ if data.respond_to?(msg)
36
+ data.public_send(msg, *args, &block)
37
+ else
38
+ super
39
+ end
40
+ end
41
+ end
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '3.1.1'
3
+ VERSION = '3.2.0'
4
4
  end
@@ -1,14 +1,14 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: rest-core 3.1.1 ruby lib
2
+ # stub: rest-core 3.2.0 ruby lib
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "rest-core"
6
- s.version = "3.1.1"
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-13"
11
+ s.date = "2014-06-27"
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 = [
@@ -42,6 +42,7 @@ Gem::Specification.new do |s|
42
42
  "lib/rest-core/middleware/auth_basic.rb",
43
43
  "lib/rest-core/middleware/bypass.rb",
44
44
  "lib/rest-core/middleware/cache.rb",
45
+ "lib/rest-core/middleware/clash_response.rb",
45
46
  "lib/rest-core/middleware/common_logger.rb",
46
47
  "lib/rest-core/middleware/default_headers.rb",
47
48
  "lib/rest-core/middleware/default_payload.rb",
@@ -58,6 +59,7 @@ Gem::Specification.new do |s|
58
59
  "lib/rest-core/middleware/oauth2_header.rb",
59
60
  "lib/rest-core/middleware/oauth2_query.rb",
60
61
  "lib/rest-core/middleware/query_response.rb",
62
+ "lib/rest-core/middleware/smash_response.rb",
61
63
  "lib/rest-core/middleware/timeout.rb",
62
64
  "lib/rest-core/patch/multi_json.rb",
63
65
  "lib/rest-core/patch/rest-client.rb",
@@ -65,11 +67,14 @@ Gem::Specification.new do |s|
65
67
  "lib/rest-core/test.rb",
66
68
  "lib/rest-core/thread_pool.rb",
67
69
  "lib/rest-core/timer.rb",
70
+ "lib/rest-core/util/clash.rb",
68
71
  "lib/rest-core/util/config.rb",
69
72
  "lib/rest-core/util/hmac.rb",
70
73
  "lib/rest-core/util/json.rb",
74
+ "lib/rest-core/util/parse_link.rb",
71
75
  "lib/rest-core/util/parse_query.rb",
72
76
  "lib/rest-core/util/payload.rb",
77
+ "lib/rest-core/util/smash.rb",
73
78
  "lib/rest-core/version.rb",
74
79
  "lib/rest-core/wrapper.rb",
75
80
  "rest-core.gemspec",
@@ -79,6 +84,8 @@ Gem::Specification.new do |s|
79
84
  "test/test_auth_basic.rb",
80
85
  "test/test_builder.rb",
81
86
  "test/test_cache.rb",
87
+ "test/test_clash.rb",
88
+ "test/test_clash_response.rb",
82
89
  "test/test_client.rb",
83
90
  "test/test_client_oauth1.rb",
84
91
  "test/test_config.rb",
@@ -94,11 +101,14 @@ Gem::Specification.new do |s|
94
101
  "test/test_json_response.rb",
95
102
  "test/test_oauth1_header.rb",
96
103
  "test/test_oauth2_header.rb",
104
+ "test/test_parse_link.rb",
97
105
  "test/test_payload.rb",
98
106
  "test/test_promise.rb",
99
107
  "test/test_query_response.rb",
100
108
  "test/test_rest-client.rb",
101
109
  "test/test_simple.rb",
110
+ "test/test_smash.rb",
111
+ "test/test_smash_response.rb",
102
112
  "test/test_thread_pool.rb",
103
113
  "test/test_timeout.rb",
104
114
  "test/test_universal.rb",
@@ -111,6 +121,8 @@ Gem::Specification.new do |s|
111
121
  "test/test_auth_basic.rb",
112
122
  "test/test_builder.rb",
113
123
  "test/test_cache.rb",
124
+ "test/test_clash.rb",
125
+ "test/test_clash_response.rb",
114
126
  "test/test_client.rb",
115
127
  "test/test_client_oauth1.rb",
116
128
  "test/test_config.rb",
@@ -126,11 +138,14 @@ Gem::Specification.new do |s|
126
138
  "test/test_json_response.rb",
127
139
  "test/test_oauth1_header.rb",
128
140
  "test/test_oauth2_header.rb",
141
+ "test/test_parse_link.rb",
129
142
  "test/test_payload.rb",
130
143
  "test/test_promise.rb",
131
144
  "test/test_query_response.rb",
132
145
  "test/test_rest-client.rb",
133
146
  "test/test_simple.rb",
147
+ "test/test_smash.rb",
148
+ "test/test_smash_response.rb",
134
149
  "test/test_thread_pool.rb",
135
150
  "test/test_timeout.rb",
136
151
  "test/test_universal.rb",
@@ -7,6 +7,18 @@ describe RC::Cache do
7
7
  Muack.verify
8
8
  end
9
9
 
10
+ def simple_client
11
+ RC::Builder.client{ use RC::Cache, {}, nil }.new
12
+ end
13
+
14
+ def json_client
15
+ RC::Builder.client do
16
+ use RC::Cache, {}, 3600 do
17
+ use RC::JsonResponse, true
18
+ end
19
+ end.new
20
+ end
21
+
10
22
  should 'basic 0' do
11
23
  c = RC::Builder.client do
12
24
  use RC::Cache, {}, 3600
@@ -60,17 +72,13 @@ describe RC::Cache do
60
72
  should 'not raise error if headers is nil' do
61
73
  path = 'http://a'
62
74
  stub_request(:get , path).to_return(:body => 'OK', :headers => nil)
63
- c = RC::Builder.client do
64
- use RC::Cache, {}, nil
65
- end.new
75
+ c = simple_client
66
76
  c.get(path).should.eq 'OK'
67
77
  c.get(path).should.eq 'OK'
68
78
  end
69
79
 
70
80
  should 'head then get' do
71
- c = RC::Builder.client do
72
- use RC::Cache, {}, nil
73
- end.new
81
+ c = simple_client
74
82
  path = 'http://example.com'
75
83
  stub_request(:head, path).to_return(:headers => {'A' => 'B'})
76
84
  c.head(path).should.eq('A' => 'B')
@@ -98,20 +106,40 @@ describe RC::Cache do
98
106
  end
99
107
 
100
108
  should 'cache the original response' do
101
- c = RC::Builder.client do
102
- use RC::Cache, {}, 3600 do
103
- use RC::JsonResponse, true
104
- end
105
- end.new
109
+ c = json_client
106
110
  stub_request(:get, 'http://me').to_return(:body => body = '{"a":"b"}')
107
111
  c.get('http://me').should.eq 'a' => 'b'
108
112
  c.cache.values.first.should.eq "200\n\n\n#{body}"
109
113
  end
110
114
 
115
+ should 'cache multiple headers' do
116
+ c = simple_client
117
+ stub_request(:get, 'http://me').to_return(:headers =>
118
+ {'Apple' => 'Orange', 'Orange' => 'Apple'})
119
+ expected = {'APPLE' => 'Orange', 'ORANGE' => 'Apple'}
120
+ args = ['http://me', {}, {RC::RESPONSE_KEY => RC::RESPONSE_HEADERS}]
121
+ 2.times{ c.get(*args).should.eq expected }
122
+ end
123
+
124
+ should 'preserve promise and REQUEST_URI' do
125
+ c = simple_client
126
+ uri = 'http://me?a=b'
127
+ stub_request(:get, uri)
128
+ args = ['http://me', {:a => 'b'}, {RC::RESPONSE_KEY => RC::PROMISE}]
129
+ 2.times{ c.get(*args).yield[RC::REQUEST_URI].should.eq uri }
130
+ end
131
+
132
+ should 'preserve promise and preserve wrapped call' do
133
+ c = json_client
134
+ stub_request(:get, 'http://me').to_return(:body => body = '{"a":"b"}')
135
+ args = ['http://me', {}, {RC::RESPONSE_KEY => RC::PROMISE}]
136
+ 2.times do
137
+ c.get(*args).then{ |r| r[RC::RESPONSE_BODY].should.eq 'a' => 'b' }.yield
138
+ end
139
+ end
140
+
111
141
  should 'multiline response' do
112
- c = RC::Builder.client do
113
- use RC::Cache, {}, 3600
114
- end.new
142
+ c = simple_client
115
143
  stub_request(:get, 'http://html').to_return(:body => body = "a\n\nb")
116
144
  c.get('http://html').should.eq body
117
145
  c.cache.values.first.should.eq "200\n\n\n#{body}"
@@ -151,14 +179,14 @@ describe RC::Cache do
151
179
  end
152
180
 
153
181
  should 'not cache dry run' do
154
- c = RC::Builder.client{use RC::Cache, {}, nil}.new
182
+ c = simple_client
155
183
  c.url('test')
156
184
  c.cache.should.eq({})
157
185
  end
158
186
 
159
187
  should 'not cache hijacking' do
160
188
  stub_request(:get, 'http://a').to_return(:body => 'ok')
161
- c = RC::Builder.client{use RC::Cache, {}, nil}.new
189
+ c = simple_client
162
190
  2.times do
163
191
  c.get('http://a', {}, RC::HIJACK => true,
164
192
  RC::RESPONSE_KEY => RC::RESPONSE_SOCKET).
@@ -170,7 +198,7 @@ describe RC::Cache do
170
198
  should 'update cache if there is cache option set to false' do
171
199
  url, body = "https://cache", 'ok'
172
200
  stub_request(:get, url).to_return(:body => body)
173
- c = RC::Builder.client{use RC::Cache, {}, nil}.new
201
+ c = simple_client
174
202
 
175
203
  c.get(url) .should.eq body
176
204
  stub_request(:get, url).to_return(:body => body.reverse).times(2)
@@ -0,0 +1,24 @@
1
+
2
+ require 'rest-core/test'
3
+
4
+ describe RC::Clash do
5
+ should 'never give nil for non-existing values' do
6
+ h = {0 => 1, 2 => {3 => 4, 5 => [6, {7 => 8}]}, 9 => false, 10 => nil}
7
+ c = RC::Clash.new(h)
8
+ c[0] .should.eq(1)
9
+ c[1] .should.eq({})
10
+ c[1][2] .should.eq({})
11
+ c[1][2][3] .should.eq({})
12
+ c[2] .should.eq(3 => 4, 5 => [6, {7 => 8}])
13
+ c[2][3] .should.eq(4)
14
+ c[2][4] .should.eq({})
15
+ c[2][4][5] .should.eq({})
16
+ c[2][5] .should.eq([6, {7 => 8}])
17
+ c[2][5][1] .should.eq(7 => 8)
18
+ c[2][5][1][7] .should.eq(8)
19
+ c[2][5][1][8] .should.eq({})
20
+ c[2][5][1][8][9].should.eq({})
21
+ c[9] .should.eq(false)
22
+ c[10] .should.eq(nil)
23
+ end
24
+ end
@@ -0,0 +1,56 @@
1
+
2
+ require 'rest-core/test'
3
+
4
+ describe RC::ClashResponse do
5
+ describe 'app' do
6
+ app = RC::ClashResponse.new(RC::Dry.new, true)
7
+
8
+ should 'do nothing' do
9
+ env = {RC::RESPONSE_BODY => []}
10
+ app.call(env) do |res|
11
+ res.should.eq(env)
12
+ res[RC::RESPONSE_BODY].should.kind_of(Array)
13
+ end
14
+ end
15
+
16
+ should 'clash' do
17
+ app.call(RC::RESPONSE_BODY => {}) do |res|
18
+ body = res[RC::RESPONSE_BODY]
19
+ body.should.kind_of(RC::Clash)
20
+ body.should.empty
21
+ body[0].should.eq({})
22
+ body[0][0].should.eq({})
23
+ end
24
+ end
25
+
26
+ describe 'client' do
27
+ body = {0 => {1 => 2}}
28
+ client = RC::Builder.client do
29
+ use RC::ClashResponse, true
30
+ run Class.new{
31
+ define_method(:call) do |env, &block|
32
+ block.call(env.merge(RC::RESPONSE_BODY => body))
33
+ end
34
+ }
35
+ end
36
+
37
+ should 'do nothing' do
38
+ b = client.new(:clash_response => false).get(''){ |res|
39
+ res.should.eq(body)
40
+ res.should.kind_of(Hash)
41
+ }.get('')
42
+ b.should.eq(body)
43
+ b.should.kind_of(Hash)
44
+ end
45
+
46
+ should 'clash' do
47
+ b = client.new.get(''){ |res|
48
+ res.should.eq(body)
49
+ res.should.kind_of(RC::Clash)
50
+ }.get('')
51
+ b.should.eq(body)
52
+ b.should.kind_of(RC::Clash)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -67,13 +67,13 @@ describe RC::Simple do
67
67
  stub(any_instance_of(WeakRef)).weakref_alive?{false}
68
68
  client.new.get(url)
69
69
  client.promises.size.should < 6
70
- client.wait
70
+ client.shutdown
71
71
  client.promises.should.empty
72
72
  end
73
73
 
74
74
  should 'have correct to_i' do
75
- stub_request(:get, 'http://localhost/').to_return(:body => '123')
76
- RC::Simple.new.get('http://localhost/').to_i.should.eq 123
75
+ stub_request(:get, url).to_return(:body => '123')
76
+ RC::Simple.new.get(url).to_i.should.eq 123
77
77
  end
78
78
 
79
79
  should 'use defaults' do
@@ -106,4 +106,9 @@ describe RC::Simple do
106
106
  c.timeout = false
107
107
  c.timeout.should.eq false # false would disable default
108
108
  end
109
+
110
+ should 'work for inheritance' do
111
+ stub_request(:get, url).to_return(:body => '123')
112
+ Class.new(RC::Simple).new.get(url).should.eq '123'
113
+ end
109
114
  end
@@ -4,6 +4,7 @@ require 'rest-core/test'
4
4
  describe RC::JsonResponse do
5
5
  describe 'app' do
6
6
  app = RC::JsonResponse.new(RC::Dry.new, true)
7
+ bad = 'bad json'
7
8
 
8
9
  should 'do nothing' do
9
10
  expected = {RC::RESPONSE_BODY => nil,
@@ -14,9 +15,26 @@ describe RC::JsonResponse do
14
15
  should 'decode' do
15
16
  expected = {RC::RESPONSE_BODY => {},
16
17
  RC::REQUEST_HEADERS => {'Accept' => 'application/json'}}
17
- app.call(RC::RESPONSE_BODY => '{}'){ |response|
18
+ app.call(RC::RESPONSE_BODY => '{}') do |response|
18
19
  response.should.eq(expected)
19
- }
20
+ end
21
+ end
22
+
23
+ should 'give proper parse error' do
24
+ app.call(RC::RESPONSE_BODY => bad) do |response|
25
+ err = response[RC::FAIL].first
26
+ err.should.kind_of(RC::Json.const_get(:ParseError))
27
+ err.should.kind_of(RC::JsonResponse::ParseError)
28
+ end
29
+ end
30
+
31
+ should 'give me original text' do
32
+ app.call(RC::RESPONSE_BODY => bad) do |response|
33
+ err = response[RC::FAIL].first
34
+ err.message .should.include(bad)
35
+ err.body .should.eq(bad)
36
+ err.cause.class.should.eq(RC::Json.const_get(:ParseError))
37
+ end
20
38
  end
21
39
  end
22
40
 
@@ -0,0 +1,43 @@
1
+
2
+ require 'rest-core/test'
3
+
4
+ describe RC::ParseLink do
5
+ describe 'http://tools.ietf.org/html/rfc5988' do
6
+ should '5.5 a' do
7
+ link = '<http://example.com/TheBook/chapter2>; rel="previous"; title="previous chapter"'
8
+ RC::ParseLink.parse_link(link).should.eq(
9
+ 'previous' => {'uri' => 'http://example.com/TheBook/chapter2',
10
+ 'rel' => 'previous',
11
+ 'title' => 'previous chapter'})
12
+ end
13
+
14
+ should '5.5 b' do
15
+ link = '</>; rel="http://example.net/foo"'
16
+ RC::ParseLink.parse_link(link).should.eq(
17
+ 'http://example.net/foo' => {'uri' => '/',
18
+ 'rel' => 'http://example.net/foo'})
19
+ end
20
+
21
+ should '5.5 c (we did not implement * and unescape for now)' do
22
+ link = <<-LINK
23
+ </TheBook/chapter2>; rel="previous"; title*=UTF-8'de'letztes%20Kapitel, </TheBook/chapter4>; rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel
24
+ LINK
25
+ RC::ParseLink.parse_link(link).should.eq(
26
+ 'previous' => {'uri' => '/TheBook/chapter2',
27
+ 'rel' => 'previous',
28
+ 'title*' => "UTF-8'de'letztes%20Kapitel"},
29
+ 'next' => {'uri' => '/TheBook/chapter4',
30
+ 'rel' => 'next',
31
+ 'title*' => "UTF-8'de'n%c3%a4chstes%20Kapitel"})
32
+ end
33
+
34
+ should '5.5 d' do
35
+ link = '<http://example.org/>; rel="start http://example.net/relation/other"'
36
+
37
+ RC::ParseLink.parse_link(link).should.eq(
38
+ 'start http://example.net/relation/other' =>
39
+ {'uri' => 'http://example.org/',
40
+ 'rel' => 'start http://example.net/relation/other'})
41
+ end
42
+ end
43
+ end
@@ -12,7 +12,8 @@ describe RC::Promise do
12
12
  end
13
13
 
14
14
  after do
15
- @client.thread_pool.shutdown
15
+ @client.shutdown
16
+ @client.thread_pool.size.should.eq 0
16
17
  Muack.verify
17
18
  end
18
19
 
@@ -44,6 +45,15 @@ describe RC::Promise do
44
45
  @promise.send(:headers).should.eq('K' => 'V')
45
46
  end
46
47
 
48
+ should 'then then then' do
49
+ plusone = lambda do |r|
50
+ r.merge(RC::RESPONSE_BODY => r[RC::RESPONSE_BODY] + 1)
51
+ end
52
+ 2.times{ @promise.then(&plusone).then(&plusone).then(&plusone) }
53
+ @promise.fulfill(0, 200, {})
54
+ @promise.future_body.should.eq 6
55
+ end
56
+
47
57
  should 'call inline if pool_size < 0' do
48
58
  @client.pool_size = -1
49
59
  current_thread = Thread.current
@@ -0,0 +1,24 @@
1
+
2
+ require 'rest-core/test'
3
+
4
+ describe RC::Smash do
5
+ should 'deep access' do
6
+ h = {0 => 1, 2 => {3 => 4, 5 => [6, {7 => 8}]}, 9 => false, 10 => nil}
7
+ c = RC::Smash.new(h)
8
+ c[0] .should.eq(1)
9
+ c[1] .should.eq(nil)
10
+ c[1, 2] .should.eq(nil)
11
+ c[1, 2, 3] .should.eq(nil)
12
+ c[2] .should.eq(3 => 4, 5 => [6, {7 => 8}])
13
+ c[2, 3] .should.eq(4)
14
+ c[2, 4] .should.eq(nil)
15
+ c[2, 4, 5] .should.eq(nil)
16
+ c[2, 5] .should.eq([6, {7 => 8}])
17
+ c[2, 5, 1] .should.eq(7 => 8)
18
+ c[2, 5, 1, 7] .should.eq(8)
19
+ c[2, 5, 1, 8] .should.eq(nil)
20
+ c[2, 5, 1, 8, 9].should.eq(nil)
21
+ c[9] .should.eq(false)
22
+ c[10] .should.eq(nil)
23
+ end
24
+ end
@@ -0,0 +1,56 @@
1
+
2
+ require 'rest-core/test'
3
+
4
+ describe RC::SmashResponse do
5
+ describe 'app' do
6
+ app = RC::SmashResponse.new(RC::Dry.new, true)
7
+
8
+ should 'do nothing' do
9
+ env = {RC::RESPONSE_BODY => []}
10
+ app.call(env) do |res|
11
+ res.should.eq(env)
12
+ res[RC::RESPONSE_BODY].should.kind_of(Array)
13
+ end
14
+ end
15
+
16
+ should 'smash' do
17
+ app.call(RC::RESPONSE_BODY => {}) do |res|
18
+ body = res[RC::RESPONSE_BODY]
19
+ body.should.kind_of(RC::Smash)
20
+ body.should.empty
21
+ body[0].should.eq(nil)
22
+ body[0, 0].should.eq(nil)
23
+ end
24
+ end
25
+
26
+ describe 'client' do
27
+ body = {0 => {1 => 2}}
28
+ client = RC::Builder.client do
29
+ use RC::SmashResponse, true
30
+ run Class.new{
31
+ define_method(:call) do |env, &block|
32
+ block.call(env.merge(RC::RESPONSE_BODY => body))
33
+ end
34
+ }
35
+ end
36
+
37
+ should 'do nothing' do
38
+ b = client.new(:smash_response => false).get(''){ |res|
39
+ res.should.eq(body)
40
+ res.should.kind_of(Hash)
41
+ }.get('')
42
+ b.should.eq(body)
43
+ b.should.kind_of(Hash)
44
+ end
45
+
46
+ should 'clash' do
47
+ b = client.new.get(''){ |res|
48
+ res.should.eq(body)
49
+ res.should.kind_of(RC::Smash)
50
+ }.get('')
51
+ b.should.eq(body)
52
+ b.should.kind_of(RC::Smash)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -16,4 +16,13 @@ describe RC::Universal do
16
16
  u.request_full(env, u.dry)[RC::REQUEST_HEADERS].should.eq(
17
17
  {'Authorization' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='}.merge(acc))
18
18
  end
19
+
20
+ should 'clash' do
21
+ url = 'http://localhost/'
22
+ stub_request(:get, url).to_return(:body => '{"a":{"b":"c"}}')
23
+ res = RC::Universal.new(:json_response => true,
24
+ :clash_response => true,
25
+ :log_method => false).get(url)
26
+ res['a']['d'].should.eq({})
27
+ end
19
28
  end
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.1.1
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-13 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: httpclient
@@ -99,6 +99,7 @@ files:
99
99
  - lib/rest-core/middleware/auth_basic.rb
100
100
  - lib/rest-core/middleware/bypass.rb
101
101
  - lib/rest-core/middleware/cache.rb
102
+ - lib/rest-core/middleware/clash_response.rb
102
103
  - lib/rest-core/middleware/common_logger.rb
103
104
  - lib/rest-core/middleware/default_headers.rb
104
105
  - lib/rest-core/middleware/default_payload.rb
@@ -115,6 +116,7 @@ files:
115
116
  - lib/rest-core/middleware/oauth2_header.rb
116
117
  - lib/rest-core/middleware/oauth2_query.rb
117
118
  - lib/rest-core/middleware/query_response.rb
119
+ - lib/rest-core/middleware/smash_response.rb
118
120
  - lib/rest-core/middleware/timeout.rb
119
121
  - lib/rest-core/patch/multi_json.rb
120
122
  - lib/rest-core/patch/rest-client.rb
@@ -122,11 +124,14 @@ files:
122
124
  - lib/rest-core/test.rb
123
125
  - lib/rest-core/thread_pool.rb
124
126
  - lib/rest-core/timer.rb
127
+ - lib/rest-core/util/clash.rb
125
128
  - lib/rest-core/util/config.rb
126
129
  - lib/rest-core/util/hmac.rb
127
130
  - lib/rest-core/util/json.rb
131
+ - lib/rest-core/util/parse_link.rb
128
132
  - lib/rest-core/util/parse_query.rb
129
133
  - lib/rest-core/util/payload.rb
134
+ - lib/rest-core/util/smash.rb
130
135
  - lib/rest-core/version.rb
131
136
  - lib/rest-core/wrapper.rb
132
137
  - rest-core.gemspec
@@ -136,6 +141,8 @@ files:
136
141
  - test/test_auth_basic.rb
137
142
  - test/test_builder.rb
138
143
  - test/test_cache.rb
144
+ - test/test_clash.rb
145
+ - test/test_clash_response.rb
139
146
  - test/test_client.rb
140
147
  - test/test_client_oauth1.rb
141
148
  - test/test_config.rb
@@ -151,11 +158,14 @@ files:
151
158
  - test/test_json_response.rb
152
159
  - test/test_oauth1_header.rb
153
160
  - test/test_oauth2_header.rb
161
+ - test/test_parse_link.rb
154
162
  - test/test_payload.rb
155
163
  - test/test_promise.rb
156
164
  - test/test_query_response.rb
157
165
  - test/test_rest-client.rb
158
166
  - test/test_simple.rb
167
+ - test/test_smash.rb
168
+ - test/test_smash_response.rb
159
169
  - test/test_thread_pool.rb
160
170
  - test/test_timeout.rb
161
171
  - test/test_universal.rb
@@ -188,6 +198,8 @@ test_files:
188
198
  - test/test_auth_basic.rb
189
199
  - test/test_builder.rb
190
200
  - test/test_cache.rb
201
+ - test/test_clash.rb
202
+ - test/test_clash_response.rb
191
203
  - test/test_client.rb
192
204
  - test/test_client_oauth1.rb
193
205
  - test/test_config.rb
@@ -203,11 +215,14 @@ test_files:
203
215
  - test/test_json_response.rb
204
216
  - test/test_oauth1_header.rb
205
217
  - test/test_oauth2_header.rb
218
+ - test/test_parse_link.rb
206
219
  - test/test_payload.rb
207
220
  - test/test_promise.rb
208
221
  - test/test_query_response.rb
209
222
  - test/test_rest-client.rb
210
223
  - test/test_simple.rb
224
+ - test/test_smash.rb
225
+ - test/test_smash_response.rb
211
226
  - test/test_thread_pool.rb
212
227
  - test/test_timeout.rb
213
228
  - test/test_universal.rb