frenetic 1.0.0.alpha.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +16 -0
  3. data/.gitignore +1 -1
  4. data/.irbrc +1 -1
  5. data/.rubocop.yml +45 -0
  6. data/.travis.yml +2 -2
  7. data/Appraisals +1 -1
  8. data/LICENSE +1 -1
  9. data/README.md +15 -15
  10. data/Rakefile +1 -1
  11. data/gemfiles/faraday_08.gemfile.lock +8 -8
  12. data/gemfiles/faraday_09.gemfile.lock +8 -8
  13. data/lib/frenetic.rb +13 -10
  14. data/lib/frenetic/briefly_memoizable.rb +9 -7
  15. data/lib/frenetic/concerns/collection_rest_methods.rb +4 -5
  16. data/lib/frenetic/concerns/hal_linked.rb +12 -9
  17. data/lib/frenetic/concerns/member_rest_methods.rb +7 -10
  18. data/lib/frenetic/concerns/structured.rb +2 -2
  19. data/lib/frenetic/connection.rb +25 -17
  20. data/lib/frenetic/errors.rb +67 -2
  21. data/lib/frenetic/hypermedia_link.rb +19 -26
  22. data/lib/frenetic/hypermedia_link_set.rb +11 -14
  23. data/lib/frenetic/middleware/hal_json.rb +3 -4
  24. data/lib/frenetic/resource.rb +31 -25
  25. data/lib/frenetic/resource_collection.rb +3 -3
  26. data/lib/frenetic/resource_mockery.rb +7 -5
  27. data/lib/frenetic/version.rb +2 -2
  28. data/spec/briefly_memoizable_spec.rb +1 -1
  29. data/spec/concerns/hal_linked_spec.rb +5 -5
  30. data/spec/concerns/member_rest_methods_spec.rb +1 -1
  31. data/spec/concerns/structured_spec.rb +6 -5
  32. data/spec/connection_spec.rb +16 -4
  33. data/spec/fixtures/test_api_requests.rb +32 -28
  34. data/spec/frenetic_spec.rb +3 -3
  35. data/spec/hypermedia_link_set_spec.rb +3 -3
  36. data/spec/hypermedia_link_spec.rb +1 -1
  37. data/spec/middleware/hal_json_spec.rb +3 -3
  38. data/spec/resource_collection_spec.rb +3 -4
  39. data/spec/resource_mockery_spec.rb +29 -6
  40. data/spec/resource_spec.rb +30 -13
  41. data/spec/spec_helper.rb +1 -1
  42. data/spec/support/i18n.rb +1 -0
  43. data/spec/support/rspec.rb +1 -1
  44. data/spec/support/timecop.rb +1 -1
  45. data/spec/support/webmock.rb +1 -1
  46. metadata +8 -4
@@ -6,7 +6,7 @@ class Frenetic
6
6
  include HalLinked
7
7
  include CollectionRestMethods
8
8
 
9
- def initialize( resource, params = {} )
9
+ def initialize(resource, params = {})
10
10
  @resource_class = resource
11
11
  @resources = []
12
12
  @params = params || {}
@@ -43,7 +43,7 @@ class Frenetic
43
43
  end
44
44
 
45
45
  def embedded_collection
46
- @params.fetch('_embedded',{}).fetch(collection_key, [])
46
+ @params.fetch('_embedded', {}).fetch(collection_key, [])
47
47
  end
48
48
  end
49
- end
49
+ end
@@ -1,6 +1,7 @@
1
1
  require 'ostruct'
2
2
  require 'delegate'
3
3
  require 'active_support/concern'
4
+ require 'active_support/core_ext/hash/deep_merge'
4
5
 
5
6
  class Frenetic
6
7
  module ResourceMockery
@@ -20,7 +21,7 @@ class Frenetic
20
21
  end
21
22
 
22
23
  def properties
23
- @params.each_with_object({}) do |(k,v), props|
24
+ @params.each_with_object({}) do |(k, v), props|
24
25
  props[k] = v.class.to_s.underscore
25
26
  end
26
27
  end
@@ -43,13 +44,14 @@ class Frenetic
43
44
 
44
45
  private
45
46
 
