hobo_fields 1.3.0.RC
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.
- 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
data/CHANGES.txt
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
== HoboFields 0.7.4 ==
|
2
|
+
|
3
|
+
Fix to using the migration generator with STI
|
4
|
+
|
5
|
+
HoboFields::Text - fix to to_html
|
6
|
+
|
7
|
+
Ensure that the bundled rich types are only loaded on demand
|
8
|
+
|
9
|
+
HoboFields::TextileString -- adding require 'redcloth'
|
10
|
+
|
11
|
+
Fix for HoboFields::EnumString -- couldn't set values using
|
12
|
+
symbols
|
13
|
+
|
14
|
+
Adding to_html to PasswordString (returns '[password-hidden]')
|
15
|
+
|
16
|
+
EnumString -- now defines constants on the class for each value in
|
17
|
+
the enum
|
18
|
+
|
19
|
+
Also, won't define an is_foo? method if that already exists
|
20
|
+
|
21
|
+
Removing HoboFields::Percentage -- this is better handled as an
|
22
|
+
application specific type
|
23
|
+
|
24
|
+
For example, is a percentage an fixnum or a float? Is 101% valid
|
25
|
+
or invalid?
|
26
|
+
|
27
|
+
Fix to validates_virtual_field
|
28
|
+
|
29
|
+
*Breaking Change* EnumString: Change to automatically defined
|
30
|
+
class methods on EnumString classes
|
31
|
+
|
32
|
+
It used to be that if you did EnumString.for(:foo, :baa), your
|
33
|
+
class had methods foo, baa and the instance got methods foo?
|
34
|
+
and baa?. There was a big problem with name clashes with other
|
35
|
+
class methods. You now get no class methods, and the instance
|
36
|
+
methods are called is_foo? and is_baa?.
|
37
|
+
|
38
|
+
Rich field type fix: don't attempt to wrap booleans
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2008 Tom Locke
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/README.txt
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
ActiveRecord::ActiveRecordError # hack for https://rails.lighthouseapp.com/projects/8994/tickets/2577-when-using-activerecordassociations-outside-of-rails-a-nameerror-is-thrown
|
6
|
+
|
7
|
+
RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name']).sub(/.*\s.*/m, '"\&"')
|
8
|
+
RUBYDOCTEST = ENV['RUBYDOCTEST'] || "#{RUBY} -S rubydoctest"
|
9
|
+
|
10
|
+
$:.unshift File.expand_path('../../hobo_support/lib', __FILE__)
|
11
|
+
$:.unshift File.expand_path('../lib', __FILE__)
|
12
|
+
require 'hobo_support'
|
13
|
+
require 'hobo_fields'
|
14
|
+
|
15
|
+
GEM_ROOT = File.expand_path('../', __FILE__)
|
16
|
+
TESTAPP_PATH = File.join Dir.tmpdir, 'hobo_fields_testapp'
|
17
|
+
BIN = File.expand_path('../bin/hobofields', __FILE__)
|
18
|
+
require 'hobo_support/common_tasks'
|
19
|
+
include HoboSupport::CommonTasks
|
20
|
+
|
21
|
+
|
22
|
+
namespace "test" do
|
23
|
+
desc "Run the doctests"
|
24
|
+
task :doctest do |t|
|
25
|
+
files=Dir['test/*.rdoctest'].map {|f| File.expand_path(f)}.join(' ')
|
26
|
+
exit(1) if !system("#{RUBYDOCTEST} #{files}")
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Run the unit tests"
|
30
|
+
task :unit do |t|
|
31
|
+
Dir["test/test_*.rb"].each do |f|
|
32
|
+
exit(1) if !system("#{RUBY} #{f}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.3.0.RC
|
data/bin/hobofields
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
if ENV["HOBODEV"]
|
5
|
+
dev_root = File.expand_path ENV["HOBODEV"], FileUtils.pwd
|
6
|
+
$:.unshift "#{dev_root}/hobo_support/lib"
|
7
|
+
else
|
8
|
+
require 'rubygems'
|
9
|
+
end
|
10
|
+
|
11
|
+
begin
|
12
|
+
require 'hobo_support/command'
|
13
|
+
rescue LoadError
|
14
|
+
puts "The 'hobo_support' gem is not installed.
|
15
|
+
You probably need to set the HOBODEV environment variable to the local repository path."
|
16
|
+
exit
|
17
|
+
end
|
18
|
+
|
19
|
+
HoboSupport::Command.run(:hobofields)
|
data/hobo_fields.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
name = File.basename( __FILE__, '.gemspec' )
|
2
|
+
version = File.read(File.expand_path('../VERSION', __FILE__)).strip
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
|
7
|
+
s.authors = ['Tom Locke']
|
8
|
+
s.email = 'tom@tomlocke.com'
|
9
|
+
s.homepage = 'http://hobocentral.net'
|
10
|
+
s.rubyforge_project = 'hobo'
|
11
|
+
s.summary = 'Rich field types and migration generator for Rails'
|
12
|
+
s.description = 'Rich field types and migration generator for Rails'
|
13
|
+
|
14
|
+
s.add_runtime_dependency('hobo_support', ["= #{version}"])
|
15
|
+
s.add_development_dependency('rubydoctest', [">= 0"])
|
16
|
+
s.add_development_dependency('redcloth', [">= 0"]) # for testing rich types
|
17
|
+
s.add_development_dependency('bluecloth', [">= 0"]) # for testing rich types
|
18
|
+
|
19
|
+
s.executables = ["hobofields"]
|
20
|
+
s.files = `git ls-files -x #{name}/* -z`.split("\0")
|
21
|
+
|
22
|
+
s.name = name
|
23
|
+
s.version = version
|
24
|
+
s.date = Date.today.to_s
|
25
|
+
|
26
|
+
s.required_rubygems_version = ">= 1.3.6"
|
27
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
28
|
+
s.require_paths = ["lib"]
|
29
|
+
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,47 @@
|
|
1
|
+
Description:
|
2
|
+
|
3
|
+
This generator compares your existing schema against the
|
4
|
+
schema declared inside your fields declarations in your
|
5
|
+
models.
|
6
|
+
|
7
|
+
If the generator finds differences, it will display the
|
8
|
+
migration it has created, and ask you if you wish to
|
9
|
+
[g]enerate migration, generate and [m]igrate now or [c]ancel?
|
10
|
+
Enter "g" to just generate the migration but do not run it.
|
11
|
+
Enter "m" to generate the migration and run it, or press "c"
|
12
|
+
to do nothing.
|
13
|
+
|
14
|
+
The generator will then prompt you for the migration name,
|
15
|
+
supplying a numbered default name.
|
16
|
+
|
17
|
+
The generator is conservative and will prompt you to resolve
|
18
|
+
any ambiguities.
|
19
|
+
|
20
|
+
Examples:
|
21
|
+
|
22
|
+
$ rails generate hobo:migration
|
23
|
+
|
24
|
+
---------- Up Migration ----------
|
25
|
+
create_table :foos do |t|
|
26
|
+
t.datetime :created_at
|
27
|
+
t.datetime :updated_at
|
28
|
+
end
|
29
|
+
----------------------------------
|
30
|
+
|
31
|
+
---------- Down Migration --------
|
32
|
+
drop_table :foos
|
33
|
+
----------------------------------
|
34
|
+
What now: [g]enerate migration, generate and [m]igrate now or [c]ancel? m
|
35
|
+
|
36
|
+
Migration filename:
|
37
|
+
(you can type spaces instead of '_' -- every little helps)
|
38
|
+
Filename [hobo_migration_2]: create_foo
|
39
|
+
exists db/migrate
|
40
|
+
create db/migrate/20091023183838_create_foo.rb
|
41
|
+
(in /work/foo)
|
42
|
+
== CreateFoo: migrating ======================================================
|
43
|
+
-- create_table(:yos)
|
44
|
+
-> 0.0856s
|
45
|
+
== CreateFoo: migrated (0.0858s) =============================================
|
46
|
+
|
47
|
+
|
@@ -0,0 +1,162 @@
|
|
1
|
+
require 'rails/generators/migration'
|
2
|
+
require 'rails/generators/active_record'
|
3
|
+
require 'generators/hobo_support/thor_shell'
|
4
|
+
|
5
|
+
module Hobo
|
6
|
+
class MigrationGenerator < Rails::Generators::Base
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
argument :name, :type => :string, :optional => true
|
10
|
+
|
11
|
+
include Rails::Generators::Migration
|
12
|
+
include Generators::HoboSupport::ThorShell
|
13
|
+
|
14
|
+
# the Rails::Generators::Migration.next_migration_number gives a NotImplementedError
|
15
|
+
# in Rails 3.0.0.beta4, so we need to implement the logic of ActiveRecord.
|
16
|
+
# For other ORMs we will wait for the rails implementation
|
17
|
+
# see http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/a507ce419076cda2
|
18
|
+
def self.next_migration_number(dirname)
|
19
|
+
ActiveRecord::Generators::Base.next_migration_number dirname
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.banner
|
23
|
+
"rails generate hobo:migration #{self.arguments.map(&:usage).join(' ')} [options]"
|
24
|
+
end
|
25
|
+
|
26
|
+
class_option :drop,
|
27
|
+
:aliases => '-d',
|
28
|
+
:type => :boolean,
|
29
|
+
:desc => "Don't prompt with 'drop or rename' - just drop everything"
|
30
|
+
|
31
|
+
class_option :default_name,
|
32
|
+
:aliases => '-n',
|
33
|
+
:type => :boolean,
|
34
|
+
:desc => "Don't prompt for a migration name - just pick one"
|
35
|
+
|
36
|
+
class_option :generate,
|
37
|
+
:aliases => '-g',
|
38
|
+
:type => :boolean,
|
39
|
+
:desc => "Don't prompt for action - generate the migration"
|
40
|
+
|
41
|
+
class_option :migrate,
|
42
|
+
:aliases => '-m',
|
43
|
+
:type => :boolean,
|
44
|
+
:desc => "Don't prompt for action - generate and migrate"
|
45
|
+
|
46
|
+
def migrate
|
47
|
+
return if migrations_pending?
|
48
|
+
|
49
|
+
generator = Generators::Hobo::Migration::Migrator.new(lambda{|c,d,k,p| extract_renames!(c,d,k,p)})
|
50
|
+
up, down = generator.generate
|
51
|
+
|
52
|
+
if up.blank?
|
53
|
+
say "Database and models match -- nothing to change"
|
54
|
+
return
|
55
|
+
end
|
56
|
+
|
57
|
+
say "\n---------- Up Migration ----------"
|
58
|
+
say up
|
59
|
+
say "----------------------------------"
|
60
|
+
|
61
|
+
say "\n---------- Down Migration --------"
|
62
|
+
say down
|
63
|
+
say "----------------------------------"
|
64
|
+
|
65
|
+
action = options[:generate] && 'g' ||
|
66
|
+
options[:migrate] && 'm' ||
|
67
|
+
choose("\nWhat now: [g]enerate migration, generate and [m]igrate now or [c]ancel?", /^(g|m|c)$/)
|
68
|
+
|
69
|
+
if action != 'c'
|
70
|
+
if name.blank? && !options[:default_name]
|
71
|
+
final_migration_name = choose("\nMigration filename: [<enter>=#{migration_name}|<custom_name>]:", /^[a-z0-9_ ]*$/, migration_name).strip.gsub(' ', '_')
|
72
|
+
end
|
73
|
+
final_migration_name = migration_name if final_migration_name.blank?
|
74
|
+
|
75
|
+
up.gsub!("\n", "\n ")
|
76
|
+
up.gsub!(/ +\n/, "\n")
|
77
|
+
down.gsub!("\n", "\n ")
|
78
|
+
down.gsub!(/ +\n/, "\n")
|
79
|
+
|
80
|
+
@up = up
|
81
|
+
@down = down
|
82
|
+
@migration_class_name = final_migration_name.camelize
|
83
|
+
|
84
|
+
migration_template 'migration.rb.erb', "db/migrate/#{final_migration_name.underscore}.rb"
|
85
|
+
rake('db:migrate') if action == 'm'
|
86
|
+
end
|
87
|
+
rescue HoboFields::Model::FieldSpec::UnknownSqlTypeError => e
|
88
|
+
say "Invalid field type: #{e}"
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def migrations_pending?
|
94
|
+
pending_migrations = ActiveRecord::Migrator.new(:up, 'db/migrate').pending_migrations
|
95
|
+
|
96
|
+
if pending_migrations.any?
|
97
|
+
say "You have #{pending_migrations.size} pending migration#{'s' if pending_migrations.size > 1}:"
|
98
|
+
pending_migrations.each do |pending_migration|
|
99
|
+
say ' %4d %s' % [pending_migration.version, pending_migration.name]
|
100
|
+
end
|
101
|
+
true
|
102
|
+
else
|
103
|
+
false
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def extract_renames!(to_create, to_drop, kind_str, name_prefix="")
|
108
|
+
to_rename = {}
|
109
|
+
|
110
|
+
unless options[:drop]
|
111
|
+
|
112
|
+
rename_to_choices = to_create
|
113
|
+
to_drop.dup.each do |t|
|
114
|
+
while true
|
115
|
+
if rename_to_choices.empty?
|
116
|
+
say "\nCONFIRM DROP! #{kind_str} #{name_prefix}#{t}"
|
117
|
+
resp = ask("Enter 'drop #{t}' to confirm or press enter to keep:")
|
118
|
+
if resp.strip == "drop " + t.to_s
|
119
|
+
break
|
120
|
+
elsif resp.strip.empty?
|
121
|
+
to_drop.delete(t)
|
122
|
+
break
|
123
|
+
else
|
124
|
+
next
|
125
|
+
end
|
126
|
+
else
|
127
|
+
say "\nDROP, RENAME or KEEP?: #{kind_str} #{name_prefix}#{t}"
|
128
|
+
say "Rename choices: #{to_create * ', '}"
|
129
|
+
resp = ask "Enter either 'drop #{t}' or one of the rename choices or press enter to keep:"
|
130
|
+
resp.strip!
|
131
|
+
|
132
|
+
if resp == "drop " + t
|
133
|
+
# Leave things as they are
|
134
|
+
break
|
135
|
+
else
|
136
|
+
resp.gsub!(' ', '_')
|
137
|
+
to_drop.delete(t)
|
138
|
+
if resp.in?(rename_to_choices)
|
139
|
+
to_rename[t] = resp
|
140
|
+
to_create.delete(resp)
|
141
|
+
rename_to_choices.delete(resp)
|
142
|
+
break
|
143
|
+
elsif resp.empty?
|
144
|
+
break
|
145
|
+
else
|
146
|
+
next
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
to_rename
|
154
|
+
end
|
155
|
+
|
156
|
+
def migration_name
|
157
|
+
name || Generators::Hobo::Migration::Migrator.default_migration_name
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|