restify 0.3.2.1.b59 → 0.3.2.1.b62

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,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NzVkNjRlMjY2MGFjMDEwOTlhMWJjYmIzMTYxMWM4MTJkZWE1NjY1MQ==
4
+ ZGMzYTA4ODFiZDdhYTBkMTQyZTA4YTIxNmM5NDcwZmQ0Yjk4MjFkYQ==
5
5
  data.tar.gz: !binary |-
6
- ZDdlYmYwOThhNjNmMTRjMzBkOTE0OGE4ZjFkY2Q0NThiZjI0NDZjYw==
6
+ ODg4MzU4NWY4ZjRjZGM4N2IyNWM3Nzk3NjY4NjI4ZTVjZjU1MTExOQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZGUyMWViNzUyYmU3NGVhMjE3MzhkM2ZhNjUxMGZhNGE2NmU4YjZmODE1MDE1
10
- ZThkNGU2MzM1NGFiOWZiNTZmZjFjNjY4YTYyZTI4MDI5MTNkZDY0M2ZiNzg5
11
- ZjE0YTFlNTVmMzMyNzg0NDllNGE4OWVlMDlhMjFlOWNlMmQ4MzQ=
9
+ M2U5M2YyZmQ5MzJmYmE3ODZhY2M2NDRiYTYwMmNiYTc3ZmYzY2VmN2Y0N2Ix
10
+ NDkxMmIxNDFlOTU3NmRkZmU0ZGRlMmU5NDdjY2UyOWFlN2I1NzgwOGZjZTQw
11
+ MmIxNzc2M2QzN2Q3ZWNiYmIzNjBhZmUwMjBmYTk4YzljMmRlNmQ=
12
12
  data.tar.gz: !binary |-
13
- MGNhODg4M2JiNWMyNzAwNjlmZDgwZTJhMzMzZGJlMzA1YjMxYmNiZWM4NDk0
14
- ODlhYWQ0ZTM5ZTBjOTI0ZjI3ZmQ3MzhkMTQyOGVhMDA2YzBiOGE5ZTBiNTcy
15
- MzdjZTI1ODMyNzU4ZTRkOTFhMGI3NmEzN2MwMTI0MDA5ZjdiNjk=
13
+ ZWYzZjQ1M2ZiMTRiZDIzOTYyMzgzM2ExMDYzODg2YzVlYjM2Yzk1ZjFlMzZi
14
+ NTc3YjZlMGJiNzcxYWFhNWE0YjBkMTIzNmQzM2Y5OGQ2NzcwNDY1MmEwMGJh
15
+ ZGI0NTRiN2RlMDgzNzBiMjIwZGRjNjMyNGNiODAwMzFiNjdkOGY=
data/lib/restify.rb CHANGED
@@ -2,7 +2,6 @@ require 'restify/version'
2
2
 
3
3
  require 'hashie'
4
4
  require 'obligation'
5
- require 'multi_json'
6
5
  require 'addressable/uri'
7
6
  require 'addressable/template'
8
7
 
@@ -10,11 +9,8 @@ require 'addressable/template'
10
9
  module Restify
11
10
  require 'restify/http'
12
11
  require 'restify/error'
13
- require 'restify/relations'
14
12
 
15
13
  require 'restify/context'
16
- require 'restify/contextual'
17
- require 'restify/collection'
18
14
  require 'restify/resource'
19
15
  require 'restify/relation'
20
16
 
@@ -22,9 +18,16 @@ module Restify
22
18
  require 'restify/request'
23
19
  require 'restify/response'
24
20
 
21
+ module Processors
22
+ require 'restify/processors/base'
23
+ require 'restify/processors/json'
24
+ end
25
+
26
+ PROCESSORS = [Processors::Json]
27
+
25
28
  class << self
26
29
  def new(uri, opts = {})
27
- Context.new(uri, http, nil, opts).request(:GET, uri)
30
+ Context.new(uri, http).request(:GET, uri)
28
31
  end
29
32
 
30
33
  def http
@@ -125,7 +125,7 @@ module Restify
125
125
  begin
126
126
  EventMachine.run {}
127
127
  rescue => e
128
- puts "Resitfy::Adapter::EM -> #{e}\n#{e.backtrace.join("\n")}"
128
+ puts "#{self.class} -> #{e}\n#{e.backtrace.join("\n")}"
129
129
  raise e
130
130
  end
131
131
  end unless EventMachine.reactor_running?
@@ -6,110 +6,40 @@ module Restify
6
6
  # and follow links.
7
7
  #
8
8
  class Context
9
- include Addressable
10
- include Relations
11
-
12
- # The response object.
13
- #
14
- # @return [Response] The response or nil.
15
- #
16
- attr_reader :response
17
-
18
9
  # Effective context URI.
19
10
  #
20
11
  # @return [Addressable::URI] Effective context URI.
21
12
  #
22
13
  attr_reader :uri
23
14
 
24
- def initialize(uri, http, response = nil, _opts = {})
25
- @uri = uri.is_a?(URI) ? uri : URI.parse(uri.to_s)
15
+ def initialize(uri, http)
16
+ @uri = uri.is_a?(Addressable::URI) ? uri : Addressable::URI.parse(uri.to_s)
26
17
  @http = http
27
- @response = response
28
18
  end
29
19
 
