jim-summon 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/README.rdoc +102 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/summon.rb +19 -4
- data/summon.gemspec +3 -3
- data/test/summon_test.rb +50 -4
- data/test/test_helper.rb +70 -1
- metadata +3 -3
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -2,7 +2,108 @@
|
|
2
2
|
|
3
3
|
Provides a nice DSL for creating dummy data using Factory Girl factory definitions.
|
4
4
|
|
5
|
-
|
5
|
+
== Why
|
6
|
+
|
7
|
+
Now that you've moved away from fixtures (well, you have, haven't you?) and started using factory_girl
|
8
|
+
in your tests and specs, it would be nice to have a succinct way to generate dummy data for use in development.
|
9
|
+
|
10
|
+
In the past I've just used a bunch of extra factories for this, but it's a lot nicer to be able to build an
|
11
|
+
arbitrary number of objects, each with its own set of associations.
|
12
|
+
|
13
|
+
== Example
|
14
|
+
|
15
|
+
Here is an example Rakefile from a project I'm working on:
|
16
|
+
|
17
|
+
namespace :summon do
|
18
|
+
desc "Builds a ton of dummy data"
|
19
|
+
task :build => ['environment', 'db:reset'] do
|
20
|
+
|
21
|
+
require 'spec/support/factories' # load factory definitions
|
22
|
+
require 'summon'
|
23
|
+
|
24
|
+
published_date = lambda {
|
25
|
+
method = %w(ago since)[rand(2)]
|
26
|
+
rand(100).days.send(method)
|
27
|
+
}
|
28
|
+
|
29
|
+
Summon(:label, 5)
|
30
|
+
Summon(:blog_topic, 10)
|
31
|
+
|
32
|
+
Summon(:user, 20) do |user|
|
33
|
+
user.blogs(3..8,
|
34
|
+
:topic => BlogTopic.all,
|
35
|
+
:published_at => published_date
|
36
|
+
) do |blog|
|
37
|
+
blog.comments 0..4
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
Summon(:artist, 20) do |artist|
|
42
|
+
artist.events 4..6
|
43
|
+
artist.releases(0..5,
|
44
|
+
:label => Label.all
|
45
|
+
) do |release|
|
46
|
+
release.tracks 8..12
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
puts "Your minions are ready!"
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
== Installation
|
56
|
+
|
57
|
+
I'd go for the gem.
|
58
|
+
|
59
|
+
sudo gem install jim-summon
|
60
|
+
|
61
|
+
== Usage
|
62
|
+
|
63
|
+
=== Specifying how many objects to build
|
64
|
+
|
65
|
+
You can use an integer or range when specifying how many objects to build:
|
66
|
+
|
67
|
+
Summon(:monkey, 3) # build 3 monkeys
|
68
|
+
Summon(:monkey, 3..6) # build between 3 and 6 monkeys
|
69
|
+
|
70
|
+
=== Object attributes
|
71
|
+
|
72
|
+
Other attributes to set on created objects (potentially overriding those defined by the factory)
|
73
|
+
are passed in as a hash:
|
74
|
+
|
75
|
+
Summon(:monkey, 42, :dangerous => true) # builds 42 dangerous monkeys
|
76
|
+
|
77
|
+
If you pass a proc in as an attribute, it will be evaluated for each object and the resulting
|
78
|
+
value used in its place.
|
79
|
+
|
80
|
+
If you pass an Array in as a value to an attribute, a value from the array will be selected at
|
81
|
+
random. This might seem odd, but I've found it's much more common to want to set an attribute
|
82
|
+
or association randomly from a set of options than set an attribute value to be an array. You
|
83
|
+
can always use a proc for this.
|
84
|
+
|
85
|
+
== Associated objects
|
86
|
+
|
87
|
+
This is where the magic really happens. Use a block to define an object's associations, and
|
88
|
+
potentially their attributes:
|
89
|
+
|
90
|
+
Summon(:car, 4) do |car| # Build 4 cars, and in each...
|
91
|
+
car.passengers 3 # Build 3 passengers
|
92
|
+
car.driver # Build one driver
|
93
|
+
end
|
94
|
+
|
95
|
+
Right now has_many and has_one associations are supported. has_many :through is not. Associations
|
96
|
+
can be nested as deep as you like:
|
97
|
+
|
98
|
+
Summon(:car, 4, :color => 'red') do |car|
|
99
|
+
car.passengers 3, :backseat_driver => true
|
100
|
+
car.driver do |driver|
|
101
|
+
driver.gloves 2
|
102
|
+
driver.jacket do |jacket|
|
103
|
+
jacket.pockets 2, :cents => [0,5,10,25,50]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
6
107
|
|
7
108
|
== Note on Patches/Pull Requests
|
8
109
|
|
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ begin
|
|
5
5
|
require 'jeweler'
|
6
6
|
Jeweler::Tasks.new do |gem|
|
7
7
|
gem.name = "summon"
|
8
|
-
gem.summary = %Q{
|
8
|
+
gem.summary = %Q{Provides a nice DSL for creating dummy data using Factory Girl factory definitions}
|
9
9
|
gem.description = %Q{Allows for easily setting up deeply nested associations}
|
10
10
|
gem.email = "jim@autonomousmachine.com"
|
11
11
|
gem.homepage = "http://github.com/jim/summon"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.1.0
|
data/lib/summon.rb
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
require 'factory_girl'
|
2
2
|
|
3
3
|
module Summon
|
4
|
-
|
4
|
+
|
5
|
+
(class << self; self; end).class_eval do
|
6
|
+
attr_accessor :noisy
|
7
|
+
end
|
8
|
+
self.noisy = false
|
9
|
+
|
5
10
|
class Conjure
|
6
11
|
|
7
12
|
attr :parent
|
@@ -11,7 +16,7 @@ module Summon
|
|
11
16
|
end
|
12
17
|
|
13
18
|
def log(string)
|
14
|
-
if parent.nil?
|
19
|
+
if parent.nil? && Summon.noisy
|
15
20
|
printf string; $stdout.flush
|
16
21
|
end
|
17
22
|
end
|
@@ -31,7 +36,7 @@ module Summon
|
|
31
36
|
end
|
32
37
|
end
|
33
38
|
|
34
|
-
quantity = args.first
|
39
|
+
quantity = args.first || 1
|
35
40
|
quantity = quantity.to_a[rand(quantity.to_a.size)] if quantity.is_a?(Range)
|
36
41
|
options = args.extract_options!
|
37
42
|
|
@@ -46,7 +51,17 @@ module Summon
|
|
46
51
|
if parent.nil?
|
47
52
|
child = Factory(name, attributes)
|
48
53
|
else
|
49
|
-
|
54
|
+
association = @parent.class.reflect_on_association(name.to_sym)
|
55
|
+
raise "Association #{name} not found on #{@parent.class.to_s}" unless association
|
56
|
+
|
57
|
+
child = case association.macro
|
58
|
+
when :has_one:
|
59
|
+
parent.send("#{name}=", Factory(name.to_s.singularize, attributes))
|
60
|
+
when :has_many:
|
61
|
+
parent.send(name).create(Factory.attributes_for(name.to_s.singularize, attributes))
|
62
|
+
else
|
63
|
+
raise "#{association.macro} macros are not supported"
|
64
|
+
end
|
50
65
|
end
|
51
66
|
yield Conjure.new(child) if block_given?
|
52
67
|
end
|
data/summon.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{summon}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jim Benton"]
|
12
|
-
s.date = %q{2009-08-
|
12
|
+
s.date = %q{2009-08-26}
|
13
13
|
s.description = %q{Allows for easily setting up deeply nested associations}
|
14
14
|
s.email = %q{jim@autonomousmachine.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
s.rdoc_options = ["--charset=UTF-8"]
|
33
33
|
s.require_paths = ["lib"]
|
34
34
|
s.rubygems_version = %q{1.3.3}
|
35
|
-
s.summary = %q{
|
35
|
+
s.summary = %q{Provides a nice DSL for creating dummy data using Factory Girl factory definitions}
|
36
36
|
s.test_files = [
|
37
37
|
"test/summon_test.rb",
|
38
38
|
"test/test_helper.rb"
|
data/test/summon_test.rb
CHANGED
@@ -1,7 +1,53 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class SummonTest <
|
4
|
-
|
5
|
-
|
3
|
+
class SummonTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
Summon.noisy = false
|
7
|
+
Corner.delete_all
|
8
|
+
Compartment.delete_all
|
9
|
+
Handle.delete_all
|
10
|
+
Box.delete_all
|
11
|
+
Secret.delete_all
|
6
12
|
end
|
7
|
-
|
13
|
+
|
14
|
+
test "building a number of objects" do
|
15
|
+
Summon(:corner, 3)
|
16
|
+
assert_equal 3, Corner.count
|
17
|
+
end
|
18
|
+
|
19
|
+
test "building a variable number of objects" do
|
20
|
+
Summon(:corner, 3..5)
|
21
|
+
assert_operator 3..5, :===, Corner.count
|
22
|
+
end
|
23
|
+
|
24
|
+
test "overriding default factory attributes" do
|
25
|
+
Summon(:corner, 1, :sharp => false)
|
26
|
+
assert_equal false, Corner.first.sharp
|
27
|
+
end
|
28
|
+
|
29
|
+
test "building has_many associations" do
|
30
|
+
Summon(:box, 1) do |b|
|
31
|
+
b.corners 3
|
32
|
+
b.compartments 2 do |c|
|
33
|
+
c.secrets 4
|
34
|
+
end
|
35
|
+
end
|
36
|
+
assert_equal 3, Box.first.corners.count
|
37
|
+
assert_equal 3, Corner.count
|
38
|
+
assert_equal 2, Box.first.compartments.count
|
39
|
+
assert_equal 2, Compartment.count
|
40
|
+
assert_equal 8, Secret.count
|
41
|
+
end
|
42
|
+
|
43
|
+
test "building has_one associations" do
|
44
|
+
Summon(:box, 1) do |b|
|
45
|
+
b.compartments 2 do |c|
|
46
|
+
c.handle
|
47
|
+
end
|
48
|
+
end
|
49
|
+
assert_equal 2, Compartment.count
|
50
|
+
assert_equal 2, Handle.count
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -1,9 +1,78 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
gem 'test-unit'
|
2
3
|
require 'test/unit'
|
4
|
+
require 'active_support'
|
5
|
+
require 'active_support/test_case'
|
6
|
+
require 'active_record'
|
7
|
+
require 'factory_girl'
|
3
8
|
|
4
9
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
5
10
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
11
|
require 'summon'
|
7
12
|
|
8
|
-
|
13
|
+
ActiveRecord::Base.logger = Logger.new(File.open('test.log', 'a'))
|
14
|
+
ActiveRecord::Base.logger.level = Logger::DEBUG
|
15
|
+
ActiveRecord::Base.colorize_logging = false
|
16
|
+
|
17
|
+
ActiveRecord::Base.establish_connection(
|
18
|
+
:adapter => 'sqlite3',
|
19
|
+
:database => ":memory:"
|
20
|
+
)
|
21
|
+
|
22
|
+
ActiveRecord::Schema.define do
|
23
|
+
create_table :boxes, :force => true do |t|
|
24
|
+
t.string :name
|
25
|
+
t.integer :depth
|
26
|
+
end
|
27
|
+
create_table :corners, :force => true do |t|
|
28
|
+
t.integer :box_id
|
29
|
+
t.boolean :sharp
|
30
|
+
end
|
31
|
+
create_table :compartments, :force => true do |t|
|
32
|
+
t.integer :box_id
|
33
|
+
t.boolean :hidden
|
34
|
+
end
|
35
|
+
create_table :handles, :force => true do |h|
|
36
|
+
h.integer :compartment_id
|
37
|
+
h.boolean :metal
|
38
|
+
end
|
39
|
+
create_table :secrets, :force => true do |s|
|
40
|
+
s.integer :compartment_id
|
41
|
+
s.boolean :valuable
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Corner < ActiveRecord::Base; end
|
46
|
+
class Secret < ActiveRecord::Base; end
|
47
|
+
class Handle < ActiveRecord::Base; end
|
48
|
+
|
49
|
+
class Compartment < ActiveRecord::Base
|
50
|
+
has_many :secrets
|
51
|
+
has_one :handle
|
52
|
+
end
|
53
|
+
|
54
|
+
class Box < ActiveRecord::Base
|
55
|
+
has_many :compartments
|
56
|
+
has_many :corners
|
57
|
+
end
|
58
|
+
|
59
|
+
Factory.define(:box) do |b|
|
60
|
+
b.name 'A box'
|
61
|
+
b.depth 12
|
62
|
+
end
|
63
|
+
|
64
|
+
Factory.define(:corner) do |c|
|
65
|
+
c.sharp true
|
66
|
+
end
|
67
|
+
|
68
|
+
Factory.define(:compartment) do |c|
|
69
|
+
c.hidden true
|
70
|
+
end
|
71
|
+
|
72
|
+
Factory.define(:handle) do |h|
|
73
|
+
h.metal true
|
9
74
|
end
|
75
|
+
|
76
|
+
Factory.define(:secret) do |c|
|
77
|
+
c.valuable true
|
78
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jim-summon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jim Benton
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-26 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -67,7 +67,7 @@ rubyforge_project:
|
|
67
67
|
rubygems_version: 1.2.0
|
68
68
|
signing_key:
|
69
69
|
specification_version: 3
|
70
|
-
summary:
|
70
|
+
summary: Provides a nice DSL for creating dummy data using Factory Girl factory definitions
|
71
71
|
test_files:
|
72
72
|
- test/summon_test.rb
|
73
73
|
- test/test_helper.rb
|