migrant 0.1.5 → 0.2.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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.2.0
data/lib/datatype/base.rb CHANGED
@@ -3,7 +3,7 @@ module DataType
3
3
 
4
4
  class Base
5
5
  attr_accessor :aliases
6
-
6
+
7
7
  # Pass the developer's ActiveRecord::Base structure and we'll
8
8
  # decide the best structure
9
9
  def initialize(options={})
@@ -12,25 +12,25 @@ module DataType
12
12
  @field = options.delete(:field)
13
13
  @aliases = options.delete(:was) || Array.new
14
14
  end
15
-
15
+
16
16
  # Default is 'ye good ol varchar(255)
17
17
  def column
18
18
  {:type => :string}.merge(@options)
19
19
  end
20
-
20
+
21
21
  def mock
22
22
  @value || self.class.default_mock
23
23
  end
24
-
24
+
25
25
  def self.default_mock
26
26
  "Some string"
27
27
  end
28
-
28
+
29
29
  # Decides if and how a column will be changed
30
30
  # Provide the details of a previously column, or simply nil to create a new column
31
- def structure_changes_from(current_structure = nil)
31
+ def structure_changes_from(current_structure = nil)
32
32
  new_structure = column
33
-
33
+
34
34
  if current_structure
35
35
  # General RDBMS data loss scenarios
36
36
  raise DataType::DangerousMigration if (new_structure[:type] != :text && [:string, :text].include?(current_structure[:type]) && new_structure[:type] != current_structure[:type])
@@ -46,7 +46,7 @@ module DataType
46
46
  column
47
47
  end
48
48
  end
49
-
49
+
50
50
  def self.migrant_data_type?; true; end
51
51
  end
52
52
  end
@@ -58,9 +58,9 @@ require 'datatype/date'
58
58
  require 'datatype/fixnum'
59
59
  require 'datatype/float'
60
60
  require 'datatype/foreign_key'
61
- require 'datatype/hash'
62
61
  require 'datatype/polymorphic'
63
62
  require 'datatype/range'
64
63
  require 'datatype/string'
65
64
  require 'datatype/symbol'
66
65
  require 'datatype/time'
66
+
@@ -4,29 +4,34 @@ module Migrant
4
4
  def structure(&block)
5
5
  # Using instance_*evil* to get the neater DSL on the models.
6
6
  # So, my_field in the structure block actually calls Migrant::Schema.my_field
7
-
7
+
8
8
  if self.superclass == ActiveRecord::Base
9
9
  @schema ||= Schema.new
10
10
  @schema.add_associations(self.reflect_on_all_associations)
11
11
  @schema.define_structure(&block)
12
+ @schema.validations.each do |field, validation|
13
+ validation = (validation.class == Hash)? validation : { validation => true }
14
+ self.validates(field, validation)
15
+ end
12
16
  else
13
17
  self.superclass.structure(&block) # For STI, cascade all fields onto the parent model
14
18
  @schema = InheritedSchema.new(self.superclass.schema)
19
+
15
20
  end
16
21
  end
17
-
22
+
18
23
  # Same as defining a structure block, but with no attributes besides
19
24
  # relationships (such as in a many-to-many)
20
25
  def no_structure
21
26
  structure {}
22
27
  end
23
-
28
+
24
29
  def mock(attributes={}, recursive=true)
25
30
  attribs = @schema.columns.reject { |column| column.is_a?(DataType::ForeignKey)}.collect { |name, data_type| [name, data_type.mock] }.flatten
26
31
 
27
32
  # Only recurse to one level, otherwise things get way too complicated
28
33
  if recursive
29
- attribs += self.reflect_on_all_associations(:belongs_to).collect do |association|
34
+ attribs += self.reflect_on_all_associations(:belongs_to).collect do |association|
30
35
  begin
31
36
  (association.klass.respond_to?(:mock))? [association.name, association.klass.mock({}, false)] : nil
32
37
  rescue NameError; nil; end # User hasn't defined association, just skip it
@@ -36,3 +41,4 @@ module Migrant
36
41
  end
37
42
  end
38
43
  end
44
+
@@ -9,23 +9,19 @@ module Migrant
9
9
  # into a schema on that model class by calling method_missing(my_field)
10
10
  # and deciding what the best schema type is for the user's requiredments
11
11
  class Schema
12
- # Global scope resolution operators will make the Migrant DSL fucking useless
13
- # So, I am doing this rather than inhering from SimpleObject, just live with it.
14
- # instance_methods.each { |m| raise 'fuckoff' if m == 'system' ; undef_method unless ['__send__', 'object_id'].include?(m) }
15
-
16
- attr_accessor :indexes, :columns, :methods_to_alias
12
+ attr_accessor :indexes, :columns, :validations, :methods_to_alias
17
13
 
18
14
  def initialize
19
15
  @proxy = SchemaProxy.new(self)
20
16
  @columns = Hash.new
21
17
  @indexes = Array.new
18
+ @validations = Hash.new
22
19
  @methods_to_alias = Array.new
23
20
  end
24
21
 
25
22
  def define_structure(&block)
26
23
  # Runs method_missing on columns given in the model "structure" DSL
27
24
  @proxy.translate_fancy_dsl(&block) if block_given?
28
- # self.instance_eval(&block) if block_given?
29
25
  end
30
26
 
31
27
  def add_associations(associations)
@@ -58,8 +54,17 @@ module Migrant
58
54
  def add_field(field, data_type = nil, options = {})
59
55
  data_type = DataType::String if data_type.nil?
60
56
 
57
+ # Fields that do special things go here.
58
+ if field == :timestamps
59
+ add_field(:updated_at, :datetime)
60
+ add_field(:created_at, :datetime)
61
+ return true
62
+ end
63
+
61
64
  # Add index if explicitly asked
62
65
  @indexes << field if options.delete(:index) || data_type.class.to_s == 'Hash' && data_type.delete(:index)
66
+ @validations[field] = options.delete(:validates) if options[:validates]
67
+
63
68
  options.merge!(:field => field)
64
69
 
65
70
  # Matches: description DataType::Paragraph, :index => true
@@ -112,7 +117,7 @@ module Migrant
112
117
 
113
118
  def method_missing(*args, &block)
114
119
  field = args.slice!(0)
115
- data_type = args.slice!(0) unless args.first.nil?
120
+ data_type = args.slice!(0) unless args.first.nil? || args.first.respond_to?(:keys)
116
121
 
117
122
  @binding.add_field(field, data_type, args.extract_options!)
118
123
  end
data/migrant.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{migrant}
8
- s.version = "0.1.5"
8
+ s.version = "0.2.0"
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"]
@@ -30,7 +30,6 @@ Gem::Specification.new do |s|
30
30
  "lib/datatype/fixnum.rb",
31
31
  "lib/datatype/float.rb",
32
32
  "lib/datatype/foreign_key.rb",
33
- "lib/datatype/hash.rb",
34
33
  "lib/datatype/polymorphic.rb",
35
34
  "lib/datatype/range.rb",
36
35
  "lib/datatype/string.rb",
@@ -83,12 +82,14 @@ Gem::Specification.new do |s|
83
82
  "test/rails_app/vendor/plugins/.gitkeep",
84
83
  "test/test_data_schema.rb",
85
84
  "test/test_migration_generator.rb",
85
+ "test/test_validations.rb",
86
86
  "test/verified_output/migrations/business_id.rb",
87
87
  "test/verified_output/migrations/create_business_categories.rb",
88
88
  "test/verified_output/migrations/create_businesses.rb",
89
89
  "test/verified_output/migrations/create_categories.rb",
90
90
  "test/verified_output/migrations/create_reviews.rb",
91
91
  "test/verified_output/migrations/create_users.rb",
92
+ "test/verified_output/migrations/created_at.rb",
92
93
  "test/verified_output/migrations/estimated_value_notes.rb",
93
94
  "test/verified_output/migrations/landline.rb"
94
95
  ]
@@ -123,12 +124,14 @@ Gem::Specification.new do |s|
123
124
  "test/rails_app/test/test_helper.rb",
124
125
  "test/test_data_schema.rb",
125
126
  "test/test_migration_generator.rb",
127
+ "test/test_validations.rb",
126
128
  "test/verified_output/migrations/business_id.rb",
127
129
  "test/verified_output/migrations/create_business_categories.rb",
128
130
  "test/verified_output/migrations/create_businesses.rb",
129
131
  "test/verified_output/migrations/create_categories.rb",
130
132
  "test/verified_output/migrations/create_reviews.rb",
131
133
  "test/verified_output/migrations/create_users.rb",
134
+ "test/verified_output/migrations/created_at.rb",
132
135
  "test/verified_output/migrations/estimated_value_notes.rb",
133
136
  "test/verified_output/migrations/landline.rb"
134
137
  ]
@@ -4,7 +4,7 @@ require 'rake'
4
4
  def rake_migrate