30
- def relations
31
- @relations ||= load_relations
20
+ def join(uri)
21
+ self.uri.join uri
32
22
  end
33
23
 
34
- def expand(uri)
35
- case uri
36
- when Addressable::Template
37
- Addressable::Template.new self.uri.join(uri.pattern).to_s
38
- else
39
- self.uri.join uri
40
- end
41
- end
24
+ def process(response)
25
+ context = Context.new response.uri, @http
26
+ processor = Restify::PROCESSORS.find { |p| p.accept? response }
27
+ processor ||= Restify::Processors::Base
42
28
 
43
- def follow
44
- if follow_location
45
- new_relation follow_location
46
- else
47
- raise RuntimeError.new 'Nothing to follow'
48
- end
29
+ processor.new(context, response).resource
49
30
  end
50
31
 
51
32
  def request(method, uri, data = nil, opts = {})
52
- request = @http.request(method, expand(uri), data, opts)
33
+ request = @http.request(method, join(uri), data, opts)
53
34
  request.then do |response|
54
35
  if response.success?
55
- inherit(uri: response.uri, response: response)
56
- .new_value(response.decoded_body)
36
+ process response
57
37
  else
58
38
  Context.raise_response_error(response)
59
39
  end
60
40
  end
61
41
  end
62
42
 
63
- def inherit_value(value)
64
- inherit.new_value value
65
- end
66
-
67
- def new_relation(uri)
68
- Relation.new(self, uri.to_s, expand(uri))
69
- end
70
-
71
- def add_relation(name, uri)
72
- @relations[name] = new_relation(uri)
73
- end
74
-
75
- def inherit(opts = {})
76
- Context.new \
77
- opts.fetch(:uri) { @uri },
78
- opts.fetch(:http) { @http },
79
- opts.fetch(:response) { nil }
80
- end
81
-
82
- def new_value(value)
83
- case value
84
- when Hash
85
- Resource.new(self, value)
86
- when Array
87
- Collection.new(self, value)
88
- else
89
- value
90
- end
91
- end
92
-
93
- private
94
-
95
- def follow_location
96
- return unless @response
97
-
98
- @response.headers['LOCATION'] || @response.headers['CONTENT-LOCATION']
99
- end
100
-
101
- def load_relations
102
- response_links.each_with_object(Hashie::Mash.new) do |link, relations|
103
- if (rel = link.metadata['rel'])
104
- relations[rel] = new_relation link.uri
105
- end
106
- end
107
- end
108
-
109
- def response_links
110
- @response ? @response.links : []
111
- end
112
-
113
43
  class << self
114
44
  def raise_response_error(response)
115
45
  case response.code
data/lib/restify/error.rb CHANGED
@@ -36,7 +36,7 @@ module Restify
36
36
  #
37
37
  def errors
38
38
  if response.decoded_body
39
- response.decoded_body['errors'] || response.decoded_body[:errors]
39
+ response.decoded_body['errors'] || response.decoded_body[:errors] || response.decoded_body
40
40
  else
41
41
  response.body
42
42
  end
@@ -0,0 +1,70 @@
1
+ module Restify
2
+ #
3
+ module Processors
4
+ #
5
+ class Base
6
+ extend Forwardable
7
+
8
+ #
9
+ attr_reader :context
10
+
11
+ #
12
+ attr_reader :response
13
+
14
+ def initialize(context, response)
15
+ @context = context
16
+ @response = response
17
+ end
18
+
19
+ def resource
20
+ @resource ||= begin
21
+ resource = load
22
+
23
+ unless resource.is_a? Restify::Resource
24
+ resource = Resource.new context, response: response, data: resource
25
+ end
26
+
27
+ resource._restify_response = response
28
+ merge_relations! resource._restify_relations
29
+
30
+ resource
31
+ end
32
+ end
33
+
34
+ # Return resource or data.
35
+ #
36
+ # Should be overridden in subclass.
37
+ #
38
+ def load
39
+
40
+ end
41
+
42
+ # @!method body
43
+ #
44
+ delegate body: :@response
45
+
46
+ private
47
+
48
+ def merge_relations!(relations)
49
+ response.links.each do |link|
50
+ name = link.metadata['rel']
51
+ value = link.uri
52
+
53
+ if !name.empty? && !relations.key?(name)
54
+ relations[name] = value
55
+ end
56
+ end
57
+
58
+ if (location = @response.follow_location)
59
+ relations[:_restify_follow] = location
60
+ end
61
+ end
62
+
63
+ class << self
64
+ def accept?(response)
65
+ false
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,83 @@
1
+ module Restify
2
+ #
3
+ module Processors
4
+ #
5
+ # Decode plain JSON responses.
6
+ #
7
+ # JSON fields matching *_url will be parsed as relations.
8
+ #
9
+ class Json < Base
10
+
11
+ def load
12
+ parse JSON.load(body), root: true
13
+ end
14
+
15
+ private
16
+
17
+ def parse(object, root: false)
18
+ case object
19
+ when Hash
20
+ data = object.each_with_object({}, &method(:parse_data))
21
+ relations = object.each_with_object({}, &method(:parse_rels))
22
+
23
+ if self.class.indifferent_access?
24
+ data = with_indifferent_access(data)
25
+ end
26
+
27
+ if root
28
+ Resource.new context, response: response, data: data, relations: relations
29
+ else
30
+ Resource.new context, data: data, relations: relations
31
+ end
32
+ when Array
33
+ object.map(&method(:parse))
34
+ else
35
+ object
36
+ end
37
+ end
38
+
39
+ def parse_data(pair, data)
40
+ data[pair[0].to_s] = parse pair[1]
41
+ end
42
+
43
+ def parse_rels(pair, relations)
44
+ name = case pair[0].to_s.downcase
45
+ when /\A(\w+)_url\z/
46
+ Regexp.last_match[1]
47
+ when 'url'
48
+ 'self'
49
+ else
50
+ return
51
+ end
52
+
53
+ return if relations.key?(name) || pair[1].nil? || pair[1].to_s =~ /\A\w*\z/
54
+
55
+ relations[name] = pair[1].to_s
56
+ end
57
+
58
+ def json
59
+ @json ||= JSON.load response.body
60
+ end
61
+
62
+ def with_indifferent_access(data)
63
+ Hashie::Mash.new data
64
+ end
65
+
66
+ class << self
67
+ def accept?(response)
68
+ response.content_type =~ /\Aapplication\/json($|;)/
69
+ end
70
+
71
+ def indifferent_access?
72
+ @@indifferent_access
73
+ end
74
+
75
+ def indifferent_access=(value)
76
+ @@indifferent_access = value
77
+ end
78
+
79
+ @@indifferent_access = true
80
+ end
81
+ end
82
+ end
83
+ end
@@ -1,10 +1,9 @@
1
1
  module Restify
