rest-core 2.1.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -2
  3. data/.travis.yml +3 -5
  4. data/CHANGES.md +65 -5
  5. data/Gemfile +10 -5
  6. data/NOTE.md +1 -1
  7. data/README.md +194 -128
  8. data/Rakefile +8 -34
  9. data/TODO.md +3 -2
  10. data/example/simple.rb +6 -4
  11. data/example/use-cases.rb +39 -122
  12. data/lib/rest-core.rb +14 -5
  13. data/lib/rest-core/builder.rb +12 -2
  14. data/lib/rest-core/client.rb +31 -25
  15. data/lib/rest-core/engine.rb +39 -0
  16. data/lib/rest-core/engine/http-client.rb +41 -0
  17. data/lib/rest-core/engine/net-http-persistent.rb +21 -0
  18. data/lib/rest-core/engine/rest-client.rb +13 -42
  19. data/lib/rest-core/event_source.rb +91 -0
  20. data/lib/rest-core/middleware.rb +17 -11
  21. data/lib/rest-core/middleware/error_detector.rb +1 -6
  22. data/lib/rest-core/middleware/oauth1_header.rb +1 -0
  23. data/lib/rest-core/middleware/oauth2_header.rb +20 -8
  24. data/lib/rest-core/middleware/oauth2_query.rb +1 -0
  25. data/lib/rest-core/middleware/timeout.rb +5 -19
  26. data/lib/rest-core/promise.rb +137 -0
  27. data/lib/rest-core/test.rb +2 -43
  28. data/lib/rest-core/thread_pool.rb +122 -0
  29. data/lib/rest-core/timer.rb +30 -0
  30. data/lib/rest-core/util/hmac.rb +0 -8
  31. data/lib/rest-core/version.rb +1 -1
  32. data/lib/rest-core/wrapper.rb +1 -1
  33. data/rest-core.gemspec +36 -25
  34. data/task/README.md +54 -0
  35. data/task/gemgem.rb +150 -156
  36. data/test/test_builder.rb +2 -2
  37. data/test/test_cache.rb +8 -8
  38. data/test/test_client.rb +16 -6
  39. data/test/test_client_oauth1.rb +1 -1
  40. data/test/test_event_source.rb +77 -0
  41. data/test/test_follow_redirect.rb +1 -1
  42. data/test/test_future.rb +16 -0
  43. data/test/test_oauth2_header.rb +28 -0
  44. data/test/test_promise.rb +89 -0
  45. data/test/test_rest-client.rb +21 -0
  46. data/test/test_thread_pool.rb +10 -0
  47. data/test/test_timeout.rb +13 -8
  48. metadata +61 -37
  49. data/example/multi.rb +0 -44
  50. data/lib/rest-core/engine/auto.rb +0 -25
  51. data/lib/rest-core/engine/em-http-request.rb +0 -90
  52. data/lib/rest-core/engine/future/future.rb +0 -107
  53. data/lib/rest-core/engine/future/future_fiber.rb +0 -32
  54. data/lib/rest-core/engine/future/future_thread.rb +0 -29
  55. data/lib/rest-core/middleware/timeout/timer_em.rb +0 -26
  56. data/lib/rest-core/middleware/timeout/timer_thread.rb +0 -36
  57. data/task/.gitignore +0 -1
  58. data/test/test_em-http-request.rb +0 -186
@@ -1,19 +1,16 @@
1
1
 
2
- require 'fiber'
3
- require 'em-http-request'
4
2
  require 'rest-core'
5
3
 
6
- require 'rr'
7
4
  require 'webmock'
5
+ require 'muack'
8
6
  require 'bacon'
9
7
 
10
8
  # for testing lighten (serialization)
11
9
  require 'yaml'
12
10
 
13
- include RR::Adapters::RRMethods
14
- include WebMock::API
15
11
  WebMock.disable_net_connect!(:allow_localhost => true)
16
12
  Bacon.summary_on_exit
13
+ Bacon::Context.send(:include, Muack::API, WebMock::API)
17
14
 
18
15
  module Kernel
19
16
  def eq? rhs
@@ -34,41 +31,3 @@ module Kernel
34
31
  f.close!
35
32
  end
36
33
  end
