her 0.8.2 → 0.9.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 (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