active_attr 0.7.0 → 0.8.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.

Potentially problematic release.


This version of active_attr might be problematic. Click here for more details.

Files changed (45) hide show
  1. data/.travis.yml +11 -1
  2. data/CHANGELOG.md +9 -0
  3. data/Gemfile +4 -6
  4. data/README.md +29 -11
  5. data/active_attr.gemspec +3 -3
  6. data/gemfiles/rails_3_2.gemfile +11 -0
  7. data/gemfiles/rails_head.gemfile +3 -0
  8. data/lib/active_attr.rb +0 -1
  9. data/lib/active_attr/mass_assignment.rb +30 -2
  10. data/lib/active_attr/matchers/have_attribute_matcher.rb +17 -4
  11. data/lib/active_attr/model.rb +2 -2
  12. data/lib/active_attr/typecasting/big_decimal_typecaster.rb +2 -0
  13. data/lib/active_attr/typecasting/date_typecaster.rb +1 -1
  14. data/lib/active_attr/version.rb +1 -1
  15. data/spec/functional/active_attr/attribute_defaults_spec.rb +12 -12
  16. data/spec/functional/active_attr/attributes_spec.rb +12 -12
  17. data/spec/functional/active_attr/chainable_initialization_spec.rb +3 -3
  18. data/spec/functional/active_attr/mass_assignment_spec.rb +125 -0
  19. data/spec/functional/active_attr/matchers/have_attribute_matcher_spec.rb +147 -66
  20. data/spec/functional/active_attr/model_spec.rb +27 -19
  21. data/spec/functional/active_attr/serialization_spec.rb +5 -5
  22. data/spec/functional/active_attr/typecasted_attributes_spec.rb +45 -45
  23. data/spec/support/mass_assignment_shared_examples.rb +12 -12
  24. data/spec/unit/active_attr/attribute_defaults_spec.rb +6 -6
  25. data/spec/unit/active_attr/attribute_definition_spec.rb +6 -6
  26. data/spec/unit/active_attr/attributes_spec.rb +38 -38
  27. data/spec/unit/active_attr/logger_spec.rb +16 -16
  28. data/spec/unit/active_attr/mass_assignment_spec.rb +1 -1
  29. data/spec/unit/active_attr/matchers_spec.rb +3 -4
  30. data/spec/unit/active_attr/query_attributes_spec.rb +75 -75
  31. data/spec/unit/active_attr/typecasted_attributes_spec.rb +10 -10
  32. data/spec/unit/active_attr/typecasting/big_decimal_typecaster_spec.rb +9 -7
  33. data/spec/unit/active_attr/typecasting/boolean_typecaster_spec.rb +27 -25
  34. data/spec/unit/active_attr/typecasting/date_time_typecaster_spec.rb +12 -10
  35. data/spec/unit/active_attr/typecasting/date_typecaster_spec.rb +14 -12
  36. data/spec/unit/active_attr/typecasting/float_typecaster_spec.rb +6 -4
  37. data/spec/unit/active_attr/typecasting/integer_typecaster_spec.rb +8 -6
  38. data/spec/unit/active_attr/typecasting/object_typecaster_spec.rb +3 -1
  39. data/spec/unit/active_attr/typecasting/string_typecaster_spec.rb +5 -3
  40. data/spec/unit/active_attr/typecasting_spec.rb +3 -5
  41. data/spec/unit/active_attr/version_spec.rb +5 -5
  42. metadata +20 -17
  43. data/lib/active_attr/mass_assignment_security.rb +0 -54
  44. data/spec/functional/active_attr/mass_assignment_security_spec.rb +0 -45
  45. data/spec/unit/active_attr/mass_assignment_security_spec.rb +0 -67
@@ -4,12 +4,12 @@ require "active_support/concern"
4
4
 
5
5
  module ActiveAttr
6
6
  describe ChainableInitialization do
7
- subject { model_class.new("arg") }
7
+ subject(:model) { model_class.new("arg") }
8
8
 
9
9
  shared_examples "chained initialization" do
