migrant 1.1.1 → 1.1.2
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.
- data/.rvmrc +1 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -0
- data/VERSION +1 -1
- data/lib/{datatype/base.rb → dsl/data_type.rb} +18 -12
- data/lib/dsl/data_types/primitives.rb +106 -0
- data/lib/generators/templates/change_migration.erb +22 -0
- data/lib/generators/templates/create_migration.erb +16 -0
- data/lib/generators/templates/create_migration.rb +16 -0
- data/lib/migrant/migration_generator.rb +41 -74
- data/lib/migrant/schema.rb +5 -4
- data/lib/migrant.rb +1 -1
- data/migrant.gemspec +14 -14
- data/test/helper.rb +24 -1
- data/test/rails_app/app/models/category.rb +1 -0
- data/test/test_data_schema.rb +4 -0
- data/test/test_migration_generator.rb +11 -6
- data/test/test_zzz_performance.rb +13 -0
- data/test/verified_output/migrations/created_at.rb +1 -1
- metadata +23 -15
- data/lib/datatype/boolean.rb +0 -15
- data/lib/datatype/date.rb +0 -13
- data/lib/datatype/fixnum.rb +0 -13
- data/lib/datatype/float.rb +0 -11
- data/lib/datatype/foreign_key.rb +0 -13
- data/lib/datatype/polymorphic.rb +0 -8
- data/lib/datatype/range.rb +0 -9
- data/lib/datatype/string.rb +0 -22
- data/lib/datatype/symbol.rb +0 -20
- data/lib/datatype/time.rb +0 -5
- /data/lib/{datatype/currency.rb → dsl/data_types/semantic.rb} +0 -0
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -71,6 +71,7 @@ GEM
|
|
71
71
|
simplecov-html (~> 0.4.0)
|
72
72
|
simplecov-html (0.4.3)
|
73
73
|
sqlite3 (1.3.3)
|
74
|
+
terminal-table (1.4.2)
|
74
75
|
thor (0.14.6)
|
75
76
|
thoughtbot-shoulda (2.11.1)
|
76
77
|
treetop (1.4.9)
|
@@ -89,5 +90,6 @@ DEPENDENCIES
|
|
89
90
|
rails (>= 3.0.0)
|
90
91
|
simplecov
|
91
92
|
sqlite3
|
93
|
+
terminal-table
|
92
94
|
thoughtbot-shoulda
|
93
95
|
turn
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.1.
|
1
|
+
1.1.2
|
@@ -62,18 +62,24 @@ module DataType
|
|
62
62
|
|
63
63
|
def self.migrant_data_type?; true; end
|
64
64
|
end
|
65
|
+
|
66
|
+
|
65
67
|
end
|
66
68
|
|
67
|
-
|
68
|
-
require '
|
69
|
-
require 'datatype/currency'
|
70
|
-
require 'datatype/date'
|
71
|
-
require 'datatype/fixnum'
|
72
|
-
require 'datatype/float'
|
73
|
-
require 'datatype/foreign_key'
|
74
|
-
require 'datatype/polymorphic'
|
75
|
-
require 'datatype/range'
|
76
|
-
require 'datatype/string'
|
77
|
-
require 'datatype/symbol'
|
78
|
-
require 'datatype/time'
|
69
|
+
require 'dsl/data_types/primitives'
|
70
|
+
require 'dsl/data_types/semantic'
|
79
71
|
|
72
|
+
# Add internal types used by Migrant
|
73
|
+
module DataType
|
74
|
+
class Polymorphic < Base; end
|
75
|
+
|
76
|
+
class ForeignKey < Fixnum
|
77
|
+
def column
|
78
|
+
{:type => :integer}
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.default_mock
|
82
|
+
nil # Will get overridden later by ModelExtensions
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module DataType
|
2
|
+
# Boolean
|
3
|
+
class TrueClass < Base
|
4
|
+
def column
|
5
|
+
{:type => :boolean}
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.default_mock
|
9
|
+
true
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class FalseClass < TrueClass; end;
|
14
|
+
|
15
|
+
# Datetime
|
16
|
+
class Date < Base
|
17
|
+
def column
|
18
|
+
{:type => :datetime}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.default_mock
|
22
|
+
::Time.now
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Time < Date; end; # No different to date type
|
27
|
+
|
28
|
+
# Integers
|
29
|
+
class Fixnum < Base
|
30
|
+
def column
|
31
|
+
{:type => :integer}.tap do |options|
|
32
|
+
options.merge!(:limit => @value.size) if @value > 2147483647 # 32-bit limit. Not checking size here because a 64-bit OS always has at least 8 byte size
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.default_mock
|
37
|
+
rand(999999).to_i
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class Bignum < Fixnum
|
42
|
+
def column
|
43
|
+
{:type => :integer, :limit => ((@value.size > 8)? @value.size : 8) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Float < Base
|
48
|
+
def column
|
49
|
+
{:type => :float}
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.default_mock
|
53
|
+
rand(100).to_f-55.0
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Range (0..10)
|
58
|
+
class Range < Base
|
59
|
+
def column
|
60
|
+
definition = {:type => :integer}
|
61
|
+
definition[:limit] = @value.max.to_s.length if @value.respond_to?(:max)
|
62
|
+
definition
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Strings
|
67
|
+
class String < Base
|
68
|
+
def initialize(options)
|
69
|
+
super(options)
|
70
|
+
@value ||= ''
|
71
|
+
end
|
72
|
+
|
73
|
+
def column
|
74
|
+
if @value.match(/[\d,]+\.\d{2}$/)
|
75
|
+
return Currency.new(@options).column
|
76
|
+
else
|
77
|
+
return @value.match(/[\r\n\t]/)? { :type => :text }.merge(@options) : super
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def mock
|
82
|
+
@value || ((self.column[:type] == :text)? self.class.long_text_mock : self.class.default_mock )
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Symbol (defaults, specified by user)
|
87
|
+
class Symbol < Base
|
88
|
+
def column
|
89
|
+
# Just construct whatever the user wants
|
90
|
+
{:type => @value || :string }.merge(@options)
|
91
|
+
end
|
92
|
+
|
93
|
+
def mock
|
94
|
+
case @value || :string
|
95
|
+
when :text then self.class.long_text_mock
|
96
|
+
when :string then self.class.short_text_mock
|
97
|
+
when :integer then Fixnum.default_mock
|
98
|
+
when :decimal, :float then Float.default_mock
|
99
|
+
when :datetime, :date then Date.default_mock
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class <%= @activity.camelize.gsub(/\s/, '') %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
<% @added_columns.each do |field, options| %>
|
4
|
+
add_column :<%= @table_name %>, :<%= field %>, :<%= options.delete(:type) %><%= (options.blank?)? '': ", "+options.inspect[1..-2] %>
|
5
|
+
<% end -%>
|
6
|
+
<% @changed_columns.each do |field, options, old_options| %>
|
7
|
+
change_column :<%= @table_name %>, :<%= field %>, :<%= options.delete(:type) %><%= (options.blank?)? '': ", "+options.inspect[1..-2] %>
|
8
|
+
<% end -%>
|
9
|
+
<% @indexes.each do |index, options| %>
|
10
|
+
add_index :<%= @table_name %>, <%= index.inspect %>
|
11
|
+
<% end -%>
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.down
|
15
|
+
<% @added_columns.each do |field, options| %>
|
16
|
+
remove_column :<%= @table_name %>, :<%= field %>
|
17
|
+
<% end -%>
|
18
|
+
<% @changed_columns.each do |field, options, old_options| %>
|
19
|
+
change_column :<%= @table_name %>, :<%= field %>, :<%= old_options.delete(:type) %><%= (old_options.blank?)? '': ", "+old_options.inspect[1..-2] %>
|
20
|
+
<% end -%>
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class <%= @activity.camelize.gsub(/\s/, '') %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :<%= @table_name %> do |t|
|
4
|
+
<% @columns.each do |field, options| %>
|
5
|
+
t.<%= options.delete(:type) %> :<%= field %><%= (options.blank?)? '': ", "+options.inspect[1..-2] %>
|
6
|
+
<% end %>
|
7
|
+
end
|
8
|
+
<% @indexes.each do |index| %>
|
9
|
+
add_index :<%= @table_name %>, <%= index.inspect %>
|
10
|
+
<% end -%>
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :<%= @table_name %>
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class <%= @activity.camelize.gsub(/\s/, '') %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :<%= @table_name %> do |t|
|
4
|
+
<% @columns.each do |field, options| %>
|
5
|
+
t.<%= options.delete(:type) %> :<%= field %><%= (options.blank?)? '': ", "+options.inspect[1..-2] %>
|
6
|
+
<% end %>
|
7
|
+
end
|
8
|
+
<% @indexes.each do |index, options| %>
|
9
|
+
add_index :<%= @table_name %>, <%= index.inspect %>
|
10
|
+
<% end -%>
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :<%= @table_name %>
|
15
|
+
end
|
16
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'erubis'
|
2
|
+
|
1
3
|
module Migrant
|
2
4
|
class MigrationGenerator
|
3
5
|
TABS = ' ' # Tabs to spaces * 2
|
@@ -21,79 +23,52 @@ module Migrant
|
|
21
23
|
ActiveRecord::Base.descendants.each do |model|
|
22
24
|
next if model.schema.nil? || !model.schema.requires_migration? # Skips inherited schemas (such as models with STI)
|
23
25
|
model.reset_column_information # db:migrate doesn't do this
|
24
|
-
|
26
|
+
@table_name = model.table_name
|
25
27
|
|
26
28
|
if model.table_exists?
|
27
29
|
# Structure ActiveRecord::Base's column information so we can compare it directly to the schema
|
28
30
|
db_schema = Hash[*model.columns.collect {|c| [c.name.to_sym, Hash[*[:type, :limit].map { |type| [type, c.send(type)] }.flatten] ] }.flatten]
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
next if changes.blank?
|
38
|
-
changed_fields, added_fields = [], []
|
39
|
-
|
40
|
-
up_code = changes.collect do |field, options|
|
41
|
-
type = options.delete(:type)
|
42
|
-
arguments = (options.blank?)? "" : ", #{options.inspect[1..-2]}"
|
43
|
-
|
44
|
-
if db_schema[field]
|
45
|
-
changed_fields << field
|
46
|
-
"change_column :#{model.table_name}, :#{field}, :#{type}#{arguments}"
|
47
|
-
else
|
48
|
-
added_fields << field
|
49
|
-
"add_column :#{model.table_name}, :#{field}, :#{type}#{arguments}"
|
50
|
-
end
|
51
|
-
end.join(NEWLINE+TABS)
|
52
|
-
|
53
|
-
activity = 'changed_'+model.table_name+[(added_fields.blank?)? nil : '_added_'+added_fields.join('_'), (changed_fields.blank?)? nil : '_modified_'+changed_fields.join('_')].compact.join('_and_')
|
54
|
-
|
55
|
-
down_code = changes.collect do |field, options|
|
56
|
-
if db_schema[field]
|
57
|
-
type = db_schema[field].delete(:type)
|
58
|
-
arguments = (db_schema[field].blank?)? "" : ", #{db_schema[field].inspect[1..-2]}"
|
59
|
-
"change_column :#{model.table_name}, :#{field}, :#{type}#{arguments}"
|
60
|
-
else
|
61
|
-
"remove_column :#{model.table_name}, :#{field}"
|
62
|
-
end
|
63
|
-
end.join(NEWLINE+TABS)
|
64
|
-
|
65
|
-
# For adapters that can report indexes, add as necessary
|
66
|
-
if ActiveRecord::Base.connection.respond_to?(:indexes)
|
67
|
-
current_indexes = ActiveRecord::Base.connection.indexes(model.table_name).collect { |index| (index.columns.length == 1)? index.columns.first.to_sym : index.columns.collect(&:to_sym) }
|
68
|
-
up_code += model.schema.indexes.uniq.collect do |index|
|
69
|
-
unless current_indexes.include?(index)
|
70
|
-
NEWLINE+TABS+"add_index :#{model.table_name}, #{index.inspect}"
|
31
|
+
@changed_columns, @added_columns = [], []
|
32
|
+
model.schema.columns.to_a.sort { |a,b| a.to_s <=> b.to_s }.each do |field_name, data_type|
|
33
|
+
begin
|
34
|
+
if (options = data_type.structure_changes_from(db_schema[field_name]))
|
35
|
+
if db_schema[field_name]
|
36
|
+
@changed_columns << [field_name, options, db_schema[field_name]]
|
37
|
+
else
|
38
|
+
@added_columns << [field_name, options]
|
71
39
|
end
|
72
|
-
end
|
40
|
+
end
|
41
|
+
rescue DataType::DangerousMigration
|
42
|
+
puts "Cannot generate migration automatically for #{model.table_name}, this would involve possible data loss on column: #{field_name}\nOld structure: #{db_schema[field_name].inspect}. New structure: #{data_type.column.inspect}\nPlease create and run this migration yourself (with the appropriate data integrity checks)"
|
43
|
+
return false
|
73
44
|
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# For adapters that can report indexes, add as necessary
|
48
|
+
if ActiveRecord::Base.connection.respond_to?(:indexes)
|
49
|
+
current_indexes = ActiveRecord::Base.connection.indexes(model.table_name).collect { |index| (index.columns.length == 1)? index.columns.first.to_sym : index.columns.collect(&:to_sym) }
|
50
|
+
@indexes = model.schema.indexes.uniq.reject { |index| current_indexes.include?(index) }.collect { |field_name| [field_name, {}] }
|
51
|
+
# Don't spam the user with indexes that columns are being created with
|
52
|
+
@new_indexes = @indexes.reject { |index, options| @changed_columns.detect { |c| c.first == index } || @added_columns.detect { |c| c.first == index } }
|
53
|
+
end
|
54
|
+
|
55
|
+
next if @changed_columns.empty? && @added_columns.empty? && @indexes.empty? # Nothing to do for this table
|
56
|
+
|
57
|
+
# Example: changed_table_added_something_and_modified_something
|
58
|
+
@activity = 'changed_'+model.table_name+[['added', @added_columns], ['modified', @changed_columns], ['indexed', @new_indexes]].reject { |v| v[1].empty? }.collect { |v| "_#{v[0]}_"+v[1].collect(&:first).join('_') }.join('_and')
|
59
|
+
@activity = @activity.split('_')[0..2].join('_') if @activity.length >= 240 # Most filesystems will raise Errno::ENAMETOOLONG otherwise
|
60
|
+
|
61
|
+
render('change_migration')
|
74
62
|
else
|
75
|
-
activity = "create_#{model.table_name}"
|
76
|
-
|
77
|
-
|
78
|
-
options.delete(:was) # Aliases not relevant when creating a new table
|
79
|
-
arguments = (options.blank?)? "" : ", #{options.inspect[1..-2]}"
|
80
|
-
(TABS*2)+"t.#{type} :#{field}#{arguments}"
|
81
|
-
end.join(NEWLINE)+NEWLINE+TABS+"end"
|
63
|
+
@activity = "create_#{model.table_name}"
|
64
|
+
@columns = model.schema.column_migrations
|
65
|
+
@indexes = model.schema.indexes
|
82
66
|
|
83
|
-
|
84
|
-
up_code += NEWLINE+TABS+model.schema.indexes.collect { |fields| "add_index :#{model.table_name}, #{fields.inspect}"}.join(NEWLINE+TABS)
|
85
|
-
end
|
86
|
-
|
87
|
-
# Indexes
|
88
|
-
# down_code += NEWLINE+TABS+model.schema.indexes.collect { |fields| "remove_index :#{model.table_name}, #{fields.inspect}"}.join(NEWLINE+TABS)
|
89
|
-
begin
|
90
|
-
filename = "#{migrations_path}/#{next_migration_number}_#{activity}.rb"
|
91
|
-
File.open(filename, 'w') { |migration| migration.write(migration_template(activity, up_code, down_code)) }
|
92
|
-
rescue Errno::ENAMETOOLONG
|
93
|
-
activity = activity.split('_')[0..2].join('_')
|
94
|
-
filename = "#{migrations_path}/#{next_migration_number}_#{activity}.rb"
|
95
|
-
File.open(filename, 'w') { |migration| migration.write(migration_template(activity, up_code, down_code)) }
|
67
|
+
render("create_migration")
|
96
68
|
end
|
69
|
+
|
70
|
+
filename = "#{migrations_path}/#{next_migration_number}_#{@activity}.rb"
|
71
|
+
File.open(filename, 'w') { |migration| migration.write(@output) }
|
97
72
|
puts "Wrote #{filename}..."
|
98
73
|
end
|
99
74
|
true
|
@@ -121,16 +96,8 @@ module Migrant
|
|
121
96
|
end
|
122
97
|
end
|
123
98
|
|
124
|
-
def
|
125
|
-
|
126
|
-
def self.up
|
127
|
-
#{up_code}
|
128
|
-
end
|
129
|
-
|
130
|
-
def self.down
|
131
|
-
#{down_code}
|
132
|
-
end
|
133
|
-
end"
|
99
|
+
def render(template_name)
|
100
|
+
@output = Erubis::Eruby.new(File.read(File.join(File.dirname(__FILE__), "../generators/templates/#{template_name}.erb"))).result(binding)
|
134
101
|
end
|
135
102
|
end
|
136
103
|
end
|
data/lib/migrant/schema.rb
CHANGED
@@ -11,17 +11,17 @@ module Migrant
|
|
11
11
|
# into a schema on that model class by calling method_missing(my_field)
|
12
12
|
# and deciding what the best schema type is for the user's requiredments
|
13
13
|
class Schema
|
14
|
-
attr_accessor :indexes, :columns, :validations
|
14
|
+
attr_accessor :indexes, :columns, :validations
|
15
15
|
|
16
16
|
def initialize
|
17
17
|
@proxy = SchemaProxy.new(self)
|
18
18
|
@columns = Hash.new
|
19
19
|
@indexes = Array.new
|
20
20
|
@validations = Hash.new
|
21
|
-
@methods_to_alias = Array.new
|
22
21
|
end
|
23
22
|
|
24
23
|
def define_structure(&block)
|
24
|
+
@validations = Hash.new
|
25
25
|
# Runs method_missing on columns given in the model "structure" DSL
|
26
26
|
@proxy.translate_fancy_dsl(&block) if block_given?
|
27
27
|
end
|
@@ -56,7 +56,8 @@ module Migrant
|
|
56
56
|
|
57
57
|
def add_field(field, data_type = nil, options = {})
|
58
58
|
data_type = DataType::String if data_type.nil?
|
59
|
-
|
59
|
+
puts [":#{field}", "#{data_type}", "#{options.inspect}"].collect { |s| s.ljust(25) }.join if ENV['DEBUG']
|
60
|
+
|
60
61
|
# Fields that do special things go here.
|
61
62
|
if field == :timestamps
|
62
63
|
add_field(:updated_at, :datetime)
|
@@ -83,8 +84,8 @@ module Migrant
|
|
83
84
|
@columns[field] = DataType::Base.new(options)
|
84
85
|
end
|
85
86
|
end
|
86
|
-
puts [":#{field}", "#{@columns[field].class}", "#{options.inspect}"].collect { |s| s.ljust(25) }.join if ENV['DEBUG']
|
87
87
|
end
|
88
|
+
|
88
89
|
end
|
89
90
|
|
90
91
|
class InheritedSchema < Schema
|
data/lib/migrant.rb
CHANGED
data/migrant.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{migrant}
|
8
|
-
s.version = "1.1.
|
8
|
+
s.version = "1.1.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Pascal Houliston"]
|
12
|
-
s.date = %q{2011-04-
|
12
|
+
s.date = %q{2011-04-12}
|
13
13
|
s.description = %q{Easier schema management for Rails that compliments your domain model.}
|
14
14
|
s.email = %q{101pascal@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -17,26 +17,21 @@ Gem::Specification.new do |s|
|
|
17
17
|
"README.rdoc"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
+
".rvmrc",
|
20
21
|
"Gemfile",
|
21
22
|
"Gemfile.lock",
|
22
23
|
"LICENSE",
|
23
24
|
"README.rdoc",
|
24
25
|
"Rakefile",
|
25
26
|
"VERSION",
|
26
|
-
"lib/
|
27
|
-
"lib/
|
28
|
-
"lib/
|
29
|
-
"lib/datatype/date.rb",
|
30
|
-
"lib/datatype/fixnum.rb",
|
31
|
-
"lib/datatype/float.rb",
|
32
|
-
"lib/datatype/foreign_key.rb",
|
33
|
-
"lib/datatype/polymorphic.rb",
|
34
|
-
"lib/datatype/range.rb",
|
35
|
-
"lib/datatype/string.rb",
|
36
|
-
"lib/datatype/symbol.rb",
|
37
|
-
"lib/datatype/time.rb",
|
27
|
+
"lib/dsl/data_type.rb",
|
28
|
+
"lib/dsl/data_types/primitives.rb",
|
29
|
+
"lib/dsl/data_types/semantic.rb",
|
38
30
|
"lib/generators/migrations.rb",
|
39
31
|
"lib/generators/model.rb",
|
32
|
+
"lib/generators/templates/change_migration.erb",
|
33
|
+
"lib/generators/templates/create_migration.erb",
|
34
|
+
"lib/generators/templates/create_migration.rb",
|
40
35
|
"lib/generators/templates/model.rb",
|
41
36
|
"lib/migrant.rb",
|
42
37
|
"lib/migrant/migration_generator.rb",
|
@@ -87,6 +82,7 @@ Gem::Specification.new do |s|
|
|
87
82
|
"test/test_data_schema.rb",
|
88
83
|
"test/test_migration_generator.rb",
|
89
84
|
"test/test_validations.rb",
|
85
|
+
"test/test_zzz_performance.rb",
|
90
86
|
"test/verified_output/migrations/business_id.rb",
|
91
87
|
"test/verified_output/migrations/create_business_categories.rb",
|
92
88
|
"test/verified_output/migrations/create_businesses.rb",
|
@@ -129,6 +125,7 @@ Gem::Specification.new do |s|
|
|
129
125
|
"test/test_data_schema.rb",
|
130
126
|
"test/test_migration_generator.rb",
|
131
127
|
"test/test_validations.rb",
|
128
|
+
"test/test_zzz_performance.rb",
|
132
129
|
"test/verified_output/migrations/business_id.rb",
|
133
130
|
"test/verified_output/migrations/create_business_categories.rb",
|
134
131
|
"test/verified_output/migrations/create_businesses.rb",
|
@@ -152,6 +149,7 @@ Gem::Specification.new do |s|
|
|
152
149
|
s.add_development_dependency(%q<turn>, [">= 0"])
|
153
150
|
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
154
151
|
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
152
|
+
s.add_development_dependency(%q<terminal-table>, [">= 0"])
|
155
153
|
else
|
156
154
|
s.add_dependency(%q<rails>, [">= 3.0.0"])
|
157
155
|
s.add_dependency(%q<faker>, [">= 0"])
|
@@ -161,6 +159,7 @@ Gem::Specification.new do |s|
|
|
161
159
|
s.add_dependency(%q<turn>, [">= 0"])
|
162
160
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
163
161
|
s.add_dependency(%q<simplecov>, [">= 0"])
|
162
|
+
s.add_dependency(%q<terminal-table>, [">= 0"])
|
164
163
|
end
|
165
164
|
else
|
166
165
|
s.add_dependency(%q<rails>, [">= 3.0.0"])
|
@@ -171,6 +170,7 @@ Gem::Specification.new do |s|
|
|
171
170
|
s.add_dependency(%q<turn>, [">= 0"])
|
172
171
|
s.add_dependency(%q<sqlite3>, [">= 0"])
|
173
172
|
s.add_dependency(%q<simplecov>, [">= 0"])
|
173
|
+
s.add_dependency(%q<terminal-table>, [">= 0"])
|
174
174
|
end
|
175
175
|
end
|
176
176
|
|
data/test/helper.rb
CHANGED
@@ -17,14 +17,36 @@ require 'rubygems'
|
|
17
17
|
require 'turn' # For nicer output
|
18
18
|
require 'test/unit'
|
19
19
|
require 'shoulda'
|
20
|
+
require 'terminal-table/import'
|
20
21
|
|
21
22
|
# Must be loaded before appropriate models so we get class method extensions
|
22
23
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
23
24
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
24
25
|
|
25
|
-
|
26
26
|
require 'migrant'
|
27
27
|
|
28
|
+
class Profiler
|
29
|
+
@@results = {}
|
30
|
+
|
31
|
+
def self.run(name, &block)
|
32
|
+
start = Time.now.to_f
|
33
|
+
yield
|
34
|
+
@@results[name] ||= {:total => 0.0, :calls => 0}
|
35
|
+
@@results[name][:total] += Time.now.to_f - start
|
36
|
+
@@results[name][:calls] += 1
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.results
|
40
|
+
unless @@results.keys.empty?
|
41
|
+
results = table do |t|
|
42
|
+
t.headings = ['Name', 'Calls', 'Total (ms)', 'Average (ms)']
|
43
|
+
@@results.collect { |name, result| [name, result[:calls], (result[:total]*1000.0).round, (result[:total] / result[:calls] * 1000.0).round] }.each { |row| t << row }
|
44
|
+
end
|
45
|
+
puts results
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
28
50
|
# Reset database
|
29
51
|
db_path = File.join(File.dirname(__FILE__), 'rails_app', 'db', 'test.sqlite3')
|
30
52
|
File.delete(db_path) if File.exists?(db_path)
|
@@ -38,3 +60,4 @@ require File.join(File.dirname(__FILE__), 'rails_app', 'config', 'environment')
|
|
38
60
|
|
39
61
|
class Test::Unit::TestCase
|
40
62
|
end
|
63
|
+
|
data/test/test_data_schema.rb
CHANGED
@@ -33,6 +33,10 @@ class TestDataSchema < Test::Unit::TestCase
|
|
33
33
|
should "generate a smallint column when given a small range" do
|
34
34
|
assert_schema(Business, :operating_days, :limit => 1, :type => :integer)
|
35
35
|
end
|
36
|
+
|
37
|
+
should "generate a large integer (size 8) for any bignum types" do
|
38
|
+
assert_schema(Category, :serial_number, :limit => 8, :type => :integer)
|
39
|
+
end
|
36
40
|
|
37
41
|
should "generate a string column when given a sentence" do
|
38
42
|
assert_schema(Business, :summary, :type => :string)
|
@@ -7,10 +7,15 @@ def rake_migrate
|
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
10
|
class TestMigrationGenerator < Test::Unit::TestCase
|
11
|
+
def generate_migrations
|
12
|
+
Profiler.run(:migration_generator) do
|
13
|
+
assert_equal true, Migrant::MigrationGenerator.new.run, "Migration Generator reported an error"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
12
17
|
def run_against_template(template)
|
13
|
-
|
18
|
+
generate_migrations
|
14
19
|
Dir.glob(File.join(File.dirname(__FILE__), 'rails_app', 'db' ,'migrate', '*.rb')).each do |migration_file|
|
15
20
|
if migration_file.include?(template)
|
16
21
|
to_test = File.open(migration_file, 'r') { |r| r.read}.strip
|
@@ -28,7 +33,7 @@ class TestMigrationGenerator < Test::Unit::TestCase
|
|
28
33
|
|
29
34
|
context "The migration generator" do
|
30
35
|
should "create migrations for all new tables" do
|
31
|
-
|
36
|
+
generate_migrations
|
32
37
|
Dir.glob(File.join(File.dirname(__FILE__), 'rails_app', 'db' ,'migrate', '*.rb')).each do |migration_file|
|
33
38
|
to_test = File.open(migration_file, 'r') { |r| r.read}.strip
|
34
39
|
File.open(File.join(File.dirname(__FILE__), 'verified_output', 'migrations', migration_file.sub(/^.*\d+_/, '')), 'r') do |file|
|
@@ -95,7 +100,7 @@ class TestMigrationGenerator < Test::Unit::TestCase
|
|
95
100
|
end
|
96
101
|
# Remove migrations
|
97
102
|
ActiveRecord::Base.timestamped_migrations = false
|
98
|
-
|
103
|
+
generate_migrations
|
99
104
|
ActiveRecord::Base.timestamped_migrations = true
|
100
105
|
|
101
106
|
assert_equal(Dir.glob(File.join(File.dirname(__FILE__), 'rails_app', 'db' ,'migrate', '*.rb')).select { |migration_file| migration_file.include?('new_field_i_made_up') }.length,
|
@@ -115,7 +120,7 @@ class TestMigrationGenerator < Test::Unit::TestCase
|
|
115
120
|
end
|
116
121
|
|
117
122
|
BusinessCategory.belongs_to(:notaclass, :polymorphic => true)
|
118
|
-
|
123
|
+
generate_migrations
|
119
124
|
rake_migrate
|
120
125
|
BusinessCategory.reset_column_information
|
121
126
|
BusinessCategory.mock!
|
@@ -144,7 +149,7 @@ class TestMigrationGenerator < Test::Unit::TestCase
|
|
144
149
|
end
|
145
150
|
|
146
151
|
BusinessCategory.belongs_to(:verylongclassthatissuretogenerateaverylargeoutputfilename, :polymorphic => true)
|
147
|
-
|
152
|
+
generate_migrations
|
148
153
|
rake_migrate
|
149
154
|
end
|
150
155
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
#SimpleProfiler.results
|
4
|
+
|
5
|
+
class TestZZZPerformance < Test::Unit::TestCase
|
6
|
+
context "Performance" do
|
7
|
+
should "be within acceptable limits" do
|
8
|
+
# Just a utility test for printing profiler results
|
9
|
+
Profiler.results
|
10
|
+
assert true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: migrant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 1.1.
|
5
|
+
version: 1.1.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Pascal Houliston
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-04-
|
13
|
+
date: 2011-04-12 00:00:00 +00:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -101,6 +101,17 @@ dependencies:
|
|
101
101
|
type: :development
|
102
102
|
prerelease: false
|
103
103
|
version_requirements: *id008
|
104
|
+
- !ruby/object:Gem::Dependency
|
105
|
+
name: terminal-table
|
106
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
107
|
+
none: false
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: "0"
|
112
|
+
type: :development
|
113
|
+
prerelease: false
|
114
|
+
version_requirements: *id009
|
104
115
|
description: Easier schema management for Rails that compliments your domain model.
|
105
116
|
email: 101pascal@gmail.com
|
106
117
|
executables: []
|
@@ -111,26 +122,21 @@ extra_rdoc_files:
|
|
111
122
|
- LICENSE
|
112
123
|
- README.rdoc
|
113
124
|
files:
|
125
|
+
- .rvmrc
|
114
126
|
- Gemfile
|
115
127
|
- Gemfile.lock
|
116
128
|
- LICENSE
|
117
129
|
- README.rdoc
|
118
130
|
- Rakefile
|
119
131
|
- VERSION
|
120
|
-
- lib/
|
121
|
-
- lib/
|
122
|
-
- lib/
|
123
|
-
- lib/datatype/date.rb
|
124
|
-
- lib/datatype/fixnum.rb
|
125
|
-
- lib/datatype/float.rb
|
126
|
-
- lib/datatype/foreign_key.rb
|
127
|
-
- lib/datatype/polymorphic.rb
|
128
|
-
- lib/datatype/range.rb
|
129
|
-
- lib/datatype/string.rb
|
130
|
-
- lib/datatype/symbol.rb
|
131
|
-
- lib/datatype/time.rb
|
132
|
+
- lib/dsl/data_type.rb
|
133
|
+
- lib/dsl/data_types/primitives.rb
|
134
|
+
- lib/dsl/data_types/semantic.rb
|
132
135
|
- lib/generators/migrations.rb
|
133
136
|
- lib/generators/model.rb
|
137
|
+
- lib/generators/templates/change_migration.erb
|
138
|
+
- lib/generators/templates/create_migration.erb
|
139
|
+
- lib/generators/templates/create_migration.rb
|
134
140
|
- lib/generators/templates/model.rb
|
135
141
|
- lib/migrant.rb
|
136
142
|
- lib/migrant/migration_generator.rb
|
@@ -181,6 +187,7 @@ files:
|
|
181
187
|
- test/test_data_schema.rb
|
182
188
|
- test/test_migration_generator.rb
|
183
189
|
- test/test_validations.rb
|
190
|
+
- test/test_zzz_performance.rb
|
184
191
|
- test/verified_output/migrations/business_id.rb
|
185
192
|
- test/verified_output/migrations/create_business_categories.rb
|
186
193
|
- test/verified_output/migrations/create_businesses.rb
|
@@ -204,7 +211,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
204
211
|
requirements:
|
205
212
|
- - ">="
|
206
213
|
- !ruby/object:Gem::Version
|
207
|
-
hash:
|
214
|
+
hash: 146286865
|
208
215
|
segments:
|
209
216
|
- 0
|
210
217
|
version: "0"
|
@@ -249,6 +256,7 @@ test_files:
|
|
249
256
|
- test/test_data_schema.rb
|
250
257
|
- test/test_migration_generator.rb
|
251
258
|
- test/test_validations.rb
|
259
|
+
- test/test_zzz_performance.rb
|
252
260
|
- test/verified_output/migrations/business_id.rb
|
253
261
|
- test/verified_output/migrations/create_business_categories.rb
|
254
262
|
- test/verified_output/migrations/create_businesses.rb
|
data/lib/datatype/boolean.rb
DELETED
data/lib/datatype/date.rb
DELETED
data/lib/datatype/fixnum.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
module DataType
|
2
|
-
class Fixnum < Base
|
3
|
-
def column
|
4
|
-
{:type => :integer}.tap do |options|
|
5
|
-
options.merge!(:limit => @value.size) if @value > 2147483647 # 32-bit limit. Not checking size here because a 64-bit OS always has at least 8 byte size
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.default_mock
|
10
|
-
rand(999999).to_i
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/lib/datatype/float.rb
DELETED
data/lib/datatype/foreign_key.rb
DELETED
data/lib/datatype/polymorphic.rb
DELETED
data/lib/datatype/range.rb
DELETED
data/lib/datatype/string.rb
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
module DataType
|
2
|
-
class String < Base
|
3
|
-
def initialize(options)
|
4
|
-
super(options)
|
5
|
-
@value ||= ''
|
6
|
-
end
|
7
|
-
|
8
|
-
def column
|
9
|
-
if @value.match(/[\d,]+\.\d{2}$/)
|
10
|
-
return Currency.new(@options).column
|
11
|
-
else
|
12
|
-
return @value.match(/[\r\n\t]/)? { :type => :text }.merge(@options) : super
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def mock
|
17
|
-
@value || ((self.column[:type] == :text)? self.class.long_text_mock : self.class.default_mock )
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
|
data/lib/datatype/symbol.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
module DataType
|
2
|
-
class Symbol < Base
|
3
|
-
def column
|
4
|
-
# Just construct whatever the user wants
|
5
|
-
{:type => @value || :string }.merge(@options)
|
6
|
-
end
|
7
|
-
|
8
|
-
def mock
|
9
|
-
case @value || :string
|
10
|
-
when :text then self.class.long_text_mock
|
11
|
-
when :string then self.class.short_text_mock
|
12
|
-
when :integer then Fixnum.default_mock
|
13
|
-
when :decimal, :float then Float.default_mock
|
14
|
-
when :datetime, :date then Date.default_mock
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
|
data/lib/datatype/time.rb
DELETED
File without changes
|