rest-core 1.0.0 → 1.0.1

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.
data/CHANGES.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGES
2
2
 
3
+ ## rest-core 1.0.1 -- 2012-05-14
4
+
5
+ * [`Auto`] Check for eventmachine first instead of cool.io
6
+ * [`EmHttpRequestFiber`] Also pass callback for errback
7
+ * [`DefaultQuery`] Make default query to {} instead of nil
8
+
3
9
  ## rest-core 1.0.0 -- 2012-03-17
4
10
 
5
11
  This is a very significant release. The most important change is now we
@@ -7,7 +13,7 @@ support asynchronous requests, by either passing a callback block or using
7
13
  fibers in Ruby 1.9 to make the whole program still look synchronous.
8
14
 
9
15
  Please read [README.md](https://github.com/cardinalblue/rest-core/blob/master/README.md)
10
- or [example](https://github.com/cardinalblue/rest-core/blob/master/example)
16
+ or [example](https://github.com/cardinalblue/rest-core/tree/master/example)
11
17
  for more detail.
12
18
 
13
19
  * [`Client`] Client#inspect is fixed for clients which do not have any
data/README.md CHANGED
@@ -49,14 +49,16 @@ dedicated clients provided by [rest-more][].
49
49
  * Fibers only work on Ruby 1.9+
50
50
  * gem [em-http-request][] (if using eventmachine)
51
51
  * gem [cool.io-http][] (if using cool.io)
52
- * gem json or yajl-ruby (if using JsonDecode middleware)
52
+ * gem json or yajl-ruby (if using `JsonDecode` middleware)
53
53
 
54
54
  [em-http-request]: https://github.com/igrigorik/em-http-request
55
55
  [cool.io-http]: https://github.com/godfat/cool.io-http
56
56
 
57
57
  ## INSTALLATION:
58
58
 
59
+ ``` shell
59
60
  gem install rest-core
61
+ ```
60
62
 
61
63
  Or if you want development version, put this in Gemfile:
62
64
 
@@ -106,14 +108,14 @@ for concepts.
106
108
 
107
109
  [example/rest-client.rb]: https://github.com/cardinalblue/rest-core/blob/master/example/rest-client.rb
108
110
  [rest-more]: https://github.com/cardinalblue/rest-more
109
- [rubyconf.tw]: http://rubyconf.tw/2011/#6
110
111
  [slides]: http://www.godfat.org/slide/2011-08-27-rest-core.html
112
+ [rubyconf.tw]: http://rubyconf.tw/2011/#6
111
113
 
112
114
  ## Asynchronous HTTP Requests:
113
115
 
114
116
  I/O bound operations shouldn't be blocking the CPU! If you have a reactor,
115
117
  i.e. event loop, you should take the advantage of that to make HTTP requests
116
- non-blocking the whole process/thread. For now, we support eventmachine and
118
+ not block the whole process/thread. For now, we support eventmachine and
117
119
  cool.io. Below is an example for eventmachine:
118
120
 
119
121
  ``` ruby
@@ -133,12 +135,13 @@ If you're passing a block, the block is called after the response is
133
135
  available. That is the block is the callback for the request.
134
136
 
135
137
  ``` ruby
136
- client = AsynchronousClient.new(:cache => {})
138
+ client = AsynchronousClient.new
137
139
  EM.run{
138
140
  client.get('cardinalblue'){ |response|
139
141
  p response
140
142
  EM.stop
141
143
  }
144
+ puts "It's not blocking..."
142
145
  }
143
146
  ```
144
147
 
@@ -154,6 +157,7 @@ If you don't understand what does this mean, you can take a look at
154
157
  p client.get('cardinalblue')
155
158
  EM.stop
156
159
  }.resume
160
+ puts "It's not blocking..."
157
161
  }
158
162
  ```
159
163
 
@@ -178,6 +182,7 @@ You can also make multi-requests synchronously like this:
178
182
  p Fiber.yield
179
183
  EM.stop
180
184
  }.resume
185
+ puts "It's not blocking..."
181
186
  }
182
187
  ```
183
188
 
data/TODO.md CHANGED
@@ -1,4 +1,22 @@
1
1
  # TODO
2
2
 
3
+ * Auto should also pick RestClient if it's not inside a fiber
4
+ * HTTP method in Requested log
3
5
  * middleware revisit (how to initialize?)
4
6
  * test utility
7
+
8
+ # BUG
9
+
10
+ * inheritance should work; assign builder?
11
+ * no error handling in cool.io
12
+
13
+ # FEATURE
14
+
15
+ * middleware composer
16
+ * RC::Payload which can handle Content-Type: application/json
17
+ * how to pass a arbitrary payload generator?
18
+ * RC::JsonRequest
19
+ * RC::FakeGetWithPayload
20
+
21
+ * ResponseThunk and EmHttpRequestThunk
22
+ * options for apps
@@ -10,12 +10,13 @@ AsynchronousClient = RestCore::Builder.client do
10
10
  run s::EmHttpRequest
11
11
  end
12
12
 
13
- client = AsynchronousClient.new(:cache => {})
13
+ client = AsynchronousClient.new
14
14
  EM.run{
15
15
  client.get('cardinalblue'){ |response|
16
16
  p response
17
17
  EM.stop
18
18
  }
19
+ puts "It's not blocking..."
19
20
  }
20
21
 
21
22
  puts
@@ -25,4 +26,5 @@ EM.run{
25
26
  p client.get('cardinalblue')
26
27
  EM.stop
27
28
  }.resume
29
+ puts "It's not blocking..."
28
30
  }
@@ -23,6 +23,7 @@ EM.run{
23
23
  result[0] = response
24
24
  fiber.resume(result) if result.size == 2
25
25
  }
26
+ puts "It's not blocking..."
26
27
  client.get('cardinalblue'){ |response|
27
28
  result[1] = response
28
29
  fiber.resume(result) if result.size == 2
@@ -30,4 +31,5 @@ EM.run{
30
31
  p Fiber.yield
31
32
  EM.stop
32
33
  }.resume
34
+ puts "It's not blocking..."
33
35
  }
@@ -9,12 +9,13 @@ class RestCore::Auto
9
9
  end
10
10
 
11
11
  def http_client
12
- if Object.const_defined?(:Coolio) && ::Coolio::Loop.default.
13
- has_active_watchers?
14
- @coolio ||= RestCore::Coolio.new
15
- elsif Object.const_defined?(:EventMachine) && ::EventMachine.
16
- reactor_running?
12
+ if Object.const_defined?(:EventMachine) && ::EventMachine.reactor_running?
17
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
+
18
19
  else
19
20
  @restclient ||= RestCore::RestClient.new
20
21
  end
@@ -13,13 +13,8 @@ class RestCore::EmHttpRequestAsync
13
13
  :body => payload.read,
14
14
  :head => payload.headers.merge(env[REQUEST_HEADERS]))
15
15
 
16
- client.callback{
17
- env[TIMER].cancel if env[TIMER]
18
- env[ASYNC].call(env.merge(
19
- RESPONSE_BODY => client.response,
20
- RESPONSE_STATUS => client.response_header.status,
21
- RESPONSE_HEADERS => client.response_header)) if env[ASYNC]
22
- }
16
+ client.callback{ respond(env, client) }
17
+ client. errback{ respond(env, client) }
23
18
 
24
19
  env[TIMER].on_timeout{
25
20
  client.close
@@ -31,4 +26,12 @@ class RestCore::EmHttpRequestAsync
31
26
 
32
27
  env
33
28
  end
29
+
30
+ def respond env, client
31
+ env[TIMER].cancel if env[TIMER]
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
34
37
  end
@@ -16,10 +16,8 @@ class RestCore::EmHttpRequestFiber
16
16
  :body => payload.read,
17
17
  :head => payload.headers.merge(env[REQUEST_HEADERS]))
18
18
 
19
- client.callback{
20
- env[TIMER].cancel if env[TIMER]
21
- f.resume(process(env, client)) if f.alive?
22
- }
19
+ client.callback{ respond(f, env, client) }
20
+ client. errback{ respond(f, env, client) }
23
21
 
24
22
  if (response = Fiber.yield).kind_of?(::Exception)
25
23
  client.close
@@ -29,6 +27,11 @@ class RestCore::EmHttpRequestFiber
29
27
  end
30
28
  end
31
29
 
30
+ def respond f, env, client
31
+ env[TIMER].cancel if env[TIMER]
32
+ f.resume(process(env, client)) if f.alive?
33
+ end
34
+
32
35
  def process env, client
33
36
  result = env.merge(RESPONSE_BODY => client.response,
34
37
  RESPONSE_STATUS => client.response_header.status,
@@ -4,6 +4,12 @@ require 'rest-core/middleware'
4
4
  class RestCore::DefaultQuery
5
5
  def self.members; [:query]; end
6
6
  include RestCore::Middleware
7
+
8
+ def initialize *args
9
+ super
10
+ @query ||= {}
11
+ end
12
+
7
13
  def call env
8
14
  app.call(env.merge(REQUEST_QUERY =>
9
15
  @query.merge(query(env)).merge(env[REQUEST_QUERY] || {})))
@@ -8,7 +8,7 @@ class RestCore::Timeout
8
8
  include RestCore::Middleware
9
9
 
10
10
  def call env
11
- return app.call(env) if env[DRY]
11
+ return app.call(env) if env[DRY] || timeout(env) == 0
12
12
  monitor(env){ |e| app.call(e) }
13
13
  end
14
14
 
@@ -21,7 +21,7 @@ class RestCore::Timeout
21
21
  end
22
22
 
23
23
  case class_name
24
- when /Coolio|EmHttpRequest/
24
+ when /EmHttpRequest|Coolio/
25
25
  if root_fiber? && env[ASYNC]
26
26
  yield(env.merge(TIMER => timeout_with_callback(env, class_name)))
27
27
  else
@@ -42,13 +42,13 @@ class RestCore::Timeout
42
42
 
43
43
  def timeout_with_callback env, class_name
44
44
  case class_name
45
+ when /EmHttpRequest/
46
+ EventMachineTimer.new(timeout(env), timeout_error)
45
47
  when /Coolio/
46
48
  timer = CoolioTimer.new(timeout(env))
47
49
  timer.error = timeout_error
48
50
  timer.attach(::Coolio::Loop.default)
49
51
  timer
50
- when /EmHttpRequest/
51
- EventMachineTimer.new(timeout(env), timeout_error)
52
52
  else
53
53
  raise "BUG: #{run} is not supported"
54
54
  end
@@ -56,6 +56,12 @@ class RestCore::Timeout
56
56
 
57
57
  def timeout_with_resume env, class_name
58
58
  case class_name
59
+ when /EmHttpRequest/
60
+ f = Fiber.current
61
+ EventMachineTimer.new(timeout(env), error = timeout_error){
62
+ f.resume(error) if f.alive?
63
+ }
64
+
59
65
  when /Coolio/
60
66
  f = Fiber.current
61
67
  timer = CoolioTimer.new(timeout(env))
@@ -64,11 +70,6 @@ class RestCore::Timeout
64
70
  timer.attach(::Coolio::Loop.default)
65
71
  timer
66
72
 
67
- when /EmHttpRequest/
68
- f = Fiber.current
69
- EventMachineTimer.new(timeout(env), error = timeout_error){
70
- f.resume(error) if f.alive?
71
- }
72
73
  else
73
74
  raise "BUG: #{run} is not supported"
74
75
  end
@@ -78,8 +79,8 @@ class RestCore::Timeout
78
79
  ::Timeout::Error.new('execution expired')
79
80
  end
80
81
 
81
- autoload :CoolioTimer,
82
- 'rest-core/middleware/timeout/coolio_timer'
83
82
  autoload :EventMachineTimer,
84
83
  'rest-core/middleware/timeout/eventmachine_timer'
84
+ autoload :CoolioTimer,
85
+ 'rest-core/middleware/timeout/coolio_timer'
85
86
  end
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '1.0.0'
3
+ VERSION = '1.0.1'
4
4
  end
@@ -2,13 +2,13 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "rest-core"
5
- s.version = "1.0.0"
5
+ s.version = "1.0.1"
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-03-17"
11
+ s.date = "2012-05-14"
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-core]: https://github.com/cardinalblue/rest-core\n[rest-more]: https://github.com/cardinalblue/rest-more"
13
13
  s.email = ["dev (XD) cardinalblue.com"]
14
14
  s.files = [
@@ -84,29 +84,33 @@ Gem::Specification.new do |s|
84
84
  "test/test_builder.rb",
85
85
  "test/test_client.rb",
86
86
  "test/test_client_oauth1.rb",
87
+ "test/test_default_query.rb",
87
88
  "test/test_error_detector.rb",
88
89
  "test/test_error_detector_http.rb",
89
90
  "test/test_follow_redirect.rb",
90
91
  "test/test_json_decode.rb",
91
92
  "test/test_oauth1_header.rb",
92
93
  "test/test_payload.rb",
94
+ "test/test_timeout.rb",
93
95
  "test/test_universal.rb",
94
96
  "test/test_wrapper.rb"]
95
97
  s.homepage = "https://github.com/cardinalblue/rest-core"
96
98
  s.require_paths = ["lib"]
97
- s.rubygems_version = "1.8.19"
99
+ s.rubygems_version = "1.8.24"
98
100
  s.summary = "Modular Ruby clients interface for REST APIs"
99
101
  s.test_files = [
100
102
  "test/test_auth_basic.rb",
101
103
  "test/test_builder.rb",
102
104
  "test/test_client.rb",
103
105
  "test/test_client_oauth1.rb",
106
+ "test/test_default_query.rb",
104
107
  "test/test_error_detector.rb",
105
108
  "test/test_error_detector_http.rb",
106
109
  "test/test_follow_redirect.rb",
107
110
  "test/test_json_decode.rb",
108
111
  "test/test_oauth1_header.rb",
109
112
  "test/test_payload.rb",
113
+ "test/test_timeout.rb",
110
114
  "test/test_universal.rb",
111
115
  "test/test_wrapper.rb"]
112
116
 
@@ -0,0 +1,45 @@
1
+
2
+ require 'rest-core/test'
3
+
4
+ describe RC::DefaultQuery do
5
+ describe 'when given query' do
6
+ before do
7
+ @app = RC::DefaultQuery.new(RC::Dry.new, {})
8
+ end
9
+
10
+ def app
11
+ @app
12
+ end
13
+
14
+ should 'do nothing' do
15
+ app.call({})[RC::REQUEST_QUERY].should.eq({})
16
+ end
17
+
18
+ should 'merge query' do
19
+ app.instance_eval{@query = {'q' => 'uery'}}
20
+
21
+ app.call({}).should.eq({RC::REQUEST_QUERY =>
22
+ {'q' => 'uery'}})
23
+
24
+ format = {'format' => 'json'}
25
+ env = {RC::REQUEST_QUERY => format}
26
+
27
+ app.call(env).should.eq({RC::REQUEST_QUERY =>
28
+ {'q' => 'uery'}.merge(format)})
29
+ end
30
+ end
31
+
32
+ describe 'when not given query' do
33
+ before do
34
+ @app = RC::DefaultQuery.new(RC::Dry.new)
35
+ end
36
+
37
+ def app
38
+ @app
39
+ end
40
+
41
+ should 'merge query with {}' do
42
+ app.call({}).should.eq({RC::REQUEST_QUERY => {}})
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+
2
+ require 'rest-core/test'
3
+
4
+ describe RC::Timeout do
5
+ before do
6
+ @app = RC::Timeout.new(RC::Dry.new, 0)
7
+ end
8
+
9
+ should 'bypass timeout if timeout is 0' do
10
+ mock(@app).monitor.times(0)
11
+ @app.call({}).should.eq({})
12
+ end
13
+
14
+ should 'run the monitor to setup timeout' do
15
+ env = {'timeout' => 2}
16
+ mock.proxy(@app).monitor(env).times(1)
17
+ @app.call(env).should.eq(env)
18
+ end
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-03-17 00:00:00.000000000 Z
13
+ date: 2012-05-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rest-client
@@ -125,12 +125,14 @@ files:
125
125
  - test/test_builder.rb
126
126
  - test/test_client.rb
127
127
  - test/test_client_oauth1.rb
128
+ - test/test_default_query.rb
128
129
  - test/test_error_detector.rb
129
130
  - test/test_error_detector_http.rb
130
131
  - test/test_follow_redirect.rb
131
132
  - test/test_json_decode.rb
132
133
  - test/test_oauth1_header.rb
133
134
  - test/test_payload.rb
135
+ - test/test_timeout.rb
134
136
  - test/test_universal.rb
135
137
  - test/test_wrapper.rb
136
138
  homepage: https://github.com/cardinalblue/rest-core
@@ -153,7 +155,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
155
  version: '0'
154
156
  requirements: []
155
157
  rubyforge_project:
156
- rubygems_version: 1.8.19
158
+ rubygems_version: 1.8.24
157
159
  signing_key:
158
160
  specification_version: 3
159
161
  summary: Modular Ruby clients interface for REST APIs
@@ -162,12 +164,14 @@ test_files:
162
164
  - test/test_builder.rb
163
165
  - test/test_client.rb
164
166
  - test/test_client_oauth1.rb
167
+ - test/test_default_query.rb
165
168
  - test/test_error_detector.rb
166
169
  - test/test_error_detector_http.rb
167
170
  - test/test_follow_redirect.rb
168
171
  - test/test_json_decode.rb
169
172
  - test/test_oauth1_header.rb
170
173
  - test/test_payload.rb
174
+ - test/test_timeout.rb
171
175
  - test/test_universal.rb
172
176
  - test/test_wrapper.rb
173
177
  has_rdoc: