her 0.8.2 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/.rubocop.yml +1291 -0
  4. data/.travis.yml +2 -0
  5. data/README.md +23 -3
  6. data/her.gemspec +1 -3
  7. data/lib/her/middleware/json_api_parser.rb +1 -1
  8. data/lib/her/model/associations/association.rb +31 -0
  9. data/lib/her/model/associations/association_proxy.rb +1 -1
  10. data/lib/her/model/attributes.rb +2 -0
  11. data/lib/her/model/orm.rb +79 -6
  12. data/lib/her/model/parse.rb +8 -12
  13. data/lib/her/model/relation.rb +45 -1
  14. data/lib/her/version.rb +1 -1
  15. data/spec/api_spec.rb +34 -31
  16. data/spec/collection_spec.rb +25 -10
  17. data/spec/json_api/model_spec.rb +75 -72
  18. data/spec/middleware/accept_json_spec.rb +1 -1
  19. data/spec/middleware/first_level_parse_json_spec.rb +20 -20
  20. data/spec/middleware/json_api_parser_spec.rb +26 -7
  21. data/spec/middleware/second_level_parse_json_spec.rb +8 -9
  22. data/spec/model/associations/association_proxy_spec.rb +2 -5
  23. data/spec/model/associations_spec.rb +248 -161
  24. data/spec/model/attributes_spec.rb +106 -99
  25. data/spec/model/callbacks_spec.rb +58 -26
  26. data/spec/model/dirty_spec.rb +30 -29
  27. data/spec/model/http_spec.rb +67 -35
  28. data/spec/model/introspection_spec.rb +26 -22
  29. data/spec/model/nested_attributes_spec.rb +31 -31
  30. data/spec/model/orm_spec.rb +312 -155
  31. data/spec/model/parse_spec.rb +77 -77
  32. data/spec/model/paths_spec.rb +109 -109
  33. data/spec/model/relation_spec.rb +76 -68
  34. data/spec/model/validations_spec.rb +6 -6
  35. data/spec/model_spec.rb +17 -17
  36. data/spec/spec_helper.rb +2 -3
  37. data/spec/support/macros/model_macros.rb +2 -2
  38. metadata +32 -59
@@ -1,163 +1,166 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe Her::JsonApi::Model do
4
4
  before do
5
- Her::API.setup :url => "https://api.example.com" do |connection|
5
+ Her::API.setup url: "https://api.example.com" do |connection|
6
6
  connection.use Her::Middleware::JsonApiParser
7
7
  connection.adapter :test do |stub|
8
- stub.get("/users/1") do |env|
9
- [
8
+ stub.get("/users/1") do
9
+ [
10
10
  200,
11
11
  {},
12
12
  {
13
13
  data: {
14
14
  id: 1,
15
- type: 'users',
15
+ type: "users",
16
16
  attributes: {
17
- name: "Roger Federer",
18
- },
17
+ name: "Roger Federer"
18
+ }
19
19
  }
20
-
20
+
21
21
  }.to_json
22
- ]
22
+ ]
23
23
  end
24
24
 
25
- stub.get("/users") do |env|
26
- [
25
+ stub.get("/users") do
26
+ [
27
27
  200,
28
28
  {},
29
29
  {
30
30
  data: [
31
31
  {
32
32
  id: 1,
33
- type: 'users',
33
+ type: "users",
34
34
  attributes: {
35
- name: "Roger Federer",
36
- },
37
- },
35
+ name: "Roger Federer"
36
+ }
37
+ },
38
38
  {
39
39
  id: 2,
40
- type: 'users',
40
+ type: "users",
41
41
  attributes: {
42
- name: "Kei Nishikori",
43
- },
42
+ name: "Kei Nishikori"
43
+ }
44
44
  }
45
45
  ]
46
46
  }.to_json
47
- ]
47
+ ]
48
48
  end
49
49
 
50
- stub.post("/users", data: {
51
- type: 'users',
50
+ stub.post("/users", data:
51
+ {
52
+ type: "users",
52
53
  attributes: {
53
- name: "Jeremy Lin",
54
- },
55
- }) do |env|
56
- [
54
+ name: "Jeremy Lin"
55
+ }
56
+ }) do
57
+ [
57
58
  201,
58
59
  {},
59
60
  {
60
61
  data: {
61
62
  id: 3,
62
- type: 'users',
63
+ type: "users",
63
64
  attributes: {
64
- name: 'Jeremy Lin',
65
- },
65
+ name: "Jeremy Lin"
66
+ }
66
67
  }
67
-
68
+
68
69
  }.to_json