37
-
38
- # https://github.com/bblimke/webmock/pull/280
39
- class ::EventMachine::WebMockHttpClient
40
- def build_request_signature
41
- headers, body = @req.headers, @req.body
42
-
43
- @conn.middleware.select {|m| m.respond_to?(:request) }.each do |m|
44
- headers, body = m.request(self, headers, body)
45
- end
46
-
47
- method = @req.method
48
- uri = @req.uri.clone
49
- auth = @req.headers[:'proxy-authorization']
50
- query = @req.query
51
-
52
- if auth
53
- userinfo = auth.join(':')
54
- userinfo = WebMock::Util::URI.encode_unsafe_chars_in_userinfo(userinfo)
55
- if @req
56
- @req.proxy.reject! {|k,v| t.to_s == 'authorization' }
57
- else
58
- options.reject! {|k,v| k.to_s == 'authorization' } #we added it to url userinfo
59
- end
60
- uri.userinfo = userinfo
61
- end
62
-
63
- uri.query = encode_query(@req.uri, query).slice(/\?(.*)/, 1)
64
-
65
- body = form_encode_body(body) if body.is_a?(Hash)
66
-
67
- WebMock::RequestSignature.new(
68
- method.downcase.to_sym,
69
- uri.to_s,
70
- :body => body || (@req.file && File.read(@req.file)),
71
- :headers => headers
72
- )
73
- end
74
- end
@@ -0,0 +1,122 @@
1
+
2
+ # reference implementation: puma
3
+ # https://github.com/puma/puma/blob/v2.7.1/lib/puma/thread_pool.rb
4
+
5
+ require 'thread'
6
+ require 'rest-core'
7
+
8
+ class RestCore::ThreadPool
9
+ include RestCore
10
+
11
+ class Queue
12
+ def initialize
13
+ @queue = []
14
+ @mutex = Mutex.new
15
+ @condv = ConditionVariable.new
16
+ end
17
+
18
+ def << task
19
+ mutex.synchronize do
20
+ queue << task
21
+ condv.signal
22
+ end
23
+ end
24
+
25
+ def pop timeout=60
26
+ mutex.synchronize do
27
+ if queue.empty?
28
+ condv.wait(mutex, timeout)
29
+ queue.shift || lambda{ false } # shutdown idle workers
30
+ else
31
+ queue.shift
32
+ end
33
+ end
34
+ end
35
+
36
+ def clear
37
+ queue.clear
38
+ end
39
+
40
+ protected
41
+ attr_reader :queue, :mutex, :condv
42
+ end
43
+
44
+ class Task < Struct.new(:job)
45
+ # this should never fail
46
+ def call
47
+ job.call unless cancelled
48
+ end
49
+
50
+ # called from the other thread telling us it's timed out
51
+ def cancel
52
+ @cancelled = true
53
+ end
54
+ protected
55
+ attr_reader :thread, :mutex, :cancelled
56
+ end
57
+
58
+ def self.[] client_class
59
+ (@pools ||= {})[client_class] ||= new(client_class)
60
+ end
61
+
62
+ attr_reader :client_class
63
+
64
+ def initialize client_class
65
+ @client_class = client_class
66
+ @queue = Queue.new
67
+ @mutex = Mutex.new
68
+ @workers = []
69
+ @waiting = 0
70
+ end
71
+
72
+ def inspect
73
+ "#<#{self.class.name} client_class=#{client_class}>"
74
+ end
75
+
76
+ def max_size
77
+ client_class.pool_size
78
+ end
79
+
80
+ def idle_time
81
+ client_class.pool_idle_time
82
+ end
83
+
84
+ def defer &job
85
+ mutex.synchronize do
86
+ task = Task.new(job)
87
+ queue << task
88
+ spawn_worker if waiting == 0 && workers.size < max_size
89
+ task
90
+ end
91
+ end
92
+
93
+ def trim force=false
94
+ queue << lambda{ false } if force || waiting > 0
95
+ end
96
+
97
+ # Block on shutting down, and should not add more jobs while shutting down
98
+ def shutdown
99
+ workers.size.times{ trim(true) }
100
+ workers.first.join && trim(true) until workers.empty?
101
+ queue.clear
102
+ end
103
+
104
+ protected
105
+ attr_reader :queue, :mutex, :condv, :workers, :waiting
106
+
107
+ private
108
+ def spawn_worker
109
+ workers << Thread.new{
110
+ Thread.current.abort_on_exception = !!$DEBUG
111
+
112
+ task = nil
113
+ begin
114
+ mutex.synchronize{ @waiting += 1 }
115
+ task = queue.pop(idle_time)
116
+ mutex.synchronize{ @waiting -= 1 }
117
+ end while task.call
118
+
119
+ mutex.synchronize{ workers.delete(Thread.current) }
120
+ }
121
+ end
122
+ end
@@ -0,0 +1,30 @@
1
+
2
+ require 'timers'
3
+
4
+ class RestCore::Timer
5
+ TimerGen = Timers.new
6
+
7
+ attr_accessor :timeout, :error
8
+ def initialize timeout, error, &block
9
+ self.timeout = timeout
10
+ self.error = error
11
+ self.block = block
12
+ start
13
+ end
14
+
15
+ def on_timeout &block
16
+ self.block = block
17
+ end
18
+
19
+ def cancel
20
+ timer.cancel
21
+ end
22
+
23
+ def start
24
+ return if timeout.nil? || timeout.zero?
25
+ self.timer = TimerGen.after(timeout){ block.call }
26
+ end
27
+
28
+ protected
29
+ attr_accessor :block, :timer
30
+ end
@@ -4,19 +4,11 @@ require 'openssl'
4
4
  module RestCore; end
