restify 1.0.1.beta1 → 1.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/lib/restify.rb +3 -1
- data/lib/restify/adapter/base.rb +4 -2
- data/lib/restify/adapter/em.rb +12 -4
- data/lib/restify/adapter/typhoeus.rb +4 -1
- data/lib/restify/cache.rb +6 -4
- data/lib/restify/context.rb +13 -5
- data/lib/restify/error.rb +5 -1
- data/lib/restify/global.rb +2 -2
- data/lib/restify/link.rb +2 -0
- data/lib/restify/processors/base.rb +9 -8
- data/lib/restify/processors/json.rb +27 -20
- data/lib/restify/promise.rb +23 -27
- data/lib/restify/registry.rb +2 -0
- data/lib/restify/relation.rb +2 -1
- data/lib/restify/request.rb +2 -0
- data/lib/restify/resource.rb +12 -14
- data/lib/restify/response.rb +6 -3
- data/lib/restify/version.rb +5 -3
- data/spec/restify/cache_spec.rb +2 -0
- data/spec/restify/global_spec.rb +2 -0
- data/spec/restify/link_spec.rb +2 -0
- data/spec/restify/processors/base_spec.rb +44 -0
- data/spec/restify/processors/json_spec.rb +31 -20
- data/spec/restify/promise_spec.rb +165 -0
- data/spec/restify/registry_spec.rb +2 -0
- data/spec/restify/relation_spec.rb +2 -1
- data/spec/restify/resource_spec.rb +2 -0
- data/spec/restify_spec.rb +2 -0
- data/spec/spec_helper.rb +17 -13
- metadata +9 -6
- data/restify.gemspec +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3acb2cc3581b8c3c47ad27c6ab1ea34406d7fa39
|
4
|
+
data.tar.gz: 91e4eb0b80116b6e13d8aca4cf8942de6ef064bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e314678c3419674b6a709db0ba224bd46b704ba24455db084dba0f7e9dfccaf4c633243e384411d1fd7046a0c34480f19353a2313190c70ed62599eb50d04a3a
|
7
|
+
data.tar.gz: 8378f0c684c143cab5c92b4799a1424370f3b0db6395296d7b4bf38b3b8c48e08274035dfcd770f8ecc52308e9b80d74247628e125635f477f2fcec7436ba670
|
data/CHANGELOG.md
CHANGED
data/lib/restify.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'restify/version'
|
2
4
|
|
3
5
|
require 'hashie'
|
@@ -30,7 +32,7 @@ module Restify
|
|
30
32
|
require 'restify/processors/json'
|
31
33
|
end
|
32
34
|
|
33
|
-
PROCESSORS = [Processors::Json]
|
35
|
+
PROCESSORS = [Processors::Json].freeze
|
34
36
|
|
35
37
|
extend Global
|
36
38
|
end
|
data/lib/restify/adapter/base.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Restify
|
2
4
|
module Adapter
|
3
5
|
class Base
|
@@ -7,8 +9,8 @@ module Restify
|
|
7
9
|
end
|
8
10
|
end
|
9
11
|
|
10
|
-
def call_native(
|
11
|
-
throw NotImplementedError.new '
|
12
|
+
def call_native(_request, _writer)
|
13
|
+
throw NotImplementedError.new 'Subclass responsibility'
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
data/lib/restify/adapter/em.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'eventmachine'
|
2
4
|
require 'em-http-request'
|
3
5
|
|
@@ -26,6 +28,7 @@ module Restify
|
|
26
28
|
@requests ||= []
|
27
29
|
end
|
28
30
|
|
31
|
+
# rubocop:disable Style/IdenticalConditionalBranches
|
29
32
|
def call(request, writer, retried = false)
|
30
33
|
if requests.empty?
|
31
34
|
requests << [request, writer, retried]
|
@@ -43,6 +46,10 @@ module Restify
|
|
43
46
|
@pipeline
|
44
47
|
end
|
45
48
|
|
49
|
+
# rubocop:disable Metrics/AbcSize
|
50
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
51
|
+
# rubocop:disable Metrics/MethodLength
|
52
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
46
53
|
def process_next
|
47
54
|
return if requests.empty?
|
48
55
|
|
@@ -55,7 +62,7 @@ module Restify
|
|
55
62
|
query: request.uri.normalized_query,
|
56
63
|
body: request.body,
|
57
64
|
head: request.headers
|
58
|
-
rescue Exception => err
|
65
|
+
rescue Exception => err # rubocop:disable RescueException
|
59
66
|
writer.reject err
|
60
67
|
requests.shift unless pipeline?
|
61
68
|
return
|
@@ -93,8 +100,7 @@ module Restify
|
|
93
100
|
EventMachine.next_tick { call request, writer }
|
94
101
|
else
|
95
102
|
begin
|
96
|
-
raise
|
97
|
-
"(#{req.response_header.status}) #{req.error}"
|
103
|
+
raise "(#{req.response_header.status}) #{req.error}"
|
98
104
|
rescue => e
|
99
105
|
writer.reject e
|
100
106
|
end
|
@@ -117,6 +123,8 @@ module Restify
|
|
117
123
|
end
|
118
124
|
|
119
125
|
def ensure_running
|
126
|
+
return if EventMachine.reactor_running?
|
127
|
+
|
120
128
|
Thread.new do
|
121
129
|
begin
|
122
130
|
EventMachine.run {}
|
@@ -124,7 +132,7 @@ module Restify
|
|
124
132
|
puts "#{self.class} -> #{e}\n#{e.backtrace.join("\n")}"
|
125
133
|
raise e
|
126
134
|
end
|
127
|
-
end
|
135
|
+
end
|
128
136
|
end
|
129
137
|
end
|
130
138
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'typhoeus'
|
2
4
|
|
3
5
|
module Restify
|
@@ -51,7 +53,7 @@ module Restify
|
|
51
53
|
def handle(native_response, writer, request)
|
52
54
|
writer.fulfill convert_back(native_response, request)
|
53
55
|
|
54
|
-
@hydra.queue convert(*@queue.pop(true))
|
56
|
+
@hydra.queue convert(*@queue.pop(true)) until @queue.empty?
|
55
57
|
end
|
56
58
|
|
57
59
|
def convert_back(response, request)
|
@@ -69,6 +71,7 @@ module Restify
|
|
69
71
|
end
|
70
72
|
end
|
71
73
|
|
74
|
+
# rubocop:disable Metrics/MethodLength
|
72
75
|
def start
|
73
76
|
Thread.new do
|
74
77
|
loop do
|
data/lib/restify/cache.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Restify
|
2
4
|
class Cache
|
3
5
|
def initialize(store)
|
@@ -9,15 +11,15 @@ module Restify
|
|
9
11
|
return response
|
10
12
|
end
|
11
13
|
|
12
|
-
yield(request).then do |
|
13
|
-
cache(
|
14
|
-
|
14
|
+
yield(request).then do |new_response|
|
15
|
+
cache(new_response)
|
16
|
+
new_response
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
20
|
private
|
19
21
|
|
20
|
-
def match(
|
22
|
+
def match(_request)
|
21
23
|
false
|
22
24
|
end
|
23
25
|
|
data/lib/restify/context.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Restify
|
2
4
|
# A resource context.
|
3
5
|
#
|
@@ -19,7 +21,12 @@ module Restify
|
|
19
21
|
attr_reader :options
|
20
22
|
|
21
23
|
def initialize(uri, **kwargs)
|
22
|
-
@uri
|
24
|
+
@uri = if uri.is_a?(Addressable::URI)
|
25
|
+
uri
|
26
|
+
else
|
27
|
+
@uri = Addressable::URI.parse(uri.to_s)
|
28
|
+
end
|
29
|
+
|
23
30
|
@options = kwargs
|
24
31
|
end
|
25
32
|
|
@@ -34,20 +41,21 @@ module Restify
|
|
34
41
|
|
35
42
|
def process(response)
|
36
43
|
context = inherit response.uri
|
37
|
-
processor = Restify::PROCESSORS.find {
|
44
|
+
processor = Restify::PROCESSORS.find {|p| p.accept? response }
|
38
45
|
processor ||= Restify::Processors::Base
|
39
46
|
|
40
47
|
processor.new(context, response).resource
|
41
48
|
end
|
42
49
|
|
43
|
-
|
50
|
+
# rubocop:disable Metrics/MethodLength
|
51
|
+
def request(method, uri, data = nil, _opts = {})
|
44
52
|
request = Request.new \
|
45
53
|
method: method,
|
46
54
|
uri: join(uri),
|
47
55
|
data: data,
|
48
56
|
headers: options.fetch(:headers, {})
|
49
57
|
|
50
|
-
ret = cache.call(request) {|
|
58
|
+
ret = cache.call(request) {|req| adapter.call(req) }
|
51
59
|
ret.then do |response|
|
52
60
|
if response.success?
|
53
61
|
process response
|
@@ -75,7 +83,7 @@ module Restify
|
|
75
83
|
when 500...600
|
76
84
|
raise ServerError.new(response)
|
77
85
|
else
|
78
|
-
raise
|
86
|
+
raise "Unknown response code: #{response.code}"
|
79
87
|
end
|
80
88
|
end
|
81
89
|
end
|
data/lib/restify/error.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Restify
|
2
4
|
#
|
3
5
|
# A {ResponseError} is returned on a non-successful
|
@@ -36,7 +38,9 @@ module Restify
|
|
36
38
|
#
|
37
39
|
def errors
|
38
40
|
if response.decoded_body
|
39
|
-
response.decoded_body['errors'] ||
|
41
|
+
response.decoded_body['errors'] ||
|
42
|
+
response.decoded_body[:errors] ||
|
43
|
+
response.decoded_body
|
40
44
|
else
|
41
45
|
response.body
|
42
46
|
end
|
data/lib/restify/global.rb
CHANGED
data/lib/restify/link.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Restify
|
2
4
|
#
|
3
5
|
module Processors
|
@@ -36,7 +38,7 @@ module Restify
|
|
36
38
|
# Should be overridden in subclass.
|
37
39
|
#
|
38
40
|
def load
|
39
|
-
|
41
|
+
body
|
40
42
|
end
|
41
43
|
|
42
44
|
# @!method body
|
@@ -50,18 +52,17 @@ module Restify
|
|
50
52
|
name = link.metadata['rel']
|
51
53
|
value = link.uri
|
52
54
|
|
53
|
-
if !name.empty? && !relations.key?(name)
|
54
|
-
relations[name] = value
|
55
|
-
end
|
55
|
+
relations[name] = value if !name.empty? && !relations.key?(name)
|
56
56
|
end
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
location = @response.follow_location
|
59
|
+
return unless location
|
60
|
+
|
61
|
+
relations[:_restify_follow] = location
|
61
62
|
end
|
62
63
|
|
63
64
|
class << self
|
64
|
-
def accept?(
|
65
|
+
def accept?(_response)
|
65
66
|
false
|
66
67
|
end
|
67
68
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'json'
|
2
4
|
|
3
5
|
module Restify
|
@@ -9,13 +11,13 @@ module Restify
|
|
9
11
|
# JSON fields matching *_url will be parsed as relations.
|
10
12
|
#
|
11
13
|
class Json < Base
|
12
|
-
|
13
14
|
def load
|
14
|
-
parse ::JSON.
|
15
|
+
parse ::JSON.parse(body), root: true
|
15
16
|
end
|
16
17
|
|
17
18
|
private
|
18
19
|
|
20
|
+
# rubocop:disable Metrics/MethodLength
|
19
21
|
def parse(object, root: false)
|
20
22
|
case object
|
21
23
|
when Hash
|
@@ -27,9 +29,14 @@ module Restify
|
|
27
29
|
end
|
28
30
|
|
29
31
|
if root
|
30
|
-
Resource.new context,
|
32
|
+
Resource.new context,
|
33
|
+
data: data,
|
34
|
+
response: response,
|
35
|
+
relations: relations
|
31
36
|
else
|
32
|
-
Resource.new context,
|
37
|
+
Resource.new context,
|
38
|
+
data: data,
|
39
|
+
relations: relations
|
33
40
|
end
|
34
41
|
when Array
|
35
42
|
object.map(&method(:parse))
|
@@ -44,21 +51,23 @@ module Restify
|
|
44
51
|
|
45
52
|
def parse_rels(pair, relations)
|
46
53
|
name = case pair[0].to_s.downcase
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
when /\A(\w+)_url\z/
|
55
|
+
Regexp.last_match[1]
|
56
|
+
when 'url'
|
57
|
+
'self'
|
58
|
+
else
|
59
|
+
return
|
60
|
+
end
|
61
|
+
|
62
|
+
if relations.key?(name) || pair[1].nil? || pair[1].to_s =~ /\A\w*\z/
|
63
|
+
return
|
53
64
|
end
|
54
65
|
|
55
|
-
return if relations.key?(name) || pair[1].nil? || pair[1].to_s =~ /\A\w*\z/
|
56
|
-
|
57
66
|
relations[name] = pair[1].to_s
|
58
67
|
end
|
59
68
|
|
60
69
|
def json
|
61
|
-
@json ||= JSON.
|
70
|
+
@json ||= JSON.parse(response.body)
|
62
71
|
end
|
63
72
|
|
64
73
|
def with_indifferent_access(data)
|
@@ -67,19 +76,17 @@ module Restify
|
|
67
76
|
|
68
77
|
class << self
|
69
78
|
def accept?(response)
|
70
|
-
response.content_type =~
|
79
|
+
response.content_type =~ %r{\Aapplication/json($|;)}
|
71
80
|
end
|
72
81
|
|
73
82
|
def indifferent_access?
|
74
|
-
|
83
|
+
@indifferent_access
|
75
84
|
end
|
76
85
|
|
77
|
-
|
78
|
-
@@indifferent_access = value
|
79
|
-
end
|
80
|
-
|
81
|
-
@@indifferent_access = true
|
86
|
+
attr_writer :indifferent_access
|
82
87
|
end
|
88
|
+
|
89
|
+
self.indifferent_access = true
|
83
90
|
end
|
84
91
|
end
|
85
92
|
end
|
data/lib/restify/promise.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Restify
|
2
4
|
#
|
3
5
|
class Promise < Concurrent::IVar
|
@@ -10,22 +12,7 @@ module Restify
|
|
10
12
|
|
11
13
|
def wait(timeout = nil)
|
12
14
|
execute if pending?
|
13
|
-
|
14
|
-
# if defined?(EventMachine)
|
15
|
-
# if incomplete?
|
16
|
-
# fiber = Fiber.current
|
17
|
-
|
18
|
-
# self.add_observer do
|
19
|
-
# EventMachine.next_tick { fiber.resume }
|
20
|
-
# end
|
21
|
-
|
22
|
-
# Fiber.yield
|
23
|
-
# else
|
24
|
-
# self
|
25
|
-
# end
|
26
|
-
# else
|
27
|
-
super
|
28
|
-
# end
|
15
|
+
super
|
29
16
|
end
|
30
17
|
|
31
18
|
def then(&block)
|
@@ -39,17 +26,16 @@ module Restify
|
|
39
26
|
protected
|
40
27
|
|
41
28
|
# @!visibility private
|
42
|
-
def ns_execute(
|
43
|
-
|
44
|
-
|
29
|
+
def ns_execute(_timeout)
|
30
|
+
return unless compare_and_set_state(:processing, :pending)
|
31
|
+
return unless @task || @dependencies.any?
|
45
32
|
|
46
|
-
|
47
|
-
|
33
|
+
executor = Concurrent::SafeTaskExecutor.new \
|
34
|
+
method(:ns_exec), rescue_exception: true
|
48
35
|
|
49
|
-
|
36
|
+
success, value, reason = executor.execute
|
50
37
|
|
51
|
-
|
52
|
-
end
|
38
|
+
complete success, value, reason
|
53
39
|
end
|
54
40
|
|
55
41
|
# @!visibility private
|
@@ -57,9 +43,7 @@ module Restify
|
|
57
43
|
args = @dependencies.any? ? @dependencies.map(&:value!) : []
|
58
44
|
value = @task ? @task.call(*args) : args
|
59
45
|
|
60
|
-
while value.is_a? Restify::Promise
|
61
|
-
value = value.value!
|
62
|
-
end
|
46
|
+
value = value.value! while value.is_a? Restify::Promise
|
63
47
|
|
64
48
|
value
|
65
49
|
end
|
@@ -70,6 +54,18 @@ module Restify
|
|
70
54
|
yield Writer.new(promise)
|
71
55
|
promise
|
72
56
|
end
|
57
|
+
|
58
|
+
def fulfilled(value)
|
59
|
+
create do |writer|
|
60
|
+
writer.fulfill value
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def rejected(value)
|
65
|
+
create do |writer|
|
66
|
+
writer.reject value
|
67
|
+
end
|
68
|
+
end
|
73
69
|
end
|
74
70
|
|
75
71
|
class Writer
|
data/lib/restify/registry.rb
CHANGED
data/lib/restify/relation.rb
CHANGED
data/lib/restify/request.rb
CHANGED
data/lib/restify/resource.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'delegate'
|
2
4
|
|
3
5
|
module Restify
|
4
6
|
#
|
5
7
|
class Resource < SimpleDelegator
|
6
|
-
|
7
8
|
# @api private
|
8
9
|
#
|
9
10
|
def initialize(context, response: nil, data: nil, relations: {})
|
@@ -23,9 +24,9 @@ module Restify
|
|
23
24
|
@relations.key?(name) || @relations.key?(name.to_s)
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
alias rel? relation?
|
28
|
+
alias has_rel? relation?
|
29
|
+
alias has_relation? relation?
|
29
30
|
|
30
31
|
# Return relation with given name.
|
31
32
|
#
|
@@ -40,7 +41,7 @@ module Restify
|
|
40
41
|
end
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
+
alias rel relation
|
44
45
|
|
45
46
|
# @!method data
|
46
47
|
#
|
@@ -64,11 +65,7 @@ module Restify
|
|
64
65
|
# @return [Relation] Relation to follow resource or nil.
|
65
66
|
#
|
66
67
|
def follow
|
67
|
-
if relation? :_restify_follow
|
68
|
-
relation :_restify_follow
|
69
|
-
else
|
70
|
-
nil
|
71
|
-
end
|
68
|
+
relation :_restify_follow if relation? :_restify_follow
|
72
69
|
end
|
73
70
|
|
74
71
|
# Follow a LOCATION or CONTEXT-LOCATION header.
|
@@ -76,11 +73,12 @@ module Restify
|
|
76
73
|
# @return [Relation] Relation to follow resource.
|
77
74
|
# @raise RuntimeError If nothing to follow.
|
78
75
|
#
|
76
|
+
# rubocop:disable Style/GuardClause
|
79
77
|
def follow!
|
80
78
|
if (rel = follow)
|
81
79
|
rel
|
82
80
|
else
|
83
|
-
raise
|
81
|
+
raise 'Nothing to follow'
|
84
82
|
end
|
85
83
|
end
|
86
84
|
|
@@ -97,9 +95,9 @@ module Restify
|
|
97
95
|
# @api private
|
98
96
|
def inspect
|
99
97
|
text = {
|
100
|
-
|
101
|
-
|
102
|
-
}.map {|k,v
|
98
|
+
'@data' => data,
|
99
|
+
'@relations' => @relations
|
100
|
+
}.map {|k, v| k + '=' + v.inspect }.join(' ')
|
103
101
|
|
104
102
|
"#<#{self.class} #{text}>"
|
105
103
|
end
|
data/lib/restify/response.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/utils'
|
2
4
|
require 'json'
|
3
5
|
|
@@ -87,6 +89,7 @@ module Restify
|
|
87
89
|
#
|
88
90
|
# @return [Array<Link>] Links.
|
89
91
|
#
|
92
|
+
# rubocop:disable Metrics/MethodLength
|
90
93
|
def links
|
91
94
|
@links ||= begin
|
92
95
|
if headers['LINK']
|
@@ -116,15 +119,15 @@ module Restify
|
|
116
119
|
# @return [Boolean] True if status code is 2XX otherwise false.
|
117
120
|
#
|
118
121
|
def success?
|
119
|
-
(200...300).
|
122
|
+
(200...300).cover? code
|
120
123
|
end
|
121
124
|
|
122
125
|
# @api private
|
123
126
|
def decoded_body
|
124
127
|
@decoded_body ||= begin
|
125
128
|
case content_type
|
126
|
-
when
|
127
|
-
JSON.
|
129
|
+
when %r{\Aapplication/json($|;)}
|
130
|
+
::JSON.parse(body)
|
128
131
|
end
|
129
132
|
end
|
130
133
|
end
|
data/lib/restify/version.rb
CHANGED
data/spec/restify/cache_spec.rb
CHANGED
data/spec/restify/global_spec.rb
CHANGED
data/spec/restify/link_spec.rb
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Restify::Processors::Base do
|
6
|
+
let(:context) { Restify::Context.new('http://test.host/') }
|
7
|
+
let(:response) { double 'response' }
|
8
|
+
|
9
|
+
before do
|
10
|
+
allow(response).to receive(:links).and_return []
|
11
|
+
allow(response).to receive(:follow_location).and_return nil
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'class' do
|
15
|
+
describe '#accept?' do
|
16
|
+
subject { described_class.accept? response }
|
17
|
+
|
18
|
+
# If no other processor accepts the request, we have an explicit fallback
|
19
|
+
# to the base processor.
|
20
|
+
it 'does not accept any responses' do
|
21
|
+
expect(subject).to be_falsey
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#resource' do
|
27
|
+
subject { described_class.new(context, response).resource }
|
28
|
+
before { allow(response).to receive(:body).and_return(body) }
|
29
|
+
|
30
|
+
describe 'parsing' do
|
31
|
+
context 'string' do
|
32
|
+
let(:body) do
|
33
|
+
<<-BODY
|
34
|
+
binaryblob
|
35
|
+
BODY
|
36
|
+
end
|
37
|
+
|
38
|
+
it { is_expected.to be_a Restify::Resource }
|
39
|
+
it { expect(subject.response).to be response }
|
40
|
+
it { is_expected.to eq body }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Restify::Processors::Json do
|
@@ -29,27 +31,29 @@ describe Restify::Processors::Json do
|
|
29
31
|
subject { described_class.new(context, response).resource }
|
30
32
|
before { allow(response).to receive(:body).and_return(body) }
|
31
33
|
|
32
|
-
|
34
|
+
describe 'parsing' do
|
33
35
|
context 'single object' do
|
34
|
-
let(:body) do
|
35
|
-
|
36
|
+
let(:body) do
|
37
|
+
<<-JSON
|
38
|
+
{"json": "value"}
|
36
39
|
JSON
|
37
40
|
end
|
38
41
|
|
39
42
|
it { is_expected.to be_a Restify::Resource }
|
40
43
|
it { expect(subject.response).to be response }
|
41
|
-
it { is_expected.to eq '
|
44
|
+
it { is_expected.to eq 'json' => 'value' }
|
42
45
|
end
|
43
46
|
|
44
47
|
context 'object with relation fields' do
|
45
|
-
let(:body) do
|
46
|
-
|
48
|
+
let(:body) do
|
49
|
+
<<-JSON
|
50
|
+
{"json": "value", "search_url": "https://google.com{?q}"}
|
47
51
|
JSON
|
48
52
|
end
|
49
53
|
|
50
54
|
it do
|
51
55
|
is_expected.to eq \
|
52
|
-
'
|
56
|
+
'json' => 'value', 'search_url' => 'https://google.com{?q}'
|
53
57
|
end
|
54
58
|
|
55
59
|
it { is_expected.to have_relation :search }
|
@@ -57,8 +61,9 @@ describe Restify::Processors::Json do
|
|
57
61
|
end
|
58
62
|
|
59
63
|
context 'object with implicit self relation' do
|
60
|
-
let(:body) do
|
61
|
-
|
64
|
+
let(:body) do
|
65
|
+
<<-JSON
|
66
|
+
{"json": "value", "url": "/self"}
|
62
67
|
JSON
|
63
68
|
end
|
64
69
|
|
@@ -66,18 +71,20 @@ describe Restify::Processors::Json do
|
|
66
71
|
end
|
67
72
|
|
68
73
|
context 'single array' do
|
69
|
-
let(:body) do
|
74
|
+
let(:body) do
|
75
|
+
<<-JSON
|
70
76
|
[1, 2, null, "STR"]
|
71
77
|
JSON
|
72
78
|
end
|
73
79
|
|
74
80
|
it { is_expected.to be_a Restify::Resource }
|
75
81
|
it { expect(subject.response).to be response }
|
76
|
-
it { is_expected.to eq [1, 2, nil,
|
82
|
+
it { is_expected.to eq [1, 2, nil, 'STR'] }
|
77
83
|
end
|
78
84
|
|
79
85
|
context 'array with objects' do
|
80
|
-
let(:body) do
|
86
|
+
let(:body) do
|
87
|
+
<<-JSON
|
81
88
|
[{"a":0}, {"b":1}]
|
82
89
|
JSON
|
83
90
|
end
|
@@ -86,15 +93,15 @@ describe Restify::Processors::Json do
|
|
86
93
|
end
|
87
94
|
|
88
95
|
context 'array with resources' do
|
89
|
-
let(:body) do
|
96
|
+
let(:body) do
|
97
|
+
<<-JSON
|
90
98
|
[{"name": "John", "self_url": "/users/john"},
|
91
99
|
{"name": "Jane", "self_url": "/users/jane"}]
|
92
100
|
JSON
|
93
101
|
end
|
94
102
|
|
95
103
|
it 'parses objects as resources' do
|
96
|
-
expect(subject.
|
97
|
-
[Restify::Resource, Restify::Resource]
|
104
|
+
expect(subject).to all(be_a(Restify::Resource))
|
98
105
|
end
|
99
106
|
|
100
107
|
it 'parses relations of resources' do
|
@@ -104,7 +111,8 @@ describe Restify::Processors::Json do
|
|
104
111
|
end
|
105
112
|
|
106
113
|
context 'nested objects' do
|
107
|
-
let(:body) do
|
114
|
+
let(:body) do
|
115
|
+
<<-JSON
|
108
116
|
{"john": {"name": "John"},
|
109
117
|
"jane": {"name": "Jane"}}
|
110
118
|
JSON
|
@@ -123,18 +131,20 @@ describe Restify::Processors::Json do
|
|
123
131
|
end
|
124
132
|
|
125
133
|
context 'single value' do
|
126
|
-
let(:body) do
|
134
|
+
let(:body) do
|
135
|
+
<<-JSON
|
127
136
|
"BLUB"
|
128
137
|
JSON
|
129
138
|
end
|
130
139
|
|
131
140
|
it { is_expected.to be_a Restify::Resource }
|
132
141
|
it { expect(subject.response).to be response }
|
133
|
-
it { is_expected.to eq
|
142
|
+
it { is_expected.to eq 'BLUB' }
|
134
143
|
end
|
135
144
|
|
136
145
|
context 'with indifferent access' do
|
137
|
-
let(:body) do
|
146
|
+
let(:body) do
|
147
|
+
<<-JSON
|
138
148
|
{"name": "John", "age": 24}
|
139
149
|
JSON
|
140
150
|
end
|
@@ -157,7 +167,8 @@ describe Restify::Processors::Json do
|
|
157
167
|
end
|
158
168
|
|
159
169
|
context 'with method getter access' do
|
160
|
-
let(:body) do
|
170
|
+
let(:body) do
|
171
|
+
<<-JSON
|
161
172
|
{"name": "John", "age": 24}
|
162
173
|
JSON
|
163
174
|
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Restify::Promise do
|
6
|
+
describe 'factory methods' do
|
7
|
+
describe '#fulfilled' do
|
8
|
+
subject { described_class.fulfilled(fulfill_value) }
|
9
|
+
let(:fulfill_value) { 42 }
|
10
|
+
|
11
|
+
it 'returns a fulfilled promise' do
|
12
|
+
expect(subject.fulfilled?).to be true
|
13
|
+
expect(subject.rejected?).to be false
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'wraps the given value' do
|
17
|
+
expect(subject.value!).to eq 42
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#rejected' do
|
22
|
+
subject { described_class.rejected(rejection_reason) }
|
23
|
+
let(:rejection_reason) { ArgumentError }
|
24
|
+
|
25
|
+
it 'returns a rejected promise' do
|
26
|
+
expect(subject.fulfilled?).to be false
|
27
|
+
expect(subject.rejected?).to be true
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'bubbles up the caught exception on #value!' do
|
31
|
+
expect { subject.value! }.to raise_error(ArgumentError)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'swallows the exception on #value' do
|
35
|
+
expect(subject.value).to be nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#create' do
|
40
|
+
context 'when fulfilling the promise in the writer block' do
|
41
|
+
subject do
|
42
|
+
described_class.create do |writer|
|
43
|
+
# Calculate a value and fulfill the promise with it
|
44
|
+
writer.fulfill 42
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'returns a fulfilled promise' do
|
49
|
+
expect(subject.fulfilled?).to be true
|
50
|
+
expect(subject.rejected?).to be false
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'wraps the given value' do
|
54
|
+
expect(subject.value!).to eq 42
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'when rejecting the promise in the writer block' do
|
59
|
+
subject do
|
60
|
+
described_class.create do |writer|
|
61
|
+
# Calculate a value and fulfill the promise with it
|
62
|
+
writer.reject ArgumentError
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'returns a rejected promise' do
|
67
|
+
expect(subject.fulfilled?).to be false
|
68
|
+
expect(subject.rejected?).to be true
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'bubbles up the caught exception on #value!' do
|
72
|
+
expect { subject.value! }.to raise_error(ArgumentError)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'swallows the exception on #value' do
|
76
|
+
expect(subject.value).to be nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'when fulfilling the promise asynchronously' do
|
81
|
+
subject do
|
82
|
+
described_class.create do |writer|
|
83
|
+
Thread.new do
|
84
|
+
sleep 0.1
|
85
|
+
writer.fulfill 42
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'returns a pending promise' do
|
91
|
+
expect(subject.fulfilled?).to be false
|
92
|
+
expect(subject.rejected?).to be false
|
93
|
+
expect(subject.pending?).to be true
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'waits for the fulfillment value' do
|
97
|
+
expect(subject.value!).to eq 42
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe 'result' do
|
104
|
+
subject { described_class.new(*dependencies, &task).value! }
|
105
|
+
let(:dependencies) { [] }
|
106
|
+
let(:task) { nil }
|
107
|
+
|
108
|
+
context 'with a task' do
|
109
|
+
let(:task) do
|
110
|
+
proc {
|
111
|
+
# Calculate the resulting value
|
112
|
+
38 + 4
|
113
|
+
}
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'is calculated using the task block' do
|
117
|
+
expect(subject).to eq 42
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'with dependencies, but no task' do
|
122
|
+
let(:dependencies) do
|
123
|
+
[
|
124
|
+
Restify::Promise.fulfilled(1),
|
125
|
+
Restify::Promise.fulfilled(2),
|
126
|
+
Restify::Promise.fulfilled(3)
|
127
|
+
]
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'is an array of the dependencies\' results' do
|
131
|
+
expect(subject).to eq [1, 2, 3]
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'with dependencies passed as an array, but no task' do
|
136
|
+
let(:dependencies) do
|
137
|
+
[[
|
138
|
+
Restify::Promise.fulfilled(1),
|
139
|
+
Restify::Promise.fulfilled(2),
|
140
|
+
Restify::Promise.fulfilled(3)
|
141
|
+
]]
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'is an array of the dependencies\' results' do
|
145
|
+
expect(subject).to eq [1, 2, 3]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'with dependencies and a task' do
|
150
|
+
let(:dependencies) do
|
151
|
+
[
|
152
|
+
Restify::Promise.fulfilled(5),
|
153
|
+
Restify::Promise.fulfilled(12)
|
154
|
+
]
|
155
|
+
end
|
156
|
+
let(:task) do
|
157
|
+
proc {|dep1, dep2| dep1 + dep2 }
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'can use the dependencies to calculate the value' do
|
161
|
+
expect(subject).to eq 17
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'spec_helper'
|
2
4
|
|
3
5
|
describe Restify::Relation do
|
@@ -26,7 +28,6 @@ describe Restify::Relation do
|
|
26
28
|
end
|
27
29
|
|
28
30
|
context 'with #to_param object' do
|
29
|
-
|
30
31
|
let(:params) { {id: ParamObject.new} }
|
31
32
|
|
32
33
|
it { expect(subject.to_s).to eq 'http://test.host/resource/42' }
|
data/spec/restify_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rspec'
|
2
4
|
require 'webmock/rspec'
|
3
5
|
|
@@ -10,19 +12,21 @@ end
|
|
10
12
|
|
11
13
|
require 'restify'
|
12
14
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
15
|
+
if ENV['ADAPTER']
|
16
|
+
case ENV['ADAPTER'].to_s.downcase
|
17
|
+
when 'em-http-request'
|
18
|
+
require 'restify/adapter/em'
|
19
|
+
Restify.adapter = Restify::Adapter::EM.new
|
20
|
+
when 'typhoeus'
|
21
|
+
require 'restify/adapter/typhoeus'
|
22
|
+
Restify.adapter = Restify::Adapter::Typhoeus.new
|
23
|
+
when 'typhoeus-sync'
|
24
|
+
require 'restify/adapter/typhoeus'
|
25
|
+
Restify.adapter = Restify::Adapter::Typhoeus.new sync: true
|
26
|
+
else
|
27
|
+
raise "Invalid adapter: #{ENV['ADAPTER']}"
|
28
|
+
end
|
29
|
+
end
|
26
30
|
|
27
31
|
require 'webmock/rspec'
|
28
32
|
require 'rspec/collection_matchers'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: restify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Graichen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -151,11 +151,12 @@ files:
|
|
151
151
|
- lib/restify/resource.rb
|
152
152
|
- lib/restify/response.rb
|
153
153
|
- lib/restify/version.rb
|
154
|
-
- restify.gemspec
|
155
154
|
- spec/restify/cache_spec.rb
|
156
155
|
- spec/restify/global_spec.rb
|
157
156
|
- spec/restify/link_spec.rb
|
157
|
+
- spec/restify/processors/base_spec.rb
|
158
158
|
- spec/restify/processors/json_spec.rb
|
159
|
+
- spec/restify/promise_spec.rb
|
159
160
|
- spec/restify/registry_spec.rb
|
160
161
|
- spec/restify/relation_spec.rb
|
161
162
|
- spec/restify/resource_spec.rb
|
@@ -176,12 +177,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
176
177
|
version: '0'
|
177
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
179
|
requirements:
|
179
|
-
- - "
|
180
|
+
- - ">="
|
180
181
|
- !ruby/object:Gem::Version
|
181
|
-
version:
|
182
|
+
version: '0'
|
182
183
|
requirements: []
|
183
184
|
rubyforge_project:
|
184
|
-
rubygems_version: 2.
|
185
|
+
rubygems_version: 2.6.11
|
185
186
|
signing_key:
|
186
187
|
specification_version: 4
|
187
188
|
summary: An experimental hypermedia REST client.
|
@@ -189,7 +190,9 @@ test_files:
|
|
189
190
|
- spec/restify/cache_spec.rb
|
190
191
|
- spec/restify/global_spec.rb
|
191
192
|
- spec/restify/link_spec.rb
|
193
|
+
- spec/restify/processors/base_spec.rb
|
192
194
|
- spec/restify/processors/json_spec.rb
|
195
|
+
- spec/restify/promise_spec.rb
|
193
196
|
- spec/restify/registry_spec.rb
|
194
197
|
- spec/restify/relation_spec.rb
|
195
198
|
- spec/restify/resource_spec.rb
|
data/restify.gemspec
DELETED
@@ -1,35 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'restify/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = 'restify'
|
8
|
-
spec.version = Restify::VERSION
|
9
|
-
spec.authors = ['Jan Graichen']
|
10
|
-
spec.email = ['jg@altimos.de']
|
11
|
-
spec.summary = 'An experimental hypermedia REST client.'
|
12
|
-
spec.description = 'An experimental hypermedia REST client that uses parallel, keep-alive and pipelined requests by default.'
|
13
|
-
spec.homepage = 'https://github.com/jgraichen/restify'
|
14
|
-
spec.license = 'LGPLv3'
|
15
|
-
|
16
|
-
spec.files = Dir['**/*'].grep(%r{^((bin|lib|test|spec|features)/|.*\.gemspec|.*LICENSE.*|.*README.*|.*CHANGELOG.*)})
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = ['lib']
|
20
|
-
|
21
|
-
spec.add_runtime_dependency 'concurrent-ruby', '~> 1.0'
|
22
|
-
spec.add_runtime_dependency 'addressable', '~> 2.3'
|
23
|
-
spec.add_runtime_dependency 'hashie', '~> 3.3'
|
24
|
-
spec.add_runtime_dependency 'rack'
|
25
|
-
spec.add_runtime_dependency 'eventmachine', '>= 1.2'
|
26
|
-
spec.add_runtime_dependency 'em-http-request', '~> 1.1.3'
|
27
|
-
spec.add_runtime_dependency 'activesupport'
|
28
|
-
|
29
|
-
spec.add_development_dependency 'bundler', '~> 1.5'
|
30
|
-
|
31
|
-
if ENV['TRAVIS_BUILD_NUMBER']
|
32
|
-
# Append travis build number for auto-releases
|
33
|
-
spec.version = "#{spec.version}.1.b#{ENV['TRAVIS_BUILD_NUMBER']}"
|
34
|
-
end
|
35
|
-
end
|