2
2
  #
3
3
  class Relation
4
- def initialize(context, source, pattern)
4
+ def initialize(context, template)
5
5
  @context = context
6
- @source = source
7
- @template = to_template(pattern)
6
+ @template = Addressable::Template.new template
8
7
  end
9
8
 
10
9
  def get(params = {})
@@ -28,9 +27,7 @@ module Restify
28
27
  end
29
28
 
30
29
  def ==(other)
31
- super ||
32
- (other.is_a?(String) && @template.pattern == other) ||
33
- (other.is_a?(String) && @source == other)
30
+ super || (other.is_a?(String) && @template.pattern == other)
34
31
  end
35
32
 
36
33
  def expand(params)
@@ -39,7 +36,8 @@ module Restify
39
36
 
40
37
  uri = @template.expand variables
41
38
  uri.query_values = (uri.query_values || {}).merge params if params.any?
42
- uri
39
+
40
+ @context.join uri
43
41
  end
44
42
 
45
43
  private
@@ -19,14 +19,14 @@ module Restify
19
19
  attr_reader :data
20
20
 
21
21
  def initialize(opts = {})
22
- @method = opts.fetch(:method, :get)
22
+ @method = opts.fetch(:method, :get).downcase
23
23
  @uri = opts.fetch(:uri) { raise ArgumentError.new ':uri required.' }
24
24
  @data = opts.fetch(:data, nil)
25
25
  end
26
26
 
27
27
  def body
28
28
  @body ||= begin
29
- MultiJson.dump(data) unless data.nil?
29
+ JSON.dump(data) unless data.nil?
30
30
  end
31
31
  end
32
32
 
@@ -1,56 +1,93 @@
1
+ require 'delegate'
2
+
1
3
  module Restify
2
4
  #
3
- class Resource < Hashie::Hash
4
- include Contextual
5
- include Relations
6
- include Hashie::Extensions::IndifferentAccess
7
- include Hashie::Extensions::MethodReader
8
-
9
- #
10
- def initialize(context, data = {})
11
- @context = context
12
-
13
- data.each_pair do |key, value|
14
- self[key.to_s] = convert_value(value)
15
-
16
- name = case key.to_s.downcase
17
- when /\A(\w+)_url\z/
18
- Regexp.last_match[1]
19
- when 'url'
20
- 'self'
21
- else
22
- next
23
- end
24
-
25
- unless @context.relation?(name) || value.nil? || value.to_s.empty?
26
- @context.add_relation name, value.to_s
27
- end
28
- end
5
+ class Resource < Delegator
6
+ extend Forwardable
7
+
8
+ # @api private
9
+ #
10
+ def initialize(context, response: nil, data: nil, relations: {})
11
+ @data = data
12
+ @context = context
13
+ @response = response
14
+ @relations = relations
29
15
  end
30
16
 
31
- # Compare with other {Resource}s or hashes.
17
+ # @api private
32
18
  #
33
- def ==(other)
34
- case other
35
- when Resource
36
- super && relations == other.relations
37
- when Hash
38
- super Hash[other.map {|k, v| [convert_key(k), v] }]
39
- else
40
- super
41
- end
19
+ def __getobj__
20
+ @data
42
21
  end
43
22
 
44
- # @private
23
+ # Check if resource has a relation with given name.
24
+ #
25
+ # @param name [String, Symbol] Relation name.
26
+ # @return [Boolean] True if resource has relation, false otherwise.
45
27
  #
46
- def convert_key(key)
47
- key.to_s
28
+ def relation?(name)
29
+ @relations.key?(name) || @relations.key?(name.to_s)
48
30
  end
49
31
 