69
- ]
70
+ ]
70
71
  end
71
72
 
72
- stub.patch("/users/1", data: {
73
- type: 'users',
73
+ stub.patch("/users/1", data:
74
+ {
75
+ type: "users",
74
76
  id: 1,
75
77
  attributes: {
76
- name: "Fed GOAT",
77
- },
78
- }) do |env|
79
- [
78
+ name: "Fed GOAT"
79
+ }
80
+ }) do
81
+ [
80
82
  200,
81
83
  {},
82
84
  {
83
85
  data: {
84
86
  id: 1,
85
- type: 'users',
87
+ type: "users",
86
88
  attributes: {
87
- name: 'Fed GOAT',
88
- },
89
+ name: "Fed GOAT"
90
+ }
89
91
  }
90
-
92
+
91
93
  }.to_json
92
- ]
94
+ ]
93
95
  end
94
96
 
95
- stub.delete("/users/1") { |env|
96
- [ 204, {}, {}, ]
97
- }
97
+ stub.delete("/users/1") do
98
+ [204, {}, {}]
99
+ end
98
100
  end
99
-
100
101
  end
101
102
 
102
103
  spawn_model("Foo::User", type: Her::JsonApi::Model)
103
104
  end
104
105
 
105
- it 'allows configuration of type' do
106
+ it "allows configuration of type" do
106
107
  spawn_model("Foo::Bar", type: Her::JsonApi::Model) do
107
108
  type :foobars
108
109
  end
109
110
 
110
- expect(Foo::Bar.instance_variable_get('@type')).to eql('foobars')
111
+ expect(Foo::Bar.instance_variable_get("@type")).to eql("foobars")
111
112
  end
112
113
 
113
- it 'finds models by id' do
114
+ it "finds models by id" do
114
115
  user = Foo::User.find(1)
115
116
  expect(user.attributes).to eql(
116
- 'id' => 1,
117
- 'name' => 'Roger Federer',
117
+ "id" => 1,
118
+ "name" => "Roger Federer"
118
119
  )
119
120
  end
120
121
 
121
- it 'finds a collection of models' do
122
+ it "finds a collection of models" do
122
123
  users = Foo::User.all
123
- expect(users.map(&:attributes)).to match_array([
124
- {
125
- 'id' => 1,
126
- 'name' => 'Roger Federer',
127
- },
128
- {
129
- 'id' => 2,
130
- 'name' => 'Kei Nishikori',
131
- }
132
- ])
124
+ expect(users.map(&:attributes)).to match_array(
125
+ [
126
+ {
127
+ "id" => 1,
128
+ "name" => "Roger Federer"
129
+ },
130
+ {
131
+ "id" => 2,
132
+ "name" => "Kei Nishikori"
133
+ }
134
+ ]
135
+ )
133
136
  end
134
137
 
135
- it 'creates a Foo::User' do
136
- user = Foo::User.new(name: 'Jeremy Lin')
138
+ it "creates a Foo::User" do
139
+ user = Foo::User.new(name: "Jeremy Lin")
137
140
  user.save
138
141
  expect(user.attributes).to eql(
139
- 'id' => 3,
140
- 'name' => 'Jeremy Lin',
142
+ "id" => 3,
143
+ "name" => "Jeremy Lin"
141
144
  )
142
145
  end
143
146
 
144
- it 'updates a Foo::User' do
147
+ it "updates a Foo::User" do
145
148
  user = Foo::User.find(1)
146
- user.name = 'Fed GOAT'
149
+ user.name = "Fed GOAT"
147
150
  user.save
148
151
  expect(user.attributes).to eql(
149
- 'id' => 1,
150
- 'name' => 'Fed GOAT',
152
+ "id" => 1,
153
+ "name" => "Fed GOAT"
151
154
  )
152
155
  end
153
156
 
154
- it 'destroys a Foo::User' do
157
+ it "destroys a Foo::User" do
155
158
  user = Foo::User.find(1)
156
159
  expect(user.destroy).to be_destroyed
157
160
  end
158
161
 
159
- context 'undefined methods' do
160
- it 'removes methods that are not compatible with json api' do
162
+ context "undefined methods" do
163
+ it "removes methods that are not compatible with json api" do
161
164
  [:parse_root_in_json, :include_root_in_json, :root_element, :primary_key].each do |method|