5
5
  module RestCore::Hmac
6
6
  module_function
7
- # Fallback to ruby-hmac gem in case system openssl
8
- # lib doesn't support SHA256 (OSX 10.5)
9
7
  def sha256 key, data
10
8
  OpenSSL::HMAC.digest('sha256', key, data)
11
- rescue RuntimeError
12
- require 'hmac-sha2'
13
- HMAC::SHA256.digest(key, data)
14
9
  end
15
10
 
16
11
  def sha1 key, data
17
12
  OpenSSL::HMAC.digest('sha1', key, data)
18
- rescue RuntimeError
19
- require 'hmac-sha1'
20
- HMAC::SHA1.digest(key, data)
21
13
  end
22
14
  end
@@ -1,4 +1,4 @@
1
1
 
2
2
  module RestCore
3
- VERSION = '2.1.2'
3
+ VERSION = '3.0.0'
4
4
  end
@@ -24,10 +24,10 @@ module RestCore::Wrapper
24
24
  end
25
25
 
26
26
  def initialize &block
27
+ @engine = nil
27
28
  @middles ||= []
28
29
  instance_eval(&block) if block_given?
29
30
  @wrapped ||= to_app
30
- @engine = nil
31
31
  end
32
32
 
33
33
  def use middle, *args, &block
@@ -1,16 +1,16 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ # stub: rest-core 3.0.0 ruby lib
2
3
 
3
4
  Gem::Specification.new do |s|
4
5
  s.name = "rest-core"
5
- s.version = "2.1.2"
6
+ s.version = "3.0.0"
6
7
 