50
- # @private
32
+ alias_method :rel?, :relation?
33
+ alias_method :has_rel?, :relation?
34
+ alias_method :has_relation?, :relation?
35
+
36
+ # Return relation with given name.
37
+ #
38
+ # @param name [String, Symbol] Relation name.
39
+ # @return [Relation] Relation.
40
+ #
41
+ def relation(name)
42
+ if @relations.key? name
43
+ Relation.new @context, @relations.fetch(name)
44
+ else
45
+ Relation.new @context, @relations.fetch(name.to_s)
46
+ end
47
+ end
48
+
49
+ alias_method :rel, :relation
50
+
51
+ # @!method response
51
52
  #
52
- def convert_value(value)
53
- @context.inherit_value(value)
53
+ # Return response if available.
54
+ #
55
+ # @return [Response] Response object.
56
+ # @see Context#response
57
+ #
58
+ attr_reader :response
59
+
60
+ # Follow a LOCATION or CONTEXT-LOCATION header.
61
+ #
62
+ # @return [Relation] Relation to follow resource.
63
+ # @raise RuntimeError If nothing to follow.
64
+ #
65
+ def follow
66
+ if relation? :_restify_follow
67
+ relation :_restify_follow
68
+ else
69
+ raise RuntimeError.new 'Nothing to follow'
70
+ end
71
+ end
72
+
73
+ # @api private
74
+ def _restify_relations
75
+ @relations
76
+ end
77
+
78
+ # @api private
79
+ def _restify_response=(response)
80
+ @response = response
81
+ end
82
+
83
+ # @api private
84
+ def inspect
85
+ text = {
86
+ "@data" => @data,
87
+ "@relations" => @relations
88
+ }.map {|k,v | k + '=' + v.inspect }.join(' ')
89
+
90
+ "#<#{self.class} #{text}>"
54
91
  end
55
92
  end
56
93
  end
@@ -77,7 +77,7 @@ module Restify
77
77
  @uri = uri
78
78
  @code = code
79
79
  @status = STATUS_CODE_TO_SYMBOL[code]
80
- @headers = headers
80
+ @headers = convert_headers(headers)
81
81
  @body = body
82
82
  @message = Rack::Utils::HTTP_STATUS_CODES[code]
83
83
  end
@@ -88,9 +88,9 @@ module Restify
88
88
  #
89
89
  def links
90
90
  @links ||= begin
91
- if headers['Link']
91
+ if headers['LINK']
92
92
  begin
93
- Link.parse(headers['Link'])
93
+ Link.parse(headers['LINK'])
94
94
  rescue ArgumentError => e
95
95
  warn e
96
96
  []
@@ -101,18 +101,12 @@ module Restify
101
101
  end
102
102
  end
103
103
 
104
- # Return decoded body according to content type.
105
- # Will return `nil` if content cannot be decoded.
104
+ # Return content type header from response headers.
106
105
  #
107
- # @return [Array, Hash, NilClass] Decoded response body.
106
+ # @return [String] Content type header.
108
107
  #
109
- def decoded_body
110
- @decoded_body ||= begin
111
- case headers['Content-Type']
112
- when /\Aapplication\/json($|;)/
113
- MultiJson.load body
114
- end
115
- end
108
+ def content_type
109
+ headers['CONTENT_TYPE']
116
110
  end
117
111
 
118
112
  # Check if response is successful e.g. the status code
@@ -123,5 +117,28 @@ module Restify
123
117
  def success?
124
118
  (200...300).include? code
125
119
  end
120
+
121
+ # @api private
122
+ def decoded_body
123
+ @decoded_body ||= begin
124
+ case content_type
125
+ when /\Aapplication\/json($|;)/
126
+ JSON.load body
127
+ end
128
+ end
129
+ end
130
+
131
+ # @api private
132
+ def follow_location
133
+ headers['LOCATION'] || headers['CONENT_LOCATION']
134
+ end
135
+
136
+ private
137
+
138
+ def convert_headers(headers)
139
+ headers.each_with_object({}) do |pair, hash|
140
+ hash[pair[0].upcase] = pair[1]
141
+ end
142
+ end
126
143
  end
127
144
  end
data/restify.gemspec CHANGED
@@ -20,11 +20,8 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_runtime_dependency 'obligation', '~> 0.1'
22
22
  spec.add_runtime_dependency 'addressable', '~> 2.3'
23
- spec.add_runtime_dependency 'http', '~> 0.8.12'
24
- spec.add_runtime_dependency 'celluloid-io', '~> 0.16.2'
25
23
  spec.add_runtime_dependency 'em-http-request'
26
24
  spec.add_runtime_dependency 'hashie', '~> 3.3'
27
- spec.add_runtime_dependency 'multi_json'
28
25
  spec.add_runtime_dependency 'rack'
29
26
 
30
27
  spec.add_development_dependency 'bundler', '~> 1.5'
