hobo_fields 1.3.0.RC

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/CHANGES.txt +38 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.txt +8 -0
  4. data/Rakefile +36 -0
  5. data/VERSION +1 -0
  6. data/bin/hobofields +19 -0
  7. data/hobo_fields.gemspec +31 -0
  8. data/lib/generators/hobo/migration/USAGE +47 -0
  9. data/lib/generators/hobo/migration/migration_generator.rb +162 -0
  10. data/lib/generators/hobo/migration/migrator.rb +445 -0
  11. data/lib/generators/hobo/migration/templates/migration.rb.erb +9 -0
  12. data/lib/generators/hobo/model/USAGE +19 -0
  13. data/lib/generators/hobo/model/model_generator.rb +11 -0
  14. data/lib/generators/hobo/model/templates/model_injection.rb.erb +18 -0
  15. data/lib/hobo_fields/extensions/active_record/attribute_methods.rb +48 -0
  16. data/lib/hobo_fields/extensions/active_record/fields_declaration.rb +21 -0
  17. data/lib/hobo_fields/field_declaration_dsl.rb +33 -0
  18. data/lib/hobo_fields/model/field_spec.rb +121 -0
  19. data/lib/hobo_fields/model/index_spec.rb +47 -0
  20. data/lib/hobo_fields/model.rb +226 -0
  21. data/lib/hobo_fields/railtie.rb +13 -0
  22. data/lib/hobo_fields/sanitize_html.rb +23 -0
  23. data/lib/hobo_fields/types/email_address.rb +26 -0
  24. data/lib/hobo_fields/types/enum_string.rb +101 -0
  25. data/lib/hobo_fields/types/html_string.rb +15 -0
  26. data/lib/hobo_fields/types/lifecycle_state.rb +16 -0
  27. data/lib/hobo_fields/types/markdown_string.rb +15 -0
  28. data/lib/hobo_fields/types/password_string.rb +15 -0
  29. data/lib/hobo_fields/types/raw_html_string.rb +13 -0
  30. data/lib/hobo_fields/types/raw_markdown_string.rb +13 -0
  31. data/lib/hobo_fields/types/serialized_object.rb +15 -0
  32. data/lib/hobo_fields/types/text.rb +16 -0
  33. data/lib/hobo_fields/types/textile_string.rb +22 -0
  34. data/lib/hobo_fields.rb +94 -0
  35. data/test/api.rdoctest +244 -0
  36. data/test/doc-only.rdoctest +96 -0
  37. data/test/generators.rdoctest +53 -0
  38. data/test/interactive_primary_key.rdoctest +54 -0
  39. data/test/migration_generator.rdoctest +639 -0
  40. data/test/migration_generator_comments.rdoctest +75 -0
  41. data/test/prepare_testapp.rb +8 -0
  42. data/test/rich_types.rdoctest +394 -0
  43. 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
@@ -0,0 +1,8 @@
1
+ = HoboFields
2
+
3
+ Rich field types and migration-generator for Rails.
4
+
5
+ Part of the Hobo project
6
+
7
+ http://hobocentral.net/hobo_fields
8
+
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)
@@ -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
+