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.
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
+