populator 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,9 @@
1
+ *0.2.2* (September 1st, 2008)
2
+
3
+ * performance improvements
4
+
5
+ * improving inline documentation
6
+
1
7
  *0.2.1* (August 30th, 2008)
2
8
 
3
9
  * wrap sqlite inserts in transaction to improve performance
@@ -10,9 +16,9 @@
10
16
 
11
17
  * improving performance when nesting factories
12
18
 
13
- * adding Populate.sentences to generate a lot of text
19
+ * adding Populator.sentences to generate a lot of text
14
20
 
15
- * adding Populate.words to fetch some random words
21
+ * adding Populator.words to fetch some random words
16
22
 
17
23
  *0.1.0* (August 27th, 2008)
18
24
 
data/Manifest CHANGED
@@ -9,6 +9,7 @@ lib/populator.rb
9
9
  LICENSE
10
10
  Manifest
11
11
  populator.gemspec
12
+ Rakefile
12
13
  README
13
14
  spec/database.yml
14
15
  spec/example_database.yml
data/README CHANGED
@@ -10,7 +10,7 @@ this code is loosely based on.
10
10
 
11
11
  Install the gem:
12
12
 
13
- gem install ryanb-populator --source http://gems.github.com
13
+ gem install populator
14
14
 
15
15
  And then load it in your project:
16
16
 
@@ -64,7 +64,7 @@ If you need to generate fake data, there are a few methods to do this.
64
64
 
65
65
  For fancier data generation, try the Faker gem.
66
66
 
67
- http://faker.rubyforge.org
67
+ http://faker.rubyforge.org
68
68
 
69
69
 
70
70
  == Important
@@ -80,7 +80,7 @@ See spec/README for instructions on running specs.
80
80
 
81
81
  This project can be found on github at the following URL.
82
82
 
83
- http://github.com/ryanb/populator/
83
+ http://github.com/ryanb/populator
84
84
 
85
85
  If you would like to contribute to this project, please fork the
86
86
  repository and send me a pull request.
data/Rakefile CHANGED
@@ -2,13 +2,13 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('populator', '0.2.1') do |p|
5
+ Echoe.new('populator', '0.2.2') do |p|
6
6
  p.summary = "Mass populate an Active Record database."
7
7
  p.description = "Mass populate an Active Record database."
8
8
  p.url = "http://github.com/ryanb/populator"
9
9
  p.author = 'Ryan Bates'
10
10
  p.email = "ryan (at) railscasts (dot) com"
11
- p.ignore_pattern = ["script/*", "**/*.sqlite3"]
11
+ p.ignore_pattern = ["script/*", "**/*.sqlite3", "tmp/*"]
12
12
  end
13
13
 
14
14
  Dir["#{File.dirname(__FILE__)}/tasks/*.rake"].sort.each { |ext| load ext }
data/TODO CHANGED
@@ -8,8 +8,6 @@ Possible
8
8
  - add random_foo method to record for randomly generating content
9
9
 
10
10
  Performance
11
- - ruby-prof to see where the bottlenecks are
12
- - benchmark to find faster solutions
13
11
  - ensure instantiating the model is really that much of a performance hit.
14
12
 
15
13
  Support Environments
@@ -6,3 +6,7 @@ require 'populator/random'
6
6
 
7
7
  require 'populator/adapters/abstract'
8
8
  require 'populator/adapters/sqlite'
9
+
10
+ # Populator is made up of several parts. To start, see Populator::ModelAdditions.
11
+ module Populator
12
+ end
@@ -13,6 +13,6 @@ module Populator
13
13
  end
14
14
  end
15
15
 
16
- class ActiveRecord::ConnectionAdapters::AbstractAdapter
16
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
17
17
  include Populator::Adapters::Abstract
18
18
  end
@@ -21,6 +21,11 @@ module Populator
21
21
  end
22
22
  end
23
23
 
