hobo_fields 1.3.0.RC
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +38 -0
- data/LICENSE.txt +22 -0
- data/README.txt +8 -0
- data/Rakefile +36 -0
- data/VERSION +1 -0
- data/bin/hobofields +19 -0
- data/hobo_fields.gemspec +31 -0
- data/lib/generators/hobo/migration/USAGE +47 -0
- data/lib/generators/hobo/migration/migration_generator.rb +162 -0
- data/lib/generators/hobo/migration/migrator.rb +445 -0
- data/lib/generators/hobo/migration/templates/migration.rb.erb +9 -0
- data/lib/generators/hobo/model/USAGE +19 -0
- data/lib/generators/hobo/model/model_generator.rb +11 -0
- data/lib/generators/hobo/model/templates/model_injection.rb.erb +18 -0
- data/lib/hobo_fields/extensions/active_record/attribute_methods.rb +48 -0
- data/lib/hobo_fields/extensions/active_record/fields_declaration.rb +21 -0
- data/lib/hobo_fields/field_declaration_dsl.rb +33 -0
- data/lib/hobo_fields/model/field_spec.rb +121 -0
- data/lib/hobo_fields/model/index_spec.rb +47 -0
- data/lib/hobo_fields/model.rb +226 -0
- data/lib/hobo_fields/railtie.rb +13 -0
- data/lib/hobo_fields/sanitize_html.rb +23 -0
- data/lib/hobo_fields/types/email_address.rb +26 -0
- data/lib/hobo_fields/types/enum_string.rb +101 -0
- data/lib/hobo_fields/types/html_string.rb +15 -0
- data/lib/hobo_fields/types/lifecycle_state.rb +16 -0
- data/lib/hobo_fields/types/markdown_string.rb +15 -0
- data/lib/hobo_fields/types/password_string.rb +15 -0
- data/lib/hobo_fields/types/raw_html_string.rb +13 -0
- data/lib/hobo_fields/types/raw_markdown_string.rb +13 -0
- data/lib/hobo_fields/types/serialized_object.rb +15 -0
- data/lib/hobo_fields/types/text.rb +16 -0
- data/lib/hobo_fields/types/textile_string.rb +22 -0
- data/lib/hobo_fields.rb +94 -0
- data/test/api.rdoctest +244 -0
- data/test/doc-only.rdoctest +96 -0
- data/test/generators.rdoctest +53 -0
- data/test/interactive_primary_key.rdoctest +54 -0
- data/test/migration_generator.rdoctest +639 -0
- data/test/migration_generator_comments.rdoctest +75 -0
- data/test/prepare_testapp.rb +8 -0
- data/test/rich_types.rdoctest +394 -0
- metadata +140 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'redcloth'
|
2
|
+
|
3
|
+
module HoboFields
|
4
|
+
module Types
|
5
|
+
class TextileString < HoboFields::Types::Text
|
6
|
+
|
7
|
+
include SanitizeHtml
|
8
|
+
|
9
|
+
def to_html(xmldoctype = true)
|
10
|
+
if blank?
|
11
|
+
""
|
12
|
+
else
|
13
|
+
textilized = RedCloth.new(self, [ :hard_breaks ])
|
14
|
+
textilized.hard_breaks = true if textilized.respond_to?("hard_breaks=")
|
15
|
+
HoboFields::SanitizeHtml.sanitize(textilized.to_html)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
HoboFields.register_type(:textile, self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/hobo_fields.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'hobo_support'
|
2
|
+
|
3
|
+
ActiveSupport::Dependencies.autoload_paths |= [ File.dirname(__FILE__) ]
|
4
|
+
|
5
|
+
module Hobo
|
6
|
+
# Empty class to represent the boolean type.
|
7
|
+
class Boolean; end
|
8
|
+
end
|
9
|
+
|
10
|
+
module HoboFields
|
11
|
+
|
12
|
+
VERSION = File.read(File.expand_path('../../VERSION', __FILE__)).strip
|
13
|
+
|
14
|
+
extend self
|
15
|
+
|
16
|
+
PLAIN_TYPES = {
|
17
|
+
:boolean => Hobo::Boolean,
|
18
|
+
:date => Date,
|
19
|
+
:datetime => ActiveSupport::TimeWithZone,
|
20
|
+
:time => Time,
|
21
|
+
:integer => Integer,
|
22
|
+
:decimal => BigDecimal,
|
23
|
+
:float => Float,
|
24
|
+
:string => String
|
25
|
+
}
|
26
|
+
|
27
|
+
ALIAS_TYPES = {
|
28
|
+
Fixnum => "integer",
|
29
|
+
Bignum => "integer"
|
30
|
+
}
|
31
|
+
|
32
|
+
# Provide a lookup for these rather than loading them all preemptively
|
33
|
+
|
34
|
+
STANDARD_TYPES = {
|
35
|
+
:raw_html => "RawHtmlString",
|
36
|
+
:html => "HtmlString",
|
37
|
+
:raw_markdown => "RawMarkdownString",
|
38
|
+
:markdown => "MarkdownString",
|
39
|
+
:textile => "TextileString",
|
40
|
+
:password => "PasswordString",
|
41
|
+
:text => "Text",
|
42
|
+
:email_address => "EmailAddress",
|
43
|
+
:serialized => "SerializedObject"
|
44
|
+
}
|
45
|
+
|
46
|
+
@field_types = PLAIN_TYPES.with_indifferent_access
|
47
|
+
@never_wrap_types = Set.new([NilClass, Hobo::Boolean, TrueClass, FalseClass])
|
48
|
+
attr_reader :field_types
|
49
|
+
|
50
|
+
def to_class(type)
|
51
|
+
if type.is_one_of?(Symbol, String)
|
52
|
+
type = type.to_sym
|
53
|
+
field_types[type] || standard_class(type)
|
54
|
+
else
|
55
|
+
type # assume it's already a class
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_name(type)
|
60
|
+
field_types.key(type) || ALIAS_TYPES[type]
|
61
|
+
end
|
62
|
+
|
63
|
+
def can_wrap?(type, val)
|
64
|
+
col_type = type::COLUMN_TYPE
|
65
|
+
return false if val.blank? && (col_type == :integer || col_type == :float || col_type == :decimal)
|
66
|
+
klass = Object.instance_method(:class).bind(val).call # Make sure we get the *real* class
|
67
|
+
init_method = type.instance_method(:initialize)
|
68
|
+
[-1,1].include?(init_method.arity) &&
|
69
|
+
init_method.owner != Object.instance_method(:initialize).owner &&
|
70
|
+
!@never_wrap_types.any? { |c| klass <= c }
|
71
|
+
end
|
72
|
+
|
73
|
+
def never_wrap(type)
|
74
|
+
@never_wrap_types << type
|
75
|
+
end
|
76
|
+
|
77
|
+
def register_type(name, klass)
|
78
|
+
field_types[name] = klass
|
79
|
+
end
|
80
|
+
|
81
|
+
def plain_type?(type_name)
|
82
|
+
type_name.in?(PLAIN_TYPES)
|
83
|
+
end
|
84
|
+
|
85
|
+
def standard_class(name)
|
86
|
+
class_name = STANDARD_TYPES[name]
|
87
|
+
"HoboFields::Types::#{class_name}".constantize if class_name
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
require 'hobo_fields/railtie'
|
93
|
+
|
94
|
+
|
data/test/api.rdoctest
ADDED
@@ -0,0 +1,244 @@
|
|
1
|
+
# HoboFields API
|
2
|
+
|
3
|
+
In order for the API examples to run we need to load the rails generators of our testapp:
|
4
|
+
{.hidden}
|
5
|
+
|
6
|
+
doctest: prepare testapp environment
|
7
|
+
doctest_require: 'prepare_testapp'
|
8
|
+
{.hidden}
|
9
|
+
|
10
|
+
## Example Models
|
11
|
+
|
12
|
+
Let's define some example models that we can use to demonstrate the API. With HoboFields we can use the 'hobo:model' generator like so:
|
13
|
+
|
14
|
+
$ rails generate hobo:model advert title:string body:text contact_address:email_address
|
15
|
+
|
16
|
+
>> Rails::Generators.invoke 'hobo:model', %w(advert title:string body:text contact_address:email_address)
|
17
|
+
{.hidden}
|
18
|
+
|
19
|
+
This will generate the test, fixture and a model file like this:
|
20
|
+
|
21
|
+
class Advert < ActiveRecord::Base
|
22
|
+
fields do
|
23
|
+
title :string
|
24
|
+
body :text
|
25
|
+
contact_address :email_address
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
(Note: `:email_address` is an example of a "Rich Type" provided by HoboFields -- more on those later)
|
31
|
+
|
32
|
+
The migration generator uses this information to create a migration. The following creates and runs the migration so we're ready to go.
|
33
|
+
|
34
|
+
$ rails generate hobo:migration -n -m
|
35
|
+
|
36
|
+
>> Rails::Generators.invoke 'hobo:migration', %w(-n -m)
|
37
|
+
>> Rails::Generators.invoke 'hobo:migration', %w(-n -m)
|
38
|
+
{.hidden}
|
39
|
+
|
40
|
+
We're now ready to start demonstrating the API
|
41
|
+
|
42
|
+
## The Basics
|
43
|
+
|
44
|
+
The main feature of HoboFields, aside from the migration generator, is the ability to declare rich types for your fields. For example, you can declare that a field is an email address, and the field will be automatically validated for correct email address syntax.
|
45
|
+
|
46
|
+
### Field Types
|
47
|
+
|
48
|
+
Field values are returned as the type you specify.
|
49
|
+
|
50
|
+
>> a = Advert.new :body => "This is the body"
|
51
|
+
>> a.body.class
|
52
|
+
=> HoboFields::Types::Text
|
53
|
+
|
54
|
+
This also works after a round-trip to the database
|
55
|
+
|
56
|
+
>> a.save
|
57
|
+
>> b = Advert.find(a.id)
|
58
|
+
>> b.body.class
|
59
|
+
=> HoboFields::Types::Text
|
60
|
+
|
61
|
+
HoboFields::Types::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
|
+
|
63
|
+
>> t = HoboFields::Types::Text.new("hello")
|
64
|
+
=> "hello"
|
65
|
+
>> t.class
|
66
|
+
=> HoboFields::Types::Text
|
67
|
+
|
68
|
+
If you define your own rich types, they need to support a one argument constructor in the same way.
|
69
|
+
|
70
|
+
Although the body of our advert is really just a string, it's very useful that it has a different type. For example, the view layer in Hobo Rapid would use this information to render a `<textarea>` rather than an `<input type='text'>` in an Advert form.
|
71
|
+
|
72
|
+
|
73
|
+
## Names vs. Classes
|
74
|
+
|
75
|
+
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
|
+
|
77
|
+
body HoboFields::Types::Text
|
78
|
+
|
79
|
+
Obviously the symbol form is a nicer:
|
80
|
+
|
81
|
+
body :text
|
82
|
+
|
83
|
+
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
|
+
|
85
|
+
>> HoboFields::Types::Text::COLUMN_TYPE
|
86
|
+
=> :text
|
87
|
+
|
88
|
+
The full set of available symbolic names is
|
89
|
+
|
90
|
+
* `:integer`
|
91
|
+
* `:float`
|
92
|
+
* `:decimal`
|
93
|
+
* `:string`
|
94
|
+
* `:text`
|
95
|
+
* `:boolean`
|
96
|
+
* `:date`
|
97
|
+
* `:datetime`
|
98
|
+
* `:html`
|
99
|
+
* `:textile`
|
100
|
+
* `:markdown`
|
101
|
+
* `:password`
|
102
|
+
* `:email_address`
|
103
|
+
|
104
|
+
You can add your own types too. More on that later.
|
105
|
+
|
106
|
+
|
107
|
+
## Model extensions
|
108
|
+
|
109
|
+
HoboFields adds a few features to your models.
|
110
|
+
|
111
|
+
### `Model.attr_type`
|
112
|
+
|
113
|
+
Returns the type (i.e. class) declared for a given field or attribute
|
114
|
+
|
115
|
+
>> Advert.attr_type :title
|
116
|
+
=> String
|
117
|
+
>> Advert.attr_type :body
|
118
|
+
=> HoboFields::Types::Text
|
119
|
+
|
120
|
+
### `Model.column`
|
121
|
+
|
122
|
+
A shorthand for accessing column metadata
|
123
|
+
|
124
|
+
>> col = Advert.column :title
|
125
|
+
>> col.name
|
126
|
+
=> "title"
|
127
|
+
>> col.klass
|
128
|
+
>> String
|
129
|
+
|
130
|
+
### `Model.attr_accessor` with types
|
131
|
+
|
132
|
+
In your HoboFields models you can also give type information to "virtual fields" (i.e. regular Ruby attributes)
|
133
|
+
|
134
|
+
>>
|
135
|
+
class Advert
|
136
|
+
attr_accessor :my_attr, :type => :text
|
137
|
+
end
|
138
|
+
>> a = Advert.new
|
139
|
+
>> a.my_attr = "hello"
|
140
|
+
>> a.my_attr.class
|
141
|
+
=> HoboFields::Types::Text
|
142
|
+
|
143
|
+
|
144
|
+
## Field validations
|
145
|
+
|
146
|
+
HoboFields gives you some shorthands for declaring some common validations right in the field declaration
|
147
|
+
|
148
|
+
### Required fields
|
149
|
+
|
150
|
+
The `:required` argument to a field gives a `validates_presence_of`:
|
151
|
+
|
152
|
+
>>
|
153
|
+
class Advert
|
154
|
+
fields do
|
155
|
+
title :string, :required
|
156
|
+
end
|
157
|
+
end
|
158
|
+
>> a = Advert.new
|
159
|
+
>> a.valid?
|
160
|
+
=> false
|
161
|
+
>> a.errors.full_messages
|
162
|
+
=> ["Title can't be blank"]
|
163
|
+
>> a.title = "Jimbo"
|
164
|
+
>> a.save
|
165
|
+
=> true
|
166
|
+
|
167
|
+
|
168
|
+
### Unique fields
|
169
|
+
|
170
|
+
The `:unique` argument in a field declaration gives `validates_uniqueness_of`:
|
171
|
+
|
172
|
+
>>
|
173
|
+
class Advert < ActiveRecord::Base
|
174
|
+
fields do
|
175
|
+
title :string, :unique
|
176
|
+
end
|
177
|
+
end
|
178
|
+
>> a = Advert.new :title => "Jimbo"
|
179
|
+
>> a.valid?
|
180
|
+
=> false
|
181
|
+
>> a.errors.full_messages
|
182
|
+
=> ["Title has already been taken"]
|
183
|
+
>> a.title = "Sambo"
|
184
|
+
>> a.save
|
185
|
+
=> true
|
186
|
+
|
187
|
+
Let's get back to the basic Advert class with no validations before we continue:
|
188
|
+
|
189
|
+
>> ActiveSupport::Dependencies.remove_constant "Advert"
|
190
|
+
>>
|
191
|
+
class Advert < ActiveRecord::Base
|
192
|
+
fields do
|
193
|
+
title :string
|
194
|
+
body :text
|
195
|
+
contact_address :email_address
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
### Type specific validations
|
201
|
+
|
202
|
+
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
|
+
|
204
|
+
>> a = Advert.new :contact_address => "not really an email address"
|
205
|
+
>> a.contact_address.class
|
206
|
+
=> HoboFields::Types::EmailAddress
|
207
|
+
>> a.contact_address.validate
|
208
|
+
=> "is invalid"
|
209
|
+
|
210
|
+
But normally that method would be called for us during validation:
|
211
|
+
|
212
|
+
>> a.valid?
|
213
|
+
=> false
|
214
|
+
>> a.errors.full_messages
|
215
|
+
=> ["Contact address is invalid"]
|
216
|
+
>> a.contact_address = "me@me.com"
|
217
|
+
>> a.valid?
|
218
|
+
=> true
|
219
|
+
|
220
|
+
You can add this capability to your own rich types just by defining `#validate`
|
221
|
+
|
222
|
+
### Validating virtual fields
|
223
|
+
|
224
|
+
You can set the type of a virtual field to a rich type, e.g.
|
225
|
+
|
226
|
+
>>
|
227
|
+
class Advert
|
228
|
+
attr_accessor :alternative_email, :type => :email_address
|
229
|
+
end
|
230
|
+
|
231
|
+
By default, virtual fields are not subject to validation.
|
232
|
+
|
233
|
+
>> a = Advert.new :alternative_email => "woot!"
|
234
|
+
>> a.valid?
|
235
|
+
=> true
|
236
|
+
|
237
|
+
To have them validated use `validate_virtual_field`:
|
238
|
+
|
239
|
+
>>
|
240
|
+
class Advert
|
241
|
+
validate_virtual_field :alternative_email
|
242
|
+
end
|
243
|
+
>> a.valid?
|
244
|
+
=> false
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# HoboFields
|
2
|
+
|
3
|
+
## Introduction
|
4
|
+
|
5
|
+
Welcome to HoboFields -- a spin-off from the Hobo project (Hobo not required!).
|
6
|
+
|
7
|
+
**HoboFields writes your Rails migrations for you! Your migration writing days are over!**
|
8
|
+
|
9
|
+
All we ask is that you declare your fields in the model. It's still perfectly DRY because you're not having to repeat that in the migration -- HoboFields does that for you. In fact, you'll come to love having them there.
|
10
|
+
|
11
|
+
It still has all the benefits of writing your own migrations, for example if you want to add some special code to migrate your old data, you can just edit the generated migration.
|
12
|
+
|
13
|
+
## Example
|
14
|
+
|
15
|
+
First off, if you're using the migration generator outside of Hobo, do remember the `--skip-migration` option when generating your models:
|
16
|
+
|
17
|
+
$ rails generate model blog_post --skip-migration
|
18
|
+
|
19
|
+
Now edit your model as follows:
|
20
|
+
|
21
|
+
class BlogPost < ActiveRecord::Base
|
22
|
+
fields do
|
23
|
+
title :string
|
24
|
+
body :text
|
25
|
+
timestamps
|
26
|
+
end
|
27
|
+
end
|
28
|
+
{: .ruby}
|
29
|
+
|
30
|
+
|
31
|
+
Then, simply run
|
32
|
+
|
33
|
+
$ rails generate hobo:migration
|
34
|
+
|
35
|
+
And voila
|
36
|
+
|
37
|
+
---------- Up Migration ----------
|
38
|
+
create_table :blog_posts do |t|
|
39
|
+
t.string :title
|
40
|
+
t.text :body
|
41
|
+
t.datetime :created_at
|
42
|
+
t.datetime :updated_at
|
43
|
+
end
|
44
|
+
----------------------------------
|
45
|
+
|
46
|
+
---------- Down Migration --------
|
47
|
+
drop_table :blog_posts
|
48
|
+
----------------------------------
|
49
|
+
{: .ruby}
|
50
|
+
|
51
|
+
The migration generator has created a migration to change from the schema that is currently in your database, to the schema that your models need. That's really all there is to it. You are now free to simply hack away on your app and run the migration generator every time the database needs to play catch-up.
|
52
|
+
|
53
|
+
Note that the migration generator is interactive -- it can't tell the difference between renaming something vs. adding one thing and removing another, so sometimes it will ask you to clarify. It's a bit picky about what it makes you type in response, because we really don't want you to lose data when someone's amazing twitter distracts you at the wrong moment.
|
54
|
+
|
55
|
+
## Installing
|
56
|
+
|
57
|
+
The simplest and recommended way to install HoboFields is as a gem:
|
58
|
+
|
59
|
+
$ gem install hobo_fields
|
60
|
+
|
61
|
+
The source lives on GitHub as part of the main Hobo repo:
|
62
|
+
|
63
|
+
- [http://github.com/tablatom/hobo](http://github.com/tablatom/hobo)
|
64
|
+
|
65
|
+
To use hobo_fields as a plugin is not as simple as it should be. You
|
66
|
+
will have to clone `git://github.com/tablatom/hobo` and then copy the
|
67
|
+
`hobo_fields` subdirectory into `/vendors/plugins`
|
68
|
+
|
69
|
+
## Rich Types
|
70
|
+
|
71
|
+
In addition to the migration generator, HoboFields provides a Rich-Type mechanism that allows you to declare your fields using higher level concepts like "email-address" or "markdown text". This can give you both automatic validations, and automatic rendering of those values in the UI (this works particularly well if you use the rest of Hobo).
|
72
|
+
|
73
|
+
Read more:
|
74
|
+
|
75
|
+
- [HoboFields Rich Types](/manual/hobo_fields/rich_types)
|
76
|
+
|
77
|
+
## API
|
78
|
+
|
79
|
+
HoboFields provides various API methods. Read more:
|
80
|
+
|
81
|
+
- [HoboFields API](/manual/hobo_fields/hobo_fields_api)
|
82
|
+
|
83
|
+
## Migration Generator Details
|
84
|
+
|
85
|
+
The migration generator doctests provide a lot more detail. They're not really that great as documentation because doctests run in a single irb session, and that doesn't fit well with the concept of a generator. Skip these unless you're really keen to see the details of the migration generator in action
|
86
|
+
|
87
|
+
- [Migration Generator Details](/manual/hobo_fields/migration_generator)
|
88
|
+
|
89
|
+
## About Doctests
|
90
|
+
|
91
|
+
HoboFields is documented and tested using *doctests*. This is an idea that comes from Python that we've been experimenting with for Hobo. Whenever you see code-blocks that start "`>>`", read them as IRB sessions. The `rdoctest` tool extracts these and runs them to verify they behave as advertised.
|
92
|
+
|
93
|
+
Doctests are a great way to get both documentation and tests from the same source. We're still experimenting with exactly how this all works though, so if the docs seem strange in places, please bear with us!
|
94
|
+
|
95
|
+
You may download rubydoctest via [github](http://www.github.com/tablatom/rubydoctest)
|
96
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
doctest: prepare testapp environment
|
2
|
+
doctest_require: 'prepare_testapp'
|
3
|
+
|
4
|
+
doctest: generate hobo:model
|
5
|
+
>> Rails::Generators.invoke 'hobo:model', %w(alpha/beta one:string two:integer)
|
6
|
+
|
7
|
+
|
8
|
+
doctest: model file exists
|
9
|
+
>> File.exist? 'app/models/alpha/beta.rb'
|
10
|
+
=> true
|
11
|
+
|
12
|
+
doctest: model content matches
|
13
|
+
>> File.read 'app/models/alpha/beta.rb'
|
14
|
+
=> "class Alpha::Beta < ActiveRecord::Base\n\n fields do\n one :string\n two :integer\n end\n\nend\n"
|
15
|
+
|
16
|
+
doctest: module file exists
|
17
|
+
>> File.exist? 'app/models/alpha.rb'
|
18
|
+
=> true
|
19
|
+
|
20
|
+
doctest: module content matches
|
21
|
+
>> File.read 'app/models/alpha.rb'
|
22
|
+
=> "module Alpha\n def self.table_name_prefix\n 'alpha_'\n end\nend\n"
|
23
|
+
|
24
|
+
|
25
|
+
doctest: test file exists
|
26
|
+
>> File.exist? 'test/unit/alpha/beta_test.rb'
|
27
|
+
=> true
|
28
|
+
|
29
|
+
doctest: test content matches
|
30
|
+
>> File.read 'test/unit/alpha/beta_test.rb'
|
31
|
+
=> "require 'test_helper'\n\nclass Alpha::BetaTest < ActiveSupport::TestCase\n # Replace this with your real tests.\n test \"the truth\" do\n assert true\n end\nend\n"
|
32
|
+
|
33
|
+
|
34
|
+
doctest: fixture file exists
|
35
|
+
>> File.exist? 'test/fixtures/alpha/betas.yml'
|
36
|
+
=> true
|
37
|
+
|
38
|
+
|
39
|
+
doctest: generate hobo:migration
|
40
|
+
>> Rails::Generators.invoke 'hobo:migration', %w(-n -m)
|
41
|
+
|
42
|
+
doctest: schema.rb file exists
|
43
|
+
>> File.exist? 'db/schema.rb'
|
44
|
+
=> true
|
45
|
+
|
46
|
+
doctest: db file exists
|
47
|
+
>> File.exist? 'db/development.sqlite3'
|
48
|
+
=> true
|
49
|
+
|
50
|
+
doctest: Alpha::Beta class exists
|
51
|
+
>> Alpha::Beta
|
52
|
+
=> Alpha::Beta(id: integer, one: string, two: integer)
|
53
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
-*- indent-tabs-mode:nil; -*-
|
2
|
+
|
3
|
+
# HoboFields - Migration Generator
|
4
|
+
|
5
|
+
Our test requires to prepare the testapp:
|
6
|
+
{.hidden}
|
7
|
+
|
8
|
+
doctest_require: 'prepare_testapp'
|
9
|
+
|
10
|
+
{.hidden}
|
11
|
+
|
12
|
+
And requires also that you enter the right choice when prompted. OK we're ready to get going.
|
13
|
+
|
14
|
+
## Alternate Primary Keys
|
15
|
+
|
16
|
+
### create
|
17
|
+
doctest: create table with custom primary_key
|
18
|
+
>>
|
19
|
+
class Foo < ActiveRecord::Base
|
20
|
+
fields do
|
21
|
+
end
|
22
|
+
set_primary_key "foo_id"
|
23
|
+
end
|
24
|
+
>> Rails::Generators.invoke 'hobo:migration', %w(-n -m)
|
25
|
+
>> Foo.primary_key
|
26
|
+
=> 'foo_id'
|
27
|
+
|
28
|
+
### migrate from
|
29
|
+
doctest: rename from custom primary_key
|
30
|
+
>>
|
31
|
+
class Foo < ActiveRecord::Base
|
32
|
+
set_primary_key "id"
|
33
|
+
end
|
34
|
+
>> Rails::Generators.invoke 'hobo:migration', %w(-n -m)
|
35
|
+
>> Foo.primary_key
|
36
|
+
=> 'id'
|
37
|
+
|
38
|
+
### migrate to
|
39
|
+
|
40
|
+
doctest: rename to custom primary_key
|
41
|
+
>>
|
42
|
+
class Foo < ActiveRecord::Base
|
43
|
+
set_primary_key "foo_id"
|
44
|
+
end
|
45
|
+
>> Rails::Generators.invoke 'hobo:migration', %w(-n -m)
|
46
|
+
>> Foo.primary_key
|
47
|
+
=> 'foo_id'
|
48
|
+
|
49
|
+
### ensure it doesn't cause further migrations
|
50
|
+
|
51
|
+
doctest: check no further migrations
|
52
|
+
>> up, down = Generators::Hobo::Migration::Migrator.run
|
53
|
+
>> up
|
54
|
+
=> ""
|