factory_boy 1.0.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/README.rdoc +68 -31
  2. data/lib/blank_slate.rb +3 -0
  3. data/lib/plant.rb +37 -46
  4. data/lib/query.rb +44 -0
  5. data/lib/reflection.rb +40 -0
  6. data/lib/selector.rb +181 -0
  7. data/lib/setup.rb +13 -22
  8. data/lib/stubber.rb +164 -21
  9. data/test/Rakefile.rb +11 -0
  10. data/test/app/models/address.rb +9 -0
  11. data/test/app/models/customer.rb +3 -0
  12. data/test/app/models/profile.rb +2 -0
  13. data/test/app/models/user.rb +7 -0
  14. data/test/databases.rake.rb +513 -0
  15. data/test/db/migrate/20101230223546_create_users.rb.rb +14 -0
  16. data/test/db/migrate/20101230223547_create_profiles.rb +15 -0
  17. data/test/db/migrate/20101230223548_create_customers.rb +11 -0
  18. data/test/db/migrate/20101230223549_create_addresses.rb +13 -0
  19. data/test/db/schema.rb +41 -0
  20. data/test/help_test.rb +15 -5
  21. data/test/plants.rb +5 -5
  22. data/test/test_basic_queries.rb +36 -0
  23. data/test/test_plant_definition.rb +129 -0
  24. data/test/test_plants_ids.rb +16 -0
  25. data/test/test_queries_on_has_many_association.rb +51 -0
  26. data/test/test_queries_on_has_one_association.rb +45 -0
  27. data/test/test_queries_on_model_attributes.rb +59 -0
  28. data/test/test_queries_with_like.rb +22 -0
  29. data/test/test_queries_with_limit.rb +28 -0
  30. data/test/test_queries_with_named_scope.rb +18 -0
  31. data/test/test_queries_with_order.rb +17 -0
  32. data/test/test_queries_with_ranges.rb +21 -0
  33. data/test/test_selector_condition.rb +26 -0
  34. data/test/test_stubbing.rb +43 -0
  35. metadata +60 -22
  36. data/test/models/adress.rb +0 -12
  37. data/test/models/customer.rb +0 -7
  38. data/test/models/profile.rb +0 -8
  39. data/test/models/user.rb +0 -8
  40. data/test/plant_tests.rb +0 -115
  41. data/test/test_plant.rb +0 -7
  42. data/test/test_plant_with_active_support.rb +0 -8
data/lib/setup.rb CHANGED
@@ -1,32 +1,23 @@
1
- begin
2
- require 'mocha' #must put there even if mocha is not used ... else mocha override these aliasings when it's required in test file.
3
- rescue LoadError
4
- end
1
+ # begin
2
+ # require 'mocha' #must put there even if mocha is not used ... else mocha override these aliasings when it's required in test file.
3
+ # rescue LoadError
4
+ # end
5
5
 
6
6
  module Plant
7
- module Run
8
- def run(result,&block)
9
- Plant.destroy
10
- original_run(result,&block)
11
- Plant.unstub_find_for_each_class
7
+ module Run
8
+ def run(result,&block)
9
+ Plant.destroy
10
+ original_run(result,&block)
11
+ Plant::Stubber.unstubs
12
+ end
12
13
  end
13
- end
14
14
  end
15
15
 
16
16
  if defined?(ActiveSupport::TestCase)
17
17
  module ActiveSupport
18
18
  class TestCase < ::Test::Unit::TestCase
19
- alias_method :original_run, :run
20
- include Plant::Run
19
+ alias_method :original_run, :run
20
+ include Plant::Run
21
21
  end
22
22
  end
23
- else
24
- module Test
25
- module Unit
26
- class TestCase
27
- alias_method :original_run, :run
28
- include Plant::Run
29
- end
30
- end
31
- end
32
- end
23
+ end
data/lib/stubber.rb CHANGED
@@ -1,36 +1,179 @@
1
1
  module Plant
2
2
  module Stubber
3
3
 