24
- class ActiveRecord::ConnectionAdapters::SQLiteAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
25
- include Populator::Adapters::Sqlite
24
+ # TODO find a better way to load the SQLite adapter
25
+ module ActiveRecord # :nodoc: all
26
+ module ConnectionAdapters
27
+ class SQLiteAdapter < ActiveRecord::ConnectionAdapters::AbstractAdapter
28
+ include Populator::Adapters::Sqlite
29
+ end
30
+ end
26
31
  end
@@ -1,14 +1,19 @@
1
1
  module Populator
2
+ # Builds multiple Populator::Record instances and saves them to the database
2
3
  class Factory
3
4
  DEFAULT_RECORDS_PER_QUERY = 1000
4
5
 
5
6
  @factories = {}
6
7
  @depth = 0
7
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.
8
12
  def self.for_model(model_class)
9
13
  @factories[model_class] ||= new(model_class)
10
14
  end
11
15
 
16
+ # Find all remaining factories and call save_records on them.
12
17
  def self.save_remaining_records
13
18
  @factories.values.each do |factory|
14
19
  factory.save_records
@@ -16,6 +21,9 @@ module Populator
16
21
  @factories = {}
17
22
  end
18
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.
19
27
  def self.remember_depth
20
28
  @depth += 1
21
29
  yield
@@ -23,17 +31,21 @@ module Populator
23
31
  save_remaining_records if @depth.zero?
24
32
  end
25
33
 
34
+ # Use for_model instead of instatiating a record directly.
26
35
  def initialize(model_class)
27
36
  @model_class = model_class
28
37
  @records = []
29
38
  end
30
39
 
40
+ # Entry method for building records. Delegates to build_records after remember_depth.
31
41
  def populate(amount, options = {}, &block)
32
42
  self.class.remember_depth do
33
43
  build_records(Populator.interpret_value(amount), options[:per_query] || DEFAULT_RECORDS_PER_QUERY, &block)
34
44
  end
35
45
  end
36
46
 
47
+ # Builds multiple Populator::Record instances and calls save_records them when
48
+ # :per_query limit option is reached.
37
49
  def build_records(amount, per_query, &block)
38
50
  amount.times do
39
51
  record = Record.new(@model_class, last_id_in_database + @records.size + 1)
@@ -43,6 +55,7 @@ module Populator
43
55
  end
44
56
  end
45
57
 
58
+ # Saves the records to the database by calling populate on the current database adapter.
46
59
  def save_records
47
60
  unless @records.empty?
48
61
  @model_class.connection.populate(@model_class.quoted_table_name, columns_sql, rows_sql_arr, "#{@model_class.name} Populate")
@@ -1,11 +1,32 @@
1
1
  module Populator
2
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.
3
24
  def populate(amount, options = {}, &block)
4
25
  Factory.for_model(self).populate(amount, options, &block)
5
26
  end
6
27
  end
7
28
  end
8
29
 
9
- class ActiveRecord::Base
30
+ ActiveRecord::Base.class_eval do
10
31
  extend Populator::ModelAdditions
11
32
  end
@@ -1,7 +1,10 @@
1
1
  module Populator
2
+ # This module adds several methods for generating random data which can be
3
+ # called directly on Populator.
2
4
  module Random
3
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)
4
6
 
7
+ # Pick a random value out of a given range.
5
8
  def value_in_range(range)
6
9
  case range.first
7
10
  when Integer then number_in_range(range)
@@ -11,16 +14,22 @@ module Populator
11
14
  end
12
15
  end
13
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.
14
19
  def words(total)
15
20
  (1..interpret_value(total)).map { WORDS.rand }.join(' ')
16
21
  end
17
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.
18
25
  def sentences(total)
19
26
  (1..interpret_value(total)).map do
20
27
  words(5..20).capitalize
21
28
  end.join('. ')
22
29
  end
23
30
 
