rest-core 1.0.3 → 2.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.
Files changed (87) hide show
  1. data/.travis.yml +6 -7
  2. data/CHANGES.md +137 -0
  3. data/Gemfile +1 -1
  4. data/README.md +183 -191
  5. data/TODO.md +5 -8
  6. data/example/multi.rb +31 -24
  7. data/example/simple.rb +28 -0
  8. data/example/use-cases.rb +194 -0
  9. data/lib/rest-core.rb +26 -19
  10. data/lib/rest-core/builder.rb +2 -2
  11. data/lib/rest-core/client.rb +40 -27
  12. data/lib/rest-core/client/universal.rb +16 -13
  13. data/lib/rest-core/client_oauth1.rb +5 -5
  14. data/lib/rest-core/engine/auto.rb +25 -0
  15. data/lib/rest-core/{app → engine}/dry.rb +1 -2
  16. data/lib/rest-core/engine/em-http-request.rb +39 -0
  17. data/lib/rest-core/engine/future/future.rb +106 -0
  18. data/lib/rest-core/engine/future/future_fiber.rb +39 -0
  19. data/lib/rest-core/engine/future/future_thread.rb +29 -0
  20. data/lib/rest-core/engine/rest-client.rb +56 -0
  21. data/lib/rest-core/middleware.rb +27 -5
  22. data/lib/rest-core/middleware/auth_basic.rb +5 -5
  23. data/lib/rest-core/middleware/bypass.rb +2 -2
  24. data/lib/rest-core/middleware/cache.rb +67 -54
  25. data/lib/rest-core/middleware/common_logger.rb +5 -8
  26. data/lib/rest-core/middleware/default_headers.rb +2 -2
  27. data/lib/rest-core/middleware/default_payload.rb +26 -2
  28. data/lib/rest-core/middleware/default_query.rb +4 -2
  29. data/lib/rest-core/middleware/default_site.rb +8 -6
  30. data/lib/rest-core/middleware/error_detector.rb +9 -16
  31. data/lib/rest-core/middleware/error_handler.rb +25 -11
  32. data/lib/rest-core/middleware/follow_redirect.rb +11 -14
  33. data/lib/rest-core/middleware/json_request.rb +19 -0
  34. data/lib/rest-core/middleware/json_response.rb +28 -0
  35. data/lib/rest-core/middleware/oauth1_header.rb +2 -7
  36. data/lib/rest-core/middleware/oauth2_header.rb +4 -7
  37. data/lib/rest-core/middleware/oauth2_query.rb +2 -2
  38. data/lib/rest-core/middleware/timeout.rb +21 -65
  39. data/lib/rest-core/middleware/timeout/{eventmachine_timer.rb → timer_em.rb} +3 -1
  40. data/lib/rest-core/middleware/timeout/timer_thread.rb +36 -0
  41. data/lib/rest-core/patch/multi_json.rb +8 -0
  42. data/lib/rest-core/test.rb +3 -12
  43. data/lib/rest-core/util/json.rb +65 -0
  44. data/lib/rest-core/util/parse_query.rb +2 -2
  45. data/lib/rest-core/version.rb +1 -1
  46. data/lib/rest-core/wrapper.rb +16 -16
  47. data/rest-core.gemspec +28 -27
  48. data/test/test_auth_basic.rb +14 -10
  49. data/test/test_builder.rb +7 -7
  50. data/test/test_cache.rb +126 -37
  51. data/test/test_client.rb +3 -1
  52. data/test/test_client_oauth1.rb +2 -3
  53. data/test/test_default_query.rb +17 -23
  54. data/test/test_em_http_request.rb +146 -0
  55. data/test/test_error_detector.rb +0 -1
  56. data/test/test_error_handler.rb +44 -0
  57. data/test/test_follow_redirect.rb +17 -19
  58. data/test/test_json_request.rb +28 -0
  59. data/test/test_json_response.rb +51 -0
  60. data/test/test_oauth1_header.rb +4 -4
  61. data/test/test_payload.rb +20 -12
  62. data/test/test_simple.rb +14 -0
  63. data/test/test_timeout.rb +11 -19
  64. data/test/test_universal.rb +5 -5
  65. data/test/test_wrapper.rb +19 -13
  66. metadata +28 -29
  67. data/doc/ToC.md +0 -7
  68. data/doc/dependency.md +0 -4
  69. data/doc/design.md +0 -4
  70. data/example/auto.rb +0 -51
  71. data/example/coolio.rb +0 -21
  72. data/example/eventmachine.rb +0 -30
  73. data/example/rest-client.rb +0 -16
  74. data/lib/rest-core/app/abstract/async_fiber.rb +0 -13
  75. data/lib/rest-core/app/auto.rb +0 -23
  76. data/lib/rest-core/app/coolio-async.rb +0 -32
  77. data/lib/rest-core/app/coolio-fiber.rb +0 -30
  78. data/lib/rest-core/app/coolio.rb +0 -9
  79. data/lib/rest-core/app/em-http-request-async.rb +0 -37
  80. data/lib/rest-core/app/em-http-request-fiber.rb +0 -45
  81. data/lib/rest-core/app/em-http-request.rb +0 -9
  82. data/lib/rest-core/app/rest-client.rb +0 -41
  83. data/lib/rest-core/middleware/json_decode.rb +0 -93
  84. data/lib/rest-core/middleware/timeout/coolio_timer.rb +0 -10
  85. data/pending/test_multi.rb +0 -123
  86. data/pending/test_test_util.rb +0 -86
  87. data/test/test_json_decode.rb +0 -24