10
10
  describe "#initialize" do
11
- it { expect { subject }.not_to raise_error }
12
- it { subject.initialized?.should be_true }
11
+ it { expect { model }.not_to raise_error }
12
+ it { model.initialized?.should be_true }
13
13
  end
14
14
  end
15
15
 
@@ -0,0 +1,125 @@
1
+ require "spec_helper"
2
+ require "active_attr/mass_assignment"
3
+ require "active_model"
4
+ require "active_model/mass_assignment_security"
5
+
6
+ module ActiveAttr
7
+ describe MassAssignment, :mass_assignment do
8
+ context "integrating with protected_attributes" do
9
+ before do
10
+ model_class.class_eval do
11
+ include MassAssignment
12
+ include ActiveModel::MassAssignmentSecurity
13
+ attr_accessor :age
14
+ end
15
+ end
16
+
17
+ shared_examples "secure mass assignment method", :secure_mass_assignment_method => true do
18
+ include_examples "mass assignment method"
19
+
20
+ it "ignores assigning an attribute protected by role-based security", :active_model_version => ">= 3.1.0" do
21
+ person = mass_assign_attributes(:age => 21)
22
+ person.age.should be_nil
23
+ end
24
+
25
+ it "ignores assigning a protected attribute" do
26
+ person = mass_assign_attributes(:first_name => "Chris")
27
+ person.age.should be_nil
28
+ end
29
+ end
30
+
31
+ shared_examples "secure mass assignment method with options", :secure_mass_assignment_method_with_options => true do
32
+ it "supports role-based mass assignment security", :active_model_version => ">= 3.1.0" do
33
+ person = mass_assign_attributes_with_options({ :age => 21 }, :as => :admin)
34
+ person.age.should == 21
35
+ end
36
+
37
+ it "skips security if passed the :without_protection option" do
38
+ person = mass_assign_attributes_with_options({ :age => 21 }, :without_protection => true)
39
+ person.age.should == 21
40
+ end
41
+ end
42
+
43
+ context "white listing attributes" do
44
+ before do
45
+ model_class.class_eval do
46
+ attr_accessible :first_name, :last_name, :name
47
+ attr_accessible :age, :as => :admin
48
+ end
49
+ end
50
+
51
+ describe "#assign_attributes", :assign_attributes, :secure_mass_assignment_method, :secure_mass_assignment_method_with_options
52
+ describe "#attributes=", :attributes=, :secure_mass_assignment_method
53
+ describe "#initialize", :initialize, :secure_mass_assignment_method, :secure_mass_assignment_method_with_options
54
+ end
55
+
56
+ context "black listing attributes" do
57
+ before do
58
+ model_class.class_eval do
59
+ attr_protected :age
60
+ attr_protected :as => :admin
61
+ end
62
+ end
63
+
64
+ describe "#assign_attributes", :assign_attributes, :secure_mass_assignment_method, :secure_mass_assignment_method_with_options
65
+ describe "#attributes=", :attributes=, :secure_mass_assignment_method
66
+ describe "#initialize", :initialize, :secure_mass_assignment_method, :secure_mass_assignment_method_with_options
67
+ end
68
+ end
69
+
70
+ context "integrating with strong_parameters", :active_model_version => ">= 3.2.0" do
71
+ let(:rails3) { Gem::Requirement.create("~> 3.2.0").satisfied_by?(Gem::Version.new(ActiveModel::VERSION::STRING)) }
72
+
73
+ before do
74
+ if rails3
75
+ require "strong_parameters"
76
+
77
+ model_class.class_eval do
78
+ include ActiveAttr::MassAssignment
79
+ include ActiveModel::MassAssignmentSecurity
80
+ include ActiveModel::ForbiddenAttributesProtection
81
+ attr_accessor :age
82
+ end
83
+ else
84
+ require "action_controller"
85
+
86
+ model_class.class_eval do
87
+ include ActiveAttr::MassAssignment
88
+ include ActiveModel::MassAssignmentSecurity
89
+ include ActiveModel::ForbiddenAttributesProtection
90
+ attr_accessor :age
91
+ end
92
+ end
93
+ end
94
+
95
+ let :forbidden_attributes_error_class do
96
+ rails3 ? ActiveModel::ForbiddenAttributes : ActiveModel::ForbiddenAttributesError
97
+ end
98
+
99
+ shared_examples "strong mass assignment method", :strong_mass_assignment_method => true do
100
+ it "raises if provided parameters when none are permitted" do
101
+ expect { mass_assign_attributes(ActionController::Parameters.new(:age => 21)) }.to raise_error forbidden_attributes_error_class
102
+ end
103
+
104
+ it "sets a permitted parameter" do
105
+ person = mass_assign_attributes(ActionController::Parameters.new(:age => 21).permit(:age))
106
+ person.age.should == 21
107
+ end
108
+
109
+ it "does not set forbidden parameters" do
110
+ person = mass_assign_attributes(ActionController::Parameters.new(:age => 21).permit(:first_name))
111
+ person.age.should be_nil
112
+ end
113
+
114
+ it "continues to set normal attributes" do
115
+ person = mass_assign_attributes(:age => 21)
116
+ person.age.should == 21
117
+ end
118
+ end
119
+
120
+ describe "#assign_attributes", :assign_attributes, :strong_mass_assignment_method
121
+ describe "#attributes=", :attributes=, :strong_mass_assignment_method
122
+ describe "#initialize", :initialize, :strong_mass_assignment_method
123
+ end
124
+ end
125
+ end
@@ -3,6 +3,7 @@ require "active_attr/attributes"
3
3
  require "active_attr/attribute_defaults"