46
- def build_params( p )
47
+ def build_params(params)
48
+ raw_params = (params || {}).with_indifferent_access
47
49
  defaults = default_attributes.with_indifferent_access
48
- @params = defaults.merge( (p || {}).with_indifferent_access )
50
+ @params = defaults.deep_merge(raw_params)
49
51
  end
50
52
 
51
53
  def build_structure
52
- @structure = OpenStruct.new( @attrs )
54
+ @structure = OpenStruct.new(@attrs)
53
55
  end
54
56
  end
55
- end
57
+ end
@@ -1,3 +1,3 @@
1
1
  class Frenetic
2
- VERSION = '1.0.0.alpha.1'
3
- end
2
+ VERSION = '1.0.0'
3
+ end
@@ -58,4 +58,4 @@ describe Frenetic::BrieflyMemoizable do
58
58
  end
59
59
  end
60
60
  end
61
- end
61
+ end
@@ -21,7 +21,7 @@ describe Frenetic::HalLinked do
21
21
 
22
22
  let(:_links) do
23
23
  {
24
- '_links' => { 'self' => { 'href' => '/api/self' }}
24
+ '_links' => { 'self' => { 'href' => '/api/self' } }
25
25
  }
26
26
  end
27
27
 
@@ -65,7 +65,7 @@ describe Frenetic::HalLinked do
65
65
  context 'with an implied self link' do
66
66
  let(:_links) do
67
67
  {
68
- '_links' => { 'self' => { 'href' => '/api/self' }}
68
+ '_links' => { 'self' => { 'href' => '/api/self' } }
69
69
  }
70
70
  end
71
71
 
@@ -92,7 +92,7 @@ describe Frenetic::HalLinked do
92
92
 
93
93
  it 'processes the link' do
94
94
  expect_any_instance_of(Frenetic::HypermediaLinkSet)
95
- .to receive(:href).with( params ).and_call_original
95
+ .to receive(:href).with(params).and_call_original
96
96
  subject
97
97
  end
98
98
  end
@@ -106,7 +106,7 @@ describe Frenetic::HalLinked do
106
106
  before do
107
107
  allow(MyTempResource)
108
108
  .to receive(:namespace)
109
- .and_return(Time.now.to_i.to_s)
109
+ .and_return(Time.now.to_i.to_s)
110
110
  end
111
111
 
112
112
  it 'raises an error' do
@@ -122,4 +122,4 @@ describe Frenetic::HalLinked do
122
122
  end
123
123
  end
124
124
  end
125
- end
125
+ end
@@ -84,4 +84,4 @@ describe Frenetic::MemberRestMethods do
84
84
  end
85
85
  end
86
86
  end
87
- end
87
+ end
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Frenetic::Structured do
4
4
  let(:my_temp_resource) do
5
5
  Class.new do
6
- def initialize( attrs = {} )
6
+ def initialize(attrs = {})
7
7
  @attrs = attrs
8
8
  end
9
9
  end
@@ -24,7 +24,7 @@ describe Frenetic::Structured do
24
24
 
25
25
  after { instance.destroy_structure! }
26
26
 
27
- subject(:instance) { MyTempResource.new( foo:'foo', bar:'bar' ) }
27
+ subject(:instance) { MyTempResource.new(foo:'foo', bar:'bar') }
28
28
 
29
29
  describe '#struct_key' do
30
30
  subject { super().struct_key }
@@ -121,9 +121,10 @@ describe Frenetic::Structured do
121
121
 
122
122
  before do
123
123
  allow(instance).to receive(:signature).and_return(new_sig)
124
- described_class.class_variable_set '@@signatures', {
124
+ described_class.class_variable_set(
125
+ '@@signatures',
125
126
  'MyTempResourceFreneticResourceStruct' => old_sig
126
- }
127
+ )
127
128
  end
128
129
 
129
130
  context 'with a fresh signature' do
@@ -206,4 +207,4 @@ describe Frenetic::Structured do
206
207
  end
207
208
  end
208
209
  end
209
- end
210
+ end
@@ -18,7 +18,7 @@ describe Frenetic::Connection do
18
18
  let(:url) { nil }
19
19
 
20
20
  it 'raises an error' do
21
- expect{subject}.to raise_error Frenetic::ConfigError, %r{Url must be present}
21
+ expect{subject}.to raise_error Frenetic::ConfigError, /Url must be present/
22
22
  end
23
23
  end
24
24
 
@@ -42,8 +42,20 @@ describe Frenetic::Connection do
42
42
  expect(subject[1]).to include :url
43
43
  end
44
44
 
45
- it 'converts URLs to URIs' do
46
- expect(subject[1]).to include url:kind_of(Addressable::URI)
45
+ context 'with specific port' do
46
+ let(:url) { 'https://example.com:8443' }
47
+ it 'converts URLs to URIs' do
48
+ expect(subject[1]).to include url:kind_of(Addressable::URI)
49
+ expect(subject[1][:url].port).to eq(8443)
50
+ end
51
+ end
52
+
53
+ context 'with no specific port' do
54
+ let(:url) { 'https://example.com' }
55
+ it 'converts URLs to URIs with port inferred from scheme' do
56
+ expect(subject[1]).to include url:kind_of(Addressable::URI)
57
+ expect(subject[1][:url].port).to eq(443)
58
+ end
47
59
  end
48
60
  end
49
61
 
@@ -134,4 +146,4 @@ describe Frenetic::Connection do
134
146
  expect(builder).to have_received(:adapter).with(:patron)
135
147
  end
136
148
  end
137
- end
149
+ end
@@ -1,78 +1,81 @@
1
1
  require 'json'
2
2
 
3
3
  class HttpStubs
4
- def initialize( rspec )
4
+ def initialize(rspec)
5
5
  @rspec = rspec
6
6
  end
7
7
 
8
8
  def defaults
9
9
  {
10
10
  status: 200,
11
- headers: { 'Content-Type'=>'application/json' },
11
+ headers: { 'Content-Type' => 'application/json' },
12
12
  body: {}
13
13
  }
14
14
  end
15
15
 
16
- def response( params = {} )
17
- defs = defaults.dup
16
+ def response(params = {})
17
+ defs = defaults.dup
18
18
  headers = params.delete :headers
19
19
 
20
20
  defs[:headers].merge! headers || {}
21
21
 
22
- defs.merge( params ).tap do |p|
22
+ defs.merge(params).tap do |p|
23
23
  p[:body] = p[:body].to_json
24
24
  end
25
25
  end
26
26
 
27
27
  def api_html_response
28
- @rspec.stub_request( :any, 'example.com/api' )
29
- .to_return response( body:'Non-JSON response', status:200 )
28
+ @rspec.stub_request(:any, 'example.com/api')
29
+ .to_return response(body:'Non-JSON response', status:200)
30
30
  end
31
31
 
32
- def api_server_error( type = :json )
32
+ def api_server_error(type = :json)
33
33
  body = '500 Server Error'
34
34
 
35
35
  body = { 'error' => body }.to_json if type == :json
36
36
 
37
- @rspec.stub_request( :any, 'example.com/api' )
38
- .to_return response( body:body, status:500 )
37
+ @rspec.stub_request(:any, 'example.com/api')
38
+ .to_return response(body:body, status:500)
39
39
  end
40
40
 
41
- def api_client_error( type = :json )
41
+ def api_client_error(type = :json)
42
42
  body = '404 Not Found'
43
43
 
44
44
  body = { 'error' => body }.to_json if type == :json
45
45
 
46
- @rspec.stub_request( :any, 'example.com/api' )
47
- .to_return defaults.merge( body:body, status:404 )
46
+ @rspec.stub_request(:any, 'example.com/api')
47
+ .to_return defaults.merge(body:body, status:404)
48
48
  end
49
49
 
50
50
  def api_description
51
- @rspec.stub_request( :any, 'example.com/api' )
52
- .to_return response( body:schema, headers:{ 'Cache-Control' => 'max-age=3600, public' } )
51
+ @rspec.stub_request(:any, 'example.com/api')
52
+ .to_return response(body:schema, headers:{ 'Cache-Control' => 'max-age=3600, public' })
53
53
  end
54
54
 
55
55
  def unknown_instance