@@ -0,0 +1,175 @@
1
+ require 'spec_helper'
2
+
3
+ describe Restify::Processors::Json do
4
+ let(:context) { Restify::Context.new('http://test.host/', nil) }
5
+ let(:response) { double 'response' }
6
+
7
+ before do
8
+ allow(response).to receive(:links).and_return []
9
+ allow(response).to receive(:follow_location).and_return nil
10
+ end
11
+
12
+ describe 'class' do
13
+ describe '#accept?' do
14
+ subject { described_class.accept? response }
15
+
16
+ it 'accepts JSON mime type (I)' do
17
+ expect(response).to receive(:content_type).and_return('application/json')
18
+ expect(subject).to be_truthy
19
+ end
20
+
21
+ it 'accepts JSON mime type (II)' do
22
+ expect(response).to receive(:content_type).and_return('application/json; abc')
23
+ expect(subject).to be_truthy
24
+ end
25
+ end
26
+ end
27
+
28
+ describe '#resource' do
29
+ subject { described_class.new(context, response).resource }
30
+ before { allow(response).to receive(:body).and_return(body) }
31
+
32
+ context 'parsing' do
33
+ context 'single object' do
34
+ let(:body) do <<-JSON
35
+ {"key": "value"}
36
+ JSON
37
+ end
38
+
39
+ it { is_expected.to be_a Restify::Resource }
40
+ it { expect(subject.response).to be response }
41
+ it { is_expected.to eq 'key' => 'value' }
42
+ end
43
+
44
+ context 'object with relation fields' do
45
+ let(:body) do <<-JSON
46
+ {"key": "value", "search_url": "https://google.com{?q}"}
47
+ JSON
48
+ end
49
+
50
+ it do
51
+ is_expected.to eq \
52
+ 'key' => 'value', 'search_url' => 'https://google.com{?q}'
53
+ end
54
+
55
+ it { is_expected.to have_relation :search }
56
+ it { expect(subject.relation(:search)).to eq 'https://google.com{?q}' }
57
+ end
58
+
59
+ context 'object with implicit self relation' do
60
+ let(:body) do <<-JSON
61
+ {"key": "value", "url": "/self"}
62
+ JSON
63
+ end
64
+
65
+ it { expect(subject.relation(:self)).to eq '/self' }
66
+ end
67
+
68
+ context 'single array' do
69
+ let(:body) do <<-JSON
70
+ [1, 2, null, "STR"]
71
+ JSON
72
+ end
73
+
74
+ it { is_expected.to be_a Restify::Resource }
75
+ it { expect(subject.response).to be response }
76
+ it { is_expected.to eq [1, 2, nil, "STR"] }
77
+ end
78
+
79
+ context 'array with objects' do
80
+ let(:body) do <<-JSON
81
+ [{"a":0}, {"b":1}]
82
+ JSON
83
+ end
84
+
85
+ it { is_expected.to eq [{'a' => 0}, {'b' => 1}] }
86
+ end
87
+
88
+ context 'array with resources' do
89
+ let(:body) do <<-JSON
90
+ [{"name": "John", "self_url": "/users/john"},
91
+ {"name": "Jane", "self_url": "/users/jane"}]
92
+ JSON
93
+ end
94
+
95
+ it 'parses objects as resources' do
96
+ expect(subject.map(&:class)).to eq \
97
+ [Restify::Resource, Restify::Resource]
98
+ end
99
+
100
+ it 'parses relations of resources' do
101
+ expect(subject.map {|r| r.relation :self }).to eq \
102
+ ['/users/john', '/users/jane']
103
+ end
104
+ end
105
+
106
+ context 'nested objects' do
107
+ let(:body) do <<-JSON
108
+ {"john": {"name": "John"},
109
+ "jane": {"name": "Jane"}}
110
+ JSON
111
+ end
112
+
113
+ it { is_expected.to be_a Restify::Resource }
114
+ it { expect(subject.response).to be response }
115
+
116
+ it 'parses objects as resources' do
117
+ expect(subject['john']).to be_a Restify::Resource
118
+ expect(subject['jane']).to be_a Restify::Resource
119
+
120
+ expect(subject['john']['name']).to eq 'John'
121
+ expect(subject['jane']['name']).to eq 'Jane'
122
+ end
123
+ end
124
+
125
+ context 'single value' do
126
+ let(:body) do <<-JSON
127
+ "BLUB"
128
+ JSON
129
+ end
130
+
131
+ it { is_expected.to be_a Restify::Resource }
132
+ it { expect(subject.response).to be response }
133
+ it { is_expected.to eq "BLUB" }
134
+ end
135
+
136
+ context 'with indifferent access' do
137
+ let(:body) do <<-JSON
138
+ {"name": "John", "age": 24}
139
+ JSON
140
+ end
141
+
142
+ it '#key?' do
143
+ expect(subject).to have_key 'name'
144
+ expect(subject).to have_key 'age'
145
+
146
+ expect(subject).to have_key :name
147
+ expect(subject).to have_key :age
148
+ end
149
+
150
+ it '#[]' do
151
+ expect(subject['name']).to eq 'John'
152
+ expect(subject['age']).to eq 24
153
+
154
+ expect(subject[:name]).to eq 'John'
155
+ expect(subject[:age]).to eq 24
156
+ end
157
+ end
158
+
159
+ context 'with method getter access' do
160
+ let(:body) do <<-JSON
161
+ {"name": "John", "age": 24}
162
+ JSON
163
+ end
164
+
165
+ it '#<method getter>' do
166
+ expect(subject).to respond_to :name
167
+ expect(subject).to respond_to :age
168
+
169
+ expect(subject.name).to eq 'John'
170
+ expect(subject.age).to eq 24
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
@@ -1,17 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Restify::Relation do
4
- let(:context) { double 'context' }
5
- let(:source) { '/resource/{id}' }
6
- let(:pattern) { "http://test.host#{source}" }
7
- let(:relation) { described_class.new context, source, pattern }
4
+ let(:context) { Restify::Context.new('http://test.host/', nil) }
5
+ let(:pattern) { '/resource/{id}' }
6
+ let(:relation) { described_class.new context, pattern }
8
7
  subject { relation }