4
4
  require "active_attr/matchers/have_attribute_matcher"
5
5
  require "active_attr/typecasted_attributes"
6
+ require "active_support/core_ext/string/strip"
6
7
 
7
8
  module ActiveAttr
8
9
  module Matchers
@@ -29,13 +30,13 @@ module ActiveAttr
29
30
  end
30
31
 
31
32
  describe "#matches?" do
32
- it { subject.matches?(model_class).should be_false }
33
+ it { matcher.matches?(model_class).should be_false }
33
34
  end
34
35
 
35
36
  describe "#failure_message" do
36
- before { subject.matches?(model_class) }
37
+ before { matcher.matches?(model_class) }
37
38
 
38
- it { subject.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::Attributes} }
39
+ it { matcher.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::Attributes} }
39
40
  end
40
41
  end
41
42
 
@@ -51,13 +52,13 @@ module ActiveAttr
51
52
  end
52
53
 
53
54
  describe "#matches?" do
54
- it { subject.matches?(model_class).should be_false }
55
+ it { matcher.matches?(model_class).should be_false }
55
56
  end
56
57
 
57
58
  describe "#failure_message" do
58
- before { subject.matches?(model_class) }
59
+ before { matcher.matches?(model_class) }
59
60
 
60
- it { subject.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::AttributeDefaults} }
61
+ it { matcher.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::AttributeDefaults} }
61
62
  end
62
63
  end
63
64
 
@@ -73,18 +74,18 @@ module ActiveAttr
73
74
  end
74
75
 
75
76
  describe "#matches?" do
76
- it { subject.matches?(model_class).should be_false }
77
+ it { matcher.matches?(model_class).should be_false }
77
78
  end
78
79
 
79
80
  describe "#failure_message" do
80
- before { subject.matches?(model_class) }
81
+ before { matcher.matches?(model_class) }
81
82
 
82
- it { subject.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::TypecastedAttributes} }
83
+ it { matcher.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::TypecastedAttributes} }
83
84
  end
84
85
  end
85
86
 
86
87
  context "a matcher with just an attribute name" do
87
- subject { described_class.new(:first_name) }
88
+ subject(:matcher) { described_class.new(:first_name) }
88
89
 
89
90
  it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
90
91
 
@@ -92,31 +93,36 @@ module ActiveAttr
92
93
  before { model_class.attribute :first_name }