4
- def self.stubs_find klass
5
- class << klass
6
- alias_method :original_find, :find
7
-
8
- def find *args
9
- case args.first
10
- when :first then Plant::Stubber.find_all(self.name.constantize).first
11
- when :last then Plant::Stubber.find_all(self.name.constantize).last
12
- when :all then Plant::Stubber.find_all(self.name.constantize)
13
- else Plant::Stubber.find(self.name.constantize)
14
- end
4
+ @@stubbed = false
5
+
6
+ def self.stubs
7
+ return if @@stubbed
8
+ stubs_finds
9
+ stubs_array
10
+ stubs_where
11
+ stubs_order
12
+ stubs_includes
13
+ stubs_limit
14
+ stubs_offset
15
+ @@stubbed = true
16
+ end
17
+
18
+ def self.unstubs
19
+ return unless @@stubbed
20
+ unstubs_where
21
+ unstubs_order
22
+ unstubs_limit
23
+ unstubs_offset
24
+ unstubs_includes
25
+ unstubs_array
26
+ unstubs_finds
27
+ @@stubbed = false
28
+ end
29
+
30
+ def self.stubs_finds
31
+ active_record_base_eigenclass = class << ActiveRecord::Base; self end
32
+
33
+ redefine(active_record_base_eigenclass, :find) do |*args|
34
+ klass = self.name.constantize
35
+ case args.first
36
+ when :first then Plant::Query.find_all(klass).first
37
+ when :last then Plant::Query.find_all(klass).last
38
+ when :all then Plant::Query.find_all(klass)
39
+ else Plant::Query.find_by_ids(klass, args)
40
+ end
41
+ end
42
+
43
+ redefine(active_record_base_eigenclass, :find_by_sql) do |*args|
44
+ Plant::Query.select(self)
45
+ end
46
+
47
+ redefine(active_record_base_eigenclass, :first) do |*args|
48
+ Plant::Query.find_all(self.name.constantize).first
49
+ end
50
+
51
+ redefine(active_record_base_eigenclass, :all) do |*args|
52
+ Plant::Query.find_all(self.name.constantize)
53
+ end
54
+
55
+ redefine(active_record_base_eigenclass, :last) do |*args|
56
+ Plant::Query.find_all(self.name.constantize).last
57
+ end
58
+
59
+ end
60
+
61
+ def self.stubs_array
62
+ redefine(Array, :method_missing) do |method, *args, &block|
63
+ case method
64
+ when :order : Plant::Query.order(self, *args)
65
+ when :limit : Plant::Query.limit(self, *args)
66
+ when :offset : Plant::Query.offset(self, *args)
15
67
  end
16
68
  end
17
69
  end
18
70
 
19
- def self.unstubs_find_for klass
20
- class << klass
21
- undef_method :find
22
- alias_method :find, :original_find
71
+ def self.stubs_where
72
+ redefine(ActiveRecord::QueryMethods, :where) do |opts, *rest|
73
+ result = original_where(opts, rest)
74
+ Plant::Query.wheres = result.where_clauses
75
+ result
76
+ end
77
+ end
78
+
79
+ def self.stubs_order
80
+ redefine(ActiveRecord::QueryMethods, :order) do |*args|
81
+ self.all.order(*args)
82
+ end
83
+ end
84
+
85
+ def self.stubs_limit
86
+ redefine(ActiveRecord::QueryMethods, :limit) do |*args|
87
+ unless self.is_a?Array
88
+ Plant::Query.find_all(self.name.constantize).limit(*args)
89
+ else
90
+ self.all.limit(*args)
91
+ end
92
+ end
93
+ end
94
+
95
+ def self.stubs_offset
96
+ redefine(ActiveRecord::QueryMethods, :offset) do |*args|
97
+ self.offset(*args)
98
+ end
99
+ end
100
+
101
+ def self.stubs_includes
102
+ redefine(ActiveRecord::QueryMethods, :includes) do |*args|
103
+ self
104
+ end
105
+ end
106
+
107
+ def self.stubs_associations_collections
108
+ ActiveRecord::Associations::AssociationCollection.send(:alias_method, :original_method_missing, :method_missing)
109
+ ActiveRecord::Associations::AssociationCollection.send(:define_method, :method_missing) do |method, *args, &block|
110
+ eval("@target.#{method}")
23
111
  end
24
112
  end
113
+
114
+ def self.stubs_attribute_methods
115
+ redefine(ActiveRecord::AttributeMethods, :method_missing)
116
+ end
117
+
118
+ def self.unstubs_associations_collections
119
+ undefine(ActiveRecord::Associations::AssociationCollection, :method_missing)
120
+ end
121
+
122
+ def self.unstubs_attribute_methods
123
+ undefine(ActiveRecord::AttributeMethods, :method_missing)
124
+ end
125
+
126
+ def self.unstubs_where
127
+ undefine(ActiveRecord::QueryMethods, :where)
128
+ end
129
+
130
+ def self.unstubs_order
131
+ undefine(ActiveRecord::QueryMethods, :order)
132
+ end
133
+
134
+ def self.unstubs_limit
135
+ undefine(ActiveRecord::QueryMethods, :limit)
136
+ end
25
137
 
