populator3 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +39 -0
- data/LICENSE +20 -0
- data/Manifest +28 -0
- data/README.rdoc +91 -0
- data/Rakefile +15 -0
- data/TODO +11 -0
- data/lib/populator/adapters/abstract.rb +18 -0
- data/lib/populator/adapters/oracle.rb +27 -0
- data/lib/populator/adapters/postgresql.rb +22 -0
- data/lib/populator/adapters/sqlite.rb +29 -0
- data/lib/populator/factory.rb +90 -0
- data/lib/populator/model_additions.rb +32 -0
- data/lib/populator/random.rb +69 -0
- data/lib/populator/record.rb +68 -0
- data/lib/populator.rb +14 -0
- data/populator3.gemspec +30 -0
- data/spec/README +23 -0
- data/spec/example_database.yml +20 -0
- data/spec/models/category.rb +15 -0
- data/spec/models/product.rb +22 -0
- data/spec/populator/factory_spec.rb +69 -0
- data/spec/populator/model_additions_spec.rb +34 -0
- data/spec/populator/random_spec.rb +49 -0
- data/spec/populator/record_spec.rb +74 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +48 -0
- data/tasks/deployment.rake +2 -0
- data/tasks/spec.rake +22 -0
- metadata +111 -0
data/CHANGELOG
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
* adding Oracle adapter (thanks Andrew N)
|
2
|
+
|
3
|
+
0.2.4 (September 9th, 2008)
|
4
|
+
|
5
|
+
* removing echoe from gem development dependencies, which didn't seem to work in the first place.
|
6
|
+
|
7
|
+
* adding Populator.paragraphs to generate paragraphs of text
|
8
|
+
|
9
|
+
0.2.3 (September 2nd, 2008)
|
10
|
+
|
11
|
+
* support single table inhertance by setting inheritance_column to class name
|
12
|
+
|
13
|
+
* support custom primary_key in model if they don't use "id"
|
14
|
+
|
15
|
+
0.2.2 (September 1st, 2008)
|
16
|
+
|
17
|
+
* performance improvements
|
18
|
+
|
19
|
+
* improving inline documentation
|
20
|
+
|
21
|
+
0.2.1 (August 30th, 2008)
|
22
|
+
|
23
|
+
* wrap sqlite inserts in transaction to improve performance
|
24
|
+
|
25
|
+
* default created_at/on and updated_at/on columns to current time
|
26
|
+
|
27
|
+
0.2.0 (August 30th, 2008)
|
28
|
+
|
29
|
+
* adding :per_query option to limit how many inserts are made per query
|
30
|
+
|
31
|
+
* improving performance when nesting factories
|
32
|
+
|
33
|
+
* adding Populator.sentences to generate a lot of text
|
34
|
+
|
35
|
+
* adding Populator.words to fetch some random words
|
36
|
+
|
37
|
+
0.1.0 (August 27th, 2008)
|
38
|
+
|
39
|
+
* initial release
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Ryan Bates
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
LICENSE
|
3
|
+
Manifest
|
4
|
+
README.rdoc
|
5
|
+
Rakefile
|
6
|
+
TODO
|
7
|
+
lib/populator.rb
|
8
|
+
lib/populator/adapters/abstract.rb
|
9
|
+
lib/populator/adapters/oracle.rb
|
10
|
+
lib/populator/adapters/postgresql.rb
|
11
|
+
lib/populator/adapters/sqlite.rb
|
12
|
+
lib/populator/factory.rb
|
13
|
+
lib/populator/model_additions.rb
|
14
|
+
lib/populator/random.rb
|
15
|
+
lib/populator/record.rb
|
16
|
+
populator3.gemspec
|
17
|
+
spec/README
|
18
|
+
spec/example_database.yml
|
19
|
+
spec/models/category.rb
|
20
|
+
spec/models/product.rb
|
21
|
+
spec/populator/factory_spec.rb
|
22
|
+
spec/populator/model_additions_spec.rb
|
23
|
+
spec/populator/random_spec.rb
|
24
|
+
spec/populator/record_spec.rb
|
25
|
+
spec/spec.opts
|
26
|
+
spec/spec_helper.rb
|
27
|
+
tasks/deployment.rake
|
28
|
+
tasks/spec.rake
|
data/README.rdoc
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
= Populator
|
2
|
+
|
3
|
+
Populate an Active Record database with mass insert.
|
4
|
+
|
5
|
+
You can find the rdocs at http://populator.rubyforge.org.
|
6
|
+
|
7
|
+
Special thanks to Zach Dennis for his ar-extensions gem which some of
|
8
|
+
this code is loosely based on.
|
9
|
+
|
10
|
+
|
11
|
+
== Install
|
12
|
+
|
13
|
+
Install the gem:
|
14
|
+
|
15
|
+
gem install populator
|
16
|
+
|
17
|
+
And then load it in your project:
|
18
|
+
|
19
|
+
require 'populator'
|
20
|
+
|
21
|
+
|
22
|
+
== Usage
|
23
|
+
|
24
|
+
This gem adds a "populate" method to all Active Record models. Pass the
|
25
|
+
number of records you want to create along with a block. In the block
|
26
|
+
you can set the column values for each record.
|
27
|
+
|
28
|
+
Person.populate(3000) do |person|
|
29
|
+
person.first_name = "John"
|
30
|
+
person.last_name = "Smith"
|
31
|
+
end
|
32
|
+
|
33
|
+
This will do a mass insert into the database so it is very fast.
|
34
|
+
The person object contains the "id" so you can set up associations.
|
35
|
+
|
36
|
+
Person.populate(3000) do |person|
|
37
|
+
person.first_name = "John"
|
38
|
+
person.last_name = "Smith"
|
39
|
+
Project.populate(30) do |project|
|
40
|
+
project.person_id = person.id
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
That will create 30 projects for each person.
|
45
|
+
|
46
|
+
Passing a range or array of values will randomly select one.
|
47
|
+
|
48
|
+
Person.populate(1000..5000) do |person|
|
49
|
+
person.gender = ['male', 'female']
|
50
|
+
person.annual_income = 10000..200000
|
51
|
+
end
|
52
|
+
|
53
|
+
This will create 1000 to 5000 men or women with the annual income
|
54
|
+
between 10,000 and 200,000.
|
55
|
+
|
56
|
+
You can pass a :per_query option to limit how many records are saved
|
57
|
+
per query. This defaults to 1000.
|
58
|
+
|
59
|
+
Person.populate(2000, :per_query => 100)
|
60
|
+
|
61
|
+
If you need to generate fake data, there are a few methods to do this.
|
62
|
+
|
63
|
+
Populator.words(3) # generates 3 random words separated by spaces
|
64
|
+
Populator.words(10..20) # generates between 10 and 20 random words
|
65
|
+
Populator.sentences(5) # generates 5 sentences
|
66
|
+
Populator.paragraphs(3) # generates 3 paragraphs
|
67
|
+
|
68
|
+
For fancier data generation, try the Faker gem.
|
69
|
+
|
70
|
+
http://faker.rubyforge.org
|
71
|
+
|
72
|
+
|
73
|
+
== Important
|
74
|
+
|
75
|
+
For performance reasons, this gem does not use actual instances of the
|
76
|
+
model. This means validations and callbacks are bypassed. It is up to
|
77
|
+
you to ensure you're adding valid data.
|
78
|
+
|
79
|
+
|
80
|
+
== Development
|
81
|
+
|
82
|
+
See spec/README for instructions on running specs.
|
83
|
+
|
84
|
+
This project can be found on github at the following URL.
|
85
|
+
|
86
|
+
http://github.com/ryanb/populator
|
87
|
+
|
88
|
+
If you find a bug, please send me a message on GitHub.
|
89
|
+
|
90
|
+
If you would like to contribute to this project, please fork the
|
91
|
+
repository and send me a pull request.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'echoe'
|
4
|
+
|
5
|
+
Echoe.new('populator3', '0.2.4') do |p|
|
6
|
+
p.summary = "Mass populate an Active Record database."
|
7
|
+
p.description = "Mass populate an Active Record database."
|
8
|
+
p.url = "http://github.com/ryanb/populator"
|
9
|
+
p.author = 'Ryan Bates'
|
10
|
+
p.email = "ryan (at) railscasts (dot) com"
|
11
|
+
p.ignore_pattern = ["script/*", "**/*.sqlite3", "tmp/*"]
|
12
|
+
p.development_dependencies = []
|
13
|
+
end
|
14
|
+
|
15
|
+
Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
|
data/TODO
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
Possible
|
2
|
+
- randomly fill every column if no block is passed to populate
|
3
|
+
- add random_foo method to record for randomly generating content
|
4
|
+
|
5
|
+
Support Environments
|
6
|
+
- sqlite 2
|
7
|
+
- old rails
|
8
|
+
- edge rails
|
9
|
+
|
10
|
+
Tests
|
11
|
+
- add db:reset, db:drop and db:create rake tasks
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Populator
|
2
|
+
module Adapters
|
3
|
+
module Abstract
|
4
|
+
# Executes multiple SQL statements in one query when joined with ";"
|
5
|
+
def execute_batch(sql, name = nil)
|
6
|
+
raise NotImplementedError, "execute_batch is an abstract method"
|
7
|
+
end
|
8
|
+
|
9
|
+
def populate(table, columns, rows, name = nil)
|
10
|
+
execute("INSERT INTO #{table} #{columns} VALUES #{rows.join(', ')}", name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
|
17
|
+
include Populator::Adapters::Abstract
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Populator
|
2
|
+
module Adapters
|
3
|
+
module Oracle
|
4
|
+
|
5
|
+
# Executes SQL statements one at a time.
|
6
|
+
|
7
|
+
def populate(table, columns, rows, name = nil)
|
8
|
+
rows.each do |row|
|
9
|
+
sql = "INSERT INTO #{table} #{columns} VALUES #{row}"
|
10
|
+
log(sql, name) do
|
11
|
+
@connection.exec(sql)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module ActiveRecord # :nodoc: all
|
21
|
+
module ConnectionAdapters
|
22
|
+
class OracleAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
|
23
|
+
include Populator::Adapters::Oracle
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Populator
|
2
|
+
module Adapters
|
3
|
+
module Postgresql
|
4
|
+
def populate(table, columns, rows, name = nil)
|
5
|
+
queries = []
|
6
|
+
rows.each do |row|
|
7
|
+
row.gsub!(/^\(\d{1,}/, "(DEFAULT")
|
8
|
+
queries << "INSERT INTO #{table} #{columns} VALUES #{row}"
|
9
|
+
end
|
10
|
+
execute(queries.join("; "), name)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ActiveRecord # :nodoc: all
|
17
|
+
module ConnectionAdapters
|
18
|
+
class PostgreSQLAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
|
19
|
+
include Populator::Adapters::Postgresql
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Populator
|
2
|
+
module Adapters
|
3
|
+
module Sqlite
|
4
|
+
# Executes multiple SQL statements in one query when joined with ";"
|
5
|
+
def execute_batch(sql, name = nil)
|
6
|
+
log(sql, name) do
|
7
|
+
@connection.transaction { |db| db.execute_batch(sql) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def populate(table, columns, rows, name = nil)
|
12
|
+
queries = []
|
13
|
+
rows.each do |row|
|
14
|
+
queries << "INSERT INTO #{table} #{columns} VALUES #{row}"
|
15
|
+
end
|
16
|
+
execute_batch(queries.join(';'), name)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# TODO find a better way to load the SQLite adapter
|
23
|
+
module ActiveRecord # :nodoc: all
|
24
|
+
module ConnectionAdapters
|
25
|
+
class SQLiteAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
|
26
|
+
include Populator::Adapters::Sqlite
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Populator
|
2
|
+
# Builds multiple Populator::Record instances and saves them to the database
|
3
|
+
class Factory
|
4
|
+
DEFAULT_RECORDS_PER_QUERY = 1000
|
5
|
+
|
6
|
+
@factories = {}
|
7
|
+
@depth = 0
|
8
|
+
|
9
|
+
# Fetches the factory dedicated to a given model class. You should always use this
|
10
|
+
# method instead of instatiating a factory directly so that a single factory is
|
11
|
+
# shared on multiple calls.
|
12
|
+
def self.for_model(model_class)
|
13
|
+
@factories[model_class] ||= new(model_class)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Find all remaining factories and call save_records on them.
|
17
|
+
def self.save_remaining_records
|
18
|
+
@factories.values.each do |factory|
|
19
|
+
factory.save_records
|
20
|
+
end
|
21
|
+
@factories = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# Keep track of nested factory calls so we can save the remaining records once we
|
25
|
+
# are done with the base factory. This makes Populator more efficient when nesting
|
26
|
+
# factories.
|
27
|
+
def self.remember_depth
|
28
|
+
@depth += 1
|
29
|
+
yield
|
30
|
+
@depth -= 1
|
31
|
+
save_remaining_records if @depth.zero?
|
32
|
+
end
|
33
|
+
|
34
|
+
# Use for_model instead of instatiating a record directly.
|
35
|
+
def initialize(model_class)
|
36
|
+
@model_class = model_class
|
37
|
+
@records = []
|
38
|
+
end
|
39
|
+
|
40
|
+
# Entry method for building records. Delegates to build_records after remember_depth.
|
41
|
+
def populate(amount, options = {}, &block)
|
42
|
+
self.class.remember_depth do
|
43
|
+
build_records(Populator.interpret_value(amount), options[:per_query] || DEFAULT_RECORDS_PER_QUERY, &block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Builds multiple Populator::Record instances and calls save_records them when
|
48
|
+
# :per_query limit option is reached.
|
49
|
+
def build_records(amount, per_query, &block)
|
50
|
+
amount.times do
|
51
|
+
record = Record.new(@model_class, last_id_in_database + @records.size + 1)
|
52
|
+
@records << record
|
53
|
+
block.call(record) if block
|
54
|
+
save_records if @records.size >= per_query
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Saves the records to the database by calling populate on the current database adapter.
|
59
|
+
def save_records
|
60
|
+
unless @records.empty?
|
61
|
+
@model_class.connection.populate(@model_class.quoted_table_name, columns_sql, rows_sql_arr, "#{@model_class.name} Populate")
|
62
|
+
@last_id_in_database = @records.last.id
|
63
|
+
@records.clear
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def quoted_column_names
|
70
|
+
@model_class.column_names.map do |column_name|
|
71
|
+
@model_class.connection.quote_column_name(column_name)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def last_id_in_database
|
76
|
+
@last_id_in_database ||= @model_class.connection.select_value("SELECT id FROM #{@model_class.quoted_table_name} ORDER BY id DESC", "#{@model_class.name} Last ID").to_i
|
77
|
+
end
|
78
|
+
|
79
|
+
def columns_sql
|
80
|
+
"(#{quoted_column_names.join(', ')})"
|
81
|
+
end
|
82
|
+
|
83
|
+
def rows_sql_arr
|
84
|
+
@records.map do |record|
|
85
|
+
quoted_attributes = record.attribute_values.map { |v| @model_class.sanitize(v) }
|
86
|
+
"(#{quoted_attributes.join(', ')})"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Populator
|
2
|
+
module ModelAdditions
|
3
|
+
# Call populate on any ActiveRecord model to fill it with data.
|
4
|
+
# Pass the number of records you want to create, and a block to
|
5
|
+
# set the attributes. You can nest calls to handle associations
|
6
|
+
# and use ranges or arrays to randomize the values.
|
7
|
+
#
|
8
|
+
# Person.populate(3000) do |person|
|
9
|
+
# person.name = "John Doe"
|
10
|
+
# person.gender = ['male', 'female']
|
11
|
+
# Project.populate(10..30, :per_query => 100) do |project|
|
12
|
+
# project.person_id = person.id
|
13
|
+
# project.due_at = 5.days.from_now..2.years.from_now
|
14
|
+
# project.name = Populator.words(1..3).titleize
|
15
|
+
# project.description = Populator.sentences(2..10)
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# The following options are supported.
|
20
|
+
#
|
21
|
+
# * <tt>:per_query</tt> - limit how many records are inserted per query, defaults to 1000
|
22
|
+
#
|
23
|
+
# Populator::Factory is where all the work happens.
|
24
|
+
def populate(amount, options = {}, &block)
|
25
|
+
Factory.for_model(self).populate(amount, options, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
ActiveRecord::Base.class_eval do
|
31
|
+
extend Populator::ModelAdditions
|
32
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Populator
|
2
|
+
# This module adds several methods for generating random data which can be
|
3
|
+
# called directly on Populator.
|
4
|
+
module Random
|
5
|
+
WORDS = %w(alias consequatur aut perferendis sit voluptatem accusantium doloremque aperiam eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo aspernatur aut odit aut fugit sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt neque dolorem ipsum quia dolor sit amet consectetur adipisci velit sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem ut enim ad minima veniam quis nostrum exercitationem ullam corporis nemo enim ipsam voluptatem quia voluptas sit suscipit laboriosam nisi ut aliquid ex ea commodi consequatur quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae et iusto odio dignissimos ducimus qui blanditiis praesentium laudantium totam rem voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident sed ut perspiciatis unde omnis iste natus error similique sunt in culpa qui officia deserunt mollitia animi id est laborum et dolorum fuga et harum quidem rerum facilis est et expedita distinctio nam libero tempore cum soluta nobis est eligendi optio cumque nihil impedit quo porro quisquam est qui minus id quod maxime placeat facere possimus omnis voluptas assumenda est omnis dolor repellendus temporibus autem quibusdam et aut consequatur vel illum qui dolorem eum fugiat quo voluptas nulla pariatur at vero eos et accusamus officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae itaque earum rerum hic tenetur a sapiente delectus ut aut reiciendis voluptatibus maiores doloribus asperiores repellat)
|
6
|
+
|
7
|
+
# Pick a random value out of a given range.
|
8
|
+
def value_in_range(range)
|
9
|
+
case range.first
|
10
|
+
when Integer then number_in_range(range)
|
11
|
+
when Time then time_in_range(range)
|
12
|
+
when Date then date_in_range(range)
|
13
|
+
else range.to_a.rand
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Generate a given number of words. If a range is passed, it will generate
|
18
|
+
# a random number of words within that range.
|
19
|
+
def words(total)
|
20
|
+
(1..interpret_value(total)).map { WORDS.rand }.join(' ')
|
21
|
+
end
|
22
|
+
|
23
|
+
# Generate a given number of sentences. If a range is passed, it will generate
|
24
|
+
# a random number of sentences within that range.
|
25
|
+
def sentences(total)
|
26
|
+
(1..interpret_value(total)).map do
|
27
|
+
words(5..20).capitalize
|
28
|
+
end.join('. ')
|
29
|
+
end
|
30
|
+
|
31
|
+
# Generate a given number of paragraphs. If a range is passed, it will generate
|
32
|
+
# a random number of paragraphs within that range.
|
33
|
+
def paragraphs(total)
|
34
|
+
(1..interpret_value(total)).map do
|
35
|
+
sentences(3..8).capitalize
|
36
|
+
end.join("\n\n")
|
37
|
+
end
|
38
|
+
|
39
|
+
# If an array or range is passed, a random value will be selected to match.
|
40
|
+
# All other values are simply returned.
|
41
|
+
def interpret_value(value)
|
42
|
+
case value
|
43
|
+
when Array then value.rand
|
44
|
+
when Range then value_in_range(value)
|
45
|
+
else value
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def time_in_range(range)
|
52
|
+
Time.at number_in_range(Range.new(range.first.to_i, range.last.to_i, range.exclude_end?))
|
53
|
+
end
|
54
|
+
|
55
|
+
def date_in_range(range)
|
56
|
+
Date.jd number_in_range(Range.new(range.first.jd, range.last.jd, range.exclude_end?))
|
57
|
+
end
|
58
|
+
|
59
|
+
def number_in_range(range)
|
60
|
+
if range.exclude_end?
|
61
|
+
rand(range.last - range.first) + range.first
|
62
|
+
else
|
63
|
+
rand((range.last+1) - range.first) + range.first
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
extend Random # load it into the populator module directly so we can call the methods
|
69
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module Populator
|
2
|
+
# This is what is passed to the block when calling populate.
|
3
|
+
class Record
|
4
|
+
attr_accessor :attributes
|
5
|
+
|
6
|
+
# Creates a new instance of Record. Some attributes are set by default:
|
7
|
+
#
|
8
|
+
# * <tt>id</tt> - defaults to id passed
|
9
|
+
# * <tt>created_at</tt> - defaults to current time
|
10
|
+
# * <tt>updated_at</tt> - defaults to current time
|
11
|
+
# * <tt>created_on</tt> - defaults to current date
|
12
|
+
# * <tt>updated_on</tt> - defaults to current date
|
13
|
+
# * <tt>type</tt> - defaults to class name (for STI)
|
14
|
+
def initialize(model_class, id)
|
15
|
+
@attributes = { model_class.primary_key.to_sym => id }
|
16
|
+
@columns = model_class.column_names
|
17
|
+
@columns.each do |column|
|
18
|
+
case column
|
19
|
+
when 'created_at', 'updated_at'
|
20
|
+
@attributes[column.to_sym] = Time.now
|
21
|
+
when 'created_on', 'updated_on'
|
22
|
+
@attributes[column.to_sym] = Date.today
|
23
|
+
when model_class.inheritance_column
|
24
|
+
@attributes[column.to_sym] = model_class.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# override id since method_missing won't catch this column name
|
30
|
+
def id
|
31
|
+
@attributes[:id]
|
32
|
+
end
|
33
|
+
|
34
|
+
# override type since method_missing won't catch this column name
|
35
|
+
def type
|
36
|
+
@attributes[:type]
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return values for all columns inside an array.
|
40
|
+
def attribute_values
|
41
|
+
@columns.map do |column|
|
42
|
+
@attributes[column.to_sym]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def attributes=(values_hash)
|
47
|
+
values_hash.each_pair do |key, value|
|
48
|
+
value = value.call if value.is_a?(Proc)
|
49
|
+
self.send((key.to_s + "=").to_sym, value)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def method_missing(sym, *args, &block)
|
56
|
+
name = sym.to_s
|
57
|
+
if @columns.include?(name.sub('=', ''))
|
58
|
+
if name.include? '='
|
59
|
+
@attributes[name.sub('=', '').to_sym] = Populator.interpret_value(args.first)
|
60
|
+
else
|
61
|
+
@attributes[sym]
|
62
|
+
end
|
63
|
+
else
|
64
|
+
super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/populator.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
require 'populator/model_additions'
|
3
|
+
require 'populator/factory'
|
4
|
+
require 'populator/record'
|
5
|
+
require 'populator/random'
|
6
|
+
|
7
|
+
require 'populator/adapters/abstract'
|
8
|
+
require 'populator/adapters/sqlite'
|
9
|
+
require 'populator/adapters/oracle'
|
10
|
+
require 'populator/adapters/postgresql'
|
11
|
+
|
12
|
+
# Populator is made up of several parts. To start, see Populator::ModelAdditions.
|
13
|
+
module Populator
|
14
|
+
end
|
data/populator3.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{populator3}
|
5
|
+
s.version = "0.2.4"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Ryan Bates"]
|
9
|
+
s.date = %q{2010-11-05}
|
10
|
+
s.description = %q{Mass populate an Active Record database.}
|
11
|
+
s.email = %q{ryan (at) railscasts (dot) com}
|
12
|
+
s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.rdoc", "TODO", "lib/populator.rb", "lib/populator/adapters/abstract.rb", "lib/populator/adapters/oracle.rb", "lib/populator/adapters/postgresql.rb", "lib/populator/adapters/sqlite.rb", "lib/populator/factory.rb", "lib/populator/model_additions.rb", "lib/populator/random.rb", "lib/populator/record.rb", "tasks/deployment.rake", "tasks/spec.rake"]
|
13
|
+
s.files = ["CHANGELOG", "LICENSE", "Manifest", "README.rdoc", "Rakefile", "TODO", "lib/populator.rb", "lib/populator/adapters/abstract.rb", "lib/populator/adapters/oracle.rb", "lib/populator/adapters/postgresql.rb", "lib/populator/adapters/sqlite.rb", "lib/populator/factory.rb", "lib/populator/model_additions.rb", "lib/populator/random.rb", "lib/populator/record.rb", "populator3.gemspec", "spec/README", "spec/example_database.yml", "spec/models/category.rb", "spec/models/product.rb", "spec/populator/factory_spec.rb", "spec/populator/model_additions_spec.rb", "spec/populator/random_spec.rb", "spec/populator/record_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tasks/deployment.rake", "tasks/spec.rake"]
|
14
|
+
s.homepage = %q{http://github.com/ryanb/populator}
|
15
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Populator3", "--main", "README.rdoc"]
|
16
|
+
s.require_paths = ["lib"]
|
17
|
+
s.rubyforge_project = %q{populator3}
|
18
|
+
s.rubygems_version = %q{1.3.7}
|
19
|
+
s.summary = %q{Mass populate an Active Record database.}
|
20
|
+
|
21
|
+
if s.respond_to? :specification_version then
|
22
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
23
|
+
s.specification_version = 3
|
24
|
+
|
25
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
26
|
+
else
|
27
|
+
end
|
28
|
+
else
|
29
|
+
end
|
30
|
+
end
|
data/spec/README
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Running Specs
|
2
|
+
-------------
|
3
|
+
|
4
|
+
To prepare the specs, run this command.
|
5
|
+
|
6
|
+
script/setup
|
7
|
+
|
8
|
+
This will generate the spec/database.yml file. Configure this to work
|
9
|
+
with your databases. You can add and remove entries here as well to
|
10
|
+
test different databases. A rake task is available to run the specs for
|
11
|
+
each database.
|
12
|
+
|
13
|
+
rake spec # Run specs under all databases
|
14
|
+
rake spec:mysql # Run specs under mysql
|
15
|
+
rake spec:sqlite3 # Run specs under sqlite3
|
16
|
+
rake spec:postgresql # Run specs under postgresql
|
17
|
+
...
|
18
|
+
|
19
|
+
Don't forget to create the user and database as necessary. You can do
|
20
|
+
so under MySQL with these commands.
|
21
|
+
|
22
|
+
CREATE DATABASE populator_test;
|
23
|
+
GRANT ALL ON populator_test.* TO populator@localhost;
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# you can add and remove entries to support different databases in tests.
|
2
|
+
|
3
|
+
sqlite3:
|
4
|
+
adapter: sqlite3
|
5
|
+
database: spec/test.sqlite3
|
6
|
+
timeout: 5000
|
7
|
+
|
8
|
+
mysql:
|
9
|
+
adapter: mysql
|
10
|
+
database: populator_test
|
11
|
+
username: populator
|
12
|
+
password:
|
13
|
+
host: localhost
|
14
|
+
|
15
|
+
postgresql:
|
16
|
+
adapter: postgresql
|
17
|
+
database: populator_test
|
18
|
+
username: populator
|
19
|
+
password: populator
|
20
|
+
host: localhost
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Category < ActiveRecord::Base
|
2
|
+
has_many :products
|
3
|
+
end
|
4
|
+
|
5
|
+
class CreateCategories < ActiveRecord::Migration
|
6
|
+
def self.up
|
7
|
+
create_table :categories do |t|
|
8
|
+
t.string :name
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.down
|
13
|
+
drop_table :categories
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Product < ActiveRecord::Base
|
2
|
+
belongs_to :category
|
3
|
+
end
|
4
|
+
|
5
|
+
class CreateProducts < ActiveRecord::Migration
|
6
|
+
def self.up
|
7
|
+
create_table :products do |t|
|
8
|
+
t.string :name
|
9
|
+
t.text :description
|
10
|
+
t.integer :stock
|
11
|
+
t.float :weight
|
12
|
+
t.decimal :price
|
13
|
+
t.datetime :released_at
|
14
|
+
t.boolean :hidden
|
15
|
+
t.integer :category_id
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.down
|
20
|
+
drop_table :products
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Populator::Factory do
|
4
|
+
describe "for products" do
|
5
|
+
before(:each) do
|
6
|
+
@factory = Populator::Factory.for_model(Product)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should only use one query when inserting records" do
|
10
|
+
$queries_executed = []
|
11
|
+
@factory.populate(5)
|
12
|
+
$queries_executed.grep(/^insert/i).should have(1).record
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should start id at 1 and increment when table is empty" do
|
16
|
+
Product.delete_all
|
17
|
+
expected_id = 1
|
18
|
+
@factory.populate(5) do |product|
|
19
|
+
product.id.should == expected_id
|
20
|
+
expected_id += 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should start id at last id and increment" do
|
25
|
+
Product.delete_all
|
26
|
+
product = Product.create
|
27
|
+
expected_id = product.id+1
|
28
|
+
@factory.populate(5) do |product|
|
29
|
+
product.id.should == expected_id
|
30
|
+
expected_id += 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should generate within range" do
|
35
|
+
Product.delete_all
|
36
|
+
@factory.populate(2..4)
|
37
|
+
Product.count.should >= 2
|
38
|
+
Product.count.should <= 4
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should limit number of records per query" do
|
42
|
+
$queries_executed = []
|
43
|
+
@factory.populate(5, :per_query => 2)
|
44
|
+
$queries_executed.grep(/^insert/i).should have(3).records
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should only use two queries when nesting factories (one for each class)" do
|
49
|
+
$queries_executed = []
|
50
|
+
Populator::Factory.for_model(Category).populate(3) do |category|
|
51
|
+
Populator::Factory.for_model(Product).populate(3) do |product|
|
52
|
+
product.category_id = category.id
|
53
|
+
end
|
54
|
+
end
|
55
|
+
$queries_executed.grep(/^insert/i).should have(2).records
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should only use one query when nesting factories of the same type" do
|
59
|
+
$queries_executed = []
|
60
|
+
Populator::Factory.for_model(Product).populate(3) do |product|
|
61
|
+
Populator::Factory.for_model(Product).populate(3)
|
62
|
+
end
|
63
|
+
$queries_executed.grep(/^insert/i).should have(1).record
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should default to 1000 records per query" do
|
67
|
+
Populator::Factory::DEFAULT_RECORDS_PER_QUERY.should == 1000
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Populator::ModelAdditions do
|
4
|
+
it "should add populate method to active record class" do
|
5
|
+
Product.should respond_to(:populate)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should add 10 records to database" do
|
9
|
+
Product.delete_all
|
10
|
+
Product.populate(10)
|
11
|
+
Product.count.should == 10
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should set attribute columns" do
|
15
|
+
Product.populate(1) do |product|
|
16
|
+
product.name = "foo"
|
17
|
+
end
|
18
|
+
Product.last.name.should == "foo"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should not pass in an instance of Active Record for performance reasons" do
|
22
|
+
Product.populate(1) do |product|
|
23
|
+
product.should_not be_kind_of(ActiveRecord::Base)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should not pass options hash" do
|
28
|
+
$queries_executed = []
|
29
|
+
Product.populate(5, :per_query => 2) do |product|
|
30
|
+
product.should_not be_kind_of(ActiveRecord::Base)
|
31
|
+
end
|
32
|
+
$queries_executed.grep(/^insert/i).should have(3).records
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Populator::Random do
|
4
|
+
it "should pick a random number in range excluding last value" do
|
5
|
+
Populator.expects(:rand).with(5).returns(3)
|
6
|
+
Populator.value_in_range(10...15).should == 13
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should pick a random number in range including last value" do
|
10
|
+
Populator.expects(:rand).with(5).returns(3)
|
11
|
+
Populator.value_in_range(10..14).should == 13
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should pick a random time in range" do
|
15
|
+
start_time = 2.days.ago
|
16
|
+
end_time = Time.now
|
17
|
+
Populator.expects(:rand).with(end_time.to_i-start_time.to_i).returns(1)
|
18
|
+
Populator.value_in_range(start_time...end_time).should == Time.at(start_time.to_i + 1)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should pick a random date in range" do
|
22
|
+
start_date = 2.years.ago.to_date
|
23
|
+
end_date = Date.today
|
24
|
+
Populator.expects(:rand).with(end_date.jd-start_date.jd).returns(1)
|
25
|
+
Populator.value_in_range(start_date...end_date).should == Date.jd(start_date.jd + 1)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should pick a random string by converting to array" do
|
29
|
+
Kernel.expects(:rand).with(5).returns(2)
|
30
|
+
Populator.value_in_range('a'..'e').should == 'c'
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should pick 3 random words" do
|
34
|
+
Populator.words(3).split.should have(3).records
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should pick a random number of random words" do
|
38
|
+
Populator.expects(:rand).with(5).returns(3)
|
39
|
+
Populator.words(10...15).split.should have(13).records
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should generate 3 random sentences" do
|
43
|
+
Populator.sentences(3).split(/\. [A-Z]/).should have(3).records
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should generate 3 random paragraphs" do
|
47
|
+
Populator.paragraphs(3).split(/\n\n/).should have(3).records
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Populator::Record do
|
4
|
+
it "should have a writer and reader methods for each column" do
|
5
|
+
record = Populator::Record.new(Product, 1)
|
6
|
+
Product.column_names.each do |column|
|
7
|
+
record.send("#{column}=", "foo")
|
8
|
+
record.send(column).should == "foo"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should return attribute values in same order as columns" do
|
13
|
+
record = Populator::Record.new(Product, nil)
|
14
|
+
record.name = "foo"
|
15
|
+
expected = Product.column_names.map { |c| "foo" if c == 'name' }
|
16
|
+
record.attribute_values.should == expected
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should assign second parameter to id" do
|
20
|
+
Populator::Record.new(Product, 2).id.should == 2
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should pick random number from range" do
|
24
|
+
record = Populator::Record.new(Product, 1)
|
25
|
+
record.stock = 2..5
|
26
|
+
record.stock.should >= 2
|
27
|
+
record.stock.should <= 5
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should pick random value from array" do
|
31
|
+
record = Populator::Record.new(Product, 1)
|
32
|
+
record.name = %w[foo bar]
|
33
|
+
%w[foo bar].should include(record.name)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should automatically set created/updated columns" do
|
37
|
+
Product.stubs(:column_names).returns(%w[id created_at updated_at created_on updated_on])
|
38
|
+
record = Populator::Record.new(Product, 1)
|
39
|
+
record.created_at.to_date.should == Date.today
|
40
|
+
record.updated_at.to_date.should == Date.today
|
41
|
+
record.created_on.should == Date.today
|
42
|
+
record.updated_on.should == Date.today
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should use custom primary_key for auto-increment if specified" do
|
46
|
+
Product.stubs(:primary_key).returns('foo')
|
47
|
+
Product.stubs(:column_names).returns(['foo', 'name'])
|
48
|
+
Populator::Record.new(Product, 123).foo.should == 123
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should default type to class name" do
|
52
|
+
Product.stubs(:column_names).returns(['id', 'type'])
|
53
|
+
Populator::Record.new(Product, 1).type.should == 'Product'
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should default specified inheritance_column to class name" do
|
57
|
+
Product.stubs(:inheritance_column).returns('foo')
|
58
|
+
Product.stubs(:column_names).returns(['id', 'foo'])
|
59
|
+
Populator::Record.new(Product, 1).foo.should == 'Product'
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should allow set via attributes hash" do
|
63
|
+
record = Populator::Record.new(Product, 1)
|
64
|
+
record.attributes = {:stock => 2..5}
|
65
|
+
record.stock.should >= 2
|
66
|
+
record.stock.should <= 5
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should take a proc object via attributes hash" do
|
70
|
+
record = Populator::Record.new(Product, 1)
|
71
|
+
record.attributes = {:stock => lambda {15}}
|
72
|
+
record.stock.should == 15
|
73
|
+
end
|
74
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec'
|
3
|
+
require 'active_support'
|
4
|
+
require 'active_record'
|
5
|
+
require File.dirname(__FILE__) + '/../lib/populator.rb'
|
6
|
+
|
7
|
+
adapter = ENV['POPULATOR_ADAPTER'] || 'sqlite3'
|
8
|
+
puts "Running on #{adapter}"
|
9
|
+
|
10
|
+
# setup database adapter
|
11
|
+
ActiveRecord::Base.establish_connection(
|
12
|
+
YAML.load(File.read(File.dirname(__FILE__) + "/database.yml"))[adapter]
|
13
|
+
)
|
14
|
+
|
15
|
+
# keep track of which queries have been executed
|
16
|
+
unless ActiveRecord::Base.connection.respond_to? :record_query
|
17
|
+
ActiveRecord::Base.connection.class.class_eval do
|
18
|
+
IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^begin /i, /^commit /i]
|
19
|
+
|
20
|
+
def record_query(sql)
|
21
|
+
$queries_executed ||= []
|
22
|
+
$queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r }
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute_with_query_record(*args, &block)
|
26
|
+
record_query(args.first)
|
27
|
+
execute_without_query_record(*args, &block)
|
28
|
+
end
|
29
|
+
alias_method_chain :execute, :query_record
|
30
|
+
|
31
|
+
def execute_batch_with_query_record(*args, &block)
|
32
|
+
record_query(args.first)
|
33
|
+
execute_batch_without_query_record(*args, &block)
|
34
|
+
end
|
35
|
+
alias_method_chain :execute_batch, :query_record
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# load models
|
40
|
+
# there's probably a better way to handle this
|
41
|
+
require File.dirname(__FILE__) + '/models/category.rb'
|
42
|
+
require File.dirname(__FILE__) + '/models/product.rb'
|
43
|
+
CreateCategories.migrate(:up) unless Category.table_exists?
|
44
|
+
CreateProducts.migrate(:up) unless Product.table_exists?
|
45
|
+
|
46
|
+
RSpec.configure do |config|
|
47
|
+
config.mock_with :mocha
|
48
|
+
end
|
data/tasks/spec.rake
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'rspec/core/rake_task'
|
2
|
+
|
3
|
+
ADAPTERS = YAML.load(File.read(File.dirname(__FILE__) + "/../spec/example_database.yml")).keys
|
4
|
+
|
5
|
+
desc "Run specs under all supported databases"
|
6
|
+
task :spec => ADAPTERS.map { |a| "spec:#{a}" }
|
7
|
+
|
8
|
+
namespace :spec do
|
9
|
+
ADAPTERS.each do |adapter|
|
10
|
+
namespace :prepare do
|
11
|
+
task adapter do
|
12
|
+
ENV["POPULATOR_ADAPTER"] = adapter
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Run specs under #{adapter}"
|
17
|
+
RSpec::Core::RakeTask.new(adapter => "spec:prepare:#{adapter}") do |t|
|
18
|
+
#t.spec_files = Rake::FileList["spec/**/*_spec.rb"]
|
19
|
+
t.rspec_opts = ["-c"]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: populator3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 2
|
8
|
+
- 4
|
9
|
+
version: 0.2.4
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ryan Bates
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-11-05 00:00:00 +03:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Mass populate an Active Record database.
|
22
|
+
email: ryan (at) railscasts (dot) com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- CHANGELOG
|
29
|
+
- LICENSE
|
30
|
+
- README.rdoc
|
31
|
+
- TODO
|
32
|
+
- lib/populator.rb
|
33
|
+
- lib/populator/adapters/abstract.rb
|
34
|
+
- lib/populator/adapters/oracle.rb
|
35
|
+
- lib/populator/adapters/postgresql.rb
|
36
|
+
- lib/populator/adapters/sqlite.rb
|
37
|
+
- lib/populator/factory.rb
|
38
|
+
- lib/populator/model_additions.rb
|
39
|
+
- lib/populator/random.rb
|
40
|
+
- lib/populator/record.rb
|
41
|
+
- tasks/deployment.rake
|
42
|
+
- tasks/spec.rake
|
43
|
+
files:
|
44
|
+
- CHANGELOG
|
45
|
+
- LICENSE
|
46
|
+
- Manifest
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
49
|
+
- TODO
|
50
|
+
- lib/populator.rb
|
51
|
+
- lib/populator/adapters/abstract.rb
|
52
|
+
- lib/populator/adapters/oracle.rb
|
53
|
+
- lib/populator/adapters/postgresql.rb
|
54
|
+
- lib/populator/adapters/sqlite.rb
|
55
|
+
- lib/populator/factory.rb
|
56
|
+
- lib/populator/model_additions.rb
|
57
|
+
- lib/populator/random.rb
|
58
|
+
- lib/populator/record.rb
|
59
|
+
- populator3.gemspec
|
60
|
+
- spec/README
|
61
|
+
- spec/example_database.yml
|
62
|
+
- spec/models/category.rb
|
63
|
+
- spec/models/product.rb
|
64
|
+
- spec/populator/factory_spec.rb
|
65
|
+
- spec/populator/model_additions_spec.rb
|
66
|
+
- spec/populator/random_spec.rb
|
67
|
+
- spec/populator/record_spec.rb
|
68
|
+
- spec/spec.opts
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
- tasks/deployment.rake
|
71
|
+
- tasks/spec.rake
|
72
|
+
has_rdoc: true
|
73
|
+
homepage: http://github.com/ryanb/populator
|
74
|
+
licenses: []
|
75
|
+
|
76
|
+
post_install_message:
|
77
|
+
rdoc_options:
|
78
|
+
- --line-numbers
|
79
|
+
- --inline-source
|
80
|
+
- --title
|
81
|
+
- Populator3
|
82
|
+
- --main
|
83
|
+
- README.rdoc
|
84
|
+
require_paths:
|
85
|
+
- lib
|
86
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
version: "0"
|
94
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
none: false
|
96
|
+
requirements:
|
97
|
+
- - ">="
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
segments:
|
100
|
+
- 1
|
101
|
+
- 2
|
102
|
+
version: "1.2"
|
103
|
+
requirements: []
|
104
|
+
|
105
|
+
rubyforge_project: populator3
|
106
|
+
rubygems_version: 1.3.7
|
107
|
+
signing_key:
|
108
|
+
specification_version: 3
|
109
|
+
summary: Mass populate an Active Record database.
|
110
|
+
test_files: []
|
111
|
+
|