93
94
 
94
95
  describe "#matches?" do
95
- it { subject.matches?(model_class).should be_true }
96
+ it { matcher.matches?(model_class).should be_true }
96
97
  end
97
98
 
98
99
  describe "#negative_failure_message" do
99
- before { subject.matches?(model_class) }
100
+ before { matcher.matches?(model_class) }
100
101
 
101
- it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name} }
102
+ it do
103
+ matcher.negative_failure_message.should == <<-MESSAGE.strip_heredoc.chomp
104
+ expected not: attribute :first_name
105
+ got: attribute :first_name
106
+ MESSAGE
107
+ end
102
108
  end
103
109
  end
104
110
 
105
111
  context "a class without the attribute" do
106
112
  describe "#matches?" do
107
- it { subject.matches?(model_class).should be_false }
113
+ it { matcher.matches?(model_class).should be_false }
108
114
  end
109
115
 
110
116
  describe "#failure_message" do
111
- before { subject.matches?(model_class) }
117
+ before { matcher.matches?(model_class) }
112
118
 
113
- it { subject.failure_message.should == %{expected Person to have attribute named first_name} }
119
+ it { matcher.failure_message.should == %{expected Person to have attribute named first_name} }
114
120
  end
115
121
  end
116
122
  end
117
123
 
118
124
  context "a matcher with a default value" do
119
- subject { described_class.new(:first_name).with_default_value_of("John") }
125
+ subject(:matcher) { described_class.new(:first_name).with_default_value_of("John") }
120
126
 
121
127
  it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
122
128
  it_should_behave_like "a matcher matching a class without ActiveAttr::AttributeDefaults"
@@ -125,13 +131,18 @@ module ActiveAttr
125
131
  before { model_class.attribute :first_name }
126
132
 
127
133
  describe "#matches?" do
128
- it { subject.matches?(model_class).should be_false }
134
+ it { matcher.matches?(model_class).should be_false }
129
135
  end
130
136
 
131
137
  describe "#failure_message" do
132
- before { subject.matches?(model_class) }
138
+ before { matcher.matches?(model_class) }
133
139
 
134
- it { subject.failure_message.should == %{expected Person to have attribute named first_name with a default value of "John"} }
140
+ it do
141
+ matcher.failure_message.should == <<-MESSAGE.strip_heredoc.chomp
142
+ expected: attribute :first_name, :default => "John"
143
+ got: attribute :first_name
144
+ MESSAGE
145
+ end
135
146
  end
136
147
  end
137
148
 
@@ -139,13 +150,18 @@ module ActiveAttr
139
150
  before { model_class.attribute :first_name, :default => "Doe" }
140
151
 
141
152
  describe "#matches?" do
142
- it { subject.matches?(model_class).should be_false }
153
+ it { matcher.matches?(model_class).should be_false }
143
154
  end
144
155
 
145
156
  describe "#failure_message" do
146
- before { subject.matches?(model_class) }
157
+ before { matcher.matches?(model_class) }
147
158
 
148
- it { subject.failure_message.should == %{expected Person to have attribute named first_name with a default value of "John"} }
159
+ it do
160
+ matcher.failure_message.should == <<-MESSAGE.strip_heredoc.chomp
161
+ expected: attribute :first_name, :default => "John"
162
+ got: attribute :first_name, :default => "Doe"
163
+ MESSAGE
164
+ end
149
165
  end
150
166
  end
151
167
 
@@ -153,19 +169,24 @@ module ActiveAttr
153
169
  before { model_class.attribute :first_name, :default => "John" }
154
170
 
155
171
  describe "#matches?" do
156
- it { subject.matches?(model_class).should be_true }
172
+ it { matcher.matches?(model_class).should be_true }
157
173
  end
158
174
 
159
175
  describe "#negative_failure_message" do
160
- before { subject.matches?(model_class) }
176
+ before { matcher.matches?(model_class) }
161
177
 