26
- def self.find_all klass
27
- Plant.all[klass] || []
138
+ def self.unstubs_offset
139
+ undefine(ActiveRecord::QueryMethods, :offset)
140
+ end
141
+
142
+ def self.unstubs_includes
143
+ undefine(ActiveRecord::QueryMethods, :includes)
28
144
  end
29
145
 
30
- def self.find klass
31
- return nil unless Plant.all[klass]
32
- Plant.all[klass].size == 1 ? Plant.all[klass].first : Plant.all[klass]
146
+ def self.unstubs_array
147
+ undefine(Array, :method_missing)
33
148
  end
34
149
 
150
+ def self.unstubs_finds
151
+ active_record_base_eigenclass = class << ActiveRecord::Base; self end
152
+
153
+ undefine(active_record_base_eigenclass, :find)
154
+ undefine(active_record_base_eigenclass, :find_by_sql)
155
+ undefine(active_record_base_eigenclass, :first)
156
+ undefine(active_record_base_eigenclass, :last)
157
+ undefine(active_record_base_eigenclass, :all)
158
+ end
159
+
160
+ private
161
+
162
+ def self.redefine klass, method, &block
163
+ klass.send(:alias_method, original_method(method), method)
164
+ klass.send(:define_method, method) do |*params|
165
+ instance_exec(*params, &block)
166
+ end
167
+ end
168
+
169
+ def self.undefine klass, method
170
+ klass.send(:undef_method, method)
171
+ klass.send(:alias_method, method, original_method(method))
172
+ end
173
+
174
+ def self.original_method method
175
+ ('original_' + method.to_s).to_sym
176
+ end
177
+
35
178
  end
