rest-core 3.1.1 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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