frenetic 0.0.20.alpha.3 → 0.0.20.alpha.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -340,6 +340,19 @@ the schema has changed. If so, it will redefine the the getter methods available
340
340
  on your Class. This is what Hypermedia APIs are all about, a loose coupling
341
341
  between client and server.
342
342
 
343
+ #### Requesting Resources
344
+
345
+ Given the above `Order` example, and a supporting API, you can query the API
346
+ like so:
347
+
348
+ ```ruby
349
+ > Order.find(1)
350
+ # <Order id=1 total=54.47>
351
+
352
+ > Order.all
353
+ # [<Order id=1 total=54.47>,<Order id=2 total=42.00>]
354
+ ```
355
+
343
356
  #### Mocking Resources
344
357
 
345
358
  Sometimes, when you are writing tests for your API client, it is helpful to have
@@ -23,6 +23,10 @@ module BrieflyMemoizable
23
23
  #
24
24
  #{memoized_ivar} ||= #{original_method}(*args) # @mime_type ||= _unmemoized_mime_type(*args)
25
25
  end # end
26
+
27
+ def reload_#{symbol}! # def reload_mime_type!
28
+ #{memoized_ivar} = nil # @mime_type = nil
29
+ end # end
26
30
  EOS
27
31
  end
28
32
  end
@@ -28,6 +28,12 @@ class Frenetic
28
28
  parse_link link, params
29
29
  end
30
30
 
31
+ def collection_url
32
+ link = links[namespace.pluralize] or raise HypermediaError, %Q{No Hypermedia GET Url found for the resource "#{namespace.pluralize}"}
33
+
34
+ link['href']
35
+ end
36
+
31
37
  def parse_link( link, params = {} )
32
38
  if link['templated']
33
39
  expand_link link, params
@@ -5,11 +5,19 @@ class Frenetic
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  module ClassMethods
8
- def find( id = nil )
9
- if response = api.get( member_url(id) ) and response.success?
8
+ def find( params = {} )
9
+ params = { id:params } unless params.is_a? Hash
10
+
11
+ if response = api.get( member_url(params) ) and response.success?
10
12
  new response.body
11
13
  end
12
14
  end
15
+
16
+ def all
17
+ if response = api.get( collection_url ) and response.success?
18
+ Frenetic::ResourceCollection.new self, response.body
19
+ end
20
+ end
13
21
  end
14
22
  end
15
23
  end
@@ -31,6 +31,7 @@ class Frenetic
31
31
  default_root_cache_age: default_root_cache_age,
32
32
  headers: headers,
33
33
  password: password,
34
+ ssl: ssl,
34
35
  url: url,
35
36
  username: username
36
37
  }
@@ -66,6 +67,10 @@ class Frenetic
66
67
  @_cfg[:password] || @_cfg[:api_key]
67
68
  end
68
69
 
70
+ def ssl
71
+ @_cfg[:ssl] || { verify:true }
72
+ end
73
+
69
74
  def url
70
75
  Addressable::URI.parse @_cfg[:url]
71
76
  end
@@ -13,7 +13,13 @@ class Frenetic
13
13
  raise ClientError, env[:body]['error']
14
14
  end
15
15
  rescue Faraday::Error::ParsingError => err
16
- raise ParsingError, err.message
16
+ if (500...599).include? env[:status]
17
+ raise ServerError, "#{env[:status]} Error encountered"
18
+ elsif (400...499).include? env[:status]
19
+ raise ClientError, "#{env[:status]} Error encountered"
20
+ else
21
+ raise ParsingError, err.message
22
+ end
17
23
  end
18
24
 
19
25
  end
@@ -69,8 +69,10 @@ class Frenetic
69
69
  @structure
70
70
  end
71
71
 
72
- def __setobj__
73
- @structure
72
+ def __setobj__( obj )
73
+ @attributes = nil
74
+
75
+ @structure = obj
74
76
  end
75
77
 
76
78
  def inspect
@@ -9,7 +9,7 @@ class Frenetic
9
9
  def initialize( resource, params = {} )
10
10
  @resource_class = resource
11
11
  @resources = []
12
- @params = params
12
+ @params = params || {}
13
13
 
14
14
  extract_resources!
15
15
  end
@@ -37,10 +37,14 @@ class Frenetic
37
37
  private
38
38
 
39
39
  def extract_resources!
40
- @resources = @params['_embedded'][collection_key].collect do |resource|
40
+ @resources = embedded_collection.collect do |resource|
41
41
  @resource_class.new resource