@@ -5,7 +5,7 @@ class RestCore::Oauth2Header
5
5
  def self.members; [:access_token_type, :access_token]; end
6
6
  include RestCore::Middleware
7
7
 
8
- def call env
8
+ def call env, &k
9
9
  start_time = Time.now
10
10
  headers = {'Authorization' =>
11
11
  "#{access_token_type(env)} #{access_token(env)}"}.
@@ -14,11 +14,8 @@ class RestCore::Oauth2Header
14
14
  event = Event::WithHeader.new(Time.now - start_time,
15
15
  "Authorization: #{headers['Authorization']}") if headers
16
16
 
17
- app.call(log(cache_key(
18
- env.merge(REQUEST_HEADERS => headers || env[REQUEST_HEADERS])), event))
19
- end
20
-
21
- def cache_key env
22
- env.merge('cache.key' => "#{request_uri(env)}&#{access_token(env)}")
17
+ app.call(log(env.merge(REQUEST_HEADERS => headers ||
18
+ env[REQUEST_HEADERS]), event),
19
+ &k)
23
20
  end
24
21
  end
@@ -5,7 +5,7 @@ class RestCore::Oauth2Query
5
5
  def self.members; [:access_token]; end
6
6
  include RestCore::Middleware
7
7
 
8
- def call env
8
+ def call env, &k
9
9
  local = if access_token(env)
