active_attr 0.5.0.alpha2 → 0.5.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.
- data/.rvmrc +29 -3
- data/.travis.yml +1 -0
- data/CHANGELOG.md +14 -1
- data/Gemfile +2 -1
- data/README.md +21 -14
- data/lib/active_attr/chainable_initialization.rb +2 -2
- data/lib/active_attr/matchers/have_attribute_matcher.rb +84 -22
- data/lib/active_attr/model.rb +2 -0
- data/lib/active_attr/query_attributes.rb +1 -2
- data/lib/active_attr/typecasted_attributes.rb +22 -6
- data/lib/active_attr/typecasting.rb +19 -7
- data/lib/active_attr/typecasting/big_decimal_typecaster.rb +36 -0
- data/lib/active_attr/typecasting/boolean.rb +2 -0
- data/lib/active_attr/typecasting/boolean_typecaster.rb +26 -4
- data/lib/active_attr/typecasting/date_time_typecaster.rb +19 -2
- data/lib/active_attr/typecasting/date_typecaster.rb +18 -2
- data/lib/active_attr/typecasting/float_typecaster.rb +18 -2
- data/lib/active_attr/typecasting/integer_typecaster.rb +19 -2
- data/lib/active_attr/typecasting/object_typecaster.rb +16 -0
- data/lib/active_attr/typecasting/string_typecaster.rb +18 -2
- data/lib/active_attr/version.rb +1 -1
- data/spec/functional/active_attr/matchers/have_attribute_matcher_spec.rb +364 -0
- data/spec/functional/active_attr/model_spec.rb +6 -0
- data/spec/functional/active_attr/typecasted_attributes_spec.rb +18 -8
- data/spec/unit/active_attr/matchers/have_attribute_matcher_spec.rb +19 -144
- data/spec/unit/active_attr/matchers_spec.rb +23 -0
- data/spec/unit/active_attr/typecasting/big_decimal_typecaster_spec.rb +39 -0
- data/spec/unit/active_attr/typecasting/date_time_typecaster_spec.rb +3 -2
- data/spec/unit/active_attr/typecasting_spec.rb +5 -0
- metadata +30 -20
@@ -0,0 +1,36 @@
|
|
1
|
+
require "bigdecimal"
|
2
|
+
require "bigdecimal/util"
|
3
|
+
require "active_support/core_ext/big_decimal/conversions"
|
4
|
+
|
5
|
+
module ActiveAttr
|
6
|
+
module Typecasting
|
7
|
+
# Typecasts an Object to a BigDecimal
|
8
|
+
#
|
9
|
+
# @example Usage
|
10
|
+
# BigDecimalTypecaster.new.call(1).to_s #=> "0.1E1"
|
11
|
+
#
|
12
|
+
# @since 0.5.0
|
13
|
+
class BigDecimalTypecaster
|
14
|
+
# Typecasts an object to a BigDecimal
|
15
|
+
#
|
16
|
+
# Attempt to convert using #to_d, else it creates a BigDecimal using the
|
17
|
+
# String representation of the value.
|
18
|
+
#
|
19
|
+
# @example Typecast a Fixnum
|
20
|
+
# typecaster.call(1).to_s #=> "0.1E1"
|
21
|
+
#
|
22
|
+
# @param [Object, #to_d, #to_s] value The object to typecast
|
23
|
+
#
|
24
|
+
# @return [BigDecimal, nil] The result of typecasting
|
25
|
+
#
|
26
|
+
# @since 0.5.0
|
27
|
+
def call(value)
|
28
|
+
if value.respond_to? :to_d
|
29
|
+
value.to_d
|
30
|
+
else
|
31
|
+
BigDecimal.new value.to_s
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -2,13 +2,35 @@ require "active_support/core_ext/object/blank"
|
|
2
2
|
|
3
3
|
module ActiveAttr
|
4
4
|
module Typecasting
|
5
|
-
#
|
5
|
+
# Typecasts an Object to true or false
|
6
|
+
#
|
7
|
+
# @example Usage
|
8
|
+
# BooleanTypecaster.new.call(1) #=> true
|
9
|
+
#
|
10
|
+
# @since 0.5.0
|
6
11
|
class BooleanTypecaster
|
7
|
-
#
|
8
|
-
#
|
12
|
+
# Values which force a false result for typecasting
|
13
|
+
#
|
14
|
+
# These values are based on the
|
15
|
+
# {YAML language}[http://yaml.org/type/bool.html].
|
16
|
+
#
|
17
|
+
# @since 0.5.0
|
9
18
|
FALSE_VALUES = ["n", "N", "no", "No", "NO", "false", "False", "FALSE", "off", "Off", "OFF", "f", "F"]
|
10
19
|
|
11
|
-
#
|
20
|
+
# Typecasts an object to true or false
|
21
|
+
#
|
22
|
+
# Similar to ActiveRecord, when the attribute is a zero value or
|
23
|
+
# is a string that represents false, typecasting returns false.
|
24
|
+
# Otherwise typecasting just checks the presence of a value.
|
25
|
+
#
|
26
|
+
# @example Typecast a Fixnum
|
27
|
+
# typecaster.call(1) #=> true
|
28
|
+
#
|
29
|
+
# @param [Object] value The object to typecast
|
30
|
+
#
|
31
|
+
# @return [true, false] The result of typecasting
|
32
|
+
#
|
33
|
+
# @since 0.5.0
|
12
34
|
def call(value)
|
13
35
|
case value
|
14
36
|
when *FALSE_VALUES then false
|
@@ -3,9 +3,26 @@ require "active_support/time"
|
|
3
3
|
|
4
4
|
module ActiveAttr
|
5
5
|
module Typecasting
|
6
|
-
#
|
6
|
+
# Typecasts an Object to a DateTime
|
7
|
+
#
|
8
|
+
# @example Usage
|
9
|
+
# typecaster = DateTimeTypecaster.new
|
10
|
+
# typecaster.call("2012-01-01") #=> Sun, 01 Jan 2012 00:00:00 +0000
|
11
|
+
#
|
12
|
+
# @since 0.5.0
|
7
13
|
class DateTimeTypecaster
|
8
|
-
#
|
14
|
+
# Typecasts an object to a DateTime
|
15
|
+
#
|
16
|
+
# Attempts to convert using #to_datetime.
|
17
|
+
#
|
18
|
+
# @example Typecast a String
|
19
|
+
# typecaster.call("2012-01-01") #=> Sun, 01 Jan 2012 00:00:00 +0000
|
20
|
+
#
|
21
|
+
# @param [Object, #to_datetime] value The object to typecast
|
22
|
+
#
|
23
|
+
# @return [DateTime, nil] The result of typecasting
|
24
|
+
#
|
25
|
+
# @since 0.5.0
|
9
26
|
def call(value)
|
10
27
|
value.to_datetime if value.respond_to? :to_datetime
|
11
28
|
end
|
@@ -3,9 +3,25 @@ require "active_support/time"
|
|
3
3
|
|
4
4
|
module ActiveAttr
|
5
5
|
module Typecasting
|
6
|
-
#
|
6
|
+
# Typecasts an Object to a Date
|
7
|
+
#
|
8
|
+
# @example Usage
|
9
|
+
# DateTypecaster.new.call("2012-01-01") #=> Sun, 01 Jan 2012
|
10
|
+
#
|
11
|
+
# @since 0.5.0
|
7
12
|
class DateTypecaster
|
8
|
-
#
|
13
|
+
# Typecasts an object to a Date
|
14
|
+
#
|
15
|
+
# Attempts to convert using #to_date.
|
16
|
+
#
|
17
|
+
# @example Typecast a String
|
18
|
+
# typecaster.call("2012-01-01") #=> Sun, 01 Jan 2012
|
19
|
+
#
|
20
|
+
# @param [Object, #to_date] value The object to typecast
|
21
|
+
#
|
22
|
+
# @return [Date, nil] The result of typecasting
|
23
|
+
#
|
24
|
+
# @since 0.5.0
|
9
25
|
def call(value)
|
10
26
|
value.to_date if value.respond_to? :to_date
|
11
27
|
end
|
@@ -1,8 +1,24 @@
|
|
1
1
|
module ActiveAttr
|
2
2
|
module Typecasting
|
3
|
-
#
|
3
|
+
# Typecasts an Object to a Float
|
4
|
+
#
|
5
|
+
# @example Usage
|
6
|
+
# FloatTypecaster.new.call(1) #=> 1.0
|
7
|
+
#
|
8
|
+
# @since 0.5.0
|
4
9
|
class FloatTypecaster
|
5
|
-
#
|
10
|
+
# Typecasts an object to a Float
|
11
|
+
#
|
12
|
+
# Attempts to convert using #to_f.
|
13
|
+
#
|
14
|
+
# @example Typecast a Fixnum
|
15
|
+
# typecaster.call(1) #=> 1.0
|
16
|
+
#
|
17
|
+
# @param [Object, #to_f] value The object to typecast
|
18
|
+
#
|
19
|
+
# @return [Float, nil] The result of typecasting
|
20
|
+
#
|
21
|
+
# @since 0.5.0
|
6
22
|
def call(value)
|
7
23
|
value.to_f if value.respond_to? :to_f
|
8
24
|
end
|
@@ -1,8 +1,25 @@
|
|
1
1
|
module ActiveAttr
|
2
2
|
module Typecasting
|
3
|
-
#
|
3
|
+
# Typecasts an Object to an Integer
|
4
|
+
#
|
5
|
+
# @example Usage
|
6
|
+
# IntegerTypecaster.new.call("1") #=> 1
|
7
|
+
#
|
8
|
+
# @since 0.5.0
|
4
9
|
class IntegerTypecaster
|
5
|
-
#
|
10
|
+
# Typecasts an object to an Integer
|
11
|
+
#
|
12
|
+
# Attempts to convert using #to_i. Handles FloatDomainError if the
|
13
|
+
# object is INFINITY or NAN.
|
14
|
+
#
|
15
|
+
# @example Typecast a String
|
16
|
+
# typecaster.call("1") #=> 1
|
17
|
+
#
|
18
|
+
# @param [Object, #to_i] value The object to typecast
|
19
|
+
#
|
20
|
+
# @return [Integer, nil] The result of typecasting
|
21
|
+
#
|
22
|
+
# @since 0.5.0
|
6
23
|
def call(value)
|
7
24
|
value.to_i if value.respond_to? :to_i
|
8
25
|
rescue FloatDomainError
|
@@ -1,6 +1,22 @@
|
|
1
1
|
module ActiveAttr
|
2
2
|
module Typecasting
|
3
|
+
# A "null" typecaster to provide uniformity
|
4
|
+
#
|
5
|
+
# @example Usage
|
6
|
+
# ObjectTypecaster.new.call("") #=> ""
|
7
|
+
#
|
8
|
+
# @since 0.5.0
|
3
9
|
class ObjectTypecaster
|
10
|
+
# Returns the original value unmodified
|
11
|
+
#
|
12
|
+
# @example Typecast an Object
|
13
|
+
# typecaster.call(1) #=> 1
|
14
|
+
#
|
15
|
+
# @param [Object] value The object to typecast
|
16
|
+
#
|
17
|
+
# @return [Object] Whatever you passed in
|
18
|
+
#
|
19
|
+
# @since 0.5.0
|
4
20
|
def call(value)
|
5
21
|
value
|
6
22
|
end
|
@@ -1,8 +1,24 @@
|
|
1
1
|
module ActiveAttr
|
2
2
|
module Typecasting
|
3
|
-
#
|
3
|
+
# Typecasts an Object to a String
|
4
|
+
#
|
5
|
+
# @example Usage
|
6
|
+
# StringTypecaster.new.call(1) #=> "1"
|
7
|
+
#
|
8
|
+
# @since 0.5.0
|
4
9
|
class StringTypecaster
|
5
|
-
#
|
10
|
+
# Typecasts an object to a String
|
11
|
+
#
|
12
|
+
# Attempts to convert using #to_s.
|
13
|
+
#
|
14
|
+
# @example Typecast a Fixnum
|
15
|
+
# typecaster.call(1) #=> "1"
|
16
|
+
#
|
17
|
+
# @param [Object, #to_s] value The object to typecast
|
18
|
+
#
|
19
|
+
# @return [String, nil] The result of typecasting
|
20
|
+
#
|
21
|
+
# @since 0.5.0
|
6
22
|
def call(value)
|
7
23
|
value.to_s if value.respond_to? :to_s
|
8
24
|
end
|
data/lib/active_attr/version.rb
CHANGED
@@ -0,0 +1,364 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "active_attr/attributes"
|
3
|
+
require "active_attr/attribute_defaults"
|
4
|
+
require "active_attr/matchers/have_attribute_matcher"
|
5
|
+
require "active_attr/typecasted_attributes"
|
6
|
+
|
7
|
+
module ActiveAttr
|
8
|
+
module Matchers
|
9
|
+
describe HaveAttributeMatcher do
|
10
|
+
let :model_class do
|
11
|
+
Class.new do
|
12
|
+
include Attributes
|
13
|
+
include AttributeDefaults
|
14
|
+
include TypecastedAttributes
|
15
|
+
|
16
|
+
def self.name
|
17
|
+
"Person"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
shared_examples "a matcher matching a class without ActiveAttr::Attributes" do
|
23
|
+
let :model_class do
|
24
|
+
Class.new do
|
25
|
+
def self.name
|
26
|
+
"Person"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#matches?" do
|
32
|
+
it { subject.matches?(model_class).should be_false }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#failure_message" do
|
36
|
+
before { subject.matches?(model_class) }
|
37
|
+
|
38
|
+
it { subject.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::Attributes} }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
shared_examples "a matcher matching a class without ActiveAttr::AttributeDefaults" do
|
43
|
+
let :model_class do
|
44
|
+
Class.new do
|
45
|
+
include Attributes
|
46
|
+
|
47
|
+
def self.name
|
48
|
+
"Person"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "#matches?" do
|
54
|
+
it { subject.matches?(model_class).should be_false }
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#failure_message" do
|
58
|
+
before { subject.matches?(model_class) }
|
59
|
+
|
60
|
+
it { subject.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::AttributeDefaults} }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
shared_examples "a matcher matching a class without ActiveAttr::TypecastedAttributes" do
|
65
|
+
let :model_class do
|
66
|
+
Class.new do
|
67
|
+
include Attributes
|
68
|
+
|
69
|
+
def self.name
|
70
|
+
"Person"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#matches?" do
|
76
|
+
it { subject.matches?(model_class).should be_false }
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#failure_message" do
|
80
|
+
before { subject.matches?(model_class) }
|
81
|
+
|
82
|
+
it { subject.failure_message.should == %{expected #{model_class.name} to include ActiveAttr::TypecastedAttributes} }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context "a matcher with just an attribute name" do
|
87
|
+
subject { described_class.new(:first_name) }
|
88
|
+
|
89
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
|
90
|
+
|
91
|
+
context "a class with the attribute" do
|
92
|
+
before { model_class.attribute :first_name }
|
93
|
+
|
94
|
+
describe "#matches?" do
|
95
|
+
it { subject.matches?(model_class).should be_true }
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#negative_failure_message" do
|
99
|
+
before { subject.matches?(model_class) }
|
100
|
+
|
101
|
+
it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name} }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context "a class without the attribute" do
|
106
|
+
describe "#matches?" do
|
107
|
+
it { subject.matches?(model_class).should be_false }
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#failure_message" do
|
111
|
+
before { subject.matches?(model_class) }
|
112
|
+
|
113
|
+
it { subject.failure_message.should == %{expected Person to have attribute named first_name} }
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context "a matcher with a default value" do
|
119
|
+
subject { described_class.new(:first_name).with_default_value_of("John") }
|
120
|
+
|
121
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
|
122
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::AttributeDefaults"
|
123
|
+
|
124
|
+
context "a class with the attribute but no default" do
|
125
|
+
before { model_class.attribute :first_name }
|
126
|
+
|
127
|
+
describe "#matches?" do
|
128
|
+
it { subject.matches?(model_class).should be_false }
|
129
|
+
end
|
130
|
+
|
131
|
+
describe "#failure_message" do
|
132
|
+
before { subject.matches?(model_class) }
|
133
|
+
|
134
|
+
it { subject.failure_message.should == %{expected Person to have attribute named first_name with a default value of "John"} }
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context "a class with the attribute and a different default" do
|
139
|
+
before { model_class.attribute :first_name, :default => "Doe" }
|
140
|
+
|
141
|
+
describe "#matches?" do
|
142
|
+
it { subject.matches?(model_class).should be_false }
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "#failure_message" do
|
146
|
+
before { subject.matches?(model_class) }
|
147
|
+
|
148
|
+
it { subject.failure_message.should == %{expected Person to have attribute named first_name with a default value of "John"} }
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context "a class with the attribute and the right default" do
|
153
|
+
before { model_class.attribute :first_name, :default => "John" }
|
154
|
+
|
155
|
+
describe "#matches?" do
|
156
|
+
it { subject.matches?(model_class).should be_true }
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "#negative_failure_message" do
|
160
|
+
before { subject.matches?(model_class) }
|
161
|
+
|
162
|
+
it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name with a default value of "John"} }
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "a matcher with a default value of false" do
|
168
|
+
subject { described_class.new(:admin).with_default_value_of(false) }
|
169
|
+
|
170
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
|
171
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::AttributeDefaults"
|
172
|
+
|
173
|
+
context "a class with the attribute but no default" do
|
174
|
+
before { model_class.attribute :admin }
|
175
|
+
|
176
|
+
describe "#matches?" do
|
177
|
+
it { subject.matches?(model_class).should be_false }
|
178
|
+
end
|
179
|
+
|
180
|
+
describe "#failure_message" do
|
181
|
+
before { subject.matches?(model_class) }
|
182
|
+
|
183
|
+
it { subject.failure_message.should == %{expected Person to have attribute named admin with a default value of false} }
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context "a class with the attribute and a default of nil" do
|
188
|
+
before { model_class.attribute :admin, :default => nil }
|
189
|
+
|
190
|
+
describe "#matches?" do
|
191
|
+
it { subject.matches?(model_class).should be_false }
|
192
|
+
end
|
193
|
+
|
194
|
+
describe "#failure_message" do
|
195
|
+
before { subject.matches?(model_class) }
|
196
|
+
|
197
|
+
it { subject.failure_message.should == %{expected Person to have attribute named admin with a default value of false} }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context "a class with the attribute and the right default" do
|
202
|
+
before { model_class.attribute :admin, :default => false }
|
203
|
+
|
204
|
+
describe "#matches?" do
|
205
|
+
it { subject.matches?(model_class).should be_true }
|
206
|
+
end
|
207
|
+
|
208
|
+
describe "#negative_failure_message" do
|
209
|
+
before { subject.matches?(model_class) }
|
210
|
+
|
211
|
+
it { subject.negative_failure_message.should == %{expected Person to not have attribute named admin with a default value of false} }
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
context "a matcher with a default value of nil" do
|
217
|
+
subject { described_class.new(:first_name).with_default_value_of(nil) }
|
218
|
+
|
219
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
|
220
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::AttributeDefaults"
|
221
|
+
|
222
|
+
context "a class with the attribute but no default" do
|
223
|
+
before { model_class.attribute :first_name }
|
224
|
+
|
225
|
+
describe "#matches?" do
|
226
|
+
it { subject.matches?(model_class).should be_true }
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "#negative_failure_message" do
|
230
|
+
before { subject.matches?(model_class) }
|
231
|
+
|
232
|
+
it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name with a default value of nil} }
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context "a class with the attribute and a default of false" do
|
237
|
+
before { model_class.attribute :first_name, :default => false }
|
238
|
+
|
239
|
+
describe "#matches?" do
|
240
|
+
it { subject.matches?(model_class).should be_false }
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "#failure_message" do
|
244
|
+
before { subject.matches?(model_class) }
|
245
|
+
|
246
|
+
it { subject.failure_message.should == %{expected Person to have attribute named first_name with a default value of nil} }
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context "a class with the attribute and the right default" do
|
251
|
+
before { model_class.attribute :first_name, :default => nil }
|
252
|
+
|
253
|
+
describe "#matches?" do
|
254
|
+
it { subject.matches?(model_class).should be_true }
|
255
|
+
end
|
256
|
+
|
257
|
+
describe "#negative_failure_message" do
|
258
|
+
before { subject.matches?(model_class) }
|
259
|
+
|
260
|
+
it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name with a default value of nil} }
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context "a matcher with a type" do
|
266
|
+
subject { described_class.new(:first_name).of_type(String) }
|
267
|
+
|
268
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
|
269
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::TypecastedAttributes"
|
270
|
+
|
271
|
+
context "a class with the attribute but no type" do
|
272
|
+
before { model_class.attribute :first_name }
|
273
|
+
|
274
|
+
describe "#matches?" do
|
275
|
+
it { subject.matches?(model_class).should be_false }
|
276
|
+
end
|
277
|
+
|
278
|
+
describe "#failure_message" do
|
279
|
+
before { subject.matches?(model_class) }
|
280
|
+
|
281
|
+
it { subject.failure_message.should == %{expected Person to have attribute named first_name of type String} }
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
context "a class with the attribute and a different type" do
|
286
|
+
before { model_class.attribute :first_name, :type => Symbol }
|
287
|
+
|
288
|
+
describe "#matches?" do
|
289
|
+
it { subject.matches?(model_class).should be_false }
|
290
|
+
end
|
291
|
+
|
292
|
+
describe "#failure_message" do
|
293
|
+
before { subject.matches?(model_class) }
|
294
|
+
|
295
|
+
it { subject.failure_message.should == %{expected Person to have attribute named first_name of type String} }
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
context "a class with the attribute and the right type" do
|
300
|
+
before { model_class.attribute :first_name, :type => String }
|
301
|
+
|
302
|
+
describe "#matches?" do
|
303
|
+
it { subject.matches?(model_class).should be_true }
|
304
|
+
end
|
305
|
+
|
306
|
+
describe "#negative_failure_message" do
|
307
|
+
before { subject.matches?(model_class) }
|
308
|
+
|
309
|
+
it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name of type String} }
|
310
|
+
end
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
context "a matcher with a type of Object" do
|
315
|
+
subject { described_class.new(:first_name).of_type(Object) }
|
316
|
+
|
317
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::Attributes"
|
318
|
+
it_should_behave_like "a matcher matching a class without ActiveAttr::TypecastedAttributes"
|
319
|
+
|
320
|
+
context "a class with the attribute but no type" do
|
321
|
+
before { model_class.attribute :first_name }
|
322
|
+
|
323
|
+
describe "#matches?" do
|
324
|
+
it { subject.matches?(model_class).should be_true }
|
325
|
+
end
|
326
|
+
|
327
|
+
describe "#negative_failure_message" do
|
328
|
+
before { subject.matches?(model_class) }
|
329
|
+
|
330
|
+
it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name of type Object} }
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
context "a class with the attribute and a different type" do
|
335
|
+
before { model_class.attribute :first_name, :type => String }
|
336
|
+
|
337
|
+
describe "#matches?" do
|
338
|
+
it { subject.matches?(model_class).should be_false }
|
339
|
+
end
|
340
|
+
|
341
|
+
describe "#failure_message" do
|
342
|
+
before { subject.matches?(model_class) }
|
343
|
+
|
344
|
+
it { subject.failure_message.should == %{expected Person to have attribute named first_name of type Object} }
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
context "a class with the attribute and the right type" do
|
349
|
+
before { model_class.attribute :first_name, :type => Object }
|
350
|
+
|
351
|
+
describe "#matches?" do
|
352
|
+
it { subject.matches?(model_class).should be_true }
|
353
|
+
end
|
354
|
+
|
355
|
+
describe "#negative_failure_message" do
|
356
|
+
before { subject.matches?(model_class) }
|
357
|
+
|
358
|
+
it { subject.negative_failure_message.should == %{expected Person to not have attribute named first_name of type Object} }
|
359
|
+
end
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
end
|