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
@@ -8,7 +8,11 @@ describe Her::Model::Associations do
8
8
 
9
9
  context "single has_many association" do
10
10
  before { Foo::User.has_many :comments }
11
- its([:has_many]) { should eql [{ :name => :comments, :data_key => :comments, :default => [], :class_name => "Comment", :path => "/comments", :inverse_of => nil }] }
11
+
12
+ describe "[:has_many]" do
13
+ subject { super()[:has_many] }
14
+ it { is_expected.to eql [{ name: :comments, data_key: :comments, default: [], class_name: "Comment", path: "/comments", inverse_of: nil }] }
15
+ end
12
16
  end
13
17
 
14
18
  context "multiple has_many associations" do
@@ -17,12 +21,19 @@ describe Her::Model::Associations do
17
21
  Foo::User.has_many :posts
18
22
  end
19
23
 
20
- its([:has_many]) { should eql [{ :name => :comments, :data_key => :comments, :default => [], :class_name => "Comment", :path => "/comments", :inverse_of => nil }, { :name => :posts, :data_key => :posts, :default => [], :class_name => "Post", :path => "/posts", :inverse_of => nil }] }
24
+ describe "[:has_many]" do
25
+ subject { super()[:has_many] }
26
+ it { is_expected.to eql [{ name: :comments, data_key: :comments, default: [], class_name: "Comment", path: "/comments", inverse_of: nil }, { name: :posts, data_key: :posts, default: [], class_name: "Post", path: "/posts", inverse_of: nil }] }
27
+ end
21
28
  end
22
29
 
23
30
  context "single has_one association" do
24
31
  before { Foo::User.has_one :category }
25
- its([:has_one]) { should eql [{ :name => :category, :data_key => :category, :default => nil, :class_name => "Category", :path => "/category" }] }
32
+
33
+ describe "[:has_one]" do
34
+ subject { super()[:has_one] }
35
+ it { is_expected.to eql [{ name: :category, data_key: :category, default: nil, class_name: "Category", path: "/category" }] }
36
+ end
26
37
  end
27
38
 
28
39
  context "multiple has_one associations" do
@@ -31,12 +42,19 @@ describe Her::Model::Associations do
31
42
  Foo::User.has_one :role
32
43
  end
33
44
 
34
- its([:has_one]) { should eql [{ :name => :category, :data_key => :category, :default => nil, :class_name => "Category", :path => "/category" }, { :name => :role, :data_key => :role, :default => nil, :class_name => "Role", :path => "/role" }] }
45
+ describe "[:has_one]" do
46
+ subject { super()[:has_one] }
47
+ it { is_expected.to eql [{ name: :category, data_key: :category, default: nil, class_name: "Category", path: "/category" }, { name: :role, data_key: :role, default: nil, class_name: "Role", path: "/role" }] }
48
+ end
35
49
  end
36
50
 
37
51
  context "single belongs_to association" do
38
52
  before { Foo::User.belongs_to :organization }
39
- its([:belongs_to]) { should eql [{ :name => :organization, :data_key => :organization, :default => nil, :class_name => "Organization", :foreign_key => "organization_id", :path => "/organizations/:id" }] }
53
+
54
+ describe "[:belongs_to]" do
55
+ subject { super()[:belongs_to] }
56
+ it { is_expected.to eql [{ name: :organization, data_key: :organization, default: nil, class_name: "Organization", foreign_key: "organization_id", path: "/organizations/:id" }] }
57
+ end
40
58
  end
41
59
 
42
60
  context "multiple belongs_to association" do
@@ -45,7 +63,10 @@ describe Her::Model::Associations do
45
63
  Foo::User.belongs_to :family
46
64
  end
47
65
 
48
- its([:belongs_to]) { should eql [{ :name => :organization, :data_key => :organization, :default => nil, :class_name => "Organization", :foreign_key => "organization_id", :path => "/organizations/:id" }, { :name => :family, :data_key => :family, :default => nil, :class_name => "Family", :foreign_key => "family_id", :path => "/families/:id" }] }
66
+ describe "[:belongs_to]" do
67
+ subject { super()[:belongs_to] }
68
+ it { is_expected.to eql [{ name: :organization, data_key: :organization, default: nil, class_name: "Organization", foreign_key: "organization_id", path: "/organizations/:id" }, { name: :family, data_key: :family, default: nil, class_name: "Family", foreign_key: "family_id", path: "/families/:id" }] }
69
+ end
49
70
  end
50
71
  end
51
72
 
@@ -55,56 +76,76 @@ describe Her::Model::Associations do
55
76
 
56
77
  context "in base class" do
57
78
  context "single has_many association" do
58
- before { Foo::User.has_many :comments, :class_name => "Post", :inverse_of => :admin, :data_key => :user_comments, :default => {} }
59
- its([:has_many]) { should eql [{ :name => :comments, :data_key => :user_comments, :default => {}, :class_name => "Post", :path => "/comments", :inverse_of => :admin }] }
79
+ before { Foo::User.has_many :comments, class_name: "Post", inverse_of: :admin, data_key: :user_comments, default: {} }
80
+
81
+ describe "[:has_many]" do
82
+ subject { super()[:has_many] }
83
+ it { is_expected.to eql [{ name: :comments, data_key: :user_comments, default: {}, class_name: "Post", path: "/comments", inverse_of: :admin }] }
84
+ end
60
85
  end
61
86
 
62
87
  context "single has_one association" do
