modalfields 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
1
+ # Define built-in column types, with default values for valid attributes
2
+ ModalFields.define do
3
+ string :limit=>255
4
+ text :limit=>nil
5
+ integer :limit=>nil
6
+ float
7
+ decimal :scale=>nil, :precision=>nil
8
+ datetime
9
+ time
10
+ date
11
+ binary :limit=>nil
12
+ boolean
13
+ end
@@ -0,0 +1 @@
1
+ Dir[File.join(File.dirname(__FILE__), '..', 'tasks', '**/*.rake')].each { |f| load f }
@@ -0,0 +1,6 @@
1
+ namespace :fields do
2
+ desc "Compare the current schema with existing field declarations"
3
+ task :check=>:environment do
4
+ ModalFields.check
5
+ end
6
+ end
@@ -0,0 +1,17 @@
1
+ namespace :db do
2
+ task :migrate do
3
+ ModalFields.update
4
+ end
5
+
6
+ task :update => [:migrate] do
7
+ ModalFields.update
8
+ end
9
+
10
+ namespace :migrate do
11
+ [:up, :down, :reset, :redo].each do |t|
12
+ task t do
13
+ ModalFields.update
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,6 @@
1
+ namespace :fields do
2
+ desc "Update the field declarations from the current schema"
3
+ task :update=>:environment do
4
+ ModalFields.update
5
+ end
6
+ end
@@ -0,0 +1,47 @@
1
+ def create_database(config)
2
+ begin
3
+ if config['adapter'] =~ /sqlite/
4
+ if File.exist?(config['database'])
5
+ $stderr.puts "#{config['database']} already exists"
6
+ else
7
+ begin
8
+ # Create the SQLite database
9
+ ActiveRecord::Base.establish_connection(config)
10
+ ActiveRecord::Base.connection
11
+ rescue
12
+ $stderr.puts $!, *($!.backtrace)
13
+ $stderr.puts "Couldn't create database for #{config.inspect}"
14
+ end
15
+ end
16
+ return # Skip the else clause of begin/rescue
17
+ else
18
+ ActiveRecord::Base.establish_connection(config)
19
+ ActiveRecord::Base.connection
20
+ end
21
+ rescue
22
+ case config['adapter']
23
+ when 'mysql'
24
+ @charset = ENV['CHARSET'] || 'utf8'
25
+ @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
26
+ begin
27
+ ActiveRecord::Base.establish_connection(config.merge('database' => nil))
28
+ ActiveRecord::Base.connection.create_database(config['database'], :charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation))
29
+ ActiveRecord::Base.establish_connection(config)
30
+ rescue
31
+ $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation} (if you set the charset manually, make sure you have a matching collation)"
32
+ end
33
+ when 'postgresql'
34
+ @encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
35
+ begin
36
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
37
+ ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
38
+ ActiveRecord::Base.establish_connection(config)
39
+ rescue
40
+ $stderr.puts $!, *($!.backtrace)
41
+ $stderr.puts "Couldn't create database for #{config.inspect}"
42
+ end
43
+ end
44
+ else
45
+ $stderr.puts "#{config['database']} already exists"
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ sqlite3:
2
+ :adapter: sqlite3
3
+ :database: modalfields_plugin.sqlite3.db
4
+
5
+ postgresql:
6
+ :adapter: postgresql
7
+ :username: postgres
8
+ :password: postgres
9
+ :database: modalfields_plugin_test
10
+ :min_messages: ERROR
11
+
@@ -0,0 +1,61 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'test/unit'
11
+ require 'shoulda'
12
+ require 'active_support'
13
+ require 'active_record'
14
+ require 'logger'
15
+
16
+ require 'active_support/core_ext/hash'
17
+
18
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
19
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
20
+ require 'modalfields'
21
+
22
+ class Test::Unit::TestCase
23
+ end
24
+
25
+ ENV['RAILS_ENV'] = 'test'
26
+ ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) # + '/../../../..'
27
+
28
+ # require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
29
+
30
+ module Rails
31
+ def self.root
32
+ ENV['RAILS_ROOT']
33
+ end
34
+ end
35
+
36
+ def load_schema
37
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')).with_indifferent_access
38
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
39
+
40
+ db_adapter = ENV['DB']
41
+
42
+ # no db passed, try one of these fine config-free DBs before bombing.
43
+ db_adapter ||=
44
+ begin
45
+ require 'rubygems'
46
+ require 'sqlite3'
47
+ 'sqlite3'
48
+ rescue MissingSourceFile
49
+ end
50
+
51
+ if db_adapter.nil?
52
+ raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite3."
53
+ end
54
+
55
+ require File.dirname(__FILE__) + '/create_database'
56
+ create_database config[db_adapter]
57
+
58
+ ActiveRecord::Base.establish_connection(config[db_adapter])
59
+ load(File.dirname(__FILE__) + "/schema.rb")
60
+ require File.dirname(__FILE__) + '/../rails/init'
61
+ end
@@ -0,0 +1,12 @@
1
+ class Author < ActiveRecord::Base
2
+
3
+ fields do
4
+ name :string
5
+ number :integer
6
+ birthdate :date
7
+ event :datetime
8
+ decnum :decimal, :default=>BigDecimal('1.2'), :precision=>10, :scale=>3
9
+ end
10
+
11
+ has_many :books
12
+ end
@@ -0,0 +1,12 @@
1
+ class Book < ActiveRecord::Base
2
+
3
+ fields do
4
+ title :string
5
+ price :decimal, :precision=>8, :scale=>2
6
+ code :string, :limit=>4
7
+ comments :text
8
+ timestamps
9
+ end
10
+
11
+ belongs_to :author
12
+ end
@@ -0,0 +1,3 @@
1
+ class Author < ActiveRecord::Base
2
+ has_many :books
3
+ end
@@ -0,0 +1,4 @@
1
+ class Book < ActiveRecord::Base
2
+
3
+ belongs_to :author
4
+ end
@@ -0,0 +1,14 @@
1
+ class Author < ActiveRecord::Base
2
+
3
+ fields {
4
+ # The comments must be prerserved
5
+ number :integer # as well as the order of field declarations,
6
+ name :string # indendationa
7
+ birthdate :date, :unique # specifications...
8
+ # etc.
9
+ decnum :decimal, :default=>BigDecimal('1.2'), :precision=>10, :scale=>3
10
+ event :datetime
11
+ }
12
+
13
+ has_many :books
14
+ end
@@ -0,0 +1,14 @@
1
+ class Book < ActiveRecord::Base
2
+
3
+ # the position of the fields block must be preserved
4
+ belongs_to :author
5
+
6
+ fields do
7
+ title :string
8
+ price :decimal, :precision=>8, :scale=>2
9
+ code :string, :limit=>4
10
+ comments :text
11
+ timestamps
12
+ end
13
+
14
+ end
@@ -0,0 +1,14 @@
1
+ class Author < ActiveRecord::Base
2
+
3
+ fields {
4
+ # The comments must be prerserved
5
+ number :integer # as well as the order of field declarations,
6
+ name :string # indendationa
7
+ birthdate :date, :unique # specifications...
8
+ # etc.
9
+ decnum :decimal, :default=>BigDecimal('1.2'), :precision=>10, :scale=>3
10
+ event :datetime
11
+ }
12
+
13
+ has_many :books
14
+ end
@@ -0,0 +1,14 @@
1
+ class Book < ActiveRecord::Base
2
+
3
+ # the position of the fields block must be preserved
4
+ belongs_to :author
5
+
6
+ fields do
7
+ title :string
8
+ price :decimal, :precision=>8, :scale=>2
9
+ code :string, :limit=>4
10
+ comments :text
11
+ timestamps
12
+ end
13
+
14
+ end
@@ -0,0 +1,14 @@
1
+ class Author < ActiveRecord::Base
2
+
3
+ fields {
4
+ # The comments must be prerserved
5
+ number :integer # as well as the order of field declarations,
6
+ name :string # indendation
7
+ birthdate :date, :unique # specifications...
8
+ # etc.
9
+ decnum :decimal, :default=>BigDecimal('1.2'), :precision=>10, :scale=>3
10
+ event :datetime
11
+ }
12
+
13
+ has_many :books
14
+ end
@@ -0,0 +1,14 @@
1
+ class Book < ActiveRecord::Base
2
+
3
+ # the position of the fields block must be preserved
4
+ belongs_to :author
5
+
6
+ fields do
7
+ title :string
8
+ price :decimal, :precision=>8, :scale=>2
9
+ code :string, :limit=>4
10
+ comments :text
11
+ timestamps
12
+ end
13
+
14
+ end
@@ -0,0 +1,15 @@
1
+ class Author < ActiveRecord::Base
2
+
3
+ fields {
4
+ # The comments must be prerserved
5
+ number :integer # as well as the order of field declarations,
6
+ name :string # indendation
7
+ xxxx :string
8
+ birthdate :integer, :unique # specifications...
9
+ # etc.
10
+ decnum :decimal, :default=>BigDecimal('1.2'), :precision=>11, :scale=>3
11
+ eventx :datetime
12
+ }
13
+
14
+ has_many :books
15
+ end
@@ -0,0 +1,14 @@
1
+ class Book < ActiveRecord::Base
2
+
3
+ # the position of the fields block must be preserved
4
+ belongs_to :author
5
+
6
+ fields do
7
+ title :string
8
+ price :decimal, :precision=>8, :scale=>4
9
+ code :string, :limit=>4
10
+ comments :text
11
+ zzzzz :integer
12
+ end
13
+
14
+ end
@@ -0,0 +1,17 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :authors, :force => true do |t|
3
+ t.string :name
4
+ t.integer :number
5
+ t.date :birthdate
6
+ t.datetime :event
7
+ t.decimal :decnum, :precision=>10, :scale=>3, :default=>BigDecimal('1.2')
8
+ end
9
+ create_table :books, :force => true do |t|
10
+ t.integer :author_id
11
+ t.string :title
12
+ t.decimal :price, :precision=>8, :scale=>2
13
+ t.string :code, :limit=>4
14
+ t.text :comments
15
+ t.timestamps
16
+ end
17
+ end
@@ -0,0 +1,127 @@
1
+ require File.dirname(__FILE__)+'/helper'
2
+
3
+ class TestDiff< Test::Unit::TestCase
4
+
5
+ context "Given model definitions without field declarations" do
6
+
7
+ setup do
8
+ load_schema
9
+ class Author < ActiveRecord::Base
10
+ has_many :books
11
+ end
12
+ class Book < ActiveRecord::Base
13
+ belongs_to :author
14
+ end
15
+ end
16
+
17
+ should "Find all fields that are not primary or foreing keys" do
18
+ new_fields, modified_fields, deleted_fields = ModalFields.send(:diff, Author)
19
+ assert modified_fields.empty?
20
+ assert deleted_fields.empty?
21
+ assert_same_elements ["number", "name", "birthdate", "decnum", "event"], new_fields.map{|f| f.name.to_s}
22
+ new_fields, modified_fields, deleted_fields = ModalFields.send(:diff, Book)
23
+ assert modified_fields.empty?
24
+ assert deleted_fields.empty?
25
+ assert_same_elements ["title", "price", "code", "comments", "created_at", "updated_at"], new_fields.map{|f| f.name.to_s}
26
+ end
27
+
28
+ teardown do
29
+ TestDiff.send(:remove_const, :Author) if defined?(Author)
30
+ TestDiff.send(:remove_const, :Book) if defined?(Book)
31
+ end
32
+
33
+ end
34
+
35
+ context "Given model definitions with up to date field declarations" do
36
+
37
+ setup do
38
+ load_schema
39
+ class Author < ActiveRecord::Base
40
+ fields do
41
+ name :string
42
+ number :integer
43
+ birthdate :date
44
+ event :datetime
45
+ decnum :decimal, :default=>BigDecimal('1.2'), :precision=>10, :scale=>3
46
+ end
47
+ has_many :books
48
+ end
49
+ class Book < ActiveRecord::Base
50
+ fields do
51
+ title :string
52
+ price :decimal, :precision=>8, :scale=>2
53
+ code :string, :limit=>4
54
+ comments :text
55
+ timestamps
56
+ end
57
+ belongs_to :author
58
+ end
59
+ end
60
+
61
+ should "not find any changes" do
62
+ new_fields, modified_fields, deleted_fields = ModalFields.send(:diff, Author)
63
+ # assert new_fields.empty?
64
+ # assert modified_fields.empty?
65
+ # assert deleted_fields.empty?
66
+ assert_same_elements [], new_fields.map{|f| f.name.to_s}
67
+ assert_same_elements [], modified_fields.map{|f| f.name.to_s}
68
+ assert_same_elements [], deleted_fields.map{|f| f.name.to_s}
69
+
70
+ new_fields, modified_fields, deleted_fields = ModalFields.send(:diff, Book)
71
+ # assert new_fields.empty?
72
+ # assert modified_fields.empty?
73
+ # assert deleted_fields.empty?
74
+ assert_same_elements [], new_fields.map{|f| f.name.to_s}
75
+ assert_same_elements [], modified_fields.map{|f| f.name.to_s}
76
+ assert_same_elements [], deleted_fields.map{|f| f.name.to_s}
77
+ end
78
+
79
+ teardown do
80
+ TestDiff.send(:remove_const, :Author) if defined?(Author)
81
+ TestDiff.send(:remove_const, :Book) if defined?(Book)
82
+ end
83
+
84
+ end
85
+
86
+ context "Given model definitions with unaccurate field declarations" do
87
+
88
+ setup do
89
+ load_schema
90
+ class Author < ActiveRecord::Base
91
+ fields do
92
+ name :string
93
+ birthdate :datetime
94
+ nationality :string
95
+ event :datetime
96
+ decnum :decimal, :default=>BigDecimal('1.2'), :precision=>10, :scale=>3
97
+ end
98
+ has_many :books
99
+ end
100
+ class Book < ActiveRecord::Base
101
+ fields do
102
+ title :string
103
+ price :decimal, :precision=>8, :scale=>2
104
+ code :string, :limit=>5
105
+ timestamps
106
+ end
107
+ end
108
+ end
109
+
110
+ should "Find schema modifications" do
111
+ new_fields, modified_fields, deleted_fields = ModalFields.send(:diff, Author)
112
+ assert_same_elements ['nationality'], deleted_fields.map{|f| f.name.to_s}
113
+ assert_same_elements ['number'], new_fields.map{|f| f.name.to_s}
114
+ assert_same_elements ['birthdate'], modified_fields.map{|f| f.name.to_s}
115
+ new_fields, modified_fields, deleted_fields = ModalFields.send(:diff, Book)
116
+ assert_same_elements [], deleted_fields.map{|f| f.name.to_s}
117
+ assert_same_elements ['comments', 'author_id'], new_fields.map{|f| f.name.to_s}
118
+ assert_same_elements ['code'], modified_fields.map{|f| f.name.to_s}
119
+ end
120
+
121
+ teardown do
122
+ TestDiff.send(:remove_const, :Author) if defined?(Author)
123
+ TestDiff.send(:remove_const, :Book) if defined?(Book)
124
+ end
125
+
126
+ end
127
+ end