5
5
  Dir.chdir(Rails.root.join('.')) do
6
6
  Rake::Task['db:migrate'].execute
7
- end
7
+ end
8
8
  end
9
9
 
10
10
 
@@ -15,13 +15,13 @@ class TestMigrationGenerator < Test::Unit::TestCase
15
15
  if migration_file.include?(template)
16
16
  correct = File.join(File.dirname(__FILE__), 'verified_output', 'migrations', template+'.rb')
17
17
  assert_equal(File.open(correct, 'r') { |r| r.read}.strip,
18
- File.open(migration_file, 'r') { |r| r.read}.strip,
18
+ File.open(migration_file, 'r') { |r| r.read}.strip,
19
19
  "Generated migration #{migration_file} does not match template #{correct}")
20
20
  rake_migrate
21
21
  return
22
22
  end
23
23
  end
24
- flunk "No migration could be found"
24
+ flunk "No migration could be found"
25
25
  end
26
26
 
27
27
  context "The migration generator" do
@@ -35,7 +35,7 @@ class TestMigrationGenerator < Test::Unit::TestCase
35
35
  end
36
36
  rake_migrate
37
37
  end
38
-
38
+
39
39
  should "generate a migration for new added fields" do
40
40
  Business.structure do
41
41
  estimated_value 5000.0
@@ -43,41 +43,48 @@ class TestMigrationGenerator < Test::Unit::TestCase
43
43
  end
44
44
  run_against_template('estimated_value_notes')
45
45
  end
46
-
46
+
47
47
  should "generate a migration to alter existing columns where no data loss would occur" do
48
48
  Business.structure do
49
49
  landline :text
50
50
  end
51
-
51
+
52
52
  run_against_template('landline')
53
53
  end
54
-
54
+
55
55
  should "generate a migration to alter existing columns while adding a new table" do
56
56
  load File.join(File.dirname(__FILE__), 'additional_models', 'review.rb')
57
57
  User.belongs_to(:business) # To generate a business_id on a User
58
58
  User.no_structure # To force schema update
59
-
59
+
60
60
  run_against_template('create_reviews')
61
61
  run_against_template('business_id')
62
62
  end
63
-
63
+
64
+ should "generate created_at and updated_at when given the column timestamps" do
65
+ Business.structure do
66
+ timestamps
67
+ end
68
+ run_against_template('created_at')
69
+ end
70
+
64
71
  should "not change existing columns where data loss may occur" do
65
72
  Business.structure do
66
- landline :integer # Was previously a string, which obviously may incur data loss
73
+ landline :integer # Was previously a string, which obviously may incur data loss
67
74
  end
68
- assert_equal(false, Migrant::MigrationGenerator.new.run, "MigrationGenerator ran a dangerous migration!")
75
+ assert_equal(false, Migrant::MigrationGenerator.new.run, "MigrationGenerator ran a dangerous migration!")
69
76
  Business.structure do
70
77
  landline :text # Undo our bad for the next tests
71
- end
78
+ end
72
79
  end
73
-
80
+
74
81
  should "exit immediately if there are pending migrations" do
75
82
  manual_migration = Rails.root.join("db/migrate/9999999999999999_my_new_migration.rb")
76
83
  File.open(manual_migration, 'w') { |f| f.write ' ' }
77
84
  assert_equal(false, Migrant::MigrationGenerator.new.run)
78
85
  File.delete(manual_migration)
79
86
  end
80
-
87
+
81
88
  should "still create sequential migrations for the folks not using timestamps" do
82
89
  Business.structure do
83
90
  new_field_i_made_up
@@ -85,8 +92,8 @@ class TestMigrationGenerator < Test::Unit::TestCase
85
92
  # Remove migrations
86
93
  ActiveRecord::Base.timestamped_migrations = false
87
94
  assert_equal true, Migrant::MigrationGenerator.new.run, "Migration Generator reported an error"
88
- ActiveRecord::Base.timestamped_migrations = true
89
-
95
+ ActiveRecord::Base.timestamped_migrations = true
96
+
90
97
  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,
91
98
  1,
92
99
  "Migration should have been generated (without a duplicate)")
@@ -98,7 +105,7 @@ class TestMigrationGenerator < Test::Unit::TestCase
98
105
  test_date_mockup DataType::Date
99
106
  test_float_mockup DataType::Float
100
107
  test_range_mockup DataType::Range
101
-
108
+
102
109
  end
103
110
  BusinessCategory.belongs_to(:nonexistant_class, :polymorphic => true)