9
8
 
10
9
  describe '#==' do
11
- it 'should equal source' do
12
- expect(subject).to eq source
13
- end
14
-
15
10
  it 'should equal pattern' do
16
11
  expect(subject).to eq pattern
17
12
  end
@@ -38,7 +33,7 @@ describe Restify::Relation do
38
33
  end
39
34
 
40
35
  context 'with unknown additional query parameter' do
41
- let(:source) { '/resource{?a,b}' }
36
+ let(:pattern) { '/resource{?a,b}' }
42
37
  let(:params) { {a: 1, b: 2, c: 3} }
43
38
 
44
39
  it { expect(subject.to_s).to eq 'http://test.host/resource?a=1&b=2&c=3' }
@@ -1,158 +1,91 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Restify::Resource do
4
- let(:data) { {} }
5
- let(:http) { double 'http' }
6
- let(:context) { Restify::Context.new 'http://example.org', http }
7
- let(:res) { described_class.new(context, data) }
8
-
9
- describe '#rel?' do
10
- let(:data) do
11
- {
12
- 'users_url' => 'http://example.org/users',
13
- 'projects_url' => 'http://example.org/projects'
14
- }
15
- end
16
-
17
- it 'should match relations' do
18
- expect(res.rel?(:users)).to eq true
19
- expect(res.rel?('users')).to eq true
20
- expect(res.rel?(:projects)).to eq true
21
- expect(res.rel?('projects')).to eq true
22
- expect(res.rel?('fuu')).to eq false
23
-
24
- expect(res).to have_rel :users
25
- expect(res).to have_rel :projects
26
-
27
- expect(res.relation?(:users)).to eq true
28
- expect(res.relation?('users')).to eq true
29
- expect(res.relation?(:projects)).to eq true
30
- expect(res.relation?('projects')).to eq true
31
- expect(res.relation?('fuu')).to eq false
32
-
33
- expect(res).to have_relation :users
34
- expect(res).to have_relation :projects
35
- end
4
+ let(:data) { {} }
5
+ let(:relations) { {} }
6
+ let(:context) { double 'context' }
7
+ let(:response) { double 'response' }
8
+ let(:resource) { described_class.new(context, response: response, data: data, relations: relations) }
9
+ subject { resource }
10
+
11
+ before do
12
+ allow(context).to receive(:relation?).and_return(false)
13
+ allow(context).to receive(:relation).and_raise(KeyError)
36
14
  end
37
15
 
38
- describe '#rel' do
39
- let(:data) do
16
+ context 'relations' do
17
+ let(:relations) do
40
18
  {
41
- 'users_url' => 'http://example.org/users',
42
- 'projects_url' => 'http://example.org/projects'
19
+ 'users' => 'http://example.org/users',
20
+ 'projects' => 'http://example.org/projects'
43
21
  }
44
22
  end
45
23
 
46
- it 'should return relation' do
47
- expect(res.rel(:users)).to eq 'http://example.org/users'
48
- expect(res.rel('users')).to eq 'http://example.org/users'
49
- expect(res.rel(:projects)).to eq 'http://example.org/projects'
50
- expect(res.rel('projects')).to eq 'http://example.org/projects'
51
- expect { res.rel(:fuu) }.to raise_error KeyError
52
-
53
- expect(res.relation(:users)).to eq 'http://example.org/users'
54
- expect(res.relation('users')).to eq 'http://example.org/users'
55
- expect(res.relation(:projects)).to eq 'http://example.org/projects'
56
- expect(res.relation('projects')).to eq 'http://example.org/projects'
57
- expect { res.relation(:fuu) }.to raise_error KeyError
24
+ describe '#relation?' do
25
+ it 'should match relations' do
26
+ expect(subject.relation?(:users)).to eq true
27
+ expect(subject.relation?('users')).to eq true
28
+ expect(subject.relation?(:projects)).to eq true
29
+ expect(subject.relation?('projects')).to eq true
30
+ expect(subject.relation?('fuu')).to eq false
31
+
32
+ expect(subject).to have_relation :users
33
+ expect(subject).to have_relation :projects
34
+
35
+ expect(subject.rel?(:users)).to eq true
36
+ expect(subject.rel?('users')).to eq true
37
+ expect(subject.rel?(:projects)).to eq true
38
+ expect(subject.rel?('projects')).to eq true
39
+ expect(subject.rel?('fuu')).to eq false
40
+
41
+ expect(subject).to have_rel :users
42
+ expect(subject).to have_rel :projects
43
+ end
58
44
  end
59
- end
60
-
61
- describe '#key?' do
62
- let(:data) { {a: 0, 'b' => 1, 0 => 2} }
63
-
64
- it 'should test for key inclusion' do
65
- expect(res.key?(:a)).to eq true
66
- expect(res.key?(:b)).to eq true
67
- expect(res.key?('a')).to eq true
68
- expect(res.key?('b')).to eq true
69
- expect(res.key?(0)).to eq true
70
-
71
- expect(res.key?(:c)).to eq false
72
- expect(res.key?('d')).to eq false
73
45
 
