restify 0.3.2.1.b59 → 0.3.2.1.b62

Sign up to get free protection for your applications and to get access to all the features.
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