162
- it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name with a default value of "John"} }
178
+ it do
179
+ matcher.negative_failure_message.should == <<-MESSAGE.strip_heredoc.chomp
180
+ expected not: attribute :first_name, :default => "John"
181
+ got: attribute :first_name, :default => "John"
182
+ MESSAGE
183
+ end
163
184
  end
164
185
  end
165
186
  end
166
187
 
167
188
  context "a matcher with a default value of false" do
168
- subject { described_class.new(:admin).with_default_value_of(false) }
189
+ subject(:matcher) { described_class.new(:admin).with_default_value_of(false) }
169
190
 
170
191
  it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
171
192
  it_should_behave_like "a matcher matching a class without ActiveAttr::AttributeDefaults"
@@ -174,13 +195,18 @@ module ActiveAttr
174
195
  before { model_class.attribute :admin }
175
196
 
176
197
  describe "#matches?" do
177
- it { subject.matches?(model_class).should be_false }
198
+ it { matcher.matches?(model_class).should be_false }
178
199
  end
179
200
 
180
201
  describe "#failure_message" do
181
- before { subject.matches?(model_class) }
202
+ before { matcher.matches?(model_class) }
182
203
 
183
- it { subject.failure_message.should == %{expected Person to have attribute named admin with a default value of false} }
204
+ it do
205
+ matcher.failure_message.should == <<-MESSAGE.strip_heredoc.chomp
206
+ expected: attribute :admin, :default => false
207
+ got: attribute :admin
208
+ MESSAGE
209
+ end
184
210
  end
185
211
  end
186
212
 
@@ -188,13 +214,18 @@ module ActiveAttr
188
214
  before { model_class.attribute :admin, :default => nil }
189
215
 
190
216
  describe "#matches?" do
191
- it { subject.matches?(model_class).should be_false }
217
+ it { matcher.matches?(model_class).should be_false }
192
218
  end
193
219
 
194
220
  describe "#failure_message" do
195
- before { subject.matches?(model_class) }
221
+ before { matcher.matches?(model_class) }
196
222
 
197
- it { subject.failure_message.should == %{expected Person to have attribute named admin with a default value of false} }
223
+ it do
224
+ matcher.failure_message.should == <<-MESSAGE.strip_heredoc.chomp
225
+ expected: attribute :admin, :default => false
226
+ got: attribute :admin, :default => nil
227
+ MESSAGE
228
+ end
198
229
  end
199
230
  end
200
231
 
@@ -202,19 +233,24 @@ module ActiveAttr
202
233
  before { model_class.attribute :admin, :default => false }
203
234
 
204
235
  describe "#matches?" do
205
- it { subject.matches?(model_class).should be_true }
236
+ it { matcher.matches?(model_class).should be_true }
206
237
  end
207
238
 
208
239
  describe "#negative_failure_message" do
209
- before { subject.matches?(model_class) }
240
+ before { matcher.matches?(model_class) }
210
241
 
211
- it { subject.negative_failure_message.should == %{expected Person to not have attribute named admin with a default value of false} }
242
+ it do
243
+ matcher.negative_failure_message.should == <<-MESSAGE.strip_heredoc.chomp
244
+ expected not: attribute :admin, :default => false
245
+ got: attribute :admin, :default => false
246
+ MESSAGE
247
+ end
212
248
  end
213
249
  end
214
250
  end
215
251
 
216
252
  context "a matcher with a default value of nil" do
217
- subject { described_class.new(:first_name).with_default_value_of(nil) }
253
+ subject(:matcher) { described_class.new(:first_name).with_default_value_of(nil) }
218
254
 
219
255
  it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
220
256
  it_should_behave_like "a matcher matching a class without ActiveAttr::AttributeDefaults"
@@ -223,13 +259,18 @@ module ActiveAttr
223
259
  before { model_class.attribute :first_name }
224
260
 
225
261
  describe "#matches?" do
226
- it { subject.matches?(model_class).should be_true }
262
+ it { matcher.matches?(model_class).should be_true }
227
263
  end
228
264
 
229
265
  describe "#negative_failure_message" do
