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

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.
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: