frenetic 1.0.0.alpha.1 → 1.0.0

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