162
165
  expect { Foo::User.new.send(method, :foo) }.to raise_error NoMethodError, "Her::JsonApi::Model does not support the #{method} configuration option"
163
166
  end
@@ -4,7 +4,7 @@ require "spec_helper"
4
4
  describe Her::Middleware::AcceptJSON do
5
5
  it "adds an Accept header" do
6
6
  described_class.new.add_header({}).tap do |headers|
7
- headers["Accept"].should == "application/json"
7
+ expect(headers["Accept"]).to eq("application/json")
8
8
  end
9
9
  end
10
10
  end
@@ -7,55 +7,55 @@ describe Her::Middleware::FirstLevelParseJSON do
7
7
  let(:body_with_errors) { "{\"id\": 1, \"name\": \"Tobias Fünke\", \"errors\": { \"name\": [ \"not_valid\", \"should_be_present\" ] }, \"metadata\": 3}" }
8
8
  let(:body_with_malformed_json) { "wut." }
9
9
  let(:body_with_invalid_json) { "true" }
10
- let(:empty_body) { '' }
10
+ let(:empty_body) { "" }
11
11
  let(:nil_body) { nil }
12
12
 
13
13
  it "parses body as json" do
14
14
  subject.parse(body_without_errors).tap do |json|
15
- json[:data].should == { :id => 1, :name => "Tobias Fünke" }
16
- json[:metadata].should == 3
15
+ expect(json[:data]).to eq(id: 1, name: "Tobias Fünke")
16
+ expect(json[:metadata]).to eq(3)
17
17
  end
18
18
  end
19
19
 
20
20
  it "parses :body key as json in the env hash" do
21
- env = { :body => body_without_errors }
21
+ env = { body: body_without_errors }
22
22
  subject.on_complete(env)
23
23
  env[:body].tap do |json|
24
- json[:data].should == { :id => 1, :name => "Tobias Fünke" }
25
- json[:metadata].should == 3
24
+ expect(json[:data]).to eq(id: 1, name: "Tobias Fünke")
25
+ expect(json[:metadata]).to eq(3)
26
26
  end
27
27
  end
28
28
 
29
- it 'ensures the errors are a hash if there are no errors' do
30
- subject.parse(body_without_errors)[:errors].should eq({})
29
+ it "ensures the errors are a hash if there are no errors" do
30
+ expect(subject.parse(body_without_errors)[:errors]).to eq({})
31
31
  end
32
32
 
33
- it 'ensures the errors are a hash if there are no errors' do
34
- subject.parse(body_with_errors)[:errors].should eq({:name => [ 'not_valid', 'should_be_present']})
33
+ it "ensures the errors are a hash if there are no errors" do
34
+ expect(subject.parse(body_with_errors)[:errors]).to eq(name: %w(not_valid should_be_present))
35
35
  end
36
36
 
37
- it 'ensures that malformed JSON throws an exception' do
37
+ it "ensures that malformed JSON throws an exception" do
38
38
  expect { subject.parse(body_with_malformed_json) }.to raise_error(Her::Errors::ParseError, 'Response from the API must behave like a Hash or an Array (last JSON response was "wut.")')
39
39
  end
40
40
 
41
- it 'ensures that invalid JSON throws an exception' do
41
+ it "ensures that invalid JSON throws an exception" do
42
42
  expect { subject.parse(body_with_invalid_json) }.to raise_error(Her::Errors::ParseError, 'Response from the API must behave like a Hash or an Array (last JSON response was "true")')
43
43
  end
44
44
 
45
- it 'ensures that a nil response returns an empty hash' do
46
- subject.parse(nil_body)[:data].should eq({})
45
+ it "ensures that a nil response returns an empty hash" do
46
+ expect(subject.parse(nil_body)[:data]).to eq({})
47
47
  end
48
48
 
49
- it 'ensures that an empty response returns an empty hash' do
50
- subject.parse(empty_body)[:data].should eq({})
49
+ it "ensures that an empty response returns an empty hash" do
50
+ expect(subject.parse(empty_body)[:data]).to eq({})
51
51
  end
52
52
 
53
- context 'with status code 204' do
54
- it 'returns an empty body' do
55
- env = { :status => 204 }
53
+ context "with status code 204" do
54
+ it "returns an empty body" do
55
+ env = { status: 204 }
56
56
  subject.on_complete(env)
