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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b00cff50046f420707ed6d6e8851d74e1392f5f
4
- data.tar.gz: fa5553ba030b9ec8bcd2457d4c24a866ad1db293
3
+ metadata.gz: 3acb2cc3581b8c3c47ad27c6ab1ea34406d7fa39
4
+ data.tar.gz: 91e4eb0b80116b6e13d8aca4cf8942de6ef064bc
5
5
  SHA512:
6
- metadata.gz: 76ad0f4229b26ba714763793a086ba2cffb62642fa1ebb329037e1b542a5802ace3f29acc1220100488f7010b2eae5963a729d812475d17fa7834e43079a1004
7
- data.tar.gz: 32908687b5e5b3234ccc5985cf1184a179d60f5589383482a4dff87abf168f7dbbefe101b4f7a4fcbe0d5ccb10b0b2d5e2c9a46dbae11dfd9cf54ddedb94baae
6
+ metadata.gz: e314678c3419674b6a709db0ba224bd46b704ba24455db084dba0f7e9dfccaf4c633243e384411d1fd7046a0c34480f19353a2313190c70ed62599eb50d04a3a
7
+ data.tar.gz: 8378f0c684c143cab5c92b4799a1424370f3b0db6395296d7b4bf38b3b8c48e08274035dfcd770f8ecc52308e9b80d74247628e125635f477f2fcec7436ba670
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.0
4
+
5
+ * Return response body if no processor matches (#7)
6
+ * Add shortcuts for creating fulfilled / rejected promises (#6)
7
+
3
8
  ## 1.0.0
4
9
 
5
10
  * Experimental cache API doing nothing for now
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
@@ -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(request, writer)
11
- throw NotImplementedError.new '#call_native not implemented. Subclass responsibility.'
12
+ def call_native(_request, _writer)
13
+ throw NotImplementedError.new 'Subclass responsibility'
12
14
  end
13
15
  end
14
16
  end
@@ -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 RuntimeError.new \
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 unless EventMachine.reactor_running?
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)) while !@queue.empty?
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 |response|
13
- cache(response)
14
- response
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(request)
22
+ def match(_request)
21
23
  false
22
24
  end
23
25
 
@@ -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 = uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri.to_s)
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 { |p| p.accept? response }
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
- def request(method, uri, data = nil, opts = {})
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) {|request| adapter.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 RuntimeError.new "Unknown response code: #{response.code}"
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'] || response.decoded_body[:errors] || response.decoded_body
41
+ response.decoded_body['errors'] ||
42
+ response.decoded_body[:errors] ||
43
+ response.decoded_body
40
44
  else
41
45
  response.body
42
46
  end
@@ -1,7 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restify
2
4
  module Global
3
- extend self
4
-
5
5
  def new(uri, **opts)
6
6
  context = resolve_context uri, **opts
7
7
 
data/lib/restify/link.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restify
2
4
  #
3
5
  # A {Link} represents a single entry from the Link header
@@ -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
- if (location = @response.follow_location)
59
- relations[:_restify_follow] = location
60
- end
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?(response)
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.load(body), root: true
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, response: response, data: data, relations: relations
32
+ Resource.new context,
33
+ data: data,
34
+ response: response,
35
+ relations: relations
31
36
  else
32
- Resource.new context, data: data, relations: relations
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
- when /\A(\w+)_url\z/
48
- Regexp.last_match[1]
49
- when 'url'
50
- 'self'
51
- else
52
- return
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.load response.body
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 =~ /\Aapplication\/json($|;)/
79
+ response.content_type =~ %r{\Aapplication/json($|;)}
71
80
  end
72
81
 
73
82
  def indifferent_access?
74
- @@indifferent_access
83
+ @indifferent_access
75
84
  end
76
85
 
77
- def indifferent_access=(value)
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
@@ -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(timeout)
43
- if compare_and_set_state(:processing, :pending)
44
- return unless @task || @dependencies.any?
29
+ def ns_execute(_timeout)
30
+ return unless compare_and_set_state(:processing, :pending)
31
+ return unless @task || @dependencies.any?
45
32
 
46
- executor = Concurrent::SafeTaskExecutor.new \
47
- method(:ns_exec), rescue_exception: true
33
+ executor = Concurrent::SafeTaskExecutor.new \
34
+ method(:ns_exec), rescue_exception: true
48
35
 
49
- success, value, reason = executor.execute
36
+ success, value, reason = executor.execute
50
37
 
51
- complete success, value, reason
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restify
2
4
  class Registry
3
5
  def initialize
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restify
2
4
  #
3
5
  class Relation
4
-
5
6
  # Relation context
6
7
  #
7
8
  # @return [Restify::Context] Context
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restify
2
4
  #
3
5
  class Request
@@ -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
- alias_method :rel?, :relation?
27
- alias_method :has_rel?, :relation?
28
- alias_method :has_relation?, :relation?
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
- alias_method :rel, :relation
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 RuntimeError.new 'Nothing to follow'
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
- "@data" => data,
101
- "@relations" => @relations
102
- }.map {|k,v | k + '=' + v.inspect }.join(' ')
98
+ '@data' => data,
99
+ '@relations' => @relations
100
+ }.map {|k, v| k + '=' + v.inspect }.join(' ')
103
101
 