63
- before { Foo::User.has_one :category, :class_name => "Topic", :foreign_key => "topic_id", :data_key => :topic, :default => nil }
64
- its([:has_one]) { should eql [{ :name => :category, :data_key => :topic, :default => nil, :class_name => "Topic", :foreign_key => "topic_id", :path => "/category" }] }
88
+ before { Foo::User.has_one :category, class_name: "Topic", foreign_key: "topic_id", data_key: :topic, default: nil }
89
+
90
+ describe "[:has_one]" do
91
+ subject { super()[:has_one] }
92
+ it { is_expected.to eql [{ name: :category, data_key: :topic, default: nil, class_name: "Topic", foreign_key: "topic_id", path: "/category" }] }
93
+ end
65
94
  end
66
95
 
67
96
  context "single belongs_to association" do
68
- before { Foo::User.belongs_to :organization, :class_name => "Business", :foreign_key => "org_id", :data_key => :org, :default => true }
69
- its([:belongs_to]) { should eql [{ :name => :organization, :data_key => :org, :default => true, :class_name => "Business", :foreign_key => "org_id", :path => "/organizations/:id" }] }
97
+ before { Foo::User.belongs_to :organization, class_name: "Business", foreign_key: "org_id", data_key: :org, default: true }
98
+
99
+ describe "[:belongs_to]" do
100
+ subject { super()[:belongs_to] }
101
+ it { is_expected.to eql [{ name: :organization, data_key: :org, default: true, class_name: "Business", foreign_key: "org_id", path: "/organizations/:id" }] }
102
+ end
70
103
  end
71
104
  end
72
105
 
73
106
  context "in parent class" do
74
- before { Foo::User.has_many :comments, :class_name => "Post" }
107
+ before { Foo::User.has_many :comments, class_name: "Post" }
75
108
 
76
109
  describe "associations accessor" do
77
110
  subject { Class.new(Foo::User).associations }
78
- its(:object_id) { should_not eql Foo::User.associations.object_id }
79
- its([:has_many]) { should eql [{ :name => :comments, :data_key => :comments, :default => [], :class_name => "Post", :path => "/comments", :inverse_of => nil }] }
111
+
112
+ describe "#object_id" do
113
+ subject { super().object_id }
114
+ it { is_expected.not_to eql Foo::User.associations.object_id }
115
+ end
116
+
117
+ describe "[:has_many]" do
118
+ subject { super()[:has_many] }
119
+ it { is_expected.to eql [{ name: :comments, data_key: :comments, default: [], class_name: "Post", path: "/comments", inverse_of: nil }] }
120
+ end
80
121
  end
81
122
  end
82
123
  end
83
124
 
84
125
  context "handling associations without details" do
85
126
  before do
86
- Her::API.setup :url => "https://api.example.com" do |builder|
127
+ Her::API.setup url: "https://api.example.com" do |builder|
87
128
  builder.use Her::Middleware::FirstLevelParseJSON
88
129
  builder.use Faraday::Request::UrlEncoded
89
130
  builder.adapter :test do |stub|
