hobofields 0.8.5 → 0.8.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +17 -2
- data/hobofields.gemspec +34 -134
- data/lib/hobo_fields/email_address.rb +1 -1
- data/lib/hobo_fields/field_spec.rb +14 -1
- data/lib/hobo_fields/migration_generator.rb +23 -21
- data/lib/hobo_fields/model_extensions.rb +3 -4
- data/lib/hobo_fields.rb +11 -5
- data/rails_generators/hobo_migration/hobo_migration_generator.rb +11 -10
- data/test/hobofields.rdoctest +22 -20
- data/test/hobofields_api.rdoctest +134 -113
- data/test/migration_generator.rdoctest +204 -174
- data/test/rich_types.rdoctest +134 -100
- data/test/test_hobofield_model_generator.rb +3 -2
- metadata +3 -3
@@ -1,41 +1,61 @@
|
|
1
|
-
# HoboFields API
|
2
1
|
|
3
|
-
|
2
|
+
# HoboFields API
|
4
3
|
|
5
4
|
In order for the API examples to run we need a connection to a database. You can ignore this if you're just looking for documentation.
|
5
|
+
{.hidden}
|
6
|
+
|
7
|
+
Our test requires rails:
|
8
|
+
{.hidden}
|
6
9
|
|
7
10
|
>> require 'rubygems'
|
8
11
|
>> require 'activesupport'
|
9
|
-
>> Dependencies.load_paths << '.'
|
10
|
-
>> Dependencies.mechanism = :require
|
11
12
|
>> require 'activerecord'
|
12
13
|
>> require 'action_controller'
|
13
|
-
|
14
|
+
{.hidden}
|
15
|
+
|
16
|
+
We need a database connection for this test:
|
17
|
+
{.hidden}
|
18
|
+
|
14
19
|
>> mysql_database = "hobofields_doctest"
|
20
|
+
>> system "mysqladmin --force drop #{mysql_database} 2> /dev/null"
|
15
21
|
>> system("mysqladmin create #{mysql_database}") or raise "could not create database"
|
16
22
|
>> ActiveRecord::Base.establish_connection(:adapter => "mysql",
|
17
23
|
:database => mysql_database,
|
18
24
|
:host => "localhost")
|
25
|
+
{.hidden}
|
26
|
+
|
27
|
+
Some load path manipulation you shouldn't need:
|
28
|
+
{.hidden}
|
29
|
+
|
30
|
+
>> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../hobofields/lib')
|
31
|
+
>> $:.unshift File.join(File.expand_path(File.dirname(__FILE__)), '../../hobosupport/lib')
|
32
|
+
{.hidden}
|
33
|
+
|
34
|
+
Require the module we're testing:
|
35
|
+
{.hidden}
|
36
|
+
|
37
|
+
>> require 'hobosupport'
|
38
|
+
>> require 'hobofields'
|
19
39
|
|
20
40
|
## Example Models
|
21
41
|
|
22
42
|
Let's define some example models that we can use to demonstrate the API. With HoboFields we define the model's fields, with their name and type, directly in the model like so:
|
23
43
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
44
|
+
>>
|
45
|
+
class Advert < ActiveRecord::Base
|
46
|
+
fields do
|
47
|
+
title :string
|
48
|
+
body :text
|
49
|
+
contact_address :email_address
|
50
|
+
end
|
51
|
+
end
|
32
52
|
|
33
53
|
(Note: `:email_address` is an example of a "Rich Type" provided by HoboFields -- more on those later)
|
34
54
|
|
35
55
|
The migration generator uses this information to create a migration. The following creates and runs the migration so we're ready to go.
|
36
56
|
|
37
|
-
|
38
|
-
|
57
|
+
>> up, down = HoboFields::MigrationGenerator.run
|
58
|
+
>> ActiveRecord::Migration.class_eval up
|
39
59
|
|
40
60
|
We're now ready to start demonstrating the API
|
41
61
|
|
@@ -47,23 +67,23 @@ The main feature of HoboFields, aside from the migration generator, is the abili
|
|
47
67
|
|
48
68
|
Field values are returned as the type you specify.
|
49
69
|
|
50
|
-
|
51
|
-
|
52
|
-
|
70
|
+
>> a = Advert.new :body => "This is the body"
|
71
|
+
>> a.body.class
|
72
|
+
=> HoboFields::Text
|
53
73
|
|
54
74
|
This also works after a round-trip to the database
|
55
75
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
76
|
+
>> a.save
|
77
|
+
>> b = Advert.find(a.id)
|
78
|
+
>> b.body.class
|
79
|
+
=> HoboFields::Text
|
60
80
|
|
61
81
|
HoboFields::Text is a simple subclass of string. It's a "wrapper type", by which we mean you pass the underlying value to the constructor.
|
62
82
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
83
|
+
>> t = HoboFields::Text.new("hello")
|
84
|
+
=> "hello"
|
85
|
+
>> t.class
|
86
|
+
=> HoboFields::Text
|
67
87
|
|
68
88
|
If you define your own rich types, they need to support a one argument constructor in the same way.
|
69
89
|
|
@@ -74,21 +94,20 @@ Although the body of our advert is really just a string, it's very useful that i
|
|
74
94
|
|
75
95
|
In the `fields do ... end` block you can give the field-type either as a name (symbol) or a class. For example, we could have said
|
76
96
|
|
77
|
-
|
97
|
+
body HoboFields::Text
|
78
98
|
|
79
99
|
Obviously the symbol form is a nicer:
|
80
100
|
|
81
|
-
|
101
|
+
body :text
|
82
102
|
|
83
103
|
If you provide a class it must define the `COLUMN_TYPE` constant. This instructs the migration generator to create the appropriate underlying database column type. It should be a symbol that is a valid column type in a Rails migration.
|
84
104
|
|
85
|
-
|
86
|
-
|
105
|
+
>> HoboFields::Text::COLUMN_TYPE
|
106
|
+
=> :text
|
87
107
|
|
88
108
|
The full set of available symbolic names is
|
89
109
|
|
90
110
|
* `:integer`
|
91
|
-
* `:big_integer`
|
92
111
|
* `:float`
|
93
112
|
* `:string`
|
94
113
|
* `:text`
|
@@ -99,7 +118,7 @@ The full set of available symbolic names is
|
|
99
118
|
* `:textile`
|
100
119
|
* `:markdown`
|
101
120
|
* `:password`
|
102
|
-
* `:
|
121
|
+
* `:email_address`
|
103
122
|
|
104
123
|
You can add your own types too. More on that later.
|
105
124
|
|
@@ -112,33 +131,33 @@ HoboFields adds a few features to your models.
|
|
112
131
|
|
113
132
|
Returns the type (i.e. class) declared for a given field or attribute
|
114
133
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
134
|
+
>> Advert.attr_type :title
|
135
|
+
=> String
|
136
|
+
>> Advert.attr_type :body
|
137
|
+
=> HoboFields::Text
|
119
138
|
|
120
139
|
### `Model.column`
|
121
140
|
|
122
141
|
A shorthand for accessing column metadata
|
123
142
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
143
|
+
>> col = Advert.column :title
|
144
|
+
>> col.name
|
145
|
+
=> "title"
|
146
|
+
>> col.klass
|
147
|
+
>> String
|
129
148
|
|
130
149
|
### `Model.attr_accessor` with types
|
131
150
|
|
132
151
|
In your HoboFields models you can also give type information to "virtual fields" (i.e. regular Ruby attributes)
|
133
152
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
153
|
+
>>
|
154
|
+
class Advert
|
155
|
+
attr_accessor :my_attr, :type => :text
|
156
|
+
end
|
157
|
+
>> a = Advert.new
|
158
|
+
>> a.my_attr = "hello"
|
159
|
+
>> a.my_attr.class
|
160
|
+
=> HoboFields::Text
|
142
161
|
|
143
162
|
|
144
163
|
## Field validations
|
@@ -149,73 +168,73 @@ HoboFields gives you some shorthands for declaring some common validations right
|
|
149
168
|
|
150
169
|
The `:required` argument to a field gives a `validates_presence_of`:
|
151
170
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
171
|
+
>>
|
172
|
+
class Advert
|
173
|
+
fields do
|
174
|
+
title :string, :required
|
175
|
+
end
|
176
|
+
end
|
177
|
+
>> a = Advert.new
|
178
|
+
>> a.valid?
|
179
|
+
=> false
|
180
|
+
>> a.errors.full_messages
|
181
|
+
=> ["Title can't be blank"]
|
182
|
+
>> a.title = "Jimbo"
|
183
|
+
>> a.save
|
184
|
+
=> true
|
166
185
|
|
167
186
|
|
168
187
|
### Unique fields
|
169
188
|
|
170
189
|
The `:unique` argument in a field declaration gives `validates_uniqueness_of`:
|
171
190
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
191
|
+
>>
|
192
|
+
class Advert < ActiveRecord::Base
|
193
|
+
fields do
|
194
|
+
title :string, :unique
|
195
|
+
end
|
196
|
+
end
|
197
|
+
>> a = Advert.new :title => "Jimbo"
|
198
|
+
>> a.valid?
|
199
|
+
=> false
|
200
|
+
>> a.errors.full_messages
|
201
|
+
=> ["Title has already been taken"]
|
202
|
+
>> a.title = "Sambo"
|
203
|
+
>> a.save
|
204
|
+
=> true
|
186
205
|
|
187
206
|
Let's get back to the basic Advert class with no validations before we continue:
|
188
207
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
208
|
+
>> ActiveSupport::Dependencies.remove_constant "Advert"
|
209
|
+
>>
|
210
|
+
class Advert < ActiveRecord::Base
|
211
|
+
fields do
|
212
|
+
title :string
|
213
|
+
body :text
|
214
|
+
contact_address :email_address
|
215
|
+
end
|
216
|
+
end
|
198
217
|
|
199
218
|
|
200
219
|
### Type specific validations
|
201
220
|
|
202
221
|
Rich types can define there own validations by a `#validate` method. It should return an error message if the value is invalid, otherwise nil. We can call that method directly to show how it works:
|
203
222
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
223
|
+
>> a = Advert.new :contact_address => "not really an email address"
|
224
|
+
>> a.contact_address.class
|
225
|
+
=> HoboFields::EmailAddress
|
226
|
+
>> a.contact_address.validate
|
227
|
+
=> "is not valid"
|
209
228
|
|
210
229
|
But normally that method would be called for us during validation:
|
211
230
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
231
|
+
>> a.valid?
|
232
|
+
=> false
|
233
|
+
>> a.errors.full_messages
|
234
|
+
=> ["Contact address is not valid"]
|
235
|
+
>> a.contact_address = "me@me.com"
|
236
|
+
>> a.valid?
|
237
|
+
=> true
|
219
238
|
|
220
239
|
You can add this capability to your own rich types just by defining `#validate`
|
221
240
|
|
@@ -223,26 +242,28 @@ You can add this capability to your own rich types just by defining `#validate`
|
|
223
242
|
|
224
243
|
You can set the type of a virtual field to a rich type, e.g.
|
225
244
|
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
245
|
+
>>
|
246
|
+
class Advert
|
247
|
+
attr_accessor :alternative_email, :type => :email_address
|
248
|
+
end
|
230
249
|
|
231
250
|
By default, virtual fields are not subject to validation.
|
232
251
|
|
233
|
-
|
234
|
-
|
235
|
-
|
252
|
+
>> a = Advert.new :alternative_email => "woot!"
|
253
|
+
>> a.valid?
|
254
|
+
=> true
|
236
255
|
|
237
256
|
To have them validated use `validate_virtual_field`:
|
238
257
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
258
|
+
>>
|
259
|
+
class Advert
|
260
|
+
validate_virtual_field :alternative_email
|
261
|
+
end
|
262
|
+
>> a.valid?
|
263
|
+
=> false
|
245
264
|
|
246
|
-
|
265
|
+
Cleanup
|
266
|
+
{.hidden}
|
247
267
|
|
248
|
-
>> system "mysqladmin --force drop #{mysql_database}"
|
268
|
+
>> system "mysqladmin --force drop #{mysql_database} 2> /dev/null"
|
269
|
+
{.hidden}
|