mongo_populator 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ # 0.1.0 (September 14th, 2011)
2
+
3
+ * initial release based on fork of http://github.com/ryanb/populator
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem 'mongo'
4
+
5
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Benjamin Cullen-Kerney, 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/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # MongoPopulator
2
+
3
+ `mongo_populator` populates a MongoDB database with placeholder data. It is built upon [`populator`](https://github.com/ryanb/populator) by Ryan Bates, but it works with the `mongo` gem in standalone scripts, and is not tied to any particular framework.
4
+
5
+ ## Installation
6
+
7
+ gem install mongo_populator
8
+
9
+ ## Usage
10
+
11
+ This gem adds a "populate" method to a `Mongo::Collection`. Pass the number of documents you want to create along with a block. In the block you can set the field values for each document.
12
+
13
+ require 'rubygems'
14
+ require 'mongo_populator'
15
+
16
+ db = Mongo::Connection.new("localhost", 27017).db("test-db")
17
+
18
+ article_collection = db.collection('article')
19
+ article_collection.populate(100) do |article|
20
+ article.title = MongoPopulator.words(4..6).capitalize
21
+ article.slug = article.title.downcase.tr(' ','-')
22
+ article.published = true
23
+ article.created_at = (Time.now - 604800)..Time.now
24
+ article.body = MongoPopulator.paragraphs(5..7)
25
+ end
26
+
27
+ Unlike the original Populator, we are letting MongoDB set each ObjectId. This makes setting up relationships only slightly more laborious.
28
+
29
+ article_collection = db.collection('article')
30
+ article_collection.populate(100) do |article|
31
+ ...
32
+ end
33
+
34
+ # create array of article _ids to select from
35
+ article_ids = db.collection('article').distinct('_id')
36
+
37
+ comment_collection = db.collection('comments')
38
+ comment_collection.populate(1000) do |comment|
39
+ ...
40
+ comment.article = article_ids
41
+ end
42
+
43
+ That will create an average of 10 comments for each article. Embedded documents are not yet supported.
44
+
45
+ Passing a range or array of values will randomly select one.
46
+
47
+ person.gender = ['male', 'female']
48
+
49
+ This will create 1000 to 5000 men or women with the annual income between 10,000 and 200,000.
50
+
51
+ If you need to generate fake data, there are a few methods to do this.
52
+
53
+ MongoPopulator.words(3) # generates 3 random words separated by spaces
54
+ MongoPopulator.words(10..20) # generates between 10 and 20 random words
55
+ MongoPopulator.sentences(5) # generates 5 sentences
56
+ MongoPopulator.paragraphs(3) # generates 3 paragraphs
57
+
58
+ For fancier data generation, try the [Faker gem](http://faker.rubyforge.org).
59
+
60
+ To persist arrays in your documents, use either #items to save a certain number of items randomly selected from a set, or #array to save a specific array.
61
+
62
+ MongoPopulator.items(1..5, %w(ape bear cat dog elephant firefox)) # populates array with provided terms
63
+ MongoPopulator.items(10..20) # populates array with random words
64
+ MongoPopulator.array('red', 'green', 'blue') # saves `['red', 'green', 'blue']` exactly
65
+
66
+ ## Development
67
+
68
+ Problems or questions? Add an [issue on GitHub](https://github.com/bak/mongo_populator/issues) or fork the project and send a pull request.
69
+
70
+ ## Special Thanks
71
+
72
+ MongoPopulator is highly derivative of, and heavily reuses, the work of Ryan Bates [via Populator](https://github.com/ryanb/populator/). Thanks, Ryan.
73
+
74
+ ## Special Thanks for the original Populator
75
+
76
+ Special thanks to Zach Dennis for his ar-extensions gem which some of this code is based on. Also many thanks to the [contributors](https://github.com/ryanb/populator/contributors). See the [CHANGELOG](https://github.com/ryanb/populator/blob/master/CHANGELOG.rdoc) for the full list.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rspec/core/rake_task'
4
+ require 'yaml'
5
+
6
+ task :default => :spec
7
+
8
+ task :spec do
9
+ desc "Run specs"
10
+ RSpec::Core::RakeTask.new do |t|
11
+ t.rspec_opts = ["-c"]
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module MongoPopulator
2
+ module CollectionAdditions
3
+
4
+ # Populate a Mongo::Collection with data
5
+ def populate(amount, &block)
6
+ Factory.for_collection(self).populate(amount, &block)
7
+ end
8
+ end
9
+
10
+ # extend host class with class methods when we're included
11
+ def self.included(host_class)
12
+ host_class.extend(CollectionAdditions)
13
+ end
14
+ end
15
+
16
+ Mongo::Collection.class_eval do
17
+ include MongoPopulator::CollectionAdditions
18
+ end
@@ -0,0 +1,73 @@
1
+ module MongoPopulator
2
+ # Builds multiple Populator::Record instances and saves them to the database
3
+ class Factory
4
+
5
+ @factories = {}
6
+ @depth = 0
7
+
8
+ # Fetches the factory dedicated to a given collection. You should always use this
9
+ # method instead of instatiating a factory directly so that a single factory is
10
+ # shared on multiple calls.
11
+ def self.for_collection(collection)
12
+ @factories[collection] ||= new(collection)
13
+ end
14
+
15
+ # Find all remaining factories and call save_records on them.
16
+ def self.save_remaining_records
17
+ @factories.values.each do |factory|
18
+ factory.save_records
19
+ end
20
+ @factories = {}
21
+ end
22
+
23
+ # Keep track of nested factory calls so we can save the remaining records once we
24
+ # are done with the base factory. This makes Populator more efficient when nesting
25
+ # factories.
26
+ def self.remember_depth
27
+ @depth += 1
28
+ yield
29
+ @depth -= 1
30
+ save_remaining_records if @depth.zero?
31
+ end
32
+
33
+ # Use for_collection instead of instatiating a record directly.
34
+ def initialize(collection)
35
+ @collection = collection
36
+ @records = []
37
+ end
38
+
39
+ # Entry method for building records. Delegates to build_records after remember_depth.
40
+ def populate(amount, &block)
41
+ self.class.remember_depth do
42
+ build_records(MongoPopulator.interpret_value(amount), &block)
43
+ end
44
+ end
45
+
46
+ # Builds multiple MongoPopulator::Record instances and calls save_records them when
47
+ # :per_query limit option is reached.
48
+ def build_records(amount, &block)
49
+ amount.times do
50
+ # index = last_id_in_database + @records.size + 1
51
+ record = Record.new(@collection)
52
+ block.call(record) if block
53
+ @records << record.attributes
54
+ save_records
55
+ end
56
+ end
57
+
58
+ # Saves the records to the database
59
+ def save_records
60
+ @records.each do |record|
61
+ @collection.insert(record)
62
+ end
63
+ # @last_id_in_database = @records.last[:_id]
64
+ @records.clear
65
+ end
66
+
67
+ private
68
+
69
+ # def last_id_in_database
70
+ # @last_id_in_database ||= @collection.distinct('_id').last
71
+ # end
72
+ end
73
+ end
@@ -0,0 +1,5 @@
1
+ module MongoPopulator
2
+
3
+ # MongoArrays can be passed directly to attributes and will be saved as arrays in mongo.
4
+ class MongoArray < Array; end
5
+ end
@@ -0,0 +1,86 @@
1
+ module MongoPopulator
2
+ # This module adds several methods for generating random data which can be
3
+ # called directly on Populator.
4
+
5
+ module Random
6
+ 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 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)
7
+
8
+ # Pick a random value out of a given range.
9
+ def value_in_range(range)
10
+ case range.first
11
+ when Integer then number_in_range(range)
12
+ when Time then time_in_range(range)
13
+ when Date then date_in_range(range)
14
+ else range.to_a[rand(range.to_a.size)]
15
+ end
16
+ end
17
+
18
+ # Generate a given number of words. If a range is passed, it will generate
19
+ # a random number of words within that range.
20
+ def words(total)
21
+ (1..interpret_value(total)).map { WORDS[rand(WORDS.size)] }.join(' ')
22
+ end
23
+
24
+ # Generate a given number of sentences. If a range is passed, it will generate
25
+ # a random number of sentences within that range.
26
+ def sentences(total)
27
+ (1..interpret_value(total)).map do
28
+ words(5..20).capitalize
29
+ end.join('. ')
30
+ end
31
+
32
+ # Generate a given number of paragraphs. If a range is passed, it will generate
33
+ # a random number of paragraphs within that range.
34
+ def paragraphs(total)
35
+ (1..interpret_value(total)).map do
36
+ sentences(3..8).capitalize
37
+ end.join("\n\n")
38
+ end
39
+
40
+ # Generate a given number of items, or for a range, generate a random number of
41
+ # items within that range, using values in array, or random words. Returns MongoArray.
42
+ def items(total, arr=nil)
43
+ out = MongoArray.new
44
+ (1..interpret_value(total)).map do
45
+ out << (arr ? arr[rand(arr.size)] : words(1))
46
+ end
47
+ return out
48
+ end
49
+
50
+ # Simply pass the values back out as a MongoArray
51
+ def array(*values)
52
+ MongoArray.new(values)
53
+ end
54
+
55
+ # If an array or range is passed, a random value will be selected to match.
56
+ # All other values are simply returned.
57
+ def interpret_value(value)
58
+ case value
59
+ when MongoArray then value
60
+ when Array then value[rand(value.size)]
61
+ when Range then value_in_range(value)
62
+ else value
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def time_in_range(range)
69
+ Time.at number_in_range(Range.new(range.first.to_i, range.last.to_i, range.exclude_end?))
70
+ end
71
+
72
+ def date_in_range(range)
73
+ Date.jd number_in_range(Range.new(range.first.jd, range.last.jd, range.exclude_end?))
74
+ end
75
+
76
+ def number_in_range(range)
77
+ if range.exclude_end?
78
+ rand(range.last - range.first) + range.first
79
+ else
80
+ rand((range.last+1) - range.first) + range.first
81
+ end
82
+ end
83
+ end
84
+
85
+ extend Random # load it into the populator module directly so we can call the methods
86
+ end
@@ -0,0 +1,30 @@
1
+ module MongoPopulator
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.
7
+ def initialize(collection)
8
+ @attributes = {}
9
+ end
10
+
11
+ def attributes=(values_hash)
12
+ values_hash.each_pair do |key, value|
13
+ value = value.call if value.is_a?(Proc)
14
+ self.send((key.to_s + "=").to_sym, value)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def method_missing(sym, *args, &block)
21
+ name = sym.to_s
22
+ if name.include? '='
23
+ @attributes[name.sub('=', '').to_sym] = MongoPopulator.interpret_value(args.first)
24
+ else
25
+ @attributes[sym]
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,12 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'mongo'
4
+ require 'mongo_populator/collection_additions'
5
+ require 'mongo_populator/factory'
6
+ require 'mongo_populator/record'
7
+ require 'mongo_populator/mongo_array'
8
+ require 'mongo_populator/random'
9
+
10
+ # MongoPopulator is made up of several parts. To start, see MongoPopulator::ModelAdditions.
11
+ module MongoPopulator
12
+ end
data/spec/README.rdoc ADDED
@@ -0,0 +1,5 @@
1
+ = Running Populator Specs
2
+
3
+ To run the specs, make sure you have mongo running on localhost port 27017, and
4
+
5
+ rake spec
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe MongoPopulator::CollectionAdditions do
4
+ before(:each) do
5
+ @collection = $db.collection('test-collection')
6
+ end
7
+
8
+ it "should add populate method to collection class" do
9
+ @collection.should respond_to(:populate)
10
+ end
11
+
12
+ it "should add 10 records to database" do
13
+ @collection.populate(10)
14
+ @collection.count.should == 10
15
+ end
16
+
17
+ it "should set attribute columns" do
18
+ @collection.populate(1) do |record|
19
+ record.name = "foo"
20
+ end
21
+ @collection.distinct('name').last.should == "foo"
22
+ end
23
+
24
+ after(:each) do
25
+ @collection.drop
26
+ end
27
+ end
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ describe MongoPopulator::Factory do
4
+ before(:each) do
5
+ @collection = $db.collection('test-collection')
6
+ @factory = MongoPopulator::Factory.for_collection(@collection)
7
+ end
8
+
9
+ it "should generate within range" do
10
+ @factory.populate(2..4)
11
+ @collection.count.should >= 2
12
+ @collection.count.should <= 4
13
+ end
14
+
15
+ after(:each) do
16
+ @collection.drop
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe MongoPopulator::Random do
4
+ it "should pick a random number in range excluding last value" do
5
+ MongoPopulator.stubs(:rand).with(5).returns(3)
6
+ MongoPopulator.value_in_range(10...15).should == 13
7
+ end
8
+
9
+ it "should pick a random number in range including last value" do
10
+ MongoPopulator.stubs(:rand).with(5).returns(3)
11
+ MongoPopulator.value_in_range(10..14).should == 13
12
+ end
13
+
14
+ it "should pick a random time in range" do
15
+ start_time = Time.now - 172800
16
+ end_time = Time.now
17
+ MongoPopulator.stubs(:rand).with(end_time.to_i-start_time.to_i).returns(1)
18
+ MongoPopulator.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 = Date.today - 63072000
23
+ end_date = Date.today
24
+ MongoPopulator.stubs(:rand).with(end_date.jd-start_date.jd).returns(1)
25
+ MongoPopulator.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
+ MongoPopulator.stubs(:rand).with(5).returns(2)
30
+ MongoPopulator.value_in_range('a'..'e').should == 'c'
31
+ end
32
+
33
+ it "should pick 3 random words" do
34
+ MongoPopulator.words(3).split.should have(3).records
35
+ end
36
+
37
+ it "should pick a random number of random words" do
38
+ MongoPopulator.stubs(:rand).returns(3)
39
+ MongoPopulator.words(10...15).split.should have(13).records
40
+ end
41
+
42
+ it "should generate 3 random sentences" do
43
+ MongoPopulator.sentences(3).split(/\. [A-Z]/).should have(3).records
44
+ end
45
+
46
+ it "should generate 3 random paragraphs" do
47
+ MongoPopulator.paragraphs(3).split(/\n\n/).should have(3).records
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ describe MongoPopulator::Record do
4
+ before(:each) do
5
+ @collection = $db.collection('test-collection')
6
+ end
7
+
8
+ it "should pick random number from range" do
9
+ record = MongoPopulator::Record.new(@collection)
10
+ record.stock = 2..5
11
+ record.stock.should >= 2
12
+ record.stock.should <= 5
13
+ end
14
+
15
+ it "should pick random value from array" do
16
+ record = MongoPopulator::Record.new(@collection)
17
+ record.name = %w[foo bar]
18
+ %w[foo bar].should include(record.name)
19
+ end
20
+
21
+ it "should allow set via attributes hash" do
22
+ record = MongoPopulator::Record.new(@collection)
23
+ record.attributes = {:stock => 2..5}
24
+ record.stock.should >= 2
25
+ record.stock.should <= 5
26
+ end
27
+
28
+ it "should take a proc object via attributes hash" do
29
+ record = MongoPopulator::Record.new(@collection)
30
+ record.attributes = {:stock => lambda {15}}
31
+ record.stock.should == 15
32
+ end
33
+
34
+ after(:each) do
35
+ @collection.drop
36
+ end
37
+ end
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ Bundler.require(:default)
5
+
6
+ require 'mongo'
7
+ require 'mongo_populator'
8
+
9
+ RSpec.configure do |config|
10
+ config.mock_with :mocha
11
+
12
+ begin
13
+ $db = Mongo::Connection.new("localhost", 27017).db("test-db")
14
+ rescue Mongo::ConnectionFailure
15
+ p "Could not connect to Mongo. Ensure that db server is running at localhost port 27017."
16
+ end
17
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongo_populator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Benjamin Cullen-Kerney
9
+ - Ryan Bates
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2011-09-14 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: mongo
17
+ requirement: &70101862524240 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 1.3.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *70101862524240
26
+ - !ruby/object:Gem::Dependency
27
+ name: rspec
28
+ requirement: &70101862523760 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.6.0
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: *70101862523760
37
+ - !ruby/object:Gem::Dependency
38
+ name: mocha
39
+ requirement: &70101862550920 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ~>
43
+ - !ruby/object:Gem::Version
44
+ version: 0.10.0
45
+ type: :development
46
+ prerelease: false
47
+ version_requirements: *70101862550920
48
+ description: Mass populate MongoDB.
49
+ email: ben.kerney -> gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - lib/mongo_populator/collection_additions.rb
55
+ - lib/mongo_populator/factory.rb
56
+ - lib/mongo_populator/mongo_array.rb
57
+ - lib/mongo_populator/random.rb
58
+ - lib/mongo_populator/record.rb
59
+ - lib/mongo_populator.rb
60
+ - spec/mongo_populator/collection_additions_spec.rb
61
+ - spec/mongo_populator/factory_spec.rb
62
+ - spec/mongo_populator/random_spec.rb
63
+ - spec/mongo_populator/record_spec.rb
64
+ - spec/README.rdoc
65
+ - spec/spec_helper.rb
66
+ - CHANGELOG.md
67
+ - Gemfile
68
+ - LICENSE
69
+ - Rakefile
70
+ - README.md
71
+ homepage: http://github.com/bak/mongo_populator
72
+ licenses: []
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: 1.8.0
89
+ requirements: []
90
+ rubyforge_project: mongo_populator
91
+ rubygems_version: 1.8.6
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Mass populate MongoDB.
95
+ test_files: []