modalfields 1.1.1

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