57
57
  env[:body].tap do |json|
58
- json[:data].should == { }
58
+ expect(json[:data]).to eq({})
59
59
  end
60
60
  end
61
61
  end
@@ -12,21 +12,40 @@ describe Her::Middleware::JsonApiParser do
12
12
  subject.on_complete(env)
13
13
  env.fetch(:body).tap do |json|
14
14
  expect(json[:data]).to eql(
15
- :type => "foo",
16
- :id => "bar",
17
- :attributes => { :baz => "qux" }
15
+ type: "foo",
16
+ id: "bar",
17
+ attributes: { baz: "qux" }
18
18
  )
19
19
  expect(json[:errors]).to eql([])
20
- expect(json[:metadata]).to eql(:api => "json api")
20
+ expect(json[:metadata]).to eql(api: "json api")
21
21
  end
22
22
  end
23
23
  end
24
24
 
25
- #context "with invalid JSON body" do
25
+ context "with status code 204" do
26
+ it "returns an empty body" do
27
+ env = { status: 204 }
28
+ subject.on_complete(env)
29
+ env[:body].tap do |json|
30
+ expect(json[:data]).to eq({})
31
+ end
32
+ end
33
+ end
34
+
35
+ context 'with status code 304' do
36
+ it 'returns an empty body' do
37
+ env = { :status => 304 }
38
+ subject.on_complete(env)
39
+ env[:body].tap do |json|
40
+ expect(json[:data]).to eq({})
41
+ end
42
+ end
43
+ end
44
+
45
+ # context "with invalid JSON body" do
26
46
  # let(:body) { '"foo"' }
27
47
  # it 'ensures that invalid JSON throws an exception' do
28
48
  # expect { subject.parse(body) }.to raise_error(Her::Errors::ParseError, 'Response from the API must behave like a Hash or an Array (last JSON response was "\"foo\"")')
29
49
  # end
30
- #end
31
-
50
+ # end
32
51
  end
@@ -8,28 +8,27 @@ describe Her::Middleware::SecondLevelParseJSON do
8
8
  let(:body) { "{\"data\": 1, \"errors\": 2, \"metadata\": 3}" }
9
9
  it "parses body as json" do
10
10
  subject.parse(body).tap do |json|
11
- json[:data].should == 1
12
- json[:errors].should == 2
13
- json[:metadata].should == 3
11
+ expect(json[:data]).to eq(1)
12
+ expect(json[:errors]).to eq(2)
13
+ expect(json[:metadata]).to eq(3)
14
14
  end
15
15
  end
16
16
 
17
17
  it "parses :body key as json in the env hash" do
18
- env = { :body => body }
18
+ env = { body: body }
19
19
  subject.on_complete(env)
20
20
  env[:body].tap do |json|
21
- json[:data].should == 1
22
- json[:errors].should == 2
23
- json[:metadata].should == 3
21
+ expect(json[:data]).to eq(1)
22
+ expect(json[:errors]).to eq(2)
23
+ expect(json[:metadata]).to eq(3)
24
24
  end
25
25
  end
26
26
  end
27
27
 
28
28
  context "with invalid JSON body" do
29
29
  let(:body) { '"foo"' }
30
- it 'ensures that invalid JSON throws an exception' do
30
+ it "ensures that invalid JSON throws an exception" do
31
31
  expect { subject.parse(body) }.to raise_error(Her::Errors::ParseError, 'Response from the API must behave like a Hash or an Array (last JSON response was "\"foo\"")')
32
32
  end
33
33
  end
34
-
35
34
  end
@@ -8,8 +8,8 @@ describe Her::Model::Associations::AssociationProxy do
8
8
  builder.use Her::Middleware::FirstLevelParseJSON
9
9
  builder.use Faraday::Request::UrlEncoded
10
10
  builder.adapter :test do |stub|
11
- stub.get("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke" }.to_json ] }
12
- stub.get("/users/1/fish") { |env| [200, {}, { :id => 1, :name => "Tobias's Fish" }.to_json ] }
11
+ stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke" }.to_json] }
12
+ stub.get("/users/1/fish") { [200, {}, { id: 1, name: "Tobias's Fish" }.to_json] }
13
13
  end
14
14
  end
15
15
  spawn_model "User" do
@@ -26,6 +26,3 @@ describe Her::Model::Associations::AssociationProxy do
26
26
  end
27
27
  end
28
28
  end
29
-
30
-
31
-