7
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = [
9
- "Cardinal Blue",
10
- "Lin Jen-Shin (godfat)"]
11
- s.date = "2013-05-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
- s.email = ["dev (XD) cardinalblue.com"]
9
+ s.require_paths = ["lib"]
10
+ s.authors = ["Lin Jen-Shin (godfat)"]
11
+ s.date = "2014-05-04"
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/godfat/rest-more"
13
+ s.email = ["godfat (XD) godfat.org"]
14
14
  s.files = [
15
15
  ".gitignore",
16
16
  ".gitmodules",
@@ -22,7 +22,6 @@ Gem::Specification.new do |s|
22
22
  "README.md",
23
23
  "Rakefile",
24
24
  "TODO.md",
25
- "example/multi.rb",
26
25
  "example/simple.rb",
27
26
  "example/use-cases.rb",
28
27
  "lib/rest-core.rb",
@@ -31,15 +30,14 @@ Gem::Specification.new do |s|
31
30
  "lib/rest-core/client/simple.rb",
32
31
  "lib/rest-core/client/universal.rb",
33
32
  "lib/rest-core/client_oauth1.rb",
34
- "lib/rest-core/engine/auto.rb",
33
+ "lib/rest-core/engine.rb",
35
34
  "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",
35
+ "lib/rest-core/engine/http-client.rb",
36
+ "lib/rest-core/engine/net-http-persistent.rb",
40
37
  "lib/rest-core/engine/rest-client.rb",
41
38
  "lib/rest-core/error.rb",
42
39
  "lib/rest-core/event.rb",
40
+ "lib/rest-core/event_source.rb",
43
41
  "lib/rest-core/middleware.rb",
44
42
  "lib/rest-core/middleware/auth_basic.rb",
45
43
  "lib/rest-core/middleware/bypass.rb",
@@ -60,11 +58,12 @@ Gem::Specification.new do |s|
60
58
  "lib/rest-core/middleware/oauth2_header.rb",
61
59
  "lib/rest-core/middleware/oauth2_query.rb",
62
60
  "lib/rest-core/middleware/timeout.rb",
63
- "lib/rest-core/middleware/timeout/timer_em.rb",
64
- "lib/rest-core/middleware/timeout/timer_thread.rb",
65
61
  "lib/rest-core/patch/multi_json.rb",
66
62
  "lib/rest-core/patch/rest-client.rb",
63
+ "lib/rest-core/promise.rb",
67
64
  "lib/rest-core/test.rb",
65
+ "lib/rest-core/thread_pool.rb",
66
+ "lib/rest-core/timer.rb",
68
67
  "lib/rest-core/util/hmac.rb",
69
68
  "lib/rest-core/util/json.rb",
70
69
  "lib/rest-core/util/parse_query.rb",
@@ -72,7 +71,7 @@ Gem::Specification.new do |s|
72
71
  "lib/rest-core/version.rb",
73
72
  "lib/rest-core/wrapper.rb",
74
73
  "rest-core.gemspec",
75
- "task/.gitignore",
74
+ "task/README.md",
76
75
  "task/gemgem.rb",
77
76
  "test/test_auth_basic.rb",
78
77
  "test/test_builder.rb",
@@ -81,25 +80,27 @@ Gem::Specification.new do |s|
81
80
  "test/test_client_oauth1.rb",
82
81
  "test/test_default_payload.rb",
83
82
  "test/test_default_query.rb",
84
- "test/test_em-http-request.rb",
85
83
  "test/test_error_detector.rb",
86
84
  "test/test_error_detector_http.rb",
87
85
  "test/test_error_handler.rb",
86
+ "test/test_event_source.rb",
88
87
  "test/test_follow_redirect.rb",
88
+ "test/test_future.rb",
89
89
  "test/test_json_request.rb",
90
90
  "test/test_json_response.rb",
91
91
  "test/test_oauth1_header.rb",
92
+ "test/test_oauth2_header.rb",
92
93
  "test/test_payload.rb",
94
+ "test/test_promise.rb",
93
95
  "test/test_rest-client.rb",
94
96
  "test/test_simple.rb",
97
+ "test/test_thread_pool.rb",
95
98
  "test/test_timeout.rb",
96
99
  "test/test_universal.rb",
97
100
  "test/test_wrapper.rb"]
98
- s.homepage = "https://github.com/cardinalblue/rest-core"
101
+ s.homepage = "https://github.com/godfat/rest-core"
99
102
  s.licenses = ["Apache License 2.0"]
100
- s.post_install_message = "# [rest-core] Since 2.1.0, Incompatible changes for POST requests:\n\n* We no longer support Rails-like POST payload, like translating\n `{:foo => [1, 2]}` to `'foo[]=1&foo[]=2'`. It would now be translated to\n `'foo=1&foo=2'`. If you like `'foo[]'` as the key, simply pass it as\n `{'foo[]' => [1, 2]}`.\n\n* This also applies to nested hashes like `{:foo => {:bar => 1}`. If you\n want that behaviour, just pass `{'foo[bar]' => 1}` which would then be\n translated to `'foo[bar]=1'`.\n"
101
- s.require_paths = ["lib"]
102
- s.rubygems_version = "2.0.3"
103
+ s.rubygems_version = "2.2.2"
103
104
  s.summary = "Modular Ruby clients interface for REST APIs."
