migrant 1.5.0 → 2.0.0.pre

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 (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -29
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -5
  5. data/Gemfile +3 -4
  6. data/LICENSE.txt +21 -0
  7. data/{README.rdoc → README.md} +57 -57
  8. data/Rakefile +4 -31
  9. data/VERSION +1 -1
  10. data/lib/dsl/data_type.rb +5 -1
  11. data/lib/dsl/data_types/primitives.rb +11 -0
  12. data/lib/generators/templates/change_migration.erb +1 -1
  13. data/lib/generators/templates/create_migration.erb +1 -1
  14. data/lib/generators/templates/create_migration.rb +1 -1
  15. data/lib/migrant/migration_generator.rb +10 -6
  16. data/lib/migrant/model_extensions.rb +1 -1
  17. data/lib/migrant/schema.rb +0 -2
  18. data/lib/railtie.rb +2 -2
  19. data/lib/tasks/db.rake +0 -6
  20. data/migrant.gemspec +30 -31
  21. metadata +63 -193
  22. data/.rvmrc +0 -1
  23. data/LICENSE +0 -20
  24. data/lib/simple_object.rb +0 -13
  25. data/test/additional_models/review.rb +0 -11
  26. data/test/helper.rb +0 -64
  27. data/test/rails_app/.gitignore +0 -4
  28. data/test/rails_app/README +0 -256
  29. data/test/rails_app/Rakefile +0 -7
  30. data/test/rails_app/app/controllers/application_controller.rb +0 -3
  31. data/test/rails_app/app/helpers/application_helper.rb +0 -2
  32. data/test/rails_app/app/models/business.rb +0 -25
  33. data/test/rails_app/app/models/business_category.rb +0 -6
  34. data/test/rails_app/app/models/category.rb +0 -10
  35. data/test/rails_app/app/models/chameleon.rb +0 -5
  36. data/test/rails_app/app/models/customer.rb +0 -9
  37. data/test/rails_app/app/models/non_migrant_model.rb +0 -3
  38. data/test/rails_app/app/models/user.rb +0 -8
  39. data/test/rails_app/app/views/layouts/application.html.erb +0 -14
  40. data/test/rails_app/config.ru +0 -4
  41. data/test/rails_app/config/application.rb +0 -16
  42. data/test/rails_app/config/boot.rb +0 -13
  43. data/test/rails_app/config/database.yml +0 -7
  44. data/test/rails_app/config/environment.rb +0 -5
  45. data/test/rails_app/config/environments/development.rb +0 -26
  46. data/test/rails_app/config/environments/production.rb +0 -49
  47. data/test/rails_app/config/environments/test.rb +0 -35
  48. data/test/rails_app/config/initializers/backtrace_silencers.rb +0 -7
  49. data/test/rails_app/config/initializers/inflections.rb +0 -10
  50. data/test/rails_app/config/initializers/mime_types.rb +0 -5
  51. data/test/rails_app/config/initializers/secret_token.rb +0 -7
  52. data/test/rails_app/config/initializers/session_store.rb +0 -8
  53. data/test/rails_app/config/locales/en.yml +0 -5
  54. data/test/rails_app/config/routes.rb +0 -58
  55. data/test/rails_app/db/seeds.rb +0 -7
  56. data/test/rails_app/lib/tasks/.gitkeep +0 -0
  57. data/test/rails_app/public/404.html +0 -26
  58. data/test/rails_app/public/422.html +0 -26
  59. data/test/rails_app/public/500.html +0 -26
  60. data/test/rails_app/script/rails +0 -6
  61. data/test/rails_app/test/performance/browsing_test.rb +0 -9
  62. data/test/rails_app/test/test_helper.rb +0 -13
  63. data/test/rails_app/vendor/plugins/.gitkeep +0 -0
  64. data/test/test_data_schema.rb +0 -108
  65. data/test/test_migration_generator.rb +0 -251
  66. data/test/test_validations.rb +0 -49
  67. data/test/test_zzz_performance.rb +0 -13
  68. data/test/verified_output/migrations/added_incompatible_spot_and_deleted_spots.rb +0 -11
  69. data/test/verified_output/migrations/business_id.rb +0 -10
  70. data/test/verified_output/migrations/businesses_indexed_name.rb +0 -8
  71. data/test/verified_output/migrations/chameleons_added_new_longer_spots_and_moved_new_spots.rb +0 -15
  72. data/test/verified_output/migrations/create_business_categories.rb +0 -14
  73. data/test/verified_output/migrations/create_businesses.rb +0 -31
  74. data/test/verified_output/migrations/create_categories.rb +0 -13
  75. data/test/verified_output/migrations/create_chameleons.rb +0 -11
  76. data/test/verified_output/migrations/create_reviews.rb +0 -18
  77. data/test/verified_output/migrations/create_users.rb +0 -19
  78. data/test/verified_output/migrations/created_at.rb +0 -11
  79. data/test/verified_output/migrations/deleted_incompatible_spot.rb +0 -9
  80. data/test/verified_output/migrations/deleted_spots.rb +0 -9
  81. data/test/verified_output/migrations/estimated_value_notes.rb +0 -11
  82. data/test/verified_output/migrations/landline.rb +0 -9
  83. data/test/verified_output/migrations/modified_verified.rb +0 -9
  84. data/test/verified_output/migrations/renamed_old_spots.rb +0 -9
File without changes
@@ -1,108 +0,0 @@
1
- require 'helper'
2
-
3
- def assert_schema(model, name, options = {})
4
- field = model.schema.column_migrations.detect {|m| m.first == name}
5
- assert_not_nil(field, 'Migration was not generated')
6
- options.each do |key, correct_value|
7
- assert_equal(correct_value, field[1][key])
8
- end
9
- end
10
-
11
- class TestDataSchema < Test::Unit::TestCase
12
- context "The schema generator" do
13
- should "generate a foreign key field for a belongs_to association" do
14
- assert_schema(Business, :user_id, :type => :integer)
15
- assert_schema(BusinessCategory, :business_id, :type => :integer)
16
- assert_schema(BusinessCategory, :category_id, :type => :integer)
17
- assert_schema(User, :category_id, :type => :integer)
18
- end
19
-
20
- should "generate foreign key fields for a *polymorphic* belongs_to association" do
21
- assert_schema(Business, :owner_id, :type => :integer)
22
- assert_schema(Business, :owner_type, :type => :string)
23
- end
24
-
25
- should "generate a string column when given a string example" do
26
- assert_schema(Business, :name)
27
- end
28
-
29
- should "generate a datetime column when given a date or time example" do
30
- assert_schema(Business, :date_established, :type => :datetime)
31
- assert_schema(Business, :next_sale, :type => :datetime)
32
- assert_schema(Business, :date_registered, :type => :date)
33
- end
34
-
35
- should "generate a smallint column when given a small range" do
36
- assert_schema(Business, :operating_days, :type => :integer)
37
- end
38
-
39
- should "generate a large integer (size 8) for any bignum types" do
40
- assert_schema(Category, :serial_number, :limit => 8, :type => :integer)
41
- end
42
-
43
- should "generate a string column when given a sentence" do
44
- assert_schema(Business, :summary, :type => :string)
45
- end
46
-
47
- should "generate a text column when given a long paragraph" do
48
- assert_schema(Business, :address, :type => :text)
49
- end
50
-
51
- should "pass on any options provided in a structure block" do
52
- assert_schema(User, :average_rating, :type => :float, :default => 0.0)
53
- end
54
-
55
- should "generate a boolean column when a true or false is given" do
56
- assert_schema(Business, :verified, :type => :boolean)
57
- end
58
-
59
- should "generate a column verbatim if no type is specified" do
60
- assert_schema(Business, :location, :type => :string, :limit => 127)
61
- end
62
-
63
- should "generate a string column when no options are given" do
64
- assert_schema(Category, :title, :type => :string)
65
- assert_schema(Category, :summary, :type => :string)
66
- end
67
-
68
- should "generate a decimal column when a currency is given" do
69
- assert_schema(User, :money_spent, :type => :decimal, :scale => 2)
70
- assert_schema(User, :money_gifted, :type => :decimal, :scale => 2)
71
- end
72
-
73
- should "generate a floating point column when a decimal is given" do
74
- assert_schema(User, :average_rating, :type => :float)
75
- end
76
-
77
- should "generate a string column when an email example or class is given" do
78
- assert_schema(User, :email, :type => :string)
79
- end
80
-
81
- should "generate indexes for all foreign keys automatically" do
82
- assert_contains(Business.schema.indexes, :user_id, 'Missing index on belongs_to')
83
- assert_contains(Business.schema.indexes, [:owner_type, :owner_id], 'Missing index on polymorphic belongs_to')
84
- assert_contains(BusinessCategory.schema.indexes, :business_id, 'Missing index on belongs_to')
85
- assert_contains(BusinessCategory.schema.indexes, :category_id, 'Missing index on belongs_to')
86
- end
87
-
88
- should "generate indexes on any column when explicitly asked to" do
89
- assert_contains(Category.schema.indexes, :title, 'Missing index on :index => true column')
90
- end
91
-
92
- should "generate a text column for serialized fields" do
93
- assert_schema(Business, :awards, :type => :text)
94
- assert_schema(Business, :managers, :type => :text)
95
-
96
- assert_equal(Array, Business.schema.columns[:awards].mock.class)
97
- assert_equal(Hash, Business.schema.columns[:managers].mock.class)
98
-
99
- assert(Business.serialized_attributes.keys.include?("awards"), "Should call ActiveRecord::Base.serialize")
100
- assert(Business.serialized_attributes.keys.include?("managers"), "Should call ActiveRecord::Base.serialize")
101
- end
102
- end
103
-
104
- should "still indicate a structure is not defined if a belongs_to association is added" do
105
- assert_equal(false, NonMigrantModel.structure_defined?)
106
- assert_equal(true, Business.structure_defined?)
107
- end
108
- end
@@ -1,251 +0,0 @@
1
- require 'helper'
2
- require 'rake'
3
-
4
- def rake_migrate
5
- Dir.chdir(Rails.root.join('.')) do
6
- Rake::Task['db:migrate'].execute
7
- end
8
- end
9
-
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
-
17
- def run_against_template(template)
18
- generate_migrations
19
- Dir.glob(File.join(File.dirname(__FILE__), 'rails_app', 'db' ,'migrate', '*.rb')).each do |migration_file|
20
- if migration_file.include?(template)
21
- to_test = File.open(migration_file, 'r') { |r| r.read}.strip
22
- File.open(File.join(File.dirname(__FILE__), 'verified_output', 'migrations', template+'.rb'), 'r') do |file|
23
- while (line = file.gets)
24
- assert_not_nil(to_test.gsub(/[\.\(\)]/, '').match(line.gsub(/[\.\(\)]/, '').strip), "Generated migration #{migration_file} missing line: #{line.gsub(/[\.\(\)]/, '').strip}")
25
- end
26
- end
27
- rake_migrate
28
- return
29
- end
30
- end
31
- flunk "No migration could be found like '#{template}'"
32
- end
33
-
34
- def any_template_match?(template)
35
- Dir.glob(File.join(File.dirname(__FILE__), 'rails_app', 'db' ,'migrate', '*.rb')).each do |migration_file|
36
- if migration_file.include?(template)
37
- return true
38
- end
39
- end
40
- false
41
- end
42
-
43
- def delete_last_migration
44
- File.delete(Dir.glob(File.join(File.dirname(__FILE__), 'rails_app', 'db' ,'migrate', '*.rb')).last)
45
- end
46
-
47
- context "The migration generator" do
48
- should "create migrations for all new tables" do
49
- generate_migrations
50
- Dir.glob(File.join(File.dirname(__FILE__), 'rails_app', 'db' ,'migrate', '*.rb')).each do |migration_file|
51
- to_test = File.open(migration_file, 'r') { |r| r.read}.strip
52
- File.open(File.join(File.dirname(__FILE__), 'verified_output', 'migrations', migration_file.sub(/^.*\d+_/, '')), 'r') do |file|
53
- while (line = file.gets)
54
- assert_not_nil(to_test.match(line.strip), "Generated migration #{migration_file} missing line: #{line}")
55
- end
56
- end
57
- end
58
- rake_migrate
59
- end
60
-
61
- should "generate a migration for new added fields" do
62
- Business.structure do
63
- estimated_value 5000.0
64
- notes
65
- end
66
- run_against_template('estimated_value_notes')
67
- end
68
-
69
- should "generate a migration to alter existing columns where no data loss would occur" do
70
- Business.structure do
71
- landline :text
72
- end
73
-
74
- run_against_template('landline')
75
- end
76
-
77
- should "generate a migration to alter existing columns while adding a new table" do
78
- load File.join(File.dirname(__FILE__), 'additional_models', 'review.rb')
79
- User.belongs_to(:business) # To generate a business_id on a User
80
- User.no_structure # To force schema update
81
-
82
- run_against_template('create_reviews')
83
- run_against_template('business_id')
84
- end
85
-
86
- should "generate created_at and updated_at when given the column timestamps" do
87
- Business.structure do
88
- timestamps
89
- end
90
- run_against_template('created_at')
91
- end
92
-
93
- should "prompt the user to confirm changing existing columns where data loss may occur" do
94
- STDIN._mock_responses('N')
95
-
96
- Business.structure do
97
- landline :integer # Was previously a string, which obviously may incur data loss
98
- end
99
- Migrant::MigrationGenerator.new.run
100
- assert(any_template_match?('modified_landline'), 'Ignored a request not to generate a dangerous migration!')
101
- Business.structure do
102
- landline :text # Undo our bad for the next tests
103
- end
104
- end
105
-
106
- should "exit immediately if there are pending migrations" do
107
- manual_migration = Rails.root.join("db/migrate/9999999999999999_my_new_migration.rb")
108
- File.open(manual_migration, 'w') { |f| f.write ' ' }
109
- assert_equal(false, Migrant::MigrationGenerator.new.run)
110
- File.delete(manual_migration)
111
- end
112
-
113
- should "still create sequential migrations for the folks not using timestamps" do
114
- Business.structure do
115
- new_field_i_made_up
116
- end
117
- # Remove migrations
118
- ActiveRecord::Base.timestamped_migrations = false
119
- generate_migrations
120
- ActiveRecord::Base.timestamped_migrations = true
121
-
122
- 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,
123
- 1,
124
- "Migration should have been generated (without a duplicate)")
125
- rake_migrate
126
- end
127
-
128
- should "recursively generate mocks for every model" do
129
- BusinessCategory.structure do
130
- test_mockup_of_text :text
131
- test_mockup_of_string :string
132
- test_mockup_of_integer :integer
133
- test_mockup_of_float :float
134
- test_mockup_of_datetime :datetime
135
- test_mockup_of_currency DataType::Currency
136
- test_mockup_serialized :serialized
137
- test_mockup_hash OpenStruct.new({'a' => 'b'})
138
- test_mockup_serialized_example :serialized, :example => OpenStruct.new({'c' => 'd'})
139
- end
140
-
141
-
142
- BusinessCategory.belongs_to(:notaclass, :polymorphic => true)
143
- generate_migrations
144
- rake_migrate
145
- BusinessCategory.reset_column_information
146
- m = BusinessCategory.mock!
147
- mock = BusinessCategory.last
148
-
149
- assert_not_nil(mock)
150
- assert(mock.test_mockup_of_text.is_a?(String))
151
- assert(mock.test_mockup_of_string.is_a?(String))
152
- assert(mock.test_mockup_of_integer.is_a?(Fixnum))
153
- assert(mock.test_mockup_of_float.is_a?(Float))
154
- assert(mock.test_mockup_of_currency.is_a?(BigDecimal))
155
- assert(mock.test_mockup_of_datetime.is_a?(Time))
156
- assert(DataType::Base.default_mock.is_a?(String))
157
- assert(mock.test_mockup_serialized.is_a?(Hash))
158
- assert(mock.test_mockup_hash.is_a?(OpenStruct))
159
- assert_equal(mock.test_mockup_hash.a, 'b')
160
- assert(mock.test_mockup_serialized_example.is_a?(OpenStruct))
161
- assert_equal(mock.test_mockup_serialized_example.c, 'd')
162
- end
163
-
164
- should "not rescursively generate mocks for an inherited model when prohibited by the user" do
165
- category_mock = BusinessCategory.mock!({}, false)
166
- assert_not_nil(category_mock)
167
- end
168
-
169
- should "generate example mocks for an inherited model when STI is in effect" do
170
- assert_equal(5.00, Customer.mock.average_rating)
171
- assert_equal("somebody@somewhere.com", Customer.mock.email)
172
- assert(Customer.mock.is_a?(Customer))
173
- end
174
-
175
-
176
- should "remove columns when requested and confirmed by the user" do
177
- Chameleon.structure
178
- Chameleon.reset_structure!
179
- Chameleon.no_structure
180
-
181
- STDIN._mock_responses('D', 'y')
182
- run_against_template('deleted_incompatible_spot')
183
- end
184
-
185
- should "not remove columns when the user does not confirm" do
186
- Chameleon.reset_structure!
187
- Chameleon.no_structure
188
-
189
- STDIN._mock_responses('D', 'n')
190
- generate_migrations
191
- rake_migrate
192
- Chameleon.structure do
193
- spots
194
- end
195
- end
196
-
197
- should "successfully rename a column missing from the schema to a new column specified by the user" do
198
- Chameleon.structure do
199
- old_spots
200
- end
201
- generate_migrations
202
- rake_migrate
203
- Chameleon.reset_structure!
204
- Chameleon.structure do
205
- new_spots
206
- end
207
- STDIN._mock_responses('M', 'new_spots')
208
- run_against_template('renamed_old_spots')
209
- end
210
-
211
- should "transfer data to an new incompatible column if the operation is safe" do
212
- Chameleon.reset_column_information
213
- Chameleon.create!(:new_spots => "22")
214
- Chameleon.reset_structure!
215
- Chameleon.structure do
216
- new_longer_spots "100", :as => :text
217
- end
218
- STDIN._mock_responses('M', 'new_longer_spots', 'M')
219
- run_against_template('chameleons_added_new_longer_spots_and_moved_new_spots')
220
- Chameleon.reset_column_information
221
- assert_equal(Chameleon.first.new_longer_spots, "22")
222
- end
223
-
224
- should "remove any column if a user elects to when a column can't be moved due to incompatible types" do
225
- Chameleon.reset_structure!
226
- Chameleon.structure do
227
- incompatible_spot 5
228
- end
229
-
230
- STDIN._mock_responses('M', 'incompatible_spot', 'N', 'Y')
231
- run_against_template('added_incompatible_spot_and_deleted_spots')
232
- end
233
-
234
- should "update a column to include a new default" do
235
- Business.structure do
236
- verified true, :default => true
237
- end
238
-
239
- run_against_template('modified_verified')
240
- end
241
-
242
- should "update indexes on a model" do
243
- Business.structure do
244
- name "The Kernel's favourite fried chickens.", :index => true
245
- end
246
-
247
- run_against_template('businesses_indexed_name')
248
- end
249
- end
250
- end
251
-
@@ -1,49 +0,0 @@
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
- should "validate multiple validations via ActiveRecord when an array is given" do
34
- Review.structure do
35
- name "ABCD", :validates => [:presence, {:length => {:maximum => 4}}]
36
- end
37
-
38
- not_present = Review.create
39
- too_long = Review.create(:name => "Textthatistoolong")
40
- correct = Review.create(:name => "ABC")
41
-
42
- assert(not_present.errors.include?(:name), "primary validation was not applied")
43
- assert(too_long.errors.include?(:name), "secondary validation was not applied")
44
- assert(!correct.errors.include?(:name), "validation for a correct model failed")
45
-
46
- end
47
-
48
- end
49
-
@@ -1,13 +0,0 @@
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
@@ -1,11 +0,0 @@
1
- class ChangedChameleonsAddedIncompatibleSpotAndDeletedSpots < ActiveRecord::Migration
2
- def self.up
3
- add_column :chameleons, :incompatible_spot, :integer
4
- remove_column :chameleons, :spots
5
- end
6
-
7
- def self.down
8
- add_column :chameleons, :spots, :string, :limit=>255
9
- remove_column :chameleons, :incompatible_spot
10
- end
11
- end
@@ -1,10 +0,0 @@
1
- class ChangedUsersAddedBusinessId < ActiveRecord::Migration
2
- def self.up
3
- add_column :users, :business_id, :integer
4
- add_index :users, :business_id
5
- end
6
-
7
- def self.down
8
- remove_column :users, :business_id
9
- end
10
- end