automigration 0.2.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/.rspec +1 -0
  2. data/.travis.yml +1 -3
  3. data/CHANGELOG.md +13 -0
  4. data/README.md +44 -23
  5. data/Rakefile +10 -12
  6. data/automigration.gemspec +4 -0
  7. data/lib/automigration.rb +5 -38
  8. data/lib/automigration/active_record_ext.rb +17 -0
  9. data/lib/automigration/db_column.rb +32 -0
  10. data/lib/automigration/dsl.rb +29 -0
  11. data/lib/automigration/engine.rb +23 -0
  12. data/lib/automigration/field.rb +75 -0
  13. data/lib/automigration/fields_keeper.rb +85 -0
  14. data/lib/automigration/migrator.rb +38 -77
  15. data/lib/automigration/version.rb +1 -1
  16. data/spec/dummy/.gitignore +2 -0
  17. data/spec/dummy/README.rdoc +261 -0
  18. data/spec/dummy/Rakefile +7 -0
  19. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  20. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  21. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  22. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  23. data/{log → spec/dummy/app/mailers}/.gitkeep +0 -0
  24. data/spec/dummy/app/models/.gitkeep +0 -0
  25. data/spec/dummy/app/models/accessible_model.rb +6 -0
  26. data/spec/dummy/app/models/auto_migration1.rb +14 -0
  27. data/{test → spec/dummy/app}/models/auto_migration1a.rb +2 -2
  28. data/{test → spec/dummy/app}/models/auto_migration2.rb +2 -2
  29. data/spec/dummy/app/models/auto_migration3.rb +5 -0
  30. data/{test → spec/dummy/app}/models/belongs_to_model.rb +0 -0
  31. data/{test → spec/dummy/app}/models/boolean_model.rb +0 -0
  32. data/{test → spec/dummy/app}/models/form_field.rb +0 -0
  33. data/{test → spec/dummy/app}/models/form_field2.rb +1 -1
  34. data/{test → spec/dummy/app}/models/local_name.rb +0 -0
  35. data/{test → spec/dummy/app}/models/local_name2.rb +0 -0
  36. data/{test → spec/dummy/app}/models/not_automigrable.rb +0 -0
  37. data/{test → spec/dummy/app}/models/searchable.rb +0 -0
  38. data/{test → spec/dummy/app}/models/simple.rb +0 -0
  39. data/{test → spec/dummy/app}/models/user1.rb +0 -0
  40. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  41. data/spec/dummy/config.ru +4 -0
  42. data/spec/dummy/config/application.rb +56 -0
  43. data/spec/dummy/config/boot.rb +10 -0
  44. data/spec/dummy/config/database.yml +14 -0
  45. data/spec/dummy/config/environment.rb +5 -0
  46. data/spec/dummy/config/environments/development.rb +37 -0
  47. data/spec/dummy/config/environments/production.rb +67 -0
  48. data/spec/dummy/config/environments/test.rb +37 -0
  49. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  50. data/spec/dummy/config/initializers/inflections.rb +15 -0
  51. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  52. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  53. data/spec/dummy/config/initializers/session_store.rb +8 -0
  54. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  55. data/spec/dummy/config/locales/en.yml +5 -0
  56. data/spec/dummy/config/routes.rb +58 -0
  57. data/spec/dummy/db/.gitkeep +0 -0
  58. data/spec/dummy/lib/assets/.gitkeep +0 -0
  59. data/spec/dummy/log/.gitkeep +0 -0
  60. data/spec/dummy/public/404.html +26 -0
  61. data/spec/dummy/public/422.html +26 -0
  62. data/spec/dummy/public/500.html +25 -0
  63. data/spec/dummy/public/favicon.ico +0 -0
  64. data/spec/dummy/script/rails +6 -0
  65. data/spec/lib/accessible_spec.rb +13 -0
  66. data/spec/lib/auto_migration_spec.rb +155 -0
  67. data/spec/lib/belongs_to_spec.rb +38 -0
  68. data/spec/lib/db_column_spec.rb +21 -0
  69. data/spec/lib/fields_spec.rb +22 -0
  70. data/spec/spec_helper.rb +24 -0
  71. metadata +106 -47
  72. data/lib/automigration/base_extention.rb +0 -15
  73. data/lib/automigration/fields/belongs_to.rb +0 -29
  74. data/lib/automigration/fields/boolean.rb +0 -9
  75. data/lib/automigration/fields/date.rb +0 -9
  76. data/lib/automigration/fields/datetime.rb +0 -9
  77. data/lib/automigration/fields/float.rb +0 -9
  78. data/lib/automigration/fields/integer.rb +0 -9
  79. data/lib/automigration/fields/password.rb +0 -9
  80. data/lib/automigration/fields/string.rb +0 -9
  81. data/lib/automigration/fields/sys/base.rb +0 -95
  82. data/lib/automigration/fields/sys/db_column.rb +0 -36
  83. data/lib/automigration/fields/sys/keeper.rb +0 -113
  84. data/lib/automigration/fields/sys/slice_creater.rb +0 -32
  85. data/lib/automigration/fields/text.rb +0 -9
  86. data/lib/automigration/fields/time.rb +0 -9
  87. data/test/auto_migration_test.rb +0 -186
  88. data/test/belongs_to_test.rb +0 -51
  89. data/test/db_column_test.rb +0 -23
  90. data/test/fields/accessible_test.rb +0 -13
  91. data/test/fields_test.rb +0 -34
  92. data/test/models/accessible_model.rb +0 -6
  93. data/test/models/auto_migration1.rb +0 -14
  94. data/test/models/auto_migration3.rb +0 -5
  95. data/test/test_helper.rb +0 -35
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -1,9 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
- before_script:
5
- - psql -c 'create database automigration_test;' -U postgres
6
4
  env:
7
5
  - "PG_USER=postgres"
8
6
  script:
9
- - bundle exec rake test
7
+ - bundle exec rake db:prepare && bundle exec rspec
@@ -0,0 +1,13 @@
1
+ # Change Log
2
+
3
+ ## Automigration 1.0.0 (March 23, 2012)
4
+
5
+ * Clean API
6
+
7
+ ## Automigration 0.2.2 (March 19, 2012)
8
+
9
+ * Remove db:auto rake task, enhance db:migrate instead
10
+
11
+ ## Automigration 0.2.1 (March 18, 2012)
12
+
13
+ * First public release
data/README.md CHANGED
@@ -1,24 +1,50 @@
1
1
  # ActiveRecord automigrations
2
2
 
3
- [<img src="https://secure.travis-ci.org/boshie/automigration.png"/>](http://travis-ci.org/boshie/automigration)
4
- [<img src="https://gemnasium.com/boshie/automigration.png"/>](http://gemnasium.com/boshie/automigration)
3
+ Create/modify/delete Active Record columns without migrations. It works only with PostgreSQL.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ gem 'automigration'
9
+ ```
5
10
 
11
+ ## Usage
6
12
 
7
- ## Overview
13
+ Add <tt>has_fields</tt> into your models:
8
14
 
9
15
  ``` ruby
10
16
  class User < ActiveRecord::Base
11
- # attributes created via migration
12
- migration_attr :secure_password, :auth_token
13
- migration_attr :salt
14
-
15
- has_fields do |f|
16
- f.string :name
17
- f.integer :login_count
17
+ has_fields do
18
+ string :name
19
+ integer :login_count
18
20
  end
19
21
  end
20
22
  ```
21
23
 
24
+ Fire in console:
25
+
26
+ ``
27
+ rake db:migrate
28
+ ```
29
+
30
+ To keep some system tables add to <tt>config/application.rb</tt>
31
+
32
+ ```
33
+ config.automigration.system_tables << %w[hits very_system_table]
34
+ ```
35
+
36
+ Supported fields:
37
+
38
+ * belongs_to
39
+ * boolean
40
+ * date
41
+ * datetime
42
+ * float
43
+ * integer
44
+ * string
45
+ * text
46
+ * time
47
+
22
48
  ## Devise support
23
49
 
24
50
  ActiveRecord::Base supports all types of devise fields with prefix devise\_
@@ -27,11 +53,11 @@ ActiveRecord::Base supports all types of devise fields with prefix devise\_
27
53
  class User < ActiveRecord::Base
28
54
  devise :database_authenticatable, :rememberable, :trackable, :validatable, :recoverable
29
55
 
30
- has_fields do |t|
31
- t.devise_database_authenticatable :null => false
32
- t.devise_rememberable
33
- t.devise_trackable
34
- t.devise_recoverable
56
+ has_fields do
57
+ devise_database_authenticatable :null => false
58
+ devise_rememberable
59
+ devise_trackable
60
+ devise_recoverable
35
61
  end
36
62
  end
37
63
  ```
@@ -41,12 +67,7 @@ end
41
67
  By default in models with has_fields always columns updated_at and created_at created. To ignore
42
68
  use has_fields(:timestamps => false)
43
69
 
44
- ## Changelog
70
+ ## Status
45
71
 
46
- ### Automigration 0.2.2 (March 19, 2012)
47
-
48
- * Remove db:auto rake task, enhance db:migrate instead
49
-
50
- ### Automigration 0.2.1 (March 18, 2012)
51
-
52
- * First public release
72
+ [<img src="https://secure.travis-ci.org/boshie/automigration.png"/>](http://travis-ci.org/boshie/automigration)
73
+ [<img src="https://gemnasium.com/boshie/automigration.png"/>](http://gemnasium.com/boshie/automigration)
data/Rakefile CHANGED
@@ -1,18 +1,16 @@
1
- require 'bundler/gem_tasks'
2
- require 'rake/testtask'
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
3
 
4
- Rake::TestTask.new :test do |t|
5
- t.libs << 'lib'
6
- t.libs << 'test'
7
- t.test_files = FileList['test/**/*_test.rb']
8
- t.verbose = true
9
- end
4
+ require "rubygems"
5
+ require "bundler/setup"
6
+ require 'rspec/core/rake_task'
10
7
 
11
8
  namespace :db do
12
- desc 'Recreate test db'
13
- task :prepare do
14
- `dropdb automigration_test`
15
- `createdb automigration_test`
9
+ desc "prepare db for specs"
10
+ task "prepare" do
11
+ system "cd spec/dummy && bundle exec rake db:drop"
12
+ system "cd spec/dummy && bundle exec rake db:create db:migrate db:test:prepare"
16
13
  end
17
14
  end
18
15
 
16
+ RSpec::Core::RakeTask.new(:spec)
@@ -20,5 +20,9 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency 'rails', '~> 3.1'
22
22
  s.add_dependency 'ansi'
23
+
23
24
  s.add_development_dependency 'pg'
25
+ s.add_development_dependency 'rspec-rails'
26
+ s.add_development_dependency 'database_cleaner'
27
+ s.add_development_dependency 'factory_girl_rails'
24
28
  end
@@ -1,42 +1,9 @@
1
- require 'rails/engine'
2
1
  require 'ansi'
3
2
  require 'automigration/version'
3
+ require 'automigration/engine'
4
4
  require 'automigration/migrator'
5
- require 'automigration/fields/sys/base'
6
- require 'automigration/fields/belongs_to'
7
- require 'automigration/fields/boolean'
8
- require 'automigration/fields/date'
9
- require 'automigration/fields/datetime'
10
- require 'automigration/fields/float'
11
- require 'automigration/fields/integer'
12
- require 'automigration/fields/password'
13
- require 'automigration/fields/string'
14
- require 'automigration/fields/text'
15
- require 'automigration/fields/time'
16
- require 'automigration/fields/sys/db_column'
17
- require 'automigration/fields/sys/keeper'
18
- require 'automigration/fields/sys/slice_creater'
5
+ require 'automigration/field'
6
+ require 'automigration/db_column'
7
+ require 'automigration/fields_keeper'
8
+ require 'automigration/dsl'
19
9
 
20
- module Automigration
21
- class Engine < ::Rails::Engine
22
- config.automigration = ActiveSupport::OrderedOptions.new
23
- config.automigration.system_tables = []
24
- config.automigration.models_load_path = []
25
- config.automigration.models_to_ignore = []
26
- config.automigration.migrations_path = nil
27
-
28
- initializer 'automigration' do |app|
29
- app.config.automigration.models_load_path << Rails.root + 'app/models'
30
- app.config.automigration.migrations_path = Rails.root + 'db/migrate'
31
-
32
- ActiveSupport.on_load(:active_record) do
33
- require 'automigration/base_extention'
34
- end
35
-
36
- Migrator.set_models_load_path(app.config.automigration.models_load_path)
37
- Migrator.set_models_to_ignore(app.config.automigration.models_to_ignore)
38
- Migrator.set_system_tables(app.config.automigration.system_tables)
39
- Migrator.set_migrations_path(app.config.automigration.migrations_path)
40
- end
41
- end
42
- end
@@ -0,0 +1,17 @@
1
+ module ActiveRecord
2
+ class Base
3
+ class_attribute :__fields_keeper
4
+ self.__fields_keeper = nil
5
+
6
+ def self.__fields_keeper_instance
7
+ self.__fields_keeper ||= ::Automigration::FieldsKeeper.new(self)
8
+ end
9
+
10
+ class << self
11
+ delegate :has_fields, :add_field, :migration_attr, :to => :__fields_keeper_instance
12
+ delegate :auto_migrable?, :migration_attrs, :to => :__fields_keeper_instance
13
+ delegate :field_db_columns, :to => :__fields_keeper_instance
14
+ delegate :fields, :field_names, :to => :__fields_keeper_instance
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,32 @@
1
+ module Automigration
2
+ class DbColumn < Struct.new(:name, :type, :options)
3
+ def initialize(name_, type_, options_)
4
+ super
5
+ options_.assert_valid_keys(:default, :null, :limit, :scale, :precision)
6
+ end
7
+
8
+ def self.from_activerecord_column(column)
9
+ out = DbColumn.new(column.name.to_sym, column.type.to_sym, {
10
+ :default => column.default,
11
+ :null => column.null,
12
+ :limit => column.limit,
13
+ :scale => column.scale,
14
+ :precision => column.precision
15
+ })
16
+ end
17
+
18
+ def the_same?(other)
19
+ (__to_array <=> other.send(:__to_array)) == 0
20
+ end
21
+
22
+ def to_options
23
+ options.reject{|k, v| v.nil?}
24
+ end
25
+
26
+ private
27
+ # compare only by 3 values
28
+ def __to_array
29
+ [name.to_s, type.to_s, options[:default].to_s]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Automigration
2
+ class Dsl
3
+ attr_reader :fields
4
+ attr_reader :devise_fields
5
+
6
+ def initialize
7
+ @fields = []
8
+ @devise_fields = []
9
+ end
10
+
11
+ Field::KIND.each do |field|
12
+ define_method field do |*args|
13
+ options = args.extract_options!
14
+ raise "wrong amount of args" unless args.size == 1
15
+ name = args[0]
16
+ @fields << {:name => name, :as => field.to_sym}.merge(options)
17
+ Field.valid_options_keys(@fields.last)
18
+ end
19
+ end
20
+
21
+ def method_missing(meth, *args, &block)
22
+ if meth.to_s =~ /^devise_(.*)/
23
+ @devise_fields << {:as => meth, :args => args}
24
+ else
25
+ super
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ require 'rails/engine'
2
+
3
+ module Automigration
4
+ class Engine < ::Rails::Engine
5
+ config.automigration = ActiveSupport::OrderedOptions.new
6
+ config.automigration.system_tables = []
7
+ config.automigration.migration_paths = []
8
+ config.automigration.model_paths = []
9
+
10
+ initializer 'automigration' do |app|
11
+ app.config.automigration.migration_paths << Rails.root + 'db/migrate'
12
+ app.config.automigration.model_paths << Rails.root + 'app/models'
13
+
14
+ ActiveSupport.on_load(:active_record) do
15
+ require 'automigration/active_record_ext'
16
+ end
17
+
18
+ Migrator.set_system_tables(app.config.automigration.system_tables)
19
+ Migrator.set_migration_paths(app.config.automigration.migration_paths)
20
+ Migrator.set_model_paths(app.config.automigration.model_paths)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,75 @@
1
+ module Automigration
2
+ module Field
3
+ KIND = %w[
4
+ belongs_to
5
+ boolean
6
+ date
7
+ datetime
8
+ float
9
+ integer
10
+ string
11
+ text
12
+ time
13
+ ]
14
+
15
+ def self.to_db_columns(field)
16
+ type = field[:as]
17
+
18
+ if type == :belongs_to
19
+ name = "#{field[:name]}_id"
20
+ column_type = :integer
21
+ else
22
+ name = field[:name]
23
+ column_type = type
24
+ end
25
+
26
+ if type == :boolean
27
+ default = !!field[:default]
28
+ else
29
+ default = field[:default]
30
+ end
31
+
32
+ Automigration::DbColumn.new(name, column_type, {
33
+ :default => default,
34
+ :null => field[:null],
35
+ :limit => field[:limit],
36
+ :scale => field[:scale],
37
+ :precision => field[:precision]
38
+ })
39
+ end
40
+
41
+ def self.valid_options_keys(field)
42
+ valid_keys = [
43
+ :name, :as, # system attributes
44
+ :default, :null, :limit, :scale, :precision, # db columns keys
45
+ :accessible # mark attribute as accessible
46
+ ]
47
+
48
+ type = field[:as]
49
+
50
+ if type == :belongs_to
51
+ valid_keys += [:class_name, :inverse_of]
52
+ end
53
+
54
+ field.assert_valid_keys(*valid_keys)
55
+ end
56
+
57
+ def self.extend_model!(model, field)
58
+ type = field[:as]
59
+ name = field[:name]
60
+ accessible = (field[:accessible] == nil) || field[:accessible]
61
+
62
+ if type == :belongs_to
63
+ model.belongs_to name, :class_name => field[:class_name], :inverse_of => field[:inverse_of]
64
+
65
+ if accessible
66
+ model.attr_accessible "#{name}_id"
67
+ end
68
+ end
69
+
70
+ if accessible
71
+ model.attr_accessible name
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,85 @@
1
+ module Automigration
2
+ class FieldsKeeper
3
+ attr_reader :fields
4
+ attr_reader :migration_attrs
5
+
6
+ def initialize(model)
7
+ @model = model
8
+ @fields = nil
9
+ @devise_fields = []
10
+ @migration_attrs = []
11
+ @timestamps_added = false
12
+
13
+ @fields_lookup = {}
14
+ end
15
+
16
+ def has_fields(options = {}, &block)
17
+ options.assert_valid_keys(:timestamps)
18
+ options.reverse_merge!(:timestamps => true)
19
+
20
+ dsl = Automigration::Dsl.new
21
+ block.arity == 1 ? block.call(dsl) : dsl.instance_exec(&block)
22
+
23
+ dsl.fields.each do |field|
24
+ Field.extend_model!(@model, field)
25
+ end
26
+
27
+ @fields ||= []
28
+ @fields += dsl.fields
29
+ @devise_fields = dsl.devise_fields
30
+
31
+ if !@timestamps_added && options[:timestamps]
32
+ @timestamps_added = true
33
+ @fields << {:as => :datetime, :name => :created_at, :accessible => false}
34
+ @fields << {:as => :datetime, :name => :updated_at, :accessible => false}
35
+ end
36
+ end
37
+
38
+ def add_field(type, name, options = {})
39
+ has_fields(:timestamps => false) do |f|
40
+ f.send type, name, options
41
+ end
42
+ end
43
+
44
+ def migration_attr(*args)
45
+ @migration_attrs += args.flatten.map(&:to_s)
46
+ end
47
+
48
+ def auto_migrable?
49
+ @fields.present?
50
+ end
51
+
52
+ def field_names
53
+ @field_names ||= fields.map{|f| f[:name]}
54
+ end
55
+
56
+ def field_db_columns
57
+ out = []
58
+
59
+ out += @fields.map do |field|
60
+ Field.to_db_columns(field)
61
+ end.flatten
62
+
63
+ if defined?(Devise::Schema)
64
+ devise_schema = Class.new do
65
+ include Devise::Schema
66
+
67
+ define_method :apply_devise_schema do |*args|
68
+ opts = args.extract_options!
69
+ raise "wrong arguments" unless args.size == 2
70
+ name = args[0]
71
+ as = args[1].to_s.underscore.to_sym
72
+ as = :datetime if as == :date_time
73
+ out << Automigration::DbColumn.new(name, as, opts)
74
+ end
75
+ end.new
76
+
77
+ @devise_fields.each do |meta|
78
+ devise_schema.send(meta[:as].to_s.sub(/^devise_/, ''), *meta[:args])
79
+ end
80
+ end
81
+
82
+ out
83
+ end
84
+ end
85
+ end