104
105
  s.test_files = [
105
106
  "test/test_auth_basic.rb",
@@ -109,17 +110,21 @@ Gem::Specification.new do |s|
109
110
  "test/test_client_oauth1.rb",
110
111
  "test/test_default_payload.rb",
111
112
  "test/test_default_query.rb",
112
- "test/test_em-http-request.rb",
113
113
  "test/test_error_detector.rb",
114
114
  "test/test_error_detector_http.rb",
115
115
  "test/test_error_handler.rb",
116
+ "test/test_event_source.rb",
116
117
  "test/test_follow_redirect.rb",
118
+ "test/test_future.rb",
117
119
  "test/test_json_request.rb",
118
120
  "test/test_json_response.rb",
119
121
  "test/test_oauth1_header.rb",
122
+ "test/test_oauth2_header.rb",
120
123
  "test/test_payload.rb",
124
+ "test/test_promise.rb",
121
125
  "test/test_rest-client.rb",
122
126
  "test/test_simple.rb",
127
+ "test/test_thread_pool.rb",
123
128
  "test/test_timeout.rb",
124
129
  "test/test_universal.rb",
125
130
  "test/test_wrapper.rb"]
@@ -128,11 +133,17 @@ Gem::Specification.new do |s|
128
133
  s.specification_version = 4
129
134
 
130
135
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
131
- s.add_runtime_dependency(%q<rest-client>, [">= 0"])
136
+ s.add_runtime_dependency(%q<httpclient>, [">= 0"])
137
+ s.add_runtime_dependency(%q<mime-types>, [">= 0"])
138
+ s.add_runtime_dependency(%q<timers>, [">= 0"])
132
139
  else
133
- s.add_dependency(%q<rest-client>, [">= 0"])
140
+ s.add_dependency(%q<httpclient>, [">= 0"])
141
+ s.add_dependency(%q<mime-types>, [">= 0"])
142
+ s.add_dependency(%q<timers>, [">= 0"])
134
143
  end
135
144
  else
136
- s.add_dependency(%q<rest-client>, [">= 0"])
145
+ s.add_dependency(%q<httpclient>, [">= 0"])
146
+ s.add_dependency(%q<mime-types>, [">= 0"])
147
+ s.add_dependency(%q<timers>, [">= 0"])
137
148
  end
138
149
  end
@@ -0,0 +1,54 @@
1
+ # Gemgem
2
+
3
+ ## DESCRIPTION:
4
+
5
+ Provided tasks:
6
+
7
+ rake clean # Remove ignored files
8
+ rake gem:build # Build gem
9
+ rake gem:install # Install gem
10
+ rake gem:release # Release gem
11
+ rake gem:spec # Generate gemspec
12
+ rake test # Run tests in memory
13
+
14
+ ## REQUIREMENTS:
15
+
16
+ * Tested with MRI (official CRuby) 1.9.3, 2.0.0, Rubinius and JRuby.
17
+
18
+ ## INSTALLATION:
19
+
20
+ git submodule add git://github.com/godfat/gemgem.git task
21
+
22
+ And in Rakefile:
23
+
24
+ ``` ruby
25
+ begin
26
+ require "#{dir = File.dirname(__FILE__)}/task/gemgem"
27
+ rescue LoadError
28
+ sh 'git submodule update --init'
29
+ exec Gem.ruby, '-S', $PROGRAM_NAME, *ARGV
30
+ end
31
+
32
+ Gemgem.init(dir) do |s|
33
+ s.name = 'your-gem'
34
+ s.version = '0.1.0'
35
+ end
36
+ ```
37
+
38
+ ## LICENSE:
39
+
40
+ Apache License 2.0
41
+
42
+ Copyright (c) 2011-2013, Lin Jen-Shin (godfat)
43
+
44
+ Licensed under the Apache License, Version 2.0 (the "License");
45
+ you may not use this file except in compliance with the License.
46
+ You may obtain a copy of the License at
47
+
48
+ <http://www.apache.org/licenses/LICENSE-2.0>
49
+
50
+ Unless required by applicable law or agreed to in writing, software
51
+ distributed under the License is distributed on an "AS IS" BASIS,
52
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
53
+ See the License for the specific language governing permissions and
54
+ limitations under the License.