rest-core 2.1.2 → 3.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 (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.