104
102
  "#<#{self.class} #{text}>"
105
103
  end
@@ -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).include? code
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 /\Aapplication\/json($|;)/
127
- JSON.load body
129
+ when %r{\Aapplication/json($|;)}
130
+ ::JSON.parse(body)
128
131
  end
129
132
  end
130
133
  end
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Restify
2
4
  module VERSION
3
5
  MAJOR = 1
4
- MINOR = 0
5
- PATCH = 1
6
- STAGE = :beta1
6
+ MINOR = 1
7
+ PATCH = 0
8
+ STAGE = nil
7
9
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.').freeze
8
10
 
9
11
  def self.to_s
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restify::Cache do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restify::Global do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restify::Link do
@@ -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
- context 'parsing' do
34
+ describe 'parsing' do
33
35
  context 'single object' do
34
- let(:body) do <<-JSON
35
- {"key": "value"}
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 'key' => 'value' }
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 <<-JSON
46
- {"key": "value", "search_url": "https://google.com{?q}"}
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
- 'key' => 'value', 'search_url' => 'https://google.com{?q}'
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 <<-JSON
61
- {"key": "value", "url": "/self"}
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 <<-JSON
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, "STR"] }
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 <<-JSON
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 <<-JSON
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.map(&:class)).to eq \
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 <<-JSON
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 <<-JSON
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 "BLUB" }
142
+ it { is_expected.to eq 'BLUB' }
134
143
  end
135
144
 
136
145
  context 'with indifferent access' do
137
- let(:body) do <<-JSON
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 <<-JSON
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::Registry do
@@ -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' }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restify::Resource do
data/spec/restify_spec.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Restify do
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
- case ENV['ADAPTER'].to_s.downcase
14
- when 'em-http-request'
15
- require 'restify/adapter/em'
16
- Restify.adapter = Restify::Adapter::EM.new
17
- when 'typhoeus'
18
- require 'restify/adapter/typhoeus'
19
- Restify.adapter = Restify::Adapter::Typhoeus.new
20
- when 'typhoeus-sync'
21
- require 'restify/adapter/typhoeus'
22
- Restify.adapter = Restify::Adapter::Typhoeus.new sync: true
23
- else
24
- raise "Invalid adapter: #{ENV['ADAPTER']}"
25
- end if ENV['ADAPTER']
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.0.1.beta1
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-01-20 00:00:00.000000000 Z
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: 1.3.1
182
+ version: '0'
182
183
  requirements: []
183
184
  rubyforge_project:
184
- rubygems_version: 2.5.1
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