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
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