74
- expect(res).to have_key :a
75
- expect(res).to have_key :b
76
- expect(res).to have_key 'a'
77
- expect(res).to have_key 'b'
78
- expect(res).to have_key 0
79
-
80
- expect(res).to_not have_key :c
81
- expect(res).to_not have_key 'd'
46
+ describe '#relation' do
47
+ it 'should return relation' do
48
+ expect(subject.rel(:users)).to be_a Restify::Relation
49
+
50
+ expect(subject.rel(:users)).to eq 'http://example.org/users'
51
+ expect(subject.rel('users')).to eq 'http://example.org/users'
52
+ expect(subject.rel(:projects)).to eq 'http://example.org/projects'
53
+ expect(subject.rel('projects')).to eq 'http://example.org/projects'
54
+ expect { subject.rel(:fuu) }.to raise_error KeyError
55
+
56
+ expect(subject.relation(:users)).to eq 'http://example.org/users'
57
+ expect(subject.relation('users')).to eq 'http://example.org/users'
58
+ expect(subject.relation(:projects)).to eq 'http://example.org/projects'
59
+ expect(subject.relation('projects')).to eq 'http://example.org/projects'
60
+ expect { subject.relation(:fuu) }.to raise_error KeyError
61
+ end
82
62
  end
83
- end
84
63
 
85
- describe '#each' do
86
- let(:data) { {a: 0, b: 1} }
87
-
88
- it 'should yield' do
89
- expect {|cb| res.each(&cb) }.to yield_control.twice
90
- expect {|cb| res.each(&cb) }.to yield_successive_args ['a', 0], ['b', 1]
91
- end
64
+ context '#follow' do
65
+ let(:relations) { {_restify_follow: 'http://localhost/10'} }
92
66
 
93
- it 'should return enumerator' do
94
- expect(res.each).to be_a Enumerator
95
- expect(res.each.to_a).to eq [['a', 0], ['b', 1]]
67
+ it 'returns follow relation' do
68
+ expect(subject.follow).to be_a Restify::Relation
69
+ expect(subject.follow).to eq 'http://localhost/10'
70
+ end
96
71
  end
97
72
  end
98
73
 
99
- describe '#[]' do
100
- let(:data) { {a: 0, b: 1} }
74
+ context 'data' do
75
+ let(:data) { double 'data' }
101
76
 
102
- it 'should return data' do
103
- expect(res[:a]).to eq 0
104
- expect(res[:b]).to eq 1
105
- end
106
- end
107
-
108
- describe '<getter>' do
109
- let(:data) { {a: 0, b: 1} }
110
-
111
- it 'should return data' do
112
- expect(res).to respond_to :a
113
- expect(res).to respond_to :b
114
-
115
- expect(res.a).to eq 0
116
- expect(res.b).to eq 1
117
- end
118
- end
119
-
120
- describe '#==' do
121
- let(:data) { {a: 0, b: 1} }
77
+ it 'should delegate methods (I)' do
78
+ expect(data).to receive(:some_method).and_return(42)
122
79
 
123
- it 'should eq hash' do
124
- expect(res).to eq a: 0, b: 1
125
- expect(res).to eq 'a' => 0, 'b' => 1
80
+ expect(subject).to respond_to :some_method
81
+ expect(subject.some_method).to eq 42
126
82
  end
127
- end
128
-
129
- describe '#include?' do
130
- let(:data) { {a: 0, b: 1} }
131
-
132
- it 'should include partial hash' do
133
- expect(res).to include a: 0
134
- expect(res).to include b: 1
135
-
136
- expect(res).to include 'a' => 0
137
- expect(res).to include 'b' => 1
138
-
139
- expect(res).to_not include a: 1
140
- expect(res).to_not include c: 0
141
- expect(res).to_not include 'a' => 1
142
- expect(res).to_not include 'c' => 0
143
- end
144
- end
145
-
146
- describe '#[]=' do
147
- let(:data) { {a: 0, b: 1} }
148
83
 
149
- it 'should return data' do
150
- res[:a] = 5
151
- res[:c] = 15
84
+ it 'should delegate methods (II)' do
85
+ expect(data).to receive(:[]).with(1).and_return(2)
152
86
 
153
- expect(res[:a]).to eq 5
154
- expect(res[:b]).to eq 1
155
- expect(res[:c]).to eq 15
87
+ expect(subject).to respond_to :[]
88
+ expect(subject[1]).to eq 2
156
89
  end
157
90
  end
158
91
  end
@@ -0,0 +1,14 @@
1
+
2
+ class Obligation::RejectedError
3
+ def backtrace
4
+ if cause
5
+ if (sup = super).nil?
6
+ sup
7
+ else
8
+ super + ["==== caused by #{cause.class}: #{cause}"] + cause.backtrace
9
+ end
10
+ else
11
+ super
12
+ end
13
+ end
14
+ end
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: 0.3.2.1.b59
4
+ version: 0.3.2.1.b62
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Graichen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-01 00:00:00.000000000 Z
11
+ date: 2015-08-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: obligation
@@ -38,34 +38,6 @@ dependencies:
38
38
  - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '2.3'
41
- - !ruby/object:Gem::Dependency
42
- name: http
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ~>
46
- - !ruby/object:Gem::Version
47
- version: 0.8.12
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - ~>
53
- - !ruby/object:Gem::Version
54
- version: 0.8.12
55
- - !ruby/object:Gem::Dependency
56
- name: celluloid-io
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ~>
60
- - !ruby/object:Gem::Version
61
- version: 0.16.2
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ~>
67
- - !ruby/object:Gem::Version
68
- version: 0.16.2
69
41
  - !ruby/object:Gem::Dependency
70
42
  name: em-http-request
71
43
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +66,6 @@ dependencies:
94
66
  - - ~>
95
67
  - !ruby/object:Gem::Version
96
68
  version: '3.3'
97
- - !ruby/object:Gem::Dependency
98
- name: multi_json
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - ! '>='
102
- - !ruby/object:Gem::Version
103
- version: '0'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - ! '>='
109
- - !ruby/object:Gem::Version
110
- version: '0'
111
69
  - !ruby/object:Gem::Dependency
112
70
  name: rack
113
71
  requirement: !ruby/object:Gem::Requirement
@@ -149,26 +107,25 @@ files:
149
107
  - lib/restify.rb
150
108
  - lib/restify/adapter/celluloid.rb
151
109
  - lib/restify/adapter/em.rb
152
- - lib/restify/collection.rb
153
110
  - lib/restify/context.rb
154
- - lib/restify/contextual.rb
155
111
  - lib/restify/error.rb
156
112
  - lib/restify/http.rb
157
113
  - lib/restify/link.rb
158
- - lib/restify/parser/json.rb
114
+ - lib/restify/processors/base.rb
115
+ - lib/restify/processors/json.rb
159
116
  - lib/restify/relation.rb
160
- - lib/restify/relations.rb
161
117
  - lib/restify/request.rb
162
118
  - lib/restify/resource.rb
163
119
  - lib/restify/response.rb
164
120
  - lib/restify/version.rb
165
121
  - restify.gemspec
166
- - spec/restify/collection_spec.rb
167
122
  - spec/restify/link_spec.rb
123
+ - spec/restify/processors/json_spec.rb
168
124
  - spec/restify/relation_spec.rb
169
125
  - spec/restify/resource_spec.rb
170
126
  - spec/restify_spec.rb
171
127
  - spec/spec_helper.rb
128
+ - spec/support/hack_causes.rb
172
129
  homepage: https://github.com/jgraichen/restify
173
130
  licenses:
174
131
  - LGPLv3
@@ -194,9 +151,10 @@ signing_key:
194
151
  specification_version: 4
195
152
  summary: An experimental hypermedia REST client.
196
153
  test_files:
197
- - spec/restify/collection_spec.rb
198
154
  - spec/restify/link_spec.rb
155
+ - spec/restify/processors/json_spec.rb
199
156
  - spec/restify/relation_spec.rb
200
157
  - spec/restify/resource_spec.rb
201
158
  - spec/restify_spec.rb
202
159
  - spec/spec_helper.rb
160
+ - spec/support/hack_causes.rb
@@ -1,15 +0,0 @@
1
- module Restify
2
- #
3
- class Collection < Array
4
- include Contextual
5
- include Relations
6
-
7
- def initialize(context, data = [])
8
- @context = context
9
-
10
- super data
11
-
12
- map! {|item| @context.inherit_value(item) }
13
- end
14
- end
15
- end
@@ -1,34 +0,0 @@
1
- require 'forwardable'
2
-
3
- module Restify
4
- module Contextual
5
- extend Forwardable
6
-
7
- # @!method relations
8
- #
9
- # Return hash of all relations.
10
- #
11
- # @return [Hashie::Mash] Relations.
12
- # @see Context#relations
13
- #
14
- delegate relations: :@context
15
-
16
- # @!method response
17
- #
18
- # Return response if available.
19
- #
20
- # @return [Response] Response object.
21
- # @see Context#response
22
- #
23
- delegate response: :@context
24
-
25
- # @!method follow
26
- #
27
- # Follow a LOCATION or CONTEXT-LOCATION header.
28
- #
29
- # @return [Relation] Relation to follow resource.
30
- # @see Context#follow
31
- #
32
- delegate follow: :@context
33
- end
34
- end
@@ -1,16 +0,0 @@
1
- module Restify
2
- #
3
- module Processors
4
- #
5
- # Decode JSON responses.
6
- class JSON
7
- def parse(str)
8
- MultiJSON.load(str)
9
- end
10
-
11
- def format
12
- :json
13
- end
14
- end
15
- end
16
- end
@@ -1,27 +0,0 @@
1
- module Restify
2
- #
3
- module Relations
4
- #
5
- # Check if resource has a relation with given name.
6
- #
7
- # @param name [String, Symbol] Relation name.
8
- # @return [Boolean] True if resource has relation, false otherwise.
9
- #
10
- def rel?(name)
11
- relations.key? name
12
- end
13
- alias_method :relation?, :rel?
14
- alias_method :has_rel?, :rel?
15
- alias_method :has_relation?, :rel?
16
-
17
- # Return relation with given name.
18
- #
19
- # @param name [String, Symbol] Relation name.
20
- # @return [Relation] Relation.
21
- #
22
- def rel(name)
23
- relations.fetch name
24
- end
25
- alias_method :relation, :rel
26
- end
27
- end
@@ -1,4 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Restify::Collection do
4
- end