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
data/doc/ToC.md DELETED
@@ -1,7 +0,0 @@
1
-
2
- # rest-core documentation
3
-
4
- ## Table of Content
5
-
6
- * [Overview and Design Concept](design.md)
7
- * [Picking Dependency](dependency.md)
@@ -1,4 +0,0 @@
1
-
2
- # Picking Dependency
3
-
4
-
@@ -1,4 +0,0 @@
1
-
2
- # Overview and Design Concept
3
-
4
-
@@ -1,51 +0,0 @@
1
-
2
- require 'rest-core'
3
- require 'eventmachine'
4
- require 'cool.io'
5
-
6
- YourClient = RestCore::Builder.client do
7
- s = RestCore
8
- use s::DefaultSite , 'https://api.github.com/users/'
9
- use s::JsonDecode , true
10
- use s::CommonLogger, method(:puts)
11
- use s::Cache , nil, 3600
12
- run s::Auto
13
- end
14
-
15
- client = YourClient.new(:cache => {})
16
- p client.get('cardinalblue') # cache miss
17
- puts
18
- p client.get('cardinalblue') # cache hit
19
-
20
- puts
21
-
22
- client = YourClient.new(:cache => {})
23
- EM.run{
24
- client.get('cardinalblue'){ |response|
25
- p response
26
- EM.stop
27
- }
28
- }
29
-
30
- puts
31
-
32
- EM.run{
33
- Fiber.new{
34
- p client.get('cardinalblue')
35
- EM.stop
36
- }.resume
37
- }
38
-
39
- puts
40
-
41
- client = YourClient.new(:cache => {})
42
- Coolio::TimerWatcher.new(1).attach(Coolio::Loop.default).on_timer{detach}
43
- client.get('cardinalblue'){ |response|
44
- p response
45
- }
46
- Coolio::Loop.default.run
47
-
48
- puts
49
- Coolio::TimerWatcher.new(1).attach(Coolio::Loop.default).on_timer{detach}
50
- Fiber.new{ p client.get('cardinalblue') }.resume
51
- Coolio::Loop.default.run
@@ -1,21 +0,0 @@
1
-
2
- require 'rest-core'
3
-
4
- AsynchronousClient = RestCore::Builder.client do
5
- s = RestCore
6
- use s::DefaultSite , 'https://api.github.com/users/'
7
- use s::JsonDecode , true
8
- use s::CommonLogger, method(:puts)
9
- use s::Cache , nil, 3600
10
- run s::Coolio
11
- end
12
-
13
- AsynchronousClient.new.get('cardinalblue'){ |response|
14
- p response
15
- }
16
- Coolio::Loop.default.run
17
-
18
- puts
19
-
20
- Fiber.new{ p AsynchronousClient.new.get('cardinalblue') }.resume
21
- Coolio::Loop.default.run
@@ -1,30 +0,0 @@
1
-
2
- require 'rest-core'
3
-
4
- AsynchronousClient = RestCore::Builder.client do
5
- s = RestCore
6
- use s::DefaultSite , 'https://api.github.com/users/'
7
- use s::JsonDecode , true
8
- use s::CommonLogger, method(:puts)
9
- use s::Cache , nil, 3600
10
- run s::EmHttpRequest
11
- end
12
-
13
- client = AsynchronousClient.new
14
- EM.run{
15
- client.get('cardinalblue'){ |response|
16
- p response
17
- EM.stop
18
- }
19
- puts "It's not blocking..."
20
- }
21
-
22
- puts
23
-
24
- EM.run{
25
- Fiber.new{
26
- p client.get('cardinalblue')
27
- EM.stop
28
- }.resume
29
- puts "It's not blocking..."
30
- }
@@ -1,16 +0,0 @@
1
-
2
- require 'rest-core'
3
-
4
- YourClient = RestCore::Builder.client do
5
- s = RestCore
6
- use s::DefaultSite , 'https://api.github.com/users/'
7
- use s::JsonDecode , true
8
- use s::CommonLogger, method(:puts)
9
- use s::Cache , nil, 3600
10
- run s::RestClient
11
- end
12
-
13
- client = YourClient.new(:cache => {})
14
- p client.get('cardinalblue') # cache miss
15
- puts
16
- p client.get('cardinalblue') # cache hit
@@ -1,13 +0,0 @@
1
-
2
- require 'rest-core/middleware'
3
-
4
- class RestCore::AsyncFiber
5
- include RestCore::Middleware
6
- def call env
7
- if env[ASYNC]
8
- async.call(env)
9
- else
10
- fiber.call(env)
11
- end
12
- end
13
- end
@@ -1,23 +0,0 @@
1
-
2
- require 'rest-core/middleware'
3
-
4
- class RestCore::Auto
5
- include RestCore::Middleware
6
- def call env
7
- client = http_client
8
- client.call(log(env, "Auto picked: #{client.class}"))
9
- end
10
-
11
- def http_client
12
- if Object.const_defined?(:EventMachine) && ::EventMachine.reactor_running?
13
- @emhttprequest ||= RestCore::EmHttpRequest.new
14
-
15
- elsif Object.const_defined?(:Coolio) && ::Coolio::Loop.default.
16
- has_active_watchers?
17
- @coolio ||= RestCore::Coolio.new
18
-
19
- else
20
- @restclient ||= RestCore::RestClient.new
21
- end
22
- end
23
- end
@@ -1,32 +0,0 @@
1
-
2
- require 'rest-core/middleware'
3
-
4
- require 'cool.io-http'
5
-
6
- class RestCore::CoolioAsync
7
- include RestCore::Middleware
8
- def call env
9
- client = ::Coolio::Http.request(:method => env[REQUEST_METHOD] ,
10
- :url => request_uri(env) ,
11
- :payload => env[REQUEST_PAYLOAD],
12
- :headers => env[REQUEST_HEADERS]){ |res|
13
-
14
- env[TIMER].detach if env[TIMER]
15
- env[ASYNC].call(env.merge(RESPONSE_BODY => res.body ,
16
- RESPONSE_STATUS => res.status,
17
- RESPONSE_HEADERS => res.headers)) if
18
- env[ASYNC]
19
- }
20
-
21
- env[TIMER].on_timer{
22
- detach
23
- client.detach
24
- env[ASYNC].call(env.merge(RESPONSE_BODY => env[TIMER].error,
25
- RESPONSE_STATUS => 0 ,
26
- RESPONSE_HEADERS => {} )) if
27
- env[ASYNC]
28
- } if env[TIMER]
29
-
30
- env
31
- end
32
- end
@@ -1,30 +0,0 @@
1
-
2
- require 'rest-core/middleware'
3
-
4
- require 'cool.io-http'
5
-
6
- class RestCore::CoolioFiber
7
- include RestCore::Middleware
8
- def call env
9
- process(env,
10
- ::Coolio::HttpFiber.request(:method => env[REQUEST_METHOD] ,
11
- :url => request_uri(env) ,
12
- :payload => env[REQUEST_PAYLOAD],
13
- :headers => env[REQUEST_HEADERS]))
14
- rescue FiberError
15
- end
16
-
17
- def process env, response
18
- Thread.current[:coolio_http_client].detach if
19
- Thread.current[:coolio_http_client].kind_of?(::Coolio::HttpFiber)
20
-
21
- raise response if response.kind_of?(::Exception)
22
-
23
- result = env.merge(RESPONSE_BODY => response.body ,
24
- RESPONSE_STATUS => response.status,
25
- RESPONSE_HEADERS => response.headers)
26
-
27
- result[ASYNC].call(result) if result[ASYNC]
28
- result
29
- end
30
- end
@@ -1,9 +0,0 @@
1
-
2
- require 'rest-core/app/abstract/async_fiber'
3
- require 'rest-core/app/coolio-async'
4
- require 'rest-core/app/coolio-fiber'
5
-
6
- class RestCore::Coolio < RestCore::AsyncFiber
7
- def async; @async ||= CoolioAsync.new; end
8
- def fiber; @fiber ||= CoolioFiber.new; end
9
- end
@@ -1,37 +0,0 @@
1
-
2
- require 'rest-core/middleware'
3
-
4
- require 'restclient/payload'
5
- require 'em-http-request'
6
-
7
- class RestCore::EmHttpRequestAsync
8
- include RestCore::Middleware
9
- def call env
10
- payload = ::RestClient::Payload.generate(env[REQUEST_PAYLOAD])
11
- client = ::EventMachine::HttpRequest.new(request_uri(env)).send(
12
- env[REQUEST_METHOD],
13
- :body => payload.read,
14
- :head => payload.headers.merge(env[REQUEST_HEADERS]))
15
-
16
- client.callback{ respond(env, client) }
17
- client. errback{ respond(env, client) }
18
-
19
- env[TIMER].on_timeout{
20
- client.close
21
- env[ASYNC].call(env.merge(RESPONSE_BODY => env[TIMER].error,
22
- RESPONSE_STATUS => 0 ,
23
- RESPONSE_HEADERS => {} )) if
24
- env[ASYNC]
25
- } if env[TIMER]
26
-
27
- env
28
- end
29
-
30
- def respond env, client
31
- env[TIMER].cancel if env[TIMER] && !env[TIMER].canceled?
32
- env[ASYNC].call(env.merge(
33
- RESPONSE_BODY => client.response,
34
- RESPONSE_STATUS => client.response_header.status,
35
- RESPONSE_HEADERS => client.response_header)) if env[ASYNC]
36
- end
37
- end
@@ -1,45 +0,0 @@
1
-
2
- require 'rest-core/middleware'
3
-
4
- require 'restclient/payload'
5
- require 'em-http-request'
6
- require 'fiber'
7
-
8
- class RestCore::EmHttpRequestFiber
9
- include RestCore::Middleware
10
- def call env
11
- f = Fiber.current
12
-
13
- payload = ::RestClient::Payload.generate(env[REQUEST_PAYLOAD])
14
- client = ::EventMachine::HttpRequest.new(request_uri(env)).send(
15
- env[REQUEST_METHOD],
16
- :body => payload.read,
17
- :head => payload.headers.merge(env[REQUEST_HEADERS]))
18
-
19
- client.callback{ respond(f, env, client) }
20
- client. errback{ respond(f, env, client) }
21
-
22
- if (response = Fiber.yield).kind_of?(::Exception)
23
- client.close
24
- raise response
25
- else
26
- response
27
- end
28
- end
29
-
30
- def respond f, env, client
31
- f.resume(process(env, client)) if f.alive?
32
- rescue FiberError
33
- # whenever timeout, client.close would be called,
34
- # and then errback would be called. in this case,
35
- # the fiber is already resumed by the timer
36
- end
37
-
38
- def process env, client
39
- result = env.merge(RESPONSE_BODY => client.response,
40
- RESPONSE_STATUS => client.response_header.status,
41
- RESPONSE_HEADERS => client.response_header)
42
- result[ASYNC].call(result) if result[ASYNC]
43
- result
44
- end
45
- end
@@ -1,9 +0,0 @@
1
-
2
- require 'rest-core/app/abstract/async_fiber'
3
- require 'rest-core/app/em-http-request-async'
4
- require 'rest-core/app/em-http-request-fiber'
5
-
6
- class RestCore::EmHttpRequest < RestCore::AsyncFiber
7
- def async; @async ||= EmHttpRequestAsync.new; end
8
- def fiber; @fiber ||= EmHttpRequestFiber.new; end
9
- end
@@ -1,41 +0,0 @@
1
-
2
- require 'rest-core/middleware'
3
-
4
- require 'restclient'
5
-
6
- require 'rest-core/patch/rest-client'
7
-
8
- class RestCore::RestClient
9
- include RestCore::Middleware
10
- def call env
11
- process(env,
12
- ::RestClient::Request.execute(:method => env[REQUEST_METHOD ],
13
- :url => request_uri(env) ,
14
- :payload => env[REQUEST_PAYLOAD],
15
- :headers => env[REQUEST_HEADERS],
16
- :max_redirects => 0))
17
-
18
- rescue ::RestClient::Exception => e
19
- process(env, e.response)
20
- end
21
-
22
- def process env, response
23
- result = env.merge(RESPONSE_BODY => response.body,
24
- RESPONSE_STATUS => response.code,
25
- RESPONSE_HEADERS => normalize_headers(
26
- response.raw_headers))
27
- result[ASYNC].call(result) if result[ASYNC]
28
- result
29
- end
30
-
31
- def normalize_headers raw_headers
32
- raw_headers.inject({}){ |r, (k, v)|
33
- r[k.to_s.upcase.tr('-', '_')] = if v.kind_of?(Array) && v.size == 1
34
- v.first
35
- else
36
- v
37
- end
38
- r
39
- }
40
- end
41
- end
@@ -1,93 +0,0 @@
1
-
2
- require 'rest-core/middleware'
3
-
4
- class RestCore::JsonDecode
5
- def self.members; [:json_decode]; end
6
- include RestCore::Middleware
7
-
8
- def call env
9
- return app.call(env) if env[DRY]
10
- if env[ASYNC]
11
- app.call(env.merge(ASYNC => lambda{ |response|
12
- env[ASYNC].call(process(response))
13
- }))
14
- else
15
- process(app.call(env))
16
- end
17
- end
18
-
19
- def process response
20
- if json_decode(response)
21
- response.merge(RESPONSE_BODY =>
22
- self.class.json_decode("[#{response[RESPONSE_BODY]}]").first)
23
- # [this].first is not needed for yajl-ruby
24
- else
25
- response
26
- end
27
- rescue self.class.const_get(:ParseError) => error
28
- fail(response, error)
29
- end
30
-
31
- module YajlRuby
32
- def self.extended mod
33
- mod.const_set(:ParseError, Yajl::ParseError)
34
- end
35
- def json_encode hash
36
- Yajl::Encoder.encode(hash)
37
- end
38
- def json_decode json
39
- Yajl::Parser.parse(json)
40
- end
41
- end
42
-
43
- module Json
44
- def self.extended mod
45
- mod.const_set(:ParseError, JSON::ParserError)
46
- end
47
- def json_encode hash
48
- JSON.dump(hash)
49
- end
50
- def json_decode json
51
- JSON.parse(json)
52
- end
53
- end
54
-
55
- module Gsub
56
- class ParseError < RuntimeError; end
57
- def self.extended mod
58
- mod.const_set(:ParseError, Gsub::ParseError)
59
- end
60
- # only works for flat hash
61
- def json_encode hash
62
- middle = hash.inject([]){ |r, (k, v)|
63
- r << "\"#{k}\":\"#{v.gsub('"','\\"')}\""
64
- }.join(',')
65
- "{#{middle}}"
66
- end
67
- def json_decode json
68
- raise NotImplementedError.new(
69
- 'You need to install either yajl-ruby, json, or json_pure gem')
70
- end
71
- end
72
-
73
- def self.select_json! mod, picked=false
74
- if Object.const_defined?(:Yajl)
75
- mod.send(:extend, YajlRuby)
76
- elsif Object.const_defined?(:JSON)
77
- mod.send(:extend, Json)
78
- elsif picked
79
- mod.send(:extend, Gsub)
80
- else
81
- # pick a json gem if available
82
- %w[yajl json].each{ |json|
83
- begin
84
- require json
85
- break
86
- rescue LoadError
87
- end
88
- }
89
- select_json!(mod, true)
90
- end
91
- end
92
- select_json!(self)
93
- end