90
- stub.get("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke", :comments => [{ :comment => { :id => 2, :body => "Tobias, you blow hard!", :user_id => 1 } }, { :comment => { :id => 3, :body => "I wouldn't mind kissing that man between the cheeks, so to speak", :user_id => 1 } }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 1, :name => "Bluth Company" }, :organization_id => 1 }.to_json] }
91
- stub.get("/users/2") { |env| [200, {}, { :id => 2, :name => "Lindsay Fünke", :organization_id => 2 }.to_json] }
92
- stub.get("/users/1/comments") { |env| [200, {}, [{ :comment => { :id => 4, :body => "They're having a FIRESALE?" } }].to_json] }
93
- stub.get("/users/2/comments") { |env| [200, {}, [{ :comment => { :id => 4, :body => "They're having a FIRESALE?" } }, { :comment => { :id => 5, :body => "Is this the tiny town from Footloose?" } }].to_json] }
94
- stub.get("/users/2/comments/5") { |env| [200, {}, { :comment => { :id => 5, :body => "Is this the tiny town from Footloose?" } }.to_json] }
95
- stub.get("/users/2/role") { |env| [200, {}, { :id => 2, :body => "User" }.to_json] }
96
- stub.get("/users/1/role") { |env| [200, {}, { :id => 3, :body => "User" }.to_json] }
97
- stub.get("/users/1/posts") { |env| [200, {}, [{:id => 1, :body => 'blogging stuff', :admin_id => 1 }].to_json] }
98
- stub.get("/organizations/1") { |env| [200, {}, { :organization => { :id => 1, :name => "Bluth Company Foo" } }.to_json] }
99
- stub.post("/users") { |env| [200, {}, { :id => 5, :name => "Mr. Krabs", :comments => [{ :comment => { :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 } }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
100
- stub.put("/users/5") { |env| [200, {}, { :id => 5, :name => "Clancy Brown", :comments => [{ :comment => { :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 } }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
101
- stub.delete("/users/5") { |env| [200, {}, { :id => 5, :name => "Clancy Brown", :comments => [{ :comment => { :id => 99, :body => "Rodríguez, nasibisibusi?", :user_id => 5 } }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 3, :name => "Krusty Krab" }, :organization_id => 3 }.to_json] }
131
+ stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke", comments: [{ comment: { id: 2, body: "Tobias, you blow hard!", user_id: 1 } }, { comment: { id: 3, body: "I wouldn't mind kissing that man between the cheeks, so to speak", user_id: 1 } }], role: { id: 1, body: "Admin" }, organization: { id: 1, name: "Bluth Company" }, organization_id: 1 }.to_json] }
132
+ stub.get("/users/2") { [200, {}, { id: 2, name: "Lindsay Fünke", organization_id: 2 }.to_json] }
133
+ stub.get("/users/1/comments") { [200, {}, [{ comment: { id: 4, body: "They're having a FIRESALE?" } }].to_json] }
134
+ stub.get("/users/2/comments") { [200, {}, [{ comment: { id: 4, body: "They're having a FIRESALE?" } }, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }].to_json] }
135
+ stub.get("/users/2/comments/5") { [200, {}, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }.to_json] }
136
+ stub.get("/users/2/role") { [200, {}, { id: 2, body: "User" }.to_json] }
137
+ stub.get("/users/1/role") { [200, {}, { id: 3, body: "User" }.to_json] }
138
+ stub.get("/users/1/posts") { [200, {}, [{ id: 1, body: "blogging stuff", admin_id: 1 }].to_json] }
139
+ stub.get("/organizations/1") { [200, {}, { organization: { id: 1, name: "Bluth Company Foo" } }.to_json] }
140
+ stub.post("/users") { [200, {}, { id: 5, name: "Mr. Krabs", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
141
+ stub.put("/users/5") { [200, {}, { id: 5, name: "Clancy Brown", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
142
+ stub.delete("/users/5") { [200, {}, { id: 5, name: "Clancy Brown", comments: [{ comment: { id: 99, body: "Rodríguez, nasibisibusi?", user_id: 5 } }], role: { id: 1, body: "Admin" }, organization: { id: 3, name: "Krusty Krab" }, organization_id: 3 }.to_json] }
102
143
 
103
144
  stub.get("/organizations/2") do |env|
104
145
  if env[:params]["admin"] == "true"
105
- [200, {}, { :organization => { :id => 2, :name => "Bluth Company (admin)" } }.to_json]
146
+ [200, {}, { organization: { id: 2, name: "Bluth Company (admin)" } }.to_json]
106
147
  else
107
- [200, {}, { :organization => { :id => 2, :name => "Bluth Company" } }.to_json]
148
+ [200, {}, { organization: { id: 2, name: "Bluth Company" } }.to_json]
108
149
  end
109
150
  end
110
151
  end
@@ -112,16 +153,18 @@ describe Her::Model::Associations do
112
153
 
113
154
  spawn_model "Foo::User" do
114
155
  has_many :comments, class_name: "Foo::Comment"
115
- has_one :role
116
- belongs_to :organization
117
- has_many :posts, :inverse_of => :admin
156
+ has_one :role, class_name: "Foo::Role"
157
+ belongs_to :organization, class_name: "Foo::Organization"
158
+ has_many :posts, inverse_of: :admin
118
159
  end
160
+
119
161
  spawn_model "Foo::Comment" do
120
162
  belongs_to :user
121
163
  parse_root_in_json true
122
164
  end
165
+
123
166
  spawn_model "Foo::Post" do
124
- belongs_to :admin, :class_name => 'Foo::User'
167
+ belongs_to :admin, class_name: "Foo::User"
125
168
  end
126
169
 
127
170
  spawn_model "Foo::Organization" do
@@ -136,136 +179,159 @@ describe Her::Model::Associations do
136
179
  end
137
180
 
138
181
  let(:user_with_included_data_after_create) { Foo::User.create }
139
- let(:user_with_included_data_after_save_existing) { Foo::User.save_existing(5, :name => "Clancy Brown") }
140
- let(:user_with_included_data_after_destroy) { Foo::User.new(:id => 5).destroy }
141
- let(:comment_without_included_parent_data) { Foo::Comment.new(:id => 7, :user_id => 1) }
182
+ let(:user_with_included_data_after_save_existing) { Foo::User.save_existing(5, name: "Clancy Brown") }
183
+ let(:user_with_included_data_after_destroy) { Foo::User.new(id: 5).destroy }
184
+ let(:comment_without_included_parent_data) { Foo::Comment.new(id: 7, user_id: 1) }
185
+ let(:new_user) { Foo::User.new }
142
186
 
143
187
  it "maps an array of included data through has_many" do
144
- @user_with_included_data.comments.first.should be_a(Foo::Comment)
145
- @user_with_included_data.comments.length.should == 2
146
- @user_with_included_data.comments.first.id.should == 2
147
- @user_with_included_data.comments.first.body.should == "Tobias, you blow hard!"
188
+ expect(@user_with_included_data.comments.first).to be_a(Foo::Comment)
189
+ expect(@user_with_included_data.comments.length).to eq(2)
190
+ expect(@user_with_included_data.comments.first.id).to eq(2)
191
+ expect(@user_with_included_data.comments.first.body).to eq("Tobias, you blow hard!")
148
192
  end
149
193
 
150
194
  it "does not refetch the parents models data if they have been fetched before" do
151
- @user_with_included_data.comments.first.user.object_id.should == @user_with_included_data.object_id
195
+ expect(@user_with_included_data.comments.first.user.object_id).to eq(@user_with_included_data.object_id)
152
196
  end
153
197
 
154
198
  it "does fetch the parent models data only once" do
155
- comment_without_included_parent_data.user.object_id.should == comment_without_included_parent_data.user.object_id
199
+ expect(comment_without_included_parent_data.user.object_id).to eq(comment_without_included_parent_data.user.object_id)
156
200
  end
157
201
 
158
202
  it "does fetch the parent models data that was cached if called with parameters" do
159
- comment_without_included_parent_data.user.object_id.should_not == comment_without_included_parent_data.user.where(:a => 2).object_id
203
+ expect(comment_without_included_parent_data.user.object_id).not_to eq(comment_without_included_parent_data.user.where(a: 2).object_id)
160
204
  end
161
205
 
162
206
  it "uses the given inverse_of key to set the parent model" do
163
- @user_with_included_data.posts.first.admin.object_id.should == @user_with_included_data.object_id
207
+ expect(@user_with_included_data.posts.first.admin.object_id).to eq(@user_with_included_data.object_id)
208
+ end
209
+
210
+ it "doesn't attempt to fetch association data for a new resource" do
211
+ expect(new_user.comments).to eq([])
212
+ expect(new_user.role).to be_nil
213
+ expect(new_user.organization).to be_nil
164
214
  end
165
215
 
166
216
  it "fetches data that was not included through has_many" do
167
- @user_without_included_data.comments.first.should be_a(Foo::Comment)
168
- @user_without_included_data.comments.length.should == 2
169
- @user_without_included_data.comments.first.id.should == 4
170
- @user_without_included_data.comments.first.body.should == "They're having a FIRESALE?"
217
+ expect(@user_without_included_data.comments.first).to be_a(Foo::Comment)
218
+ expect(@user_without_included_data.comments.length).to eq(2)
219
+ expect(@user_without_included_data.comments.first.id).to eq(4)
220
+ expect(@user_without_included_data.comments.first.body).to eq("They're having a FIRESALE?")
171
221
  end
172
222
 
173
223
  it "fetches has_many data even if it was included, only if called with parameters" do
174
- @user_with_included_data.comments.where(:foo_id => 1).length.should == 1
224
+ expect(@user_with_included_data.comments.where(foo_id: 1).length).to eq(1)
175
225
  end
176
226
 
177
227
  it "fetches data that was not included through has_many only once" do
178
- @user_without_included_data.comments.first.object_id.should == @user_without_included_data.comments.first.object_id
228
+ expect(@user_without_included_data.comments.first.object_id).to eq(@user_without_included_data.comments.first.object_id)
179
229
  end
180
230
 
181
231
  it "fetches data that was cached through has_many if called with parameters" do
182
- @user_without_included_data.comments.first.object_id.should_not == @user_without_included_data.comments.where(:foo_id => 1).first.object_id
232
+ expect(@user_without_included_data.comments.first.object_id).not_to eq(@user_without_included_data.comments.where(foo_id: 1).first.object_id)
233
+ end
234
+
235
+ it "fetches data again after being reloaded" do
236
+ expect { @user_without_included_data.comments.reload }.to change { @user_without_included_data.comments.first.object_id }
183
237
  end
184
238
 
185
239
  it "maps an array of included data through has_one" do
186
- @user_with_included_data.role.should be_a(Foo::Role)
187
- @user_with_included_data.role.object_id.should == @user_with_included_data.role.object_id
188
- @user_with_included_data.role.id.should == 1
189
- @user_with_included_data.role.body.should == "Admin"
240
+ expect(@user_with_included_data.role).to be_a(Foo::Role)
241
+ expect(@user_with_included_data.role.object_id).to eq(@user_with_included_data.role.object_id)
242
+ expect(@user_with_included_data.role.id).to eq(1)
243
+ expect(@user_with_included_data.role.body).to eq("Admin")
190
244
  end
191
245
 
192
246
  it "fetches data that was not included through has_one" do
193
- @user_without_included_data.role.should be_a(Foo::Role)
194
- @user_without_included_data.role.id.should == 2
195
- @user_without_included_data.role.body.should == "User"
247
+ expect(@user_without_included_data.role).to be_a(Foo::Role)
248
+ expect(@user_without_included_data.role.id).to eq(2)
249
+ expect(@user_without_included_data.role.body).to eq("User")
196
250
  end
197
251
 
198
252
  it "fetches has_one data even if it was included, only if called with parameters" do
199
- @user_with_included_data.role.where(:foo_id => 2).id.should == 3
253
+ expect(@user_with_included_data.role.where(foo_id: 2).id).to eq(3)
200
254
  end
201
255
 
202
256
  it "maps an array of included data through belongs_to" do
203
- @user_with_included_data.organization.should be_a(Foo::Organization)
204
- @user_with_included_data.organization.id.should == 1
205
- @user_with_included_data.organization.name.should == "Bluth Company"
257
+ expect(@user_with_included_data.organization).to be_a(Foo::Organization)
258
+ expect(@user_with_included_data.organization.id).to eq(1)
259
+ expect(@user_with_included_data.organization.name).to eq("Bluth Company")
206
260
  end
207
261
 
208
262
  it "fetches data that was not included through belongs_to" do
209
- @user_without_included_data.organization.should be_a(Foo::Organization)
210
- @user_without_included_data.organization.id.should == 2
211
- @user_without_included_data.organization.name.should == "Bluth Company"
263
+ expect(@user_without_included_data.organization).to be_a(Foo::Organization)
264
+ expect(@user_without_included_data.organization.id).to eq(2)
265
+ expect(@user_without_included_data.organization.name).to eq("Bluth Company")
212
266
  end
213
267
 
214
268
  it "returns nil if the foreign key is nil" do
215
- @user_without_organization_and_not_persisted.organization.should be_nil
269
+ expect(@user_without_organization_and_not_persisted.organization).to be_nil
216
270
  end
217
271
 
218
272
  it "fetches belongs_to data even if it was included, only if called with parameters" do
219
- @user_with_included_data.organization.where(:foo_id => 1).name.should == "Bluth Company Foo"
273
+ expect(@user_with_included_data.organization.where(foo_id: 1).name).to eq("Bluth Company Foo")
220
274
  end
221
275
 
222
276
  it "can tell if it has a association" do
223
- @user_without_included_data.has_association?(:unknown_association).should be false
224
- @user_without_included_data.has_association?(:organization).should be true
277
+ expect(@user_without_included_data.has_association?(:unknown_association)).to be false
278
+ expect(@user_without_included_data.has_association?(:organization)).to be true
225
279
  end
226
280
 
227
281
  it "fetches the resource corresponding to a named association" do
228
- @user_without_included_data.get_association(:unknown_association).should be_nil
229
- @user_without_included_data.get_association(:organization).name.should == "Bluth Company"
282
+ expect(@user_without_included_data.get_association(:unknown_association)).to be_nil
283
+ expect(@user_without_included_data.get_association(:organization).name).to eq("Bluth Company")
230
284
  end
231
285
 
232
286
  it "pass query string parameters when additional arguments are passed" do
233
- @user_without_included_data.organization.where(:admin => true).name.should == "Bluth Company (admin)"
234
- @user_without_included_data.organization.name.should == "Bluth Company"
287
+ expect(@user_without_included_data.organization.where(admin: true).name).to eq("Bluth Company (admin)")
288
+ expect(@user_without_included_data.organization.name).to eq("Bluth Company")
235
289
  end
236
290
 
237
291
  it "fetches data with the specified id when calling find" do
238
292
  comment = @user_without_included_data.comments.find(5)
239
- comment.should be_a(Foo::Comment)
240
- comment.id.should eq(5)
293
+ expect(comment).to be_a(Foo::Comment)
294
+ expect(comment.id).to eq(5)
241
295
  end
242
296
 
243
297
  it "'s associations responds to #empty?" do
244
- @user_without_included_data.organization.respond_to?(:empty?).should be_truthy
245
- @user_without_included_data.organization.should_not be_empty
298
+ expect(@user_without_included_data.organization.respond_to?(:empty?)).to be_truthy
299
+ expect(@user_without_included_data.organization).not_to be_empty
300
+ end
301
+
302
+ it "includes has_many relationships in params by default" do
303
+ params = @user_with_included_data.to_params
304
+ expect(params[:comments]).to be_kind_of(Array)
305
+ expect(params[:comments].length).to eq(2)
246
306
  end
247
307
 
248
- it 'includes has_many relationships in params by default' do
308
+ it "includes has_one relationship in params by default" do
249
309
  params = @user_with_included_data.to_params
250
- params[:comments].should be_kind_of(Array)
251
- params[:comments].length.should eq(2)
310
+ expect(params[:role]).to be_kind_of(Hash)
311
+ expect(params[:role]).not_to be_empty
312
+ end
313
+
314
+ it "includes belongs_to relationship in params by default" do
315
+ params = @user_with_included_data.to_params
316
+ expect(params[:organization]).to be_kind_of(Hash)
317
+ expect(params[:organization]).not_to be_empty
252
318
  end
253
319
 
254
320
  [:create, :save_existing, :destroy].each do |type|
255
321
  context "after #{type}" do
256
- let(:subject) { self.send("user_with_included_data_after_#{type}")}
322
+ let(:subject) { send("user_with_included_data_after_#{type}") }
257
323
 
258
324
  it "maps an array of included data through has_many" do
259
- subject.comments.first.should be_a(Foo::Comment)
260
- subject.comments.length.should == 1
261
- subject.comments.first.id.should == 99
262
- subject.comments.first.body.should == "Rodríguez, nasibisibusi?"
325
+ expect(subject.comments.first).to be_a(Foo::Comment)
326
+ expect(subject.comments.length).to eq(1)
327
+ expect(subject.comments.first.id).to eq(99)
328
+ expect(subject.comments.first.body).to eq("Rodríguez, nasibisibusi?")
263
329
  end
264
330
 
265
331
  it "maps an array of included data through has_one" do
266
- subject.role.should be_a(Foo::Role)
267
- subject.role.id.should == 1
268
- subject.role.body.should == "Admin"
332
+ expect(subject.role).to be_a(Foo::Role)
333
+ expect(subject.role.id).to eq(1)
334
+ expect(subject.role.body).to eq("Admin")
269
335
  end
270
336
  end
271
337
  end
@@ -273,29 +339,38 @@ describe Her::Model::Associations do
273
339
 
274
340
  context "handling associations with details in active_model_serializers format" do
275
341
  before do
276
- Her::API.setup :url => "https://api.example.com" do |builder|
342
+ Her::API.setup url: "https://api.example.com" do |builder|
277
343
  builder.use Her::Middleware::FirstLevelParseJSON
278
344
  builder.use Faraday::Request::UrlEncoded
279
345
  builder.adapter :test do |stub|
280
- stub.get("/users/1") { |env| [200, {}, { :user => { :id => 1, :name => "Tobias Fünke", :comments => [{ :id => 2, :body => "Tobias, you blow hard!", :user_id => 1 }, { :id => 3, :body => "I wouldn't mind kissing that man between the cheeks, so to speak", :user_id => 1 }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 1, :name => "Bluth Company" }, :organization_id => 1 } }.to_json] }
281
- stub.get("/users/2") { |env| [200, {}, { :user => { :id => 2, :name => "Lindsay Fünke", :organization_id => 1 } }.to_json] }
282
- stub.get("/users/1/comments") { |env| [200, {}, { :comments => [{ :id => 4, :body => "They're having a FIRESALE?" }] }.to_json] }
283
- stub.get("/users/2/comments") { |env| [200, {}, { :comments => [{ :id => 4, :body => "They're having a FIRESALE?" }, { :id => 5, :body => "Is this the tiny town from Footloose?" }] }.to_json] }
284
- stub.get("/users/2/comments/5") { |env| [200, {}, { :comment => { :id => 5, :body => "Is this the tiny town from Footloose?" } }.to_json] }
285
- stub.get("/organizations/1") { |env| [200, {}, { :organization => { :id => 1, :name => "Bluth Company Foo" } }.to_json] }
346
+ stub.get("/users/1") { [200, {}, { user: { id: 1, name: "Tobias Fünke", comments: [{ id: 2, body: "Tobias, you blow hard!", user_id: 1 }, { id: 3, body: "I wouldn't mind kissing that man between the cheeks, so to speak", user_id: 1 }], role: { id: 1, body: "Admin" }, organization: { id: 1, name: "Bluth Company" }, organization_id: 1 } }.to_json] }
347
+ stub.get("/users/2") { [200, {}, { user: { id: 2, name: "Lindsay Fünke", organization_id: 1 } }.to_json] }
348
+ stub.get("/users/1/comments") { [200, {}, { comments: [{ id: 4, body: "They're having a FIRESALE?" }] }.to_json] }
349
+ stub.get("/users/2/comments") { [200, {}, { comments: [{ id: 4, body: "They're having a FIRESALE?" }, { id: 5, body: "Is this the tiny town from Footloose?" }] }.to_json] }
350
+ stub.get("/users/2/comments/5") { [200, {}, { comment: { id: 5, body: "Is this the tiny town from Footloose?" } }.to_json] }
351
+ stub.get("/organizations/1") { [200, {}, { organization: { id: 1, name: "Bluth Company Foo" } }.to_json] }
286
352
  end
287
353
  end
354
+
288
355
  spawn_model "Foo::User" do
289
- parse_root_in_json true, :format => :active_model_serializers
356
+ parse_root_in_json true, format: :active_model_serializers
290
357
  has_many :comments, class_name: "Foo::Comment"
291
- belongs_to :organization
358
+ has_one :role, class_name: "Foo::Role"
359
+ belongs_to :organization, class_name: "Foo::Organization"
360
+ end
361
+
362
+ spawn_model "Foo::Role" do
363
+ belongs_to :user
364
+ parse_root_in_json true, format: :active_model_serializers
292
365
  end
366
+
293
367
  spawn_model "Foo::Comment" do
294
368
  belongs_to :user
295
- parse_root_in_json true, :format => :active_model_serializers
369
+ parse_root_in_json true, format: :active_model_serializers
296
370
  end
371
+
297
372
  spawn_model "Foo::Organization" do
298
- parse_root_in_json true, :format => :active_model_serializers
373
+ parse_root_in_json true, format: :active_model_serializers
299
374
  end
300
375
 
301
376
  @user_with_included_data = Foo::User.find(1)
@@ -303,72 +378,84 @@ describe Her::Model::Associations do
303
378
  end
304
379
 
305
380
  it "maps an array of included data through has_many" do
306
- @user_with_included_data.comments.first.should be_a(Foo::Comment)
307
- @user_with_included_data.comments.length.should == 2
308
- @user_with_included_data.comments.first.id.should == 2
309
- @user_with_included_data.comments.first.body.should == "Tobias, you blow hard!"
381
+ expect(@user_with_included_data.comments.first).to be_a(Foo::Comment)
382
+ expect(@user_with_included_data.comments.length).to eq(2)
383
+ expect(@user_with_included_data.comments.first.id).to eq(2)
384
+ expect(@user_with_included_data.comments.first.body).to eq("Tobias, you blow hard!")
310
385
  end
311
386
 
312
387
  it "does not refetch the parents models data if they have been fetched before" do
313
- @user_with_included_data.comments.first.user.object_id.should == @user_with_included_data.object_id
388
+ expect(@user_with_included_data.comments.first.user.object_id).to eq(@user_with_included_data.object_id)
314
389
  end
315
390
 
316
391
  it "fetches data that was not included through has_many" do
317
- @user_without_included_data.comments.first.should be_a(Foo::Comment)
318
- @user_without_included_data.comments.length.should == 2
319
- @user_without_included_data.comments.first.id.should == 4
320
- @user_without_included_data.comments.first.body.should == "They're having a FIRESALE?"
392
+ expect(@user_without_included_data.comments.first).to be_a(Foo::Comment)
393
+ expect(@user_without_included_data.comments.length).to eq(2)
394
+ expect(@user_without_included_data.comments.first.id).to eq(4)
395
+ expect(@user_without_included_data.comments.first.body).to eq("They're having a FIRESALE?")
321
396
  end
322
397
 
323
398
  it "fetches has_many data even if it was included, only if called with parameters" do
324
- @user_with_included_data.comments.where(:foo_id => 1).length.should == 1
399
+ expect(@user_with_included_data.comments.where(foo_id: 1).length).to eq(1)
325
400
  end
326
401
 
327
402
  it "maps an array of included data through belongs_to" do
328
- @user_with_included_data.organization.should be_a(Foo::Organization)
329
- @user_with_included_data.organization.id.should == 1
330
- @user_with_included_data.organization.name.should == "Bluth Company"
403
+ expect(@user_with_included_data.organization).to be_a(Foo::Organization)
404
+ expect(@user_with_included_data.organization.id).to eq(1)
405
+ expect(@user_with_included_data.organization.name).to eq("Bluth Company")
331
406
  end
332
407
 
333
408
  it "fetches data that was not included through belongs_to" do
334
- @user_without_included_data.organization.should be_a(Foo::Organization)
335
- @user_without_included_data.organization.id.should == 1
336
- @user_without_included_data.organization.name.should == "Bluth Company Foo"
409
+ expect(@user_without_included_data.organization).to be_a(Foo::Organization)
410
+ expect(@user_without_included_data.organization.id).to eq(1)
411
+ expect(@user_without_included_data.organization.name).to eq("Bluth Company Foo")
337
412
  end
338
413
 
339
414
  it "fetches belongs_to data even if it was included, only if called with parameters" do
340
- @user_with_included_data.organization.where(:foo_id => 1).name.should == "Bluth Company Foo"
415
+ expect(@user_with_included_data.organization.where(foo_id: 1).name).to eq("Bluth Company Foo")
341
416
  end
342
417
 
343
418
  it "fetches data with the specified id when calling find" do
344
419
  comment = @user_without_included_data.comments.find(5)
345
- comment.should be_a(Foo::Comment)
346
- comment.id.should eq(5)
420
+ expect(comment).to be_a(Foo::Comment)
421
+ expect(comment.id).to eq(5)
422
+ end
423
+
424
+ it "includes has_many relationships in params by default" do
425
+ params = @user_with_included_data.to_params
426
+ expect(params[:comments]).to be_kind_of(Array)
427
+ expect(params[:comments].length).to eq(2)
428
+ end
429
+
430
+ it "includes has_one relationships in params by default" do
431
+ params = @user_with_included_data.to_params
432
+ expect(params[:role]).to be_kind_of(Hash)
433
+ expect(params[:role]).not_to be_empty
347
434
  end
348
435
 
349
- it 'includes has_many relationships in params by default' do
436
+ it "includes belongs_to relationship in params by default" do
350
437
  params = @user_with_included_data.to_params
351
- params[:comments].should be_kind_of(Array)
352
- params[:comments].length.should eq(2)
438
+ expect(params[:organization]).to be_kind_of(Hash)
439
+ expect(params[:organization]).not_to be_empty
353
440
  end
354
441
  end
355
442
 
356
443
  context "handling associations with details" do
357
444
  before do
358
- Her::API.setup :url => "https://api.example.com" do |builder|
445
+ Her::API.setup url: "https://api.example.com" do |builder|
359
446
  builder.use Her::Middleware::FirstLevelParseJSON
360
447
  builder.use Faraday::Request::UrlEncoded
361
448
  builder.adapter :test do |stub|
362
- stub.get("/users/1") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke", :organization => { :id => 1, :name => "Bluth Company Inc." }, :organization_id => 1 }.to_json] }
363
- stub.get("/users/4") { |env| [200, {}, { :id => 1, :name => "Tobias Fünke", :organization => { :id => 1, :name => "Bluth Company Inc." } }.to_json] }
364
- stub.get("/users/2") { |env| [200, {}, { :id => 2, :name => "Lindsay Fünke", :organization_id => 1 }.to_json] }
365
- stub.get("/users/3") { |env| [200, {}, { :id => 2, :name => "Lindsay Fünke", :company => nil }.to_json] }
366
- stub.get("/companies/1") { |env| [200, {}, { :id => 1, :name => "Bluth Company" }.to_json] }
449
+ stub.get("/users/1") { [200, {}, { id: 1, name: "Tobias Fünke", organization: { id: 1, name: "Bluth Company Inc." }, organization_id: 1 }.to_json] }
450
+ stub.get("/users/4") { [200, {}, { id: 1, name: "Tobias Fünke", organization: { id: 1, name: "Bluth Company Inc." } }.to_json] }
451
+ stub.get("/users/2") { [200, {}, { id: 2, name: "Lindsay Fünke", organization_id: 1 }.to_json] }
452
+ stub.get("/users/3") { [200, {}, { id: 2, name: "Lindsay Fünke", company: nil }.to_json] }
453
+ stub.get("/companies/1") { [200, {}, { id: 1, name: "Bluth Company" }.to_json] }
367
454
  end
368
455
  end
369
456
 
370
457
  spawn_model "Foo::User" do
371
- belongs_to :company, :path => "/organizations/:id", :foreign_key => :organization_id, :data_key => :organization
458
+ belongs_to :company, path: "/organizations/:id", foreign_key: :organization_id, data_key: :organization
372
459
  end
373
460
 
374
461
  spawn_model "Foo::Company"
@@ -380,23 +467,23 @@ describe Her::Model::Associations do
380
467
  end
381
468
 
382
469
  it "maps an array of included data through belongs_to" do
383
- @user_with_included_data.company.should be_a(Foo::Company)
384
- @user_with_included_data.company.id.should == 1
385
- @user_with_included_data.company.name.should == "Bluth Company Inc."
470
+ expect(@user_with_included_data.company).to be_a(Foo::Company)
471
+ expect(@user_with_included_data.company.id).to eq(1)
472
+ expect(@user_with_included_data.company.name).to eq("Bluth Company Inc.")
386
473
  end
387
474
 
388
475
  it "does not map included data if it’s nil" do
389
- @user_with_included_nil_data.company.should be_nil
476
+ expect(@user_with_included_nil_data.company).to be_nil
390
477
  end
391
478
 
392
479
  it "fetches data that was not included through belongs_to" do
393
- @user_without_included_data.company.should be_a(Foo::Company)
394
- @user_without_included_data.company.id.should == 1
395
- @user_without_included_data.company.name.should == "Bluth Company"
480
+ expect(@user_without_included_data.company).to be_a(Foo::Company)
481
+ expect(@user_without_included_data.company.id).to eq(1)
482
+ expect(@user_without_included_data.company.name).to eq("Bluth Company")
396
483
  end
397
484
 
398
485
  it "does not require foreugn key to have nested object" do
399
- @user_with_included_data_but_no_fk.company.name.should == "Bluth Company Inc."
486
+ expect(@user_with_included_data_but_no_fk.company.name).to eq("Bluth Company Inc.")
400
487
  end
401
488
  end
402
489
 
@@ -420,30 +507,30 @@ describe Her::Model::Associations do
420
507
  subject { user_with_role.role }
421
508
 
422
509
  it "doesnt mask the object's basic methods" do
423
- subject.class.should == Foo::Role
510
+ expect(subject.class).to eq(Foo::Role)
424
511
  end
425
512
 
426
513
  it "doesnt mask core methods like extend" do
427
514
  committer = Module.new
428
- subject.extend committer
429
- associated_value.should be_kind_of committer
515
+ subject.extend committer
516
+ expect(associated_value).to be_kind_of committer
430
517
  end
431
518
 
432
519
  it "can return the association object" do
433
- subject.association.should be_kind_of Her::Model::Associations::Association
520
+ expect(subject.association).to be_kind_of Her::Model::Associations::Association
434
521
  end
435
522
 
436
523
  it "still can call fetch via the association" do
437
- subject.association.fetch.should eq associated_value
524
+ expect(subject.association.fetch).to eq associated_value
438
525
  end
439
526
 
440
527
  it "calls missing methods on associated value" do
441
- subject.present?.should == "of_course"
528
+ expect(subject.present?).to eq("of_course")
442
529
  end
443
530
 
444
531
  it "can use association methods like where" do
445
- subject.where(role: 'committer').association.
446
- params.should include :role
532
+ expect(subject.where(role: "committer").association
533
+ .params).to include :role
447
534
  end
448
535
  end
449
536
 
@@ -457,20 +544,20 @@ describe Her::Model::Associations do
457
544
 
458
545
  context "with #build" do
459
546
  it "takes the parent primary key" do
460
- @comment = Foo::User.new(:id => 10).comments.build(:body => "Hello!")
461
- @comment.body.should == "Hello!"
462
- @comment.user_id.should == 10
547
+ @comment = Foo::User.new(id: 10).comments.build(body: "Hello!")
548
+ expect(@comment.body).to eq("Hello!")
549
+ expect(@comment.user_id).to eq(10)
463
550
  end
464
551
  end
465
552
 
466
553
  context "with #create" do
467
554
  before do
468
- Her::API.setup :url => "https://api.example.com" do |builder|
555
+ Her::API.setup url: "https://api.example.com" do |builder|
469
556
  builder.use Her::Middleware::FirstLevelParseJSON
470
557
  builder.use Faraday::Request::UrlEncoded
471
558
  builder.adapter :test do |stub|
472
- stub.get("/users/10") { |env| [200, {}, { :id => 10 }.to_json] }
473
- stub.post("/comments") { |env| [200, {}, { :id => 1, :body => Faraday::Utils.parse_query(env[:body])['body'], :user_id => Faraday::Utils.parse_query(env[:body])['user_id'].to_i }.to_json] }
559
+ stub.get("/users/10") { [200, {}, { id: 10 }.to_json] }
560
+ stub.post("/comments") { |env| [200, {}, { id: 1, body: Faraday::Utils.parse_query(env[:body])["body"], user_id: Faraday::Utils.parse_query(env[:body])["user_id"].to_i }.to_json] }
474
561
  end
475
562
  end
476
563
 
@@ -480,24 +567,24 @@ describe Her::Model::Associations do
480
567
 
481
568
  it "takes the parent primary key and saves the resource" do
482
569
  @user = Foo::User.find(10)
483
- @comment = @user.comments.create(:body => "Hello!")
484
- @comment.id.should == 1
485
- @comment.body.should == "Hello!"
486
- @comment.user_id.should == 10
487
- @user.comments.should == [@comment]
570
+ @comment = @user.comments.create(body: "Hello!")
571
+ expect(@comment.id).to eq(1)
572
+ expect(@comment.body).to eq("Hello!")
573
+ expect(@comment.user_id).to eq(10)
574
+ expect(@user.comments).to eq([@comment])
488
575
  end
489
576
  end
490
577
 
491
578
  context "with #new" do
492
579
  it "creates nested models from hash attibutes" do
493
- user = Foo::User.new(:name => "vic", :comments => [{:text => "hello"}])
494
- user.comments.first.text.should == "hello"
580
+ user = Foo::User.new(name: "vic", comments: [{ text: "hello" }])
581
+ expect(user.comments.first.text).to eq("hello")
495
582
  end
496
583
 
497
584
  it "assigns nested models if given as already constructed objects" do
498
- bye = Foo::Comment.new(:text => "goodbye")
499
- user = Foo::User.new(:name => 'vic', :comments => [bye])
500
- user.comments.first.text.should == 'goodbye'
585
+ bye = Foo::Comment.new(text: "goodbye")
586
+ user = Foo::User.new(name: "vic", comments: [bye])
587
+ expect(user.comments.first.text).to eq("goodbye")
501
588
  end
502
589
  end
503
590
  end