cainlevy / semantic-attributes

object-oriented activerecord validations and machine/human formatting

This URL has Read+Write access

semantic-attributes / gist.rdoc
0b163757 » cainlevy 2008-10-07 condensing predicates into ... 1 ==Describing
2
3 Format:
4
5 #{attribute_name}_#{verb}_#{required}?_#{predicate}(options = {})
6
7 Example:
8
9 class Post < ActiveRecord::Base
10 belongs_to :author
11
12 title_is_required
13 author_is_a_required_association
14 body_has_length :below => 256
15 end
16
17 ==Predicates
18
19 ===aliased
20 Use when the attribute may only contain certain values, but those values have human labels.
21
22 Example:
23
24 class User < ActiveRecord::Base
25 classification_is_aliased :options => {
26 1 => "user",
27 2 => "admin",
28 3 => "superadmin"
29 }
30 end
31
32 ===association
33 Use when an association has a minimum or maximum number of records, or when you need to require that it exists. Note that it's ok for two records to require each other -- there won't be any infinitely recursive validation problems.
34
35 Example:
36
37 class User < ActiveRecord::Base
38 has_many :quotes
39
40 quotes_is_an_association :max => 3
41 end
42
43 class Quote < ActiveRecord::Base
44 belongs_to :user
45
46 user_is_a_required_association
47 end
48
49 ===blacklisted
50 Use when you need to make sure some value is NOT saved. Maybe you've reserved some for yourself?
51
a7280506 » cainlevy 2009-01-20 refactor the Blacklisted pr... 52 By default this is not case sensitive. Which means that by default this assumes you only have strings. If you need to blacklist other data types, set :case_sensitive => false.
53
0b163757 » cainlevy 2008-10-07 condensing predicates into ... 54 Example:
55
56 class User < ActiveRecord::Base
a7280506 » cainlevy 2009-01-20 refactor the Blacklisted pr... 57 username_is_blacklisted :restricted => %w(admin superadmin god user anonymous)
0b163757 » cainlevy 2008-10-07 condensing predicates into ... 58 end
59
60 ===domain
61 Use when you need to capture a domain name, without protocol or path information.
62
63 Example:
64
65 class Account < ActiveRecord::Base
66 cname_is_domain
67 end
68
69 ===email
70 Use when you want to eliminate malformed email addresses. This will _not_ ensure deliverability -- that requires a field test.
71
72 Example:
73
74 class User < ActiveRecord::Base
75 email_address_is_email
76 end
77
78 ===enumerated aka whitelisted
79 Use when you want to limit the values a field may have. Useful for constraining polymorphic associations! Note that because of how required-ness is handled, if a field is empty this predicate will not be evaluated.
80
806c2187 » cainlevy 2009-01-07 the Enumerated predicate no... 81 Note that this predicate implies required-ness.
82
0b163757 » cainlevy 2008-10-07 condensing predicates into ... 83 Example:
84
85 class Favorite < ActiveRecord::Base
86 belongs_to :favoritable, :polymorphic => true
87
88 # only allow favoriting of a User or Project
89 favoritable_type_is_enumerated :options => %w(User Project)
90 end
91
92 ===hex_color
93 Use when you need to capture hex colors. Useful for theming! All colors will be stored in the database with a leading pound sign, expanded to the full six character size (e.g. "a1e" becomes "#aa11ee").
94
95 Example:
96
97 class Account < ActiveRecord::Base
98 background_is_hex_color
99 end
100
99c4a4ba » cainlevy 2008-11-18 extending the Length predic... 101 ===length aka size
102 Use when you need to set an upper or lower boundary on the length of a field. Note that this also works on arrays and hashes.
0b163757 » cainlevy 2008-10-07 condensing predicates into ... 103
104 Example:
105
106 class User < ActiveRecord::Base
107 username_has_length :range => 3..20
108 # the following are identical:
109 password_has_length :above => 3
110 password_has_length :above => 4, :exactly => true
111 end
112
113 ===number
114 Use when you have a numeric field that needs to be constrained on the number line.
115
116 Example:
117
118 class Auction < ActiveRecord::Base
119 buyout_is_number :integer => true
7f66dbbb » cainlevy 2008-12-03 Adding :at_least and :no_mo... 120 bid_increment_is_number :at_least => 5
0b163757 » cainlevy 2008-10-07 condensing predicates into ... 121 quantity_is_number :range => 1..10
122 end
123
124 ===pattern
125 Use when you need to define a regular expression pattern for a field. Actually, DON'T USE THIS. Instead, extend it and create a new predicate!
126
127 ===phone_number
128 Use when you want to validate phone numbers against a formal numbering plan. Currently only supports NANP (North American Numbering Plan), which uses the +1 prefix. This predicate is smart enough to exclude the bogus 555-01xx numbers.
129
130 If you use Semantic Attributes in an international application before I do, please help by contributing back to this predicate.
131
132 Example:
133
134 class User < ActiveRecord::Base
135 mobile_is_a_phone_number
136 end
137
138 ===required
139 Use when you simple need a field to be required. Note that if the field has any other semantics, you should add required-ness to those!
140
141 Example:
142
143 class User < ActiveRecord::Base
144 password_is_required
145 end
146
147 ===same_as
148 Use when you need some attribute to be the same as another attribute, aka this-is-how-you-do-password-confirmation.
149
150 Example:
151
152 class User < ActiveRecord::Base
153 password_confirmation_is_same_as :method => :password
154 end
155
156 ===time
55162668 » cainlevy 2009-02-06 making the Time predicate u... 157 Use when you have a time field that needs to be constrained on the timeline. You may set your constraint either absolutely (e.g. after Jan 1, 2005) or relatively (e.g. no older than 5 minutes from now).
0b163757 » cainlevy 2008-10-07 condensing predicates into ... 158
55162668 » cainlevy 2009-02-06 making the Time predicate u... 159 Example:
160
161 class Project < ActiveRecord::Base
162 # this deadline must be after Jan 1, 2005
163 deadline_is_time :after => Time.parse("2005-01-01 00:00:00")
164 end
165
166 class Project < ActiveRecord::Base
167 # this deadline must be no older than 5 days and no further in the future than 1 week, as of the time of validation.
168 deadline_is_time :distance => (-5.days)..(1.week)
169 end
0b163757 » cainlevy 2008-10-07 condensing predicates into ... 170
171 ===unique
172 Use when you need an attribute to be unique, possibly in the scope of some other attributes. By default this is not case sensitive.
173
174 Example:
175
176 class User < ActiveRecord::Base
177 email_is_unique :scope => [:account_id]
178 end
179
180 ===url
181 Use when you have url. Please, use it! URLs can be complex. You may constrain your url to a list of domains, schemes, or ports. You may allow or disallow ip addresses.
182
183 Example:
184
185 class User < ActiveRecord::Base
186 homepage_is_url :domain => %w(com net biz info edu)
187 backup_is_url :schemes => %w(https), :ports => [443], :implied_scheme => 'https'
188 end
189
190 ===usa_state
191 Use when you have a USA state (or territory). Stores all states using USPS abbreviation.
192
193 Example:
194
195 class Address < ActiveRecord::Base
196 state_is_a_usa_state :with_territories => true
197 end
198
199 ===usa_zip_code
200 Use when you have a USA postal code, possibly with the extended +4 syntax.
201
202 Example:
203
204 class Address < ActiveRecord::Base
205 # :extended may be any of :allowed, :required, or false (default)
206 postal_code_is_a_usa_zip_code :extended => :allowed
207 end
208