230
- before { subject.matches?(model_class) }
266
+ before { matcher.matches?(model_class) }
231
267
 
232
- it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name with a default value of nil} }
268
+ it do
269
+ matcher.negative_failure_message.should == <<-MESSAGE.strip_heredoc.chomp
270
+ expected not: attribute :first_name, :default => nil
271
+ got: attribute :first_name
272
+ MESSAGE
273
+ end
233
274
  end
234
275
  end
235
276
 
@@ -237,13 +278,18 @@ module ActiveAttr
237
278
  before { model_class.attribute :first_name, :default => false }
238
279
 
239
280
  describe "#matches?" do
240
- it { subject.matches?(model_class).should be_false }
281
+ it { matcher.matches?(model_class).should be_false }
241
282
  end
242
283
 
243
284
  describe "#failure_message" do
244
- before { subject.matches?(model_class) }
285
+ before { matcher.matches?(model_class) }
245
286
 
246
- it { subject.failure_message.should == %{expected Person to have attribute named first_name with a default value of nil} }
287
+ it do
288
+ matcher.failure_message.should == <<-MESSAGE.strip_heredoc.chomp
289
+ expected: attribute :first_name, :default => nil
290
+ got: attribute :first_name, :default => false
291
+ MESSAGE
292
+ end
247
293
  end
248
294
  end
249
295
 
@@ -251,19 +297,24 @@ module ActiveAttr
251
297
  before { model_class.attribute :first_name, :default => nil }
252
298
 
253
299
  describe "#matches?" do
254
- it { subject.matches?(model_class).should be_true }
300
+ it { matcher.matches?(model_class).should be_true }
255
301
  end
256
302
 
257
303
  describe "#negative_failure_message" do
258
- before { subject.matches?(model_class) }
304
+ before { matcher.matches?(model_class) }
259
305
 
260
- it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name with a default value of nil} }
306
+ it do
307
+ matcher.negative_failure_message.should == <<-MESSAGE.strip_heredoc.chomp
308
+ expected not: attribute :first_name, :default => nil
309
+ got: attribute :first_name, :default => nil
310
+ MESSAGE
311
+ end
261
312
  end
262
313
  end
263
314
  end
264
315
 
265
316
  context "a matcher with a type" do
266
- subject { described_class.new(:first_name).of_type(String) }
317
+ subject(:matcher) { described_class.new(:first_name).of_type(String) }
267
318
 
268
319
  it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
269
320
  it_should_behave_like "a matcher matching a class without ActiveAttr::TypecastedAttributes"
@@ -272,13 +323,18 @@ module ActiveAttr
272
323
  before { model_class.attribute :first_name }
273
324
 
274
325
  describe "#matches?" do
275
- it { subject.matches?(model_class).should be_false }
326
+ it { matcher.matches?(model_class).should be_false }
276
327
  end
277
328
 
278
329
  describe "#failure_message" do
279
- before { subject.matches?(model_class) }
330
+ before { matcher.matches?(model_class) }
280
331
 
281
- it { subject.failure_message.should == %{expected Person to have attribute named first_name of type String} }
332
+ it do
333
+ matcher.failure_message.should == <<-MESSAGE.strip_heredoc.chomp
334
+ expected: attribute :first_name, :type => String
335
+ got: attribute :first_name
336
+ MESSAGE
337
+ end
282
338
  end
283
339
  end
284
340
 
@@ -286,13 +342,18 @@ module ActiveAttr
286
342
  before { model_class.attribute :first_name, :type => Symbol }
287
343
 
288
344
  describe "#matches?" do
289
- it { subject.matches?(model_class).should be_false }
345
+ it { matcher.matches?(model_class).should be_false }
290
346
  end
291
347
 
292
348
  describe "#failure_message" do
293
- before { subject.matches?(model_class) }
349
+ before { matcher.matches?(model_class) }
294
350
 
