automigration 0.2.2 → 1.0.0

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 (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