56
- @rspec.stub_request( :get, 'example.com/api/my_temp_resources/1' )
57
- .to_return response( body:{ 'error' => '404 Not Found' }, status:404 )
56
+ @rspec.stub_request(:get, 'example.com/api/my_temp_resources/1')
57
+ .to_return response(body:{ 'error' => '404 Not Found' }, status:404)
58
58
  end
59
59
 
60
60
  def known_instance
61
- @rspec.stub_request( :get, 'example.com/api/my_temp_resources/1' )
62
- .to_return response( body:{ 'name' => 'Resource Name' } )
61
+ @rspec.stub_request(:get, 'example.com/api/my_temp_resources/1')
62
+ .to_return response(body:{ 'name' => 'Resource Name' })
63
63
  end
64
64
 
65
65
  def known_resource
66
- @rspec.stub_request( :get, 'example.com/api/my_temp_resources' )
67
- .to_return response( body:{
68
- '_embedded' => {
69
- 'my_temp_resources' => [
70
- { 'name' => 'Resource Name' }
71
- ]
66
+ @rspec.stub_request(:get, 'example.com/api/my_temp_resources')
67
+ .to_return response(
68
+ body: {
69
+ '_embedded' => {
70
+ 'my_temp_resources' => [
71
+ { 'name' => 'Resource Name' }
72
+ ]
73
+ }
72
74
  }
73
- } )
75
+ )
74
76
  end
75
77
 
78
+ # rubocop:disable Metrics/MethodLength
76
79
  def schema
77
80
  {
78
81
  _embedded: {
@@ -110,10 +113,11 @@ class HttpStubs
110
113
  }
111
114
  }
112
115
  end
116
+ # rubocop:enable Metrics/MethodLength
113
117
  end
114
118
 
115
119
  RSpec.configure do |c|
116
120
  c.before :all do
117
- @stubs = HttpStubs.new( self )
121
+ @stubs = HttpStubs.new(self)
118
122
  end
119
- end
123
+ end
@@ -17,7 +17,7 @@ describe Frenetic do
17
17
  expect(subject).to include headers:kind_of(Hash)
18
18
  expect(subject).to include middleware:[]
19
19
  expect(subject).to include :password
20
- expect(subject).to include ssl:{verify:true}
20
+ expect(subject).to include ssl:{ verify:true }
21
21
  expect(subject).to include test_mode:false
22
22
  expect(subject).to include :url
23
23
  expect(subject).to include :username
@@ -37,7 +37,7 @@ describe Frenetic do
37
37
  end
38
38
 
39
39
  describe '#configure' do
40
- subject { instance.configure {|c| } }
40
+ subject { instance.configure {|c| c } }
41
41
 
42
42
  it 'resets the Connection' do
43
43
  prev_connection = instance.connection
@@ -240,4 +240,4 @@ describe Frenetic do
240
240
  # expect(instance.connection).to have_received(:delete)
241
241
  # end
242
242
  # end
243
- end
243
+ end
@@ -93,7 +93,7 @@ describe Frenetic::HypermediaLinkSet do
93
93
 
94
94
  context 'with multiple matching links' do
95
95
  let(:link_a) do
96
- Frenetic::HypermediaLink.new( href:'/foo/{id}', templated:true )
96
+ Frenetic::HypermediaLink.new(href:'/foo/{id}', templated:true)
97
97
  end
98
98
 
99
99
  let(:links) do
@@ -126,7 +126,7 @@ describe Frenetic::HypermediaLinkSet do
126
126
  subject { super()[rel] }
127
127
 
128
128
  let(:link_b) do
129
- Frenetic::HypermediaLink.new( href:'/bar', rel:'bar' )
129
+ Frenetic::HypermediaLink.new(href:'/bar', rel:'bar')
130
130
  end
131
131
 
132
132
  let(:links) do
@@ -152,4 +152,4 @@ describe Frenetic::HypermediaLinkSet do
152
152
  end
153
153
  end
154
154
  end
155
- end
155
+ end
@@ -150,4 +150,4 @@ describe Frenetic::HypermediaLink do
150
150
  expect(subject).to eq 'foo'
151
151
  end
152
152
  end
153
- end
153
+ end
@@ -16,9 +16,9 @@ describe Frenetic::Middleware::HalJson do
16
16
  let(:options) { Hash.new }
17
17
  let(:headers) { Hash.new }
18
18
  let(:middleware) do
19
- described_class.new(lambda {|env|
19
+ described_class.new(lambda do |env|
20
20
  Faraday::Response.new(env)
21
- }, options)
21
+ end, options)
22
22
  end
23
23
 
24
24
  it 'does not change nil body' do
@@ -78,4 +78,4 @@ describe Frenetic::Middleware::HalJson do
78
78
  end
79
79
  end
80
80
  end
81
- end
81
+ end
@@ -17,11 +17,10 @@ describe Frenetic::ResourceCollection do
17
17
 
18
18
  before do
19
19
  stub_const 'MyTempResource', my_temp_resource
20
-
21
20
  @stubs.api_description
22
21
  end
23
22
 
24
- let(:collection_response) {
23
+ let(:collection_response) do
25
24
  {
26
25
  '_embedded' => {
27
26
  'my_temp_resources' => [
@@ -39,7 +38,7 @@ describe Frenetic::ResourceCollection do
39
38
  }
40
39
  }
41
40
  }
42
- }
41
+ end
43
42
 
44
43
  subject(:instance) { described_class.new(MyTempResource, collection_response) }
45
44
 
@@ -84,4 +83,4 @@ describe Frenetic::ResourceCollection do
84
83
  expect(subject).to be_an_instance_of MyTempResource
85
84
  end
86
85
  end
87
- end
86
+ end
@@ -10,18 +10,38 @@ describe Frenetic::ResourceMockery do
10
10
  let(:my_mocked_resource) do
11
11
  Class.new(my_temp_resource) do
12
12
  def self.default_attributes
13
- { qux:'qux' }
13
+ {
14
+ qux: 'qux',
15
+ _embedded: {
16
+ embedded_resource: {
17
+ plugh: 'xyzzy'
18
+ }
19
+ }
20
+ }
14
21
  end
15
22
  end
16
23
  end
17
24
 
25
+ let(:params) do
26
+ {
27
+ foo: 1,
28
+ bar: 'baz',
29
+ _embedded: {
30
+ embedded_resource: {
31
+ grault: 'garply'
32
+ },
33
+ another_resource: {
34
+ waldo: 'fred'
35
+ }
36
+ }
37
+ }
38
+ end
39
+
18
40
  before do
19
41
  stub_const 'MyNamespace::MyMockedResource', my_mocked_resource
20
42
  MyNamespace::MyMockedResource.send :include, described_class
21
43
  end
22
44
 
23
- let(:params) { { foo:1, bar:'baz' } }
24
-
25
45
  subject { MyNamespace::MyMockedResource.new params }
26
46
 
27
47
  it 'violates some basic CS principles by telling the parent-class of its existence' do
@@ -44,6 +64,9 @@ describe Frenetic::ResourceMockery do
44
64
  expect(subject).to include 'foo' => 1
45
65
  expect(subject).to include 'bar' => 'baz'
46
66
  expect(subject).to include 'qux' => 'qux'
67
+ expect(subject['_embedded']['embedded_resource']).to include 'plugh' => 'xyzzy'
68
+ expect(subject['_embedded']['embedded_resource']).to include 'grault' => 'garply'
69
+ expect(subject['_embedded']['another_resource']).to include 'waldo' => 'fred'
47
70
  end
48
71
  end
49
72
 
@@ -53,7 +76,7 @@ describe Frenetic::ResourceMockery do
53
76
  subject { MyNamespace::MyMockedResource.default_attributes }
54
77
 
55
78
  it 'allows implementors to specify sane defaults' do
56
- expect(subject).to eq Hash.new
79
+ expect(subject).to eq({})
57
80
  end
58
81
  end
59
82
 
@@ -63,7 +86,7 @@ describe Frenetic::ResourceMockery do
63
86
  subject { MyNamespace::MyMockedResource.new.default_attributes }
64
87
 
65
88
  it 'proxies to the class method' do
66
- expect(subject).to eq Hash.new
89
+ expect(subject).to eq({})
67
90
  end
68
91
  end
69
- end
92
+ end