104
111
  assert_equal true, Migrant::MigrationGenerator.new.run, "Migration Generator reported an error"
@@ -111,4 +118,4 @@ class TestMigrationGenerator < Test::Unit::TestCase
111
118
 
112
119
  end
113
120
  end
114
-
121
+
@@ -0,0 +1,34 @@
1
+ require 'helper'
2
+
3
+ class TestValidations < Test::Unit::TestCase
4
+ should "validate via ActiveRecord when the validates symbol is supplied" do
5
+ Business.structure do
6
+ website :string, :validates => :presence
7
+ end
8
+
9
+ business = Business.create
10
+ assert(business.errors.include?(:website), "Validation was not applied")
11
+ end
12
+
13
+ should "validate via ActiveRecord when the full validation hash is supplied" do
14
+ Category.structure do
15
+ summary :string, :validates => { :format => { :with => /Symphony\d/ } }
16
+ end
17
+
18
+ bad_category = Category.create
19
+ good_category = Category.create(:summary => "Symphony5")
20
+ assert(bad_category.errors.include?(:summary), "Validation was not applied")
21
+ assert(!good_category.errors.include?(:summary), "Validation options were incorrect")
22
+ end
23
+
24
+ should "validate via ActiveRecord when no field name is given" do
25
+ User.structure do
26
+ email :validates => :presence
27
+ end
28
+
29
+ user = User.create
30
+ assert(user.errors.include?(:email), "Validation was not applied")
31
+ end
32
+
33
+ end
34
+
@@ -0,0 +1,11 @@
1
+ class BusinessesModifyFieldsUpdatedAtCreatedAt < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :businesses, :updated_at, :datetime
4
+ add_column :businesses, :created_at, :datetime
5
+ end
6
+
7
+ def self.down
8
+ remove_column :businesses, :updated_at
9
+ remove_column :businesses, :created_at
10
+ end
11
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 5
9
- version: 0.1.5
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Pascal Houliston
@@ -163,7 +163,6 @@ files:
163
163
  - lib/datatype/fixnum.rb
164
164
  - lib/datatype/float.rb
165
165
  - lib/datatype/foreign_key.rb
166
- - lib/datatype/hash.rb
167
166
  - lib/datatype/polymorphic.rb
168
167
  - lib/datatype/range.rb
169
168
  - lib/datatype/string.rb
@@ -216,12 +215,14 @@ files:
216
215
  - test/rails_app/vendor/plugins/.gitkeep
217
216
  - test/test_data_schema.rb
218
217
  - test/test_migration_generator.rb
218
+ - test/test_validations.rb
219
219
  - test/verified_output/migrations/business_id.rb
220
220
  - test/verified_output/migrations/create_business_categories.rb
221
221
  - test/verified_output/migrations/create_businesses.rb
222
222
  - test/verified_output/migrations/create_categories.rb
223
223
  - test/verified_output/migrations/create_reviews.rb
224
224
  - test/verified_output/migrations/create_users.rb
225
+ - test/verified_output/migrations/created_at.rb
225
226
  - test/verified_output/migrations/estimated_value_notes.rb
226
227
  - test/verified_output/migrations/landline.rb
227
228
  has_rdoc: true
@@ -238,7 +239,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
238
239
  requirements:
239
240
  - - ">="
240
241
  - !ruby/object:Gem::Version
241
- hash: -454091891
242
+ hash: -984502067
242
243
  segments:
243
244
  - 0
244
245
  version: "0"
@@ -284,11 +285,13 @@ test_files:
284
285
  - test/rails_app/test/test_helper.rb
285
286
  - test/test_data_schema.rb
286
287
  - test/test_migration_generator.rb
288
+ - test/test_validations.rb
287
289
  - test/verified_output/migrations/business_id.rb
288
290
  - test/verified_output/migrations/create_business_categories.rb
289
291
  - test/verified_output/migrations/create_businesses.rb
290
292
  - test/verified_output/migrations/create_categories.rb
291
293
  - test/verified_output/migrations/create_reviews.rb
292
294
  - test/verified_output/migrations/create_users.rb
295
+ - test/verified_output/migrations/created_at.rb
293
296
  - test/verified_output/migrations/estimated_value_notes.rb
294
297
  - test/verified_output/migrations/landline.rb
data/lib/datatype/hash.rb DELETED
@@ -1,10 +0,0 @@
1
- module DataType
2
- class Hash < Base
3
- def column
4
- @options = @value # Assign developer's options verbatim
5
- super
6
- end
7
- end
8
- end
9
-
10
-