10
10
  env.merge(REQUEST_QUERY =>
11
11
  {'access_token' => access_token(env)}.
@@ -14,6 +14,6 @@ class RestCore::Oauth2Query
14
14
  env
15
15
  end
16
16
 
17
- app.call(local)
17
+ app.call(local, &k)
18
18
  end
19
19
  end
@@ -7,9 +7,18 @@ class RestCore::Timeout
7
7
  def self.members; [:timeout]; end
8
8
  include RestCore::Middleware
9
9
 
10
- def call env
11
- return app.call(env) if env[DRY] || timeout(env) == 0
12
- monitor(env){ |e| app.call(e) }
10
+ def call env, &k
11
+ return app.call(env, &k) if env[DRY] || timeout(env) == 0
12
+ monitor(env){ |e|
13
+ app.call(e){ |r|
14
+ if r[ASYNC] ||
15
+ !(exp = (r[FAIL]||[]).find{ |f| f.kind_of?(::Timeout::Error) })
16
+ # we do nothing special for callback and rest-client
17
+ k.call(r)
18
+ else
19
+ # it would go to this branch only under response future
20
+ raise exp
21
+ end}}
13
22
  end
14
23
 
15
24
  def monitor env
@@ -20,73 +29,20 @@ class RestCore::Timeout
20
29
  name
21
30
  end
22
31
 
23
- case class_name
24
- when /EmHttpRequest|Coolio/
25
- if root_fiber? && env[ASYNC]
26
- yield(env.merge(TIMER => timeout_with_callback(env, class_name)))
27
- else
28
- timer = timeout_with_resume(env, class_name)
29
- response = yield(env.merge(TIMER => timer))
30
- timer.cancel unless timer.canceled?
31
- response
32
- end
33
- else
34
- ::Timeout.timeout(timeout(env)){ yield(env) }
35
- end
36
- end
37
-
38
- def root_fiber?
39
- if RestCore.const_defined?(:RootFiber)
40
- RootFiber == Fiber.current
41
- else
42
- true
43
- end
44
- end
45
-
46
- def timeout_with_callback env, class_name
47
- case class_name
48
- when /EmHttpRequest/
49
- EventMachineTimer.new(timeout(env), timeout_error)
50
- when /Coolio/
51
- timer = CoolioTimer.new(timeout(env))
52
- timer.error = timeout_error
53
- timer.attach(::Coolio::Loop.default)
54
- timer
55
- else
56
- raise "BUG: #{run} is not supported"
57
- end
58
- end
59
-
60
- def timeout_with_resume env, class_name
61
- case class_name
62
- when /EmHttpRequest/
63
- f = Fiber.current
64
- EventMachineTimer.new(timeout(env), error = timeout_error){
65
- f.resume(error) if f.alive?
66
- # no need to check if the fiber is already resumed or not,
67
- # because monitor should have already handled this in the
68
- # case of fibers
69
- }
70
-
71
- when /Coolio/
72
- f = Fiber.current
73
- timer = CoolioTimer.new(timeout(env))
74
- error = timer.error = timeout_error
75
- timer.on_timer{ f.resume(error) if f.alive? }
76
- timer.attach(::Coolio::Loop.default)
77
- timer
32
+ timer = case class_name
33
+ when /EmHttpRequest/
34
+ TimerEm
35
+ else
36
+ TimerThread
37
+ end.new(timeout(env), timeout_error)
78
38
 
79
- else
80
- raise "BUG: #{run} is not supported"
81
- end
39
+ yield(env.merge(TIMER => timer))
82
40
  end
83
41
 
84
42
  def timeout_error
85
43
  ::Timeout::Error.new('execution expired')
86
44
  end
87
45
 
88
- autoload :EventMachineTimer,
89
- 'rest-core/middleware/timeout/eventmachine_timer'
90
- autoload :CoolioTimer,
91
- 'rest-core/middleware/timeout/coolio_timer'
46
+ autoload :TimerEm , 'rest-core/middleware/timeout/timer_em'
47
+ autoload :TimerThread, 'rest-core/middleware/timeout/timer_thread'
92
48
  end
@@ -1,5 +1,7 @@
1
1
 
2
- class RestCore::Timeout::EventMachineTimer < ::EventMachine::Timer
2
+ require 'eventmachine'
3
+
4
+ class RestCore::Timeout::TimerEm < ::EventMachine::Timer
3
5
  attr_accessor :timeout, :error
4
6
 
5
7
  def initialize timeout, error, &block
@@ -0,0 +1,36 @@
1
+
2
+ class RestCore::Timeout::TimerThread
3
+ attr_accessor :timeout, :error
4
+
5
+ def initialize timeout, error, &block
6
+ t = Thread.current
7
+ self.timeout = timeout
8
+ self.error = error
9
+ self.block = block || lambda{ t.raise error }
10
+ @canceled = false
11
+ start
12
+ end
13
+
14
+ def on_timeout &block
15
+ self.block = block
16
+ end
17
+
18
+ def cancel
19
+ @canceled = true
20
+ end
21
+
22
+ def canceled?
23
+ @canceled
24
+ end
25
+
26
+ def start
27
+ return if timeout.nil? || timeout.zero?
28
+ self.thread = Thread.new{
29
+ sleep(timeout)
30
+ block.call unless canceled?
31
+ }
32
+ end
33
+
34
+ protected
35
+ attr_accessor :block, :thread
36
+ end
@@ -0,0 +1,8 @@
1
+
2
+ # encode and decode will be remove in multi_json 2.0
3
+ module MultiJson
4
+ class << self
5
+ alias_method :dump, :encode if not respond_to?(:dump)
6
+ alias_method :load, :decode if not respond_to?(:load)
7
+ end
8
+ end
@@ -1,4 +1,6 @@
1
1
 
2
+ require 'fiber'
3
+ require 'em-http-request'
2
4
  require 'rest-core'
3
5
 
4
6
  require 'rr'
@@ -10,20 +12,9 @@ require 'yaml'
10
12
 
11
13
  include RR::Adapters::RRMethods
12
14
  include WebMock::API
13
- WebMock.disable_net_connect!
15
+ WebMock.disable_net_connect!(:allow_localhost => true)
14
16
  Bacon.summary_on_exit
15
17
 
16
- module TestHelper
17
- module_function
18
- def normalize_query query
19
- '?' + query[1..-1].split('&').sort.join('&')
20
- end
21
-
22
- def normalize_url url
23
- url.sub(/\?.+/){ |query| TestHelper.normalize_query(query) }
24
- end
25
- end
26
-
27
18
  module Kernel
28
19
  def eq? rhs
29
20
  self == rhs
@@ -0,0 +1,65 @@
1
+
2
+ module RestCore; end
3
+ module RestCore::Json
4
+ module MultiJson
5
+ def self.extended mod
6
+ require 'rest-core/patch/multi_json'
7
+ mod.const_set(:ParseError, ::MultiJson::DecodeError)
8
+ end
9
+ def encode hash
10
+ ::MultiJson.dump(hash)
11
+ end
12
+ def decode json
13
+ ::MultiJson.load(json)
14
+ end
15
+ end
16
+
17
+ module YajlRuby
18
+ def self.extended mod
19
+ mod.const_set(:ParseError, Yajl::ParseError)
20
+ end
21
+ def encode hash
22
+ Yajl::Encoder.encode(hash)
23
+ end
24
+ def decode json
25
+ Yajl::Parser.parse(json)
26
+ end
27
+ end
28
+
29
+ module Json
30
+ def self.extended mod
31
+ mod.const_set(:ParseError, JSON::ParserError)
32
+ end
33
+ def encode hash
34
+ JSON.dump(hash)
35
+ end
36
+ def decode json
37
+ JSON.parse(json)
38
+ end
39
+ end
40
+
41
+ def self.select_json! mod, picked=false
42
+ if Object.const_defined?(:MultiJson)
43
+ mod.send(:extend, MultiJson)
44
+ elsif Object.const_defined?(:Yajl)
45
+ mod.send(:extend, YajlRuby)
46
+ elsif Object.const_defined?(:JSON)
47
+ mod.send(:extend, Json)
48
+ elsif picked
49
+ raise LoadError.new(
50
+ 'No JSON library found. Tried: multi_json, yajl-ruby, json.')
51
+ else
52
+ # pick a json gem if available
53
+ %w[multi_json yajl json].each{ |json|
54
+ begin
55
+ require json
56
+ break
57
+ rescue LoadError
58
+ end
59
+ }
60
+ select_json!(mod, true)
61
+ end
62
+ end
63
+
64
+ select_json!(self)
65
+ end
@@ -12,8 +12,8 @@ module RestCore::ParseQuery
12
12
  def parse_query(qs, d = nil)
13
13
  params = {}
14
14
 
15
- (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
16
- k, v = p.split('=', 2).map { |x| unescape(x) }
15
+ (qs || '').split(d ? /[#{d}] */n : /[&;] */n).each do |p|
16
+ k, v = p.split('=', 2).map { |x| URI.decode_www_form_component(x) }
17
17
  if cur = params[k]
18
18
  if cur.class == Array
19
19
  params[k] << v
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '1.0.3'
3
+ VERSION = '2.0.0'
4
4
  end
@@ -4,38 +4,38 @@ require 'rest-core'
4
4
  module RestCore::Wrapper
5
5
  include RestCore
6
6
 
7
- module DefaultApp
8
- def default_app
9
- @default_app ||= RestCore::Dry
7
+ module DefaultEngine
8
+ def default_engine
9
+ @default_engine ||= RestCore::Dry
10
10
  end
11
11
  end
12
12
 
13
13
  def self.included mod
14
- mod.send(:extend, DefaultApp)
14
+ mod.send(:extend, DefaultEngine)
15
15
  class << mod
16
- attr_writer :default_app
16
+ attr_writer :default_engine
17
17
  end
18
18
  end
19
19
 
20
- attr_reader :init, :middles, :wrapped
21
- attr_writer :default_app
22
- def default_app
23
- @default_app ||= self.class.default_app
20
+ attr_reader :middles, :wrapped
21
+ attr_writer :default_engine
22
+ def default_engine
23
+ @default_engine ||= self.class.default_engine
24
24
  end
25
25
 
26
26
  def initialize &block
27
27
  @middles ||= []
28
28
  instance_eval(&block) if block_given?
29
29
  @wrapped ||= to_app
30
- @init = nil
30
+ @engine = nil
31
31
  end
32
32
 
33
33
  def use middle, *args, &block
34
34
  middles << [middle, args, block]
35
35
  end
36
36
 
37
- def run app
38
- @init = app
37
+ def run engine
38
+ @engine = engine
39
39
  end
40
40
 
41
41
  def members
@@ -46,14 +46,14 @@ module RestCore::Wrapper
46
46
  else
47
47
  middle.members
48
48
  end if middle.respond_to?(:members)
49
- }.flatten
49
+ }.flatten.compact
50
50
  end
51
51
 
52
- def to_app app=init || default_app
52
+ def to_app engine=@engine || default_engine
53
53
  # === foldr m.new app middles
54
- middles.reverse.inject(app.new){ |app_, (middle, args, block)|
54
+ middles.reverse.inject(engine.new){ |app, (middle, args, block)|
55
55
  begin
56
- middle.new(app_, *partial_deep_copy(args), &block)
56
+ middle.new(app, *partial_deep_copy(args), &block)
57
57
  rescue ArgumentError => e
58
58
  raise ArgumentError.new("#{middle}: #{e}")
59
59
  end
@@ -2,14 +2,14 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rest-core"
5
- s.version = "1.0.3"
5
+ s.version = "2.0.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = [
9
9
  "Cardinal Blue",
10
10
  "Lin Jen-Shin (godfat)"]
11
- s.date = "2012-08-15"
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-core]: https://github.com/cardinalblue/rest-core\n[rest-more]: https://github.com/cardinalblue/rest-more"
11
+ s.date = "2012-10-31"
12
+ s.description = "Modular Ruby clients interface for REST APIs\n\nThere has been an explosion in the number of REST APIs available today.\nTo address the need for a way to access these APIs easily and elegantly,\nwe have developed rest-core, which consists of composable middleware\nthat allows you to build a REST client for any REST API. Or in the case of\ncommon APIs such as Facebook, Github, and Twitter, you can simply use the\ndedicated clients provided by [rest-more][].\n\n[rest-more]: https://github.com/cardinalblue/rest-more"
13
13
  s.email = ["dev (XD) cardinalblue.com"]
14
14
  s.files = [
15
15
  ".gitignore",
@@ -22,30 +22,22 @@ Gem::Specification.new do |s|
22
22
  "README.md",
23
23
  "Rakefile",
24
24
  "TODO.md",
25
- "doc/ToC.md",
26
- "doc/dependency.md",
27
- "doc/design.md",
28
- "example/auto.rb",
29
- "example/coolio.rb",
30
- "example/eventmachine.rb",
31
25
  "example/multi.rb",
32
- "example/rest-client.rb",
26
+ "example/simple.rb",
27
+ "example/use-cases.rb",
33
28
  "lib/rest-core.rb",
34
- "lib/rest-core/app/abstract/async_fiber.rb",
35
- "lib/rest-core/app/auto.rb",
36
- "lib/rest-core/app/coolio-async.rb",
37
- "lib/rest-core/app/coolio-fiber.rb",
38
- "lib/rest-core/app/coolio.rb",
39
- "lib/rest-core/app/dry.rb",
40
- "lib/rest-core/app/em-http-request-async.rb",
41
- "lib/rest-core/app/em-http-request-fiber.rb",
42
- "lib/rest-core/app/em-http-request.rb",
43
- "lib/rest-core/app/rest-client.rb",
44
29
  "lib/rest-core/builder.rb",
45
30
  "lib/rest-core/client.rb",
46
31
  "lib/rest-core/client/simple.rb",
47
32
  "lib/rest-core/client/universal.rb",
48
33
  "lib/rest-core/client_oauth1.rb",
34
+ "lib/rest-core/engine/auto.rb",
35
+ "lib/rest-core/engine/dry.rb",
36
+ "lib/rest-core/engine/em-http-request.rb",
37
+ "lib/rest-core/engine/future/future.rb",
38
+ "lib/rest-core/engine/future/future_fiber.rb",
39
+ "lib/rest-core/engine/future/future_thread.rb",
40
+ "lib/rest-core/engine/rest-client.rb",
49
41
  "lib/rest-core/error.rb",
50
42
  "lib/rest-core/event.rb",
51
43
  "lib/rest-core/middleware.rb",
@@ -62,21 +54,22 @@ Gem::Specification.new do |s|
62
54
  "lib/rest-core/middleware/error_detector_http.rb",
63
55
  "lib/rest-core/middleware/error_handler.rb",
64
56
  "lib/rest-core/middleware/follow_redirect.rb",
65
- "lib/rest-core/middleware/json_decode.rb",
57
+ "lib/rest-core/middleware/json_request.rb",
58
+ "lib/rest-core/middleware/json_response.rb",
66
59
  "lib/rest-core/middleware/oauth1_header.rb",
67
60
  "lib/rest-core/middleware/oauth2_header.rb",
68
61
  "lib/rest-core/middleware/oauth2_query.rb",
69
62
  "lib/rest-core/middleware/timeout.rb",
70
- "lib/rest-core/middleware/timeout/coolio_timer.rb",
71
- "lib/rest-core/middleware/timeout/eventmachine_timer.rb",
63
+ "lib/rest-core/middleware/timeout/timer_em.rb",
64
+ "lib/rest-core/middleware/timeout/timer_thread.rb",
65
+ "lib/rest-core/patch/multi_json.rb",
72
66
  "lib/rest-core/patch/rest-client.rb",
73
67
  "lib/rest-core/test.rb",
74
68
  "lib/rest-core/util/hmac.rb",
69
+ "lib/rest-core/util/json.rb",
75
70
  "lib/rest-core/util/parse_query.rb",
76
71
  "lib/rest-core/version.rb",
77
72
  "lib/rest-core/wrapper.rb",
78
- "pending/test_multi.rb",
79
- "pending/test_test_util.rb",
80
73
  "rest-core.gemspec",
81
74
  "test/test_auth_basic.rb",
82
75
  "test/test_builder.rb",
@@ -84,12 +77,16 @@ Gem::Specification.new do |s|
84
77
  "test/test_client.rb",
85
78
  "test/test_client_oauth1.rb",
86
79
  "test/test_default_query.rb",
80
+ "test/test_em_http_request.rb",
87
81
  "test/test_error_detector.rb",
88
82
  "test/test_error_detector_http.rb",
83
+ "test/test_error_handler.rb",
89
84
  "test/test_follow_redirect.rb",
90
- "test/test_json_decode.rb",
85
+ "test/test_json_request.rb",
86
+ "test/test_json_response.rb",
91
87
  "test/test_oauth1_header.rb",
92
88
  "test/test_payload.rb",
89
+ "test/test_simple.rb",
93
90
  "test/test_timeout.rb",
94
91
  "test/test_universal.rb",
95
92
  "test/test_wrapper.rb"]
@@ -104,12 +101,16 @@ Gem::Specification.new do |s|
104
101
  "test/test_client.rb",
105
102
  "test/test_client_oauth1.rb",
106
103
  "test/test_default_query.rb",
104
+ "test/test_em_http_request.rb",
107
105
  "test/test_error_detector.rb",
108
106
  "test/test_error_detector_http.rb",
107
+ "test/test_error_handler.rb",
109
108
  "test/test_follow_redirect.rb",
110
- "test/test_json_decode.rb",
109
+ "test/test_json_request.rb",
110
+ "test/test_json_response.rb",
111
111
  "test/test_oauth1_header.rb",
112
112
  "test/test_payload.rb",
113
+ "test/test_simple.rb",
113
114
  "test/test_timeout.rb",
114
115
  "test/test_universal.rb",
115
116
  "test/test_wrapper.rb"]