active_attr 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.

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