36
- end
179
+ end
data/test/Rakefile.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'rails/all'
3
+ require 'active_record'
4
+ require 'rake'
5
+ require File.join(File.dirname(__FILE__), 'databases.rake.rb')
6
+ ActiveRecord::Base.establish_connection(
7
+ :adapter => "sqlite3",
8
+ :database => "db/test.sqlite3"
9
+ )
10
+ ENV['SCHEMA']= File.join(File.dirname(__FILE__), 'db/schema.rb')
11
+
@@ -0,0 +1,9 @@
1
+ class Address < ActiveRecord::Base
2
+
3
+ belongs_to :user
4
+
5
+ def self.find
6
+ "original_find"
7
+ end
8
+
9
+ end
@@ -0,0 +1,3 @@
1
+ class Customer < ActiveRecord::Base
2
+
3
+ end
@@ -0,0 +1,2 @@
1
+ class Profile < ActiveRecord::Base
2
+ end
@@ -0,0 +1,7 @@
1
+ class User < ActiveRecord::Base
2
+ scope :albert, :conditions => { :name => 'Albert' }
3
+
4
+ has_one :profile
5
+ has_many :addresses
6
+
7
+ end
@@ -0,0 +1,513 @@
1
+ namespace :db do
2
+ task :load_config => :rails_env do
3
+ require 'active_record'
4
+ ActiveRecord::Base.configurations = Rails.application.config.database_configuration
5
+ end
6
+
7
+ namespace :create do
8
+ # desc 'Create all the local databases defined in config/database.yml'
9
+ task :all => :load_config do
10
+ ActiveRecord::Base.configurations.each_value do |config|
11
+ # Skip entries that don't have a database key, such as the first entry here:
12
+ #
13
+ # defaults: &defaults
14
+ # adapter: mysql
15
+ # username: root
16
+ # password:
17
+ # host: localhost
18
+ #
19
+ # development:
20
+ # database: blog_development
21
+ # <<: *defaults
22
+ next unless config['database']
23
+ # Only connect to local databases
24
+ local_database?(config) { create_database(config) }
25
+ end
26
+ end
27
+ end
28
+
29
+ desc 'Create the database from config/database.yml for the current Rails.env (use db:create:all to create all dbs in the config)'
30
+ task :create => :load_config do
31
+ # Make the test database at the same time as the development one, if it exists
32
+ if Rails.env.development? && ActiveRecord::Base.configurations['test']
33
+ create_database(ActiveRecord::Base.configurations['test'])
34
+ end
35
+ create_database(ActiveRecord::Base.configurations[Rails.env])
36
+ end
37
+
38
+ def create_database(config)
39
+ begin
40
+ if config['adapter'] =~ /sqlite/
41
+ if File.exist?(config['database'])
42
+ $stderr.puts "#{config['database']} already exists"
43
+ else
44
+ begin
45
+ # Create the SQLite database
46
+ ActiveRecord::Base.establish_connection(config)
47
+ ActiveRecord::Base.connection
48
+ rescue
49
+ $stderr.puts $!, *($!.backtrace)
50
+ $stderr.puts "Couldn't create database for #{config.inspect}"
51
+ end
52
+ end
53
+ return # Skip the else clause of begin/rescue
54
+ else
55
+ ActiveRecord::Base.establish_connection(config)
56
+ ActiveRecord::Base.connection
57
+ end
58
+ rescue
59
+ case config['adapter']
60
+ when /mysql/
61
+ @charset = ENV['CHARSET'] || 'utf8'
62
+ @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
63
+ creation_options = {:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)}
64
+ error_class = config['adapter'] =~ /mysql2/ ? Mysql2::Error : Mysql::Error
65
+ access_denied_error = 1045
66
+ begin
67
+ ActiveRecord::Base.establish_connection(config.merge('database' => nil))
68
+ ActiveRecord::Base.connection.create_database(config['database'], creation_options)
69
+ ActiveRecord::Base.establish_connection(config)
70
+ rescue error_class => sqlerr
71
+ if sqlerr.errno == access_denied_error
72
+ print "#{sqlerr.error}. \nPlease provide the root password for your mysql installation\n>"
73
+ root_password = $stdin.gets.strip
74
+ grant_statement = "GRANT ALL PRIVILEGES ON #{config['database']}.* " \
75
+ "TO '#{config['username']}'@'localhost' " \
76
+ "IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;"
77
+ ActiveRecord::Base.establish_connection(config.merge(
78
+ 'database' => nil, 'username' => 'root', 'password' => root_password))
79
+ ActiveRecord::Base.connection.create_database(config['database'], creation_options)
80
+ ActiveRecord::Base.connection.execute grant_statement
81
+ ActiveRecord::Base.establish_connection(config)
82
+ else
83
+ $stderr.puts sqlerr.error
84
+ $stderr.puts "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation}"
85
+ $stderr.puts "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
86
+ end
87
+ end
88
+ when 'postgresql'
89
+ @encoding = config[:encoding] || ENV['CHARSET'] || 'utf8'
90
+ begin
91
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
92
+ ActiveRecord::Base.connection.create_database(config['database'], config.merge('encoding' => @encoding))
93
+ ActiveRecord::Base.establish_connection(config)
94
+ rescue
95
+ $stderr.puts $!, *($!.backtrace)
96
+ $stderr.puts "Couldn't create database for #{config.inspect}"
97
+ end
98
+ end
99
+ else
100
+ $stderr.puts "#{config['database']} already exists"
101
+ end
102
+ end
103
+
104
+ namespace :drop do
105
+ # desc 'Drops all the local databases defined in config/database.yml'
106
+ task :all => :load_config do
107
+ ActiveRecord::Base.configurations.each_value do |config|
108
+ # Skip entries that don't have a database key
109
+ next unless config['database']
110
+ begin
111
+ # Only connect to local databases
112
+ local_database?(config) { drop_database(config) }
113
+ rescue Exception => e
114
+ $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ desc 'Drops the database for the current Rails.env (use db:drop:all to drop all databases)'
121
+ task :drop do
122
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
123
+ begin
124
+ drop_database(config)
125
+ rescue Exception => e
126
+ $stderr.puts "Couldn't drop #{config['database']} : #{e.inspect}"
127
+ end
128
+ end
129
+
130
+ def local_database?(config, &block)
131
+ if %w( 127.0.0.1 localhost ).include?(config['host']) || config['host'].blank?
132
+ yield
133
+ else
134
+ $stderr.puts "This task only modifies local databases. #{config['database']} is on a remote host."
135
+ end
136
+ end
137
+
138
+
139
+ desc "Migrate the database (options: VERSION=x, VERBOSE=false)."
140
+ task :migrate do
141
+ ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
142
+ ActiveRecord::Migrator.migrate("db/migrate/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
143
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
144
+ end
145
+
146
+ namespace :migrate do
147
+ # desc 'Rollbacks the database one migration and re migrate up (options: STEP=x, VERSION=x).'
148
+ task :redo do
149
+ if ENV["VERSION"]
150
+ Rake::Task["db:migrate:down"].invoke
151
+ Rake::Task["db:migrate:up"].invoke
152
+ else
153
+ Rake::Task["db:rollback"].invoke
154
+ Rake::Task["db:migrate"].invoke
155
+ end
156
+ end
157
+
158
+ # desc 'Resets your database using your migrations for the current environment'
159
+ task :reset => ["db:drop", "db:create", "db:migrate"]
160
+
161
+ # desc 'Runs the "up" for a given migration VERSION.'
162
+ task :up do
163
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
164
+ raise "VERSION is required" unless version
165
+ ActiveRecord::Migrator.run(:up, "db/migrate/", version)
166
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
167
+ end
168
+
169
+ # desc 'Runs the "down" for a given migration VERSION.'
170
+ task :down do
171
+ version = ENV["VERSION"] ? ENV["VERSION"].to_i : nil
172
+ raise "VERSION is required" unless version
173
+ ActiveRecord::Migrator.run(:down, "db/migrate/", version)
174
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
175
+ end
176
+
177
+ desc "Display status of migrations"
178
+ task :status do
179
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
180
+ ActiveRecord::Base.establish_connection(config)
181
+ unless ActiveRecord::Base.connection.table_exists?(ActiveRecord::Migrator.schema_migrations_table_name)
182
+ puts 'Schema migrations table does not exist yet.'
183
+ next # means "return" for rake task
184
+ end
185
+ db_list = ActiveRecord::Base.connection.select_values("SELECT version FROM #{ActiveRecord::Migrator.schema_migrations_table_name}")
186
+ file_list = []
187
+ Dir.foreach(File.join(Rails.root, 'db', 'migrate')) do |file|
188
+ # only files matching "20091231235959_some_name.rb" pattern
189
+ if match_data = /(\d{14})_(.+)\.rb/.match(file)
190
+ status = db_list.delete(match_data[1]) ? 'up' : 'down'
191
+ file_list << [status, match_data[1], match_data[2]]
192
+ end
193
+ end
194
+ # output
195
+ puts "\ndatabase: #{config['database']}\n\n"
196
+ puts "#{"Status".center(8)} #{"Migration ID".ljust(14)} Migration Name"
197
+ puts "-" * 50
198
+ file_list.each do |file|
199
+ puts "#{file[0].center(8)} #{file[1].ljust(14)} #{file[2].humanize}"
200
+ end
201
+ db_list.each do |version|
202
+ puts "#{'up'.center(8)} #{version.ljust(14)} *** NO FILE ***"
203
+ end
204
+ puts
205
+ end
206
+ end
207
+
208
+ desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n).'
209
+ task :rollback do
210
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
211
+ ActiveRecord::Migrator.rollback('db/migrate/', step)
212
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
213
+ end
214
+
215
+ # desc 'Pushes the schema to the next version (specify steps w/ STEP=n).'
216
+ task :forward do
217
+ step = ENV['STEP'] ? ENV['STEP'].to_i : 1
218
+ ActiveRecord::Migrator.forward('db/migrate/', step)
219
+ Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
220
+ end
221
+
222
+ # desc 'Drops and recreates the database from db/schema.rb for the current environment and loads the seeds.'
223
+ task :reset => [ 'db:drop', 'db:setup' ]
224
+
225
+ # desc "Retrieves the charset for the current environment's database"
226
+ task :charset do
227
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
228
+ case config['adapter']
229
+ when /mysql/
230
+ ActiveRecord::Base.establish_connection(config)
231
+ puts ActiveRecord::Base.connection.charset
232
+ when 'postgresql'
233
+ ActiveRecord::Base.establish_connection(config)
234
+ puts ActiveRecord::Base.connection.encoding
235
+ when 'sqlite3'
236
+ ActiveRecord::Base.establish_connection(config)
237
+ puts ActiveRecord::Base.connection.encoding
238
+ else
239
+ $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
240
+ end
241
+ end
242
+
243
+ # desc "Retrieves the collation for the current environment's database"
244
+ task :collation do
245
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
246
+ case config['adapter']
247
+ when /mysql/
248
+ ActiveRecord::Base.establish_connection(config)
249
+ puts ActiveRecord::Base.connection.collation
250
+ else
251
+ $stderr.puts 'sorry, your database adapter is not supported yet, feel free to submit a patch'
252
+ end
253
+ end
254
+
255
+ desc "Retrieves the current schema version number"
256
+ task :version do
257
+ puts "Current version: #{ActiveRecord::Migrator.current_version}"
258
+ end
259
+
260
+ # desc "Raises an error if there are pending migrations"
261
+ task :abort_if_pending_migrations do
262
+ if defined? ActiveRecord
263
+ pending_migrations = ActiveRecord::Migrator.new(:up, 'db/migrate').pending_migrations
264
+
265
+ if pending_migrations.any?
266
+ puts "You have #{pending_migrations.size} pending migrations:"
267
+ pending_migrations.each do |pending_migration|
268
+ puts ' %4d %s' % [pending_migration.version, pending_migration.name]
269
+ end
270
+ abort %{Run "rake db:migrate" to update your database then try again.}
271
+ end
272
+ end
273
+ end
274
+
275
+ desc 'Create the database, load the schema, and initialize with the seed data (use db:reset to also drop the db first)'
276
+ task :setup => [ 'db:create', 'db:schema:load', 'db:seed' ]
277
+
278
+ desc 'Load the seed data from db/seeds.rb'
279
+ task :seed => 'db:abort_if_pending_migrations' do
280
+ seed_file = File.join(Rails.root, 'db', 'seeds.rb')
281
+ load(seed_file) if File.exist?(seed_file)
282
+ end
283
+
284
+ namespace :fixtures do
285
+ desc "Load fixtures into the current environment's database. Load specific fixtures using FIXTURES=x,y. Load from subdirectory in test/fixtures using FIXTURES_DIR=z. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
286
+ task :load do
287
+ require 'active_record/fixtures'
288
+
289
+ ActiveRecord::Base.establish_connection(Rails.env)
290
+ base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
291
+ fixtures_dir = ENV['FIXTURES_DIR'] ? File.join(base_dir, ENV['FIXTURES_DIR']) : base_dir
292
+
293
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/).map {|f| File.join(fixtures_dir, f) } : Dir["#{fixtures_dir}/**/*.{yml,csv}"]).each do |fixture_file|
294
+ Fixtures.create_fixtures(fixtures_dir, fixture_file[(fixtures_dir.size + 1)..-5])
295
+ end
296
+ end
297
+
298
+ # desc "Search for a fixture given a LABEL or ID. Specify an alternative path (eg. spec/fixtures) using FIXTURES_PATH=spec/fixtures."
299
+ task :identify do
300
+ require 'active_record/fixtures'
301
+
302
+ label, id = ENV["LABEL"], ENV["ID"]
303
+ raise "LABEL or ID required" if label.blank? && id.blank?
304
+
305
+ puts %Q(The fixture ID for "#{label}" is #{Fixtures.identify(label)}.) if label
306
+
307
+ base_dir = ENV['FIXTURES_PATH'] ? File.join(Rails.root, ENV['FIXTURES_PATH']) : File.join(Rails.root, 'test', 'fixtures')
308
+ Dir["#{base_dir}/**/*.yml"].each do |file|
309
+ if data = YAML::load(ERB.new(IO.read(file)).result)
310
+ data.keys.each do |key|
311
+ key_id = Fixtures.identify(key)
312
+
313
+ if key == label || key_id == id.to_i
314
+ puts "#{file}: #{key} (#{key_id})"
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
320
+ end
321
+
322
+ namespace :schema do
323
+ desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
324
+ task :dump do
325
+ require 'active_record/schema_dumper'
326
+ File.open(ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb", "w") do |file|
327
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
328
+ end
329
+ Rake::Task["db:schema:dump"].reenable
330
+ end
331
+
332
+ desc "Load a schema.rb file into the database"
333
+ task :load do
334
+ file = ENV['SCHEMA'] || "#{Rails.root}/db/schema.rb"
335
+ if File.exists?(file)
336
+ load(file)
337
+ else
338
+ abort %{#{file} doesn't exist yet. Run "rake db:migrate" to create it then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/boot.rb to limit the frameworks that will be loaded}
339
+ end
340
+ end
341
+ end
342
+
343
+ namespace :structure do
344
+ desc "Dump the database structure to an SQL file"
345
+ task :dump do
346
+ abcs = ActiveRecord::Base.configurations
347
+ case abcs[Rails.env]["adapter"]
348
+ when /mysql/, "oci", "oracle"
349
+ ActiveRecord::Base.establish_connection(abcs[Rails.env])
350
+ File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
351
+ when "postgresql"
352
+ ENV['PGHOST'] = abcs[Rails.env]["host"] if abcs[Rails.env]["host"]
353
+ ENV['PGPORT'] = abcs[Rails.env]["port"].to_s if abcs[Rails.env]["port"]
354
+ ENV['PGPASSWORD'] = abcs[Rails.env]["password"].to_s if abcs[Rails.env]["password"]
355
+ search_path = abcs[Rails.env]["schema_search_path"]
356
+ unless search_path.blank?
357
+ search_path = search_path.split(",").map{|search_path| "--schema=#{search_path.strip}" }.join(" ")
358
+ end
359
+ `pg_dump -i -U "#{abcs[Rails.env]["username"]}" -s -x -O -f db/#{Rails.env}_structure.sql #{search_path} #{abcs[Rails.env]["database"]}`
360
+ raise "Error dumping database" if $?.exitstatus == 1
361
+ when "sqlite", "sqlite3"
362
+ dbfile = abcs[Rails.env]["database"] || abcs[Rails.env]["dbfile"]
363
+ `#{abcs[Rails.env]["adapter"]} #{dbfile} .schema > db/#{Rails.env}_structure.sql`
364
+ when "sqlserver"
365
+ `scptxfr /s #{abcs[Rails.env]["host"]} /d #{abcs[Rails.env]["database"]} /I /f db\\#{Rails.env}_structure.sql /q /A /r`
366
+ `scptxfr /s #{abcs[Rails.env]["host"]} /d #{abcs[Rails.env]["database"]} /I /F db\ /q /A /r`
367
+ when "firebird"
368
+ set_firebird_env(abcs[Rails.env])
369
+ db_string = firebird_db_string(abcs[Rails.env])
370
+ sh "isql -a #{db_string} > #{Rails.root}/db/#{Rails.env}_structure.sql"
371
+ else
372
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
373
+ end
374
+
375
+ if ActiveRecord::Base.connection.supports_migrations?
376
+ File.open("#{Rails.root}/db/#{Rails.env}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
377
+ end
378
+ end
379
+ end
380
+
381
+ namespace :test do
382
+ # desc "Recreate the test database from the current schema.rb"
383
+ task :load do
384
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])
385
+ ActiveRecord::Schema.verbose = false
386
+ Rake::Task["db:schema:load"].invoke
387
+ end
388
+
389
+ # desc "Recreate the test database from the current environment's database schema"
390
+ task :clone => %w(db:schema:dump db:test:load)
391
+
392
+ # desc "Recreate the test databases from the development structure"
393
+ task :clone_structure => [ "db:structure:dump", "db:test:purge" ] do
394
+ abcs = ActiveRecord::Base.configurations
395
+ case abcs["test"]["adapter"]
396
+ when /mysql/
397
+ ActiveRecord::Base.establish_connection(:test)
398
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
399
+ IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split("\n\n").each do |table|
400
+ ActiveRecord::Base.connection.execute(table)
401
+ end
402
+ when "postgresql"
403
+ ENV['PGHOST'] = abcs["test"]["host"] if abcs["test"]["host"]
404
+ ENV['PGPORT'] = abcs["test"]["port"].to_s if abcs["test"]["port"]
405
+ ENV['PGPASSWORD'] = abcs["test"]["password"].to_s if abcs["test"]["password"]
406
+ `psql -U "#{abcs["test"]["username"]}" -f #{Rails.root}/db/#{Rails.env}_structure.sql #{abcs["test"]["database"]}`
407
+ when "sqlite", "sqlite3"
408
+ dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
409
+ `#{abcs["test"]["adapter"]} #{dbfile} < #{Rails.root}/db/#{Rails.env}_structure.sql`
410
+ when "sqlserver"
411
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{Rails.env}_structure.sql`
412
+ when "oci", "oracle"
413
+ ActiveRecord::Base.establish_connection(:test)
414
+ IO.readlines("#{Rails.root}/db/#{Rails.env}_structure.sql").join.split(";\n\n").each do |ddl|
415
+ ActiveRecord::Base.connection.execute(ddl)
416
+ end
417
+ when "firebird"
418
+ set_firebird_env(abcs["test"])
419
+ db_string = firebird_db_string(abcs["test"])
420
+ sh "isql -i #{Rails.root}/db/#{Rails.env}_structure.sql #{db_string}"
421
+ else
422
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
423
+ end
424
+ end
425
+
426
+ # desc "Empty the test database"
427
+ task :purge do
428
+ abcs = ActiveRecord::Base.configurations
429
+ case abcs["test"]["adapter"]
430
+ when /mysql/
431
+ ActiveRecord::Base.establish_connection(:test)
432
+ ActiveRecord::Base.connection.recreate_database(abcs["test"]["database"], abcs["test"])
433
+ when "postgresql"
434
+ ActiveRecord::Base.clear_active_connections!
435
+ drop_database(abcs['test'])
436
+ create_database(abcs['test'])
437
+ when "sqlite","sqlite3"
438
+ dbfile = abcs["test"]["database"] || abcs["test"]["dbfile"]
439
+ File.delete(dbfile) if File.exist?(dbfile)
440
+ when "sqlserver"
441
+ dropfkscript = "#{abcs["test"]["host"]}.#{abcs["test"]["database"]}.DP1".gsub(/\\/,'-')
442
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{dropfkscript}`
443
+ `osql -E -S #{abcs["test"]["host"]} -d #{abcs["test"]["database"]} -i db\\#{Rails.env}_structure.sql`
444
+ when "oci", "oracle"
445
+ ActiveRecord::Base.establish_connection(:test)
446
+ ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
447
+ ActiveRecord::Base.connection.execute(ddl)
448
+ end
449
+ when "firebird"
450
+ ActiveRecord::Base.establish_connection(:test)
451
+ ActiveRecord::Base.connection.recreate_database!
452
+ else
453
+ raise "Task not supported by '#{abcs["test"]["adapter"]}'"
454
+ end
455
+ end
456
+
457
+ # desc 'Check for pending migrations and load the test schema'
458
+ task :prepare => 'db:abort_if_pending_migrations' do
459
+ if defined?(ActiveRecord) && !ActiveRecord::Base.configurations.blank?
460
+ Rake::Task[{ :sql => "db:test:clone_structure", :ruby => "db:test:load" }[ActiveRecord::Base.schema_format]].invoke
461
+ end
462
+ end
463
+ end
464
+
465
+ namespace :sessions do
466
+ # desc "Creates a sessions migration for use with ActiveRecord::SessionStore"
467
+ task :create do
468
+ raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
469
+ require 'rails/generators'
470
+ Rails::Generators.configure!
471
+ require 'rails/generators/rails/session_migration/session_migration_generator'
472
+ Rails::Generators::SessionMigrationGenerator.start [ ENV["MIGRATION"] || "add_sessions_table" ]
473
+ end
474
+
475
+ # desc "Clear the sessions table"
476
+ task :clear do
477
+ ActiveRecord::Base.connection.execute "DELETE FROM #{session_table_name}"
478
+ end
479
+ end
480
+ end
481
+
482
+ task 'test:prepare' => 'db:test:prepare'
483
+
484
+
485
+ def drop_database(config)
486
+ case config['adapter']
487
+ when /mysql/
488
+ ActiveRecord::Base.establish_connection(config)
489
+ ActiveRecord::Base.connection.drop_database config['database']
490
+ when /^sqlite/
491
+ require 'pathname'
492
+ path = Pathname.new(config['database'])
493
+ file = path.absolute? ? path.to_s : File.join(Rails.root, path)
494
+
495
+ FileUtils.rm(file)
496
+ when 'postgresql'
497
+ ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
498
+ ActiveRecord::Base.connection.drop_database config['database']
499
+ end
500
+ end
501
+
502
+ def session_table_name
503
+ ActiveRecord::SessionStore::Session.table_name
504
+ end
505
+
506
+ def set_firebird_env(config)
507
+ ENV["ISC_USER"] = config["username"].to_s if config["username"]
508
+ ENV["ISC_PASSWORD"] = config["password"].to_s if config["password"]
509
+ end
510
+
511
+ def firebird_db_string(config)
512
+ FireRuby::Database.db_string_for(config.symbolize_keys)
513
+ end