295
- it { subject.failure_message.should == %{expected Person to have attribute named first_name of type String} }
351
+ it do
352
+ matcher.failure_message.should == <<-MESSAGE.strip_heredoc.chomp
353
+ expected: attribute :first_name, :type => String
354
+ got: attribute :first_name, :type => Symbol
355
+ MESSAGE
356
+ end
296
357
  end
297
358
  end
298
359
 
@@ -300,19 +361,24 @@ module ActiveAttr
300
361
  before { model_class.attribute :first_name, :type => String }
301
362
 
302
363
  describe "#matches?" do
303
- it { subject.matches?(model_class).should be_true }
364
+ it { matcher.matches?(model_class).should be_true }
304
365
  end
305
366
 
306
367
  describe "#negative_failure_message" do
307
- before { subject.matches?(model_class) }
368
+ before { matcher.matches?(model_class) }
308
369
 
309
- it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name of type String} }
370
+ it do
371
+ matcher.negative_failure_message.should == <<-MESSAGE.strip_heredoc.chomp
372
+ expected not: attribute :first_name, :type => String
373
+ got: attribute :first_name, :type => String
374
+ MESSAGE
375
+ end
310
376
  end
311
377
  end
312
378
  end
313
379
 
314
380
  context "a matcher with a type of Object" do
315
- subject { described_class.new(:first_name).of_type(Object) }
381
+ subject(:matcher) { described_class.new(:first_name).of_type(Object) }
316
382
 
317
383
  it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
318
384
  it_should_behave_like "a matcher matching a class without ActiveAttr::TypecastedAttributes"
@@ -321,13 +387,18 @@ module ActiveAttr
321
387
  before { model_class.attribute :first_name }
322
388
 
323
389
  describe "#matches?" do
324
- it { subject.matches?(model_class).should be_true }
390
+ it { matcher.matches?(model_class).should be_true }
325
391
  end
326
392
 
327
393
  describe "#negative_failure_message" do
328
- before { subject.matches?(model_class) }
394
+ before { matcher.matches?(model_class) }
329
395
 
330
- it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name of type Object} }
396
+ it do
397
+ matcher.negative_failure_message.should == <<-MESSAGE.strip_heredoc.chomp
398
+ expected not: attribute :first_name, :type => Object
399
+ got: attribute :first_name
400
+ MESSAGE
401
+ end
331
402
  end
332
403
  end
333
404
 
@@ -335,13 +406,18 @@ module ActiveAttr
335
406
  before { model_class.attribute :first_name, :type => String }
336
407
 
337
408
  describe "#matches?" do
338
- it { subject.matches?(model_class).should be_false }
409
+ it { matcher.matches?(model_class).should be_false }
339
410
  end
340
411
 
341
412
  describe "#failure_message" do
342
- before { subject.matches?(model_class) }
413
+ before { matcher.matches?(model_class) }
343
414
 
344
- it { subject.failure_message.should == %{expected Person to have attribute named first_name of type Object} }
415
+ it do
416
+ matcher.failure_message.should == <<-MESSAGE.strip_heredoc.chomp
417
+ expected: attribute :first_name, :type => Object
418
+ got: attribute :first_name, :type => String
419
+ MESSAGE
420
+ end
345
421
  end
346
422
  end
347
423
 
@@ -349,13 +425,18 @@ module ActiveAttr
349
425
  before { model_class.attribute :first_name, :type => Object }
350
426
 
351
427
  describe "#matches?" do
352
- it { subject.matches?(model_class).should be_true }
428
+ it { matcher.matches?(model_class).should be_true }
353
429
  end
354
430
 
355
431
  describe "#negative_failure_message" do
356
- before { subject.matches?(model_class) }
432
+ before { matcher.matches?(model_class) }
357
433
 
358
- it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name of type Object} }
434
+ it do
435
+ matcher.negative_failure_message.should == <<-MESSAGE.strip_heredoc.chomp
436
+ expected not: attribute :first_name, :type => Object
437
+ got: attribute :first_name, :type => Object
438
+ MESSAGE
439
+ end
359
440
  end
360
441
  end
361
442
  end