31
+ # If an array or range is passed, a random value will be selected to match.
32
+ # All other values are simply returned.
24
33
  def interpret_value(value)
25
34
  case value
26
35
  when Array then value.rand
@@ -1,7 +1,15 @@
1
1
  module Populator
2
+ # This is what is passed to the block when calling populate.
2
3
  class Record
3
4
  attr_accessor :attributes
4
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
5
13
  def initialize(model_class, id)
6
14
  @attributes = { :id => id }
7
15
  @columns = model_class.column_names
@@ -12,22 +20,34 @@ module Populator
12
20
  if column == 'created_on' || column == 'updated_on'
13
21
  @attributes[column.to_sym] = Date.today
14
22
  end
15
- self.instance_eval <<-EOS
16
- def #{column}=(value)
17
- @attributes[:#{column}] = Populator.interpret_value(value)
18
- end
19
-
20
- def #{column}
21
- @attributes[:#{column}]
22
- end
23
- EOS
24
23
  end
25
24
  end
26
25
 
26
+ # override id since method_missing won't catch this column name
27
+ def id
28
+ @attributes[:id]
29
+ end
30
+
31
+ # Return values for all columns inside an array.
27
32
  def attribute_values
28
33
  @columns.map do |column|
29
34
  @attributes[column.to_sym]
30
35
  end
31
36
  end
37
+
38
+ private
39
+
40
+ def method_missing(sym, *args, &block)
41
+ name = sym.to_s
42
+ if @columns.include?(name.sub('=', ''))
43
+ if name.include? '='
44
+ @attributes[name.sub('=', '').to_sym] = Populator.interpret_value(args.first)
45
+ else
46
+ @attributes[sym]
47
+ end
48
+ else
49
+ super
50
+ end
51
+ end
32
52
  end
33
53
  end
@@ -1,11 +1,11 @@
1
1
 
2
- # Gem::Specification for Populator-0.2.1
2
+ # Gem::Specification for Populator-0.2.2
3
3
  # Originally generated by Echoe
4
4
 
5
5
  --- !ruby/object:Gem::Specification
6
6
  name: populator
7
7
  version: !ruby/object:Gem::Version
8
- version: 0.2.1
8
+ version: 0.2.2
9
9
  platform: ruby
10
10
  authors:
11
11
  - Ryan Bates
@@ -57,6 +57,7 @@ files:
57
57
  - LICENSE
58
58
  - Manifest
59
59
  - populator.gemspec
60
+ - Rakefile
60
61
  - README
61
62
  - spec/database.yml
62
63
  - spec/example_database.yml
@@ -72,7 +73,6 @@ files:
72
73
  - tasks/deployment.rake
73
74
  - tasks/spec.rake
74
75
  - TODO
75
- - Rakefile
76
76
  has_rdoc: true
77
77
  homepage: http://github.com/ryanb/populator
78
78
  post_install_message:
@@ -5,7 +5,7 @@ require 'active_record'
5
5
  require File.dirname(__FILE__) + '/../lib/populator.rb'
6
6
 
7
7
  adapter = ENV['POPULATOR_ADAPTER'] || 'sqlite3'
8
- puts "Running specs on #{adapter}"
8
+ puts "Running on #{adapter}"
9
9
 
10
10
  # setup database adapter
11
11
  ActiveRecord::Base.establish_connection(
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: populator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Bates
@@ -54,6 +54,7 @@ files:
54
54
  - LICENSE
55
55
  - Manifest
56
56
  - populator.gemspec
57
+ - Rakefile
57
58
  - README
58
59
  - spec/database.yml
59
60
  - spec/example_database.yml
@@ -69,7 +70,6 @@ files:
69
70
  - tasks/deployment.rake
70
71
  - tasks/spec.rake
71
72
  - TODO
72
- - Rakefile
73
73
  has_rdoc: true
74
74
  homepage: http://github.com/ryanb/populator
75
75
  post_install_message: