rest-core 1.0.3 → 2.0.0

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