42
42
  end
43
43
  end
44
44
 
45
+ def embedded_collection
46
+ @params.fetch('_embedded',{}).fetch(collection_key, [])
47
+ end
48
+
45
49
  end
46
50
  end
@@ -1,3 +1,3 @@
1
1
  class Frenetic
2
- VERSION = '0.0.20.alpha.3'
2
+ VERSION = '0.0.20.alpha.4'
3
3
  end
@@ -53,6 +53,16 @@ describe BrieflyMemoizable do
53
53
 
54
54
  instance.fetch
55
55
  end
56
+
57
+ context 'after it has been reloaded' do
58
+ before { instance.reload_fetch! }
59
+
60
+ it 'should be called' do
61
+ instance.should_receive(:external_call).once.and_call_original
62
+
63
+ instance.fetch
64
+ end
65
+ end
56
66
  end
57
67
  end
58
68
  end
@@ -38,16 +38,16 @@ describe Frenetic::HalLinked do
38
38
 
39
39
  subject { MyTempResource.new(_links).member_url }
40
40
 
41
- let(:_links) do
42
- {
43
- '_links' => {
44
- 'self' => { 'href' => '/api/self' },
45
- 'my_temp_resource' => {
46
- 'href' => '/api/my_temp_resource/{id}', 'templated' => true
47
- }
41
+ let(:_links) do
42
+ {
43
+ '_links' => {
44
+ 'self' => { 'href' => '/api/self' },
45
+ 'my_temp_resource' => {
46
+ 'href' => '/api/my_temp_resource/{id}', 'templated' => true
48
47
  }
49
48
  }
50
- end
49
+ }
50
+ end
51
51
 
52
52
  context 'with a link that matches the resource name' do
53
53
  it 'should return the named link' do
@@ -113,4 +113,26 @@ describe Frenetic::HalLinked do
113
113
  end
114
114
  end
115
115
  end
116
+
117
+ describe '.collection_url' do
118
+ subject { MyTempResource.collection_url }
119
+
120
+ before { @stubs.api_description }
121
+
122
+ context 'for an unknown resource' do
123
+ before do
124
+ MyTempResource.stub(:namespace).and_return Time.now.to_i.to_s
125
+ end
126
+
127
+ it 'should raise an error' do
128
+ expect{ subject }.to raise_error Frenetic::HypermediaError
129
+ end
130
+ end
131
+
132
+ context 'with a non-templated URL' do
133
+ it 'simply return the URL' do
134
+ subject.should == '/api/my_temp_resources'
135
+ end
136
+ end
137
+ end
116
138
  end
@@ -23,19 +23,45 @@ describe Frenetic::MemberRestMethods do
23
23
  subject { MyTempResource.find 1 }
24
24
 
25
25
  context 'for a known instance' do
26
- before { @stubs.known_resource }
26
+ before { @stubs.known_instance }
27
27
 
28
28
  it 'should return the instance' do
29
29
  expect(subject).to be_a MyTempResource
30
30
  end
31
+
32
+ context 'and a Hash argument' do
33
+ subject { MyTempResource.find id:1 }
34
+
35
+ it 'should return the instance' do
36
+ expect(subject).to be_a MyTempResource
37
+ end
38
+ end
31
39
  end
32
40
 
33
41
  context 'for an unknown instance' do
34
- before { @stubs.unknown_resource }
42
+ before { @stubs.unknown_instance }
35
43
 
36
44
  it 'should raise an error' do
37
45
  expect{ subject }.to raise_error Frenetic::ClientError
38
46
  end
39
47
  end
40
48
  end
49
+
50
+ describe '.all' do
51
+ before { @stubs.api_description }
52
+
53
+ subject { MyTempResource.all }
54
+
55
+ context 'for a known resource' do
56
+ before { @stubs.known_resource }
57
+
58
+ it 'should return a resource collection' do
59
+ expect(subject).to be_an_instance_of Frenetic::ResourceCollection
60
+ end
61
+
62
+ it 'should instantiate all resources in the collection' do
63
+ expect(subject.first).to be_an_instance_of MyTempResource
64
+ end
65
+ end
66
+ end
41
67
  end
@@ -18,6 +18,7 @@ describe Frenetic::Configuration do
18
18
  it { should include :default_root_cache_age }
19
19
  it { should include :headers }
20
20
  it { should include :password }
21
+ it { should include :ssl }
21
22
  it { should include :url }
22
23
  it { should include :username }
23
24
  end
@@ -94,6 +95,12 @@ describe Frenetic::Configuration do
94
95
  end
95
96
  end
96
97
 
98
+ describe '#ssl' do
99
+ subject { instance.ssl }
100
+
101
+ it { should include verify:true }
102
+ end
103
+
97
104
  describe '#url' do
98
105
  let(:cfg) do
99
106
  { url:'http://example.org' }
@@ -25,9 +25,18 @@ class HttpStubs
25
25
  end
26
26
  end
27
27
 
28
- def api_server_error
28
+ def api_html_response
29
29
  @rspec.stub_request( :any, 'example.com/api' )
30
- .to_return response( body:{error:'500 Server Error'}, status:500 )
30
+ .to_return response( body:'Non-JSON response', status:200 )
31
+ end
32
+
33
+ def api_server_error( type = :json )
34
+ body = '500 Server Error'
35
+
36
+ body = { 'error' => body }.to_json if type == :json
37
+
38
+ @rspec.stub_request( :any, 'example.com/api' )
39
+ .to_return response( body:body, status:500 )
31
40
  end
32
41
 
33
42
  def api_client_error( type = :json )
@@ -44,16 +53,27 @@ class HttpStubs
44
53
  .to_return response( body:schema, headers:{ 'Cache-Control' => 'max-age=3600, public' } )
45
54
  end
46
55
 
47
- def unknown_resource
56
+ def unknown_instance
48
57
  @rspec.stub_request( :get, 'example.com/api/my_temp_resources/1' )
49
58
  .to_return response( body:{ 'error' => '404 Not Found' }, status:404 )
50
59
  end
51
60
 
52
- def known_resource
61
+ def known_instance
53
62
  @rspec.stub_request( :get, 'example.com/api/my_temp_resources/1' )
54
63
  .to_return response( body:{ 'name' => 'Resource Name' } )
55
64
  end
56
65
 
66
+ def known_resource
67
+ @rspec.stub_request( :get, 'example.com/api/my_temp_resources' )
68
+ .to_return response( body:{
69
+ '_embedded' => {
70
+ 'my_temp_resources' => [
71
+ { 'name' => 'Resource Name' }
72
+ ]
73
+ }
74
+ } )
75
+ end
76
+
57
77
  def schema
58
78
  {
59
79
  _embedded: {
@@ -78,10 +78,28 @@ describe Frenetic do
78
78
  end
79
79
 
80
80
  context 'JSON parsing error' do
81
- before { @stubs.api_client_error :text }
81
+ context 'for an otherwise successful response' do
82
+ before { @stubs.api_html_response }
82
83
 
83
- it 'should raise an error' do
84
- expect{ subject }.to raise_error Frenetic::ParsingError
84
+ it 'should raise an error' do
85
+ expect{ subject }.to raise_error Frenetic::ParsingError
86
+ end
87
+ end
88
+
89
+ context 'for a server error' do
90
+ before { @stubs.api_server_error :text }
91
+
92
+ it 'should raise an error' do
93
+ expect{ subject }.to raise_error Frenetic::ServerError, '500 Error encountered'
94
+ end
95
+ end
96
+
97
+ context 'for a client error' do
98
+ before { @stubs.api_client_error :text }
99
+
100
+ it 'should raise an error' do
101
+ expect{ subject }.to raise_error Frenetic::ClientError, '404 Error encountered'
102
+ end
85
103
  end
86
104
  end
87
105
  end
@@ -67,8 +67,14 @@ describe Frenetic::ResourceCollection do
67
67
  subject.links.should_not be_empty
68
68
  end
69
69
 
70
+ context 'for a non-embedded resource' do
71
+ subject { described_class.new(MyTempResource) }
72
+
73
+ it { should be_empty }
74
+ end
75
+
70
76
  describe '#get' do
71
- before { @stubs.known_resource }
77
+ before { @stubs.known_instance }
72
78
 
73
79
  subject { super().get(1) }
74
80
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frenetic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.20.alpha.3
4
+ version: 0.0.20.alpha.4
5
5
  prerelease: 7
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-05-14 00:00:00.000000000 Z
12
+ date: 2013-05-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -215,7 +215,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
215
215
  version: '0'
216
216
  segments:
217
217
  - 0
218
- hash: -3162981887620573122
218
+ hash: -3576003086095464905
219
219
  required_rubygems_version: !ruby/object:Gem::Requirement
220
220
  none: false
221
221
  requirements: