fabrication 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +0 -0
- data/lib/fabrication.rb +36 -0
- data/lib/fabrication/fabricator.rb +33 -0
- data/lib/fabrication/generator/active_record.rb +42 -0
- data/lib/fabrication/generator/base.rb +25 -0
- data/lib/fabrication/version.rb +3 -0
- data/spec/block_generated_fields_spec.rb +33 -0
- data/spec/fabrication_spec.rb +24 -0
- data/spec/fabricator_spec.rb +41 -0
- data/spec/generator/active_record_spec.rb +54 -0
- data/spec/generator/base_spec.rb +29 -0
- data/spec/multiple_instance_spec.rb +32 -0
- data/spec/simple_object_spec.rb +37 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/database_setup.rb +34 -0
- data/spec/support/helper_objects.rb +1 -0
- metadata +147 -0
data/README.markdown
ADDED
File without changes
|
data/lib/fabrication.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Fabrication
|
2
|
+
|
3
|
+
autoload :Fabricator, 'fabrication/fabricator'
|
4
|
+
|
5
|
+
module Generator
|
6
|
+
autoload :ActiveRecord, 'fabrication/generator/active_record'
|
7
|
+
autoload :Base, 'fabrication/generator/base'
|
8
|
+
end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def schematic(name, &block)
|
13
|
+
fabricators[name] = Fabricator.new(name, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
def generate(name, options)
|
17
|
+
fabricators[name].fabricate(options)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def fabricators
|
23
|
+
@@fabricators ||= {}
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
def Fabricator(name, &block)
|
31
|
+
Fabrication.schematic(name, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def Fabricate(name, options={})
|
35
|
+
Fabrication.generate(name, options)
|
36
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Fabrication::Fabricator
|
2
|
+
|
3
|
+
def initialize(class_name, &block)
|
4
|
+
klass = class_for(class_name)
|
5
|
+
if klass.ancestors.include?(ActiveRecord::Base)
|
6
|
+
@fabricator = Fabrication::Generator::ActiveRecord.new(klass, &block)
|
7
|
+
else
|
8
|
+
@fabricator = Fabrication::Generator::Base.new(klass, &block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def fabricate(options={})
|
13
|
+
@fabricator.generate(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
#Stolen directly from factory_girl. Thanks thoughtbot!
|
17
|
+
def class_for(class_or_to_s)
|
18
|
+
if class_or_to_s.respond_to?(:to_sym)
|
19
|
+
class_name = variable_name_to_class_name(class_or_to_s)
|
20
|
+
class_name.split('::').inject(Object) do |object, string|
|
21
|
+
object.const_get(string)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
class_or_to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
#Stolen directly from factory_girl. Thanks thoughtbot!
|
29
|
+
def variable_name_to_class_name(name)
|
30
|
+
name.to_s.gsub(/\/(.?)/){"::#{$1.upcase}"}.gsub(/(?:^|_)(.)/){$1.upcase}
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Fabrication::Generator::ActiveRecord < Fabrication::Generator::Base
|
2
|
+
|
3
|
+
def generate(options)
|
4
|
+
@options = options
|
5
|
+
@instance = super
|
6
|
+
@instance.save
|
7
|
+
@instance
|
8
|
+
end
|
9
|
+
|
10
|
+
def method_missing(method_name, *args, &block)
|
11
|
+
method_name = method_name.to_s
|
12
|
+
unless @options.include?(method_name.to_sym)
|
13
|
+
if block_given?
|
14
|
+
unless @instance.class.columns.map(&:name).include?(method_name)
|
15
|
+
# copy the original getter
|
16
|
+
@instance.instance_variable_set("@__#{method_name}_original", @instance.method(method_name).clone)
|
17
|
+
|
18
|
+
# store the block for lazy generation
|
19
|
+
@instance.instance_variable_set("@__#{method_name}_block", block)
|
20
|
+
|
21
|
+
# redefine the getter
|
22
|
+
@instance.instance_eval %<
|
23
|
+
def #{method_name}
|
24
|
+
original_value = @__#{method_name}_original.call
|
25
|
+
if @__#{method_name}_block.present?
|
26
|
+
original_value = #{method_name}= @__#{method_name}_block.call(self)
|
27
|
+
@__#{method_name}_block = nil
|
28
|
+
@__#{method_name}_original.call
|
29
|
+
end
|
30
|
+
original_value
|
31
|
+
end
|
32
|
+
>
|
33
|
+
else
|
34
|
+
assign(@instance, method_name, yield)
|
35
|
+
end
|
36
|
+
else
|
37
|
+
assign(@instance, method_name, args.first)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Fabrication::Generator::Base
|
2
|
+
|
3
|
+
def initialize(klass, &block)
|
4
|
+
@klass = klass
|
5
|
+
@block = block
|
6
|
+
end
|
7
|
+
|
8
|
+
def generate(options)
|
9
|
+
@instance = @klass.new
|
10
|
+
instance_eval &@block
|
11
|
+
options.each { |k,v| assign(@instance, k, v) }
|
12
|
+
@instance
|
13
|
+
end
|
14
|
+
|
15
|
+
def method_missing(method_name, *args, &block)
|
16
|
+
assign(@instance, method_name.to_s, block_given? ? yield : args.first)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def assign(instance, method_name, value)
|
22
|
+
instance.send("#{method_name.to_s}=", value)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fabrication do
|
4
|
+
|
5
|
+
context 'block generated fields' do
|
6
|
+
|
7
|
+
let(:person) do
|
8
|
+
Fabricate(:person)
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:all) do
|
12
|
+
Fabricator(:person) do
|
13
|
+
first_name { Faker::Name.first_name }
|
14
|
+
last_name { Faker::Name.last_name }
|
15
|
+
age { rand(100) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'has a first name' do
|
20
|
+
person.first_name.should be
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'has a last name' do
|
24
|
+
person.last_name.should be
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'has an age' do
|
28
|
+
person.age.should be
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fabrication do
|
4
|
+
|
5
|
+
context 'with an active record object' do
|
6
|
+
|
7
|
+
before(:all) { TestMigration.up }
|
8
|
+
after(:all) { TestMigration.down }
|
9
|
+
|
10
|
+
before do
|
11
|
+
Fabricator(:company) do
|
12
|
+
name { Faker::Company.name }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:company) { Fabricate(:company) }
|
17
|
+
|
18
|
+
it 'generates field blocks immediately' do
|
19
|
+
company.name.should be
|
20
|
+
end
|
21
|
+
it 'overrides associations'
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fabrication::Fabricator do
|
4
|
+
|
5
|
+
it 'generates a new object every time' do
|
6
|
+
f = Fabrication::Fabricator.new(:person) { first_name '1' }
|
7
|
+
f.fabricate.should_not == f.fabricate
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'with a plain old ruby object' do
|
11
|
+
|
12
|
+
let(:fabricator) { Fabrication::Fabricator.new(:person) { first_name '1' } }
|
13
|
+
|
14
|
+
it 'fabricates a Person instance' do
|
15
|
+
fabricator.fabricate.instance_of?(Person).should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'uses the base generator' do
|
19
|
+
fabricator.instance_variable_get(:@fabricator).instance_of?(Fabrication::Generator::Base).should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with an activerecord object' do
|
25
|
+
|
26
|
+
before(:all) { TestMigration.up }
|
27
|
+
after(:all) { TestMigration.down }
|
28
|
+
|
29
|
+
let(:fabricator) { Fabrication::Fabricator.new(:company) { name '1' } }
|
30
|
+
|
31
|
+
it 'fabricates a Company instance' do
|
32
|
+
fabricator.fabricate.instance_of?(Company).should be_true
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'uses the activerecord generator' do
|
36
|
+
fabricator.instance_variable_get(:@fabricator).instance_of?(Fabrication::Generator::ActiveRecord).should be_true
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fabrication::Generator::ActiveRecord do
|
4
|
+
|
5
|
+
before(:all) { TestMigration.up }
|
6
|
+
after(:all) { TestMigration.down }
|
7
|
+
|
8
|
+
context 'active record object' do
|
9
|
+
|
10
|
+
let(:company) do
|
11
|
+
Fabrication::Generator::ActiveRecord.new(Company) do
|
12
|
+
name 'Company Name'
|
13
|
+
divisions { |c| [Fabricate(:division, :company => c)] }
|
14
|
+
end.generate({:name => 'Something'})
|
15
|
+
end
|
16
|
+
|
17
|
+
before(:all) do
|
18
|
+
Fabricator(:division) do
|
19
|
+
name "Division Name"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
before { company }
|
24
|
+
|
25
|
+
it 'persists the company upon creation' do
|
26
|
+
Company.find_by_name('Something').should be
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'does not persist the divisions immediately' do
|
30
|
+
Division.count.should == 0
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'upon accessing the divisions association' do
|
34
|
+
|
35
|
+
let(:divisions) { company.divisions }
|
36
|
+
|
37
|
+
it 'generates the divisions' do
|
38
|
+
divisions.length.should == 1
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'persists the divisions' do
|
42
|
+
divisions
|
43
|
+
Division.find_all_by_company_id(company.id).count.should == 1
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'can load the divisions from the database' do
|
47
|
+
company.reload.divisions.length.should == 1
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fabrication::Generator::Base do
|
4
|
+
|
5
|
+
let(:person) do
|
6
|
+
Fabrication::Generator::Base.new(Person) do
|
7
|
+
first_name 'Some'
|
8
|
+
last_name { Faker::Name.last_name }
|
9
|
+
age 40
|
10
|
+
end.generate({:first_name => 'Body'})
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'generates an instance' do
|
14
|
+
person.instance_of?(Person).should be_true
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'generates the first name immediately' do
|
18
|
+
person.instance_variable_get(:@first_name).should == 'Body'
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'generates the last name immediately' do
|
22
|
+
person.instance_variable_get(:@last_name).should be
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'generates the age immediately' do
|
26
|
+
person.instance_variable_get(:@age).should == 40
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fabrication do
|
4
|
+
|
5
|
+
context 'multiple instance' do
|
6
|
+
|
7
|
+
let(:person1) { Fabricate(:person, :first_name => 'Jane') }
|
8
|
+
let(:person2) { Fabricate(:person, :first_name => 'John') }
|
9
|
+
|
10
|
+
before(:all) do
|
11
|
+
Fabricator(:person) do
|
12
|
+
first_name { Faker::Name.first_name }
|
13
|
+
last_name { Faker::Name.last_name }
|
14
|
+
age { rand(100) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'person1 is named Jane' do
|
19
|
+
person1.first_name.should == 'Jane'
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'person2 is named John' do
|
23
|
+
person2.first_name.should == 'John'
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'they have different last names' do
|
27
|
+
person1.last_name.should_not == person2.last_name
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Fabrication do
|
4
|
+
|
5
|
+
context 'static fields' do
|
6
|
+
|
7
|
+
let(:person) do
|
8
|
+
Fabricate(:person, :last_name => 'Awesome')
|
9
|
+
end
|
10
|
+
|
11
|
+
before(:all) do
|
12
|
+
Fabricator(:person) do
|
13
|
+
first_name 'Joe'
|
14
|
+
last_name 'Schmoe'
|
15
|
+
age 78
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'has the default first name' do
|
20
|
+
person.first_name.should == 'Joe'
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'has an overridden last name' do
|
24
|
+
person.last_name.should == 'Awesome'
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'has the default age' do
|
28
|
+
person.age.should == 78
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'generates a fresh object every time' do
|
32
|
+
Fabricate(:person).should_not == person
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# change this if sqlite is unavailable
|
2
|
+
dbconfig = {
|
3
|
+
:adapter => 'sqlite3',
|
4
|
+
:database => ':memory:'
|
5
|
+
}
|
6
|
+
|
7
|
+
ActiveRecord::Base.establish_connection(dbconfig)
|
8
|
+
ActiveRecord::Migration.verbose = false
|
9
|
+
|
10
|
+
class TestMigration < ActiveRecord::Migration
|
11
|
+
def self.up
|
12
|
+
create_table :companies, :force => true do |t|
|
13
|
+
t.column :name, :string
|
14
|
+
end
|
15
|
+
|
16
|
+
create_table :divisions, :force => true do |t|
|
17
|
+
t.column :name, :string
|
18
|
+
t.references :company
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.down
|
23
|
+
drop_table :companies
|
24
|
+
drop_table :divisions
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Company < ActiveRecord::Base
|
29
|
+
has_many :divisions
|
30
|
+
end
|
31
|
+
|
32
|
+
class Division < ActiveRecord::Base
|
33
|
+
belongs_to :company
|
34
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
class Person; attr_accessor :age, :first_name, :last_name end
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: fabrication
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Paul Elliott
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-06-15 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
- 9
|
34
|
+
version: 1.2.9
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: ffaker
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 15
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 4
|
49
|
+
- 0
|
50
|
+
version: 0.4.0
|
51
|
+
type: :development
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: activerecord
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 9
|
62
|
+
segments:
|
63
|
+
- 2
|
64
|
+
- 3
|
65
|
+
- 5
|
66
|
+
version: 2.3.5
|
67
|
+
type: :development
|
68
|
+
version_requirements: *id003
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3-ruby
|
71
|
+
prerelease: false
|
72
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 27
|
78
|
+
segments:
|
79
|
+
- 1
|
80
|
+
- 3
|
81
|
+
- 0
|
82
|
+
version: 1.3.0
|
83
|
+
type: :development
|
84
|
+
version_requirements: *id004
|
85
|
+
description: Fabrication is an object generation framework that lazily generated attributes as they are used
|
86
|
+
email:
|
87
|
+
- paul@hashrocket.com
|
88
|
+
executables: []
|
89
|
+
|
90
|
+
extensions: []
|
91
|
+
|
92
|
+
extra_rdoc_files: []
|
93
|
+
|
94
|
+
files:
|
95
|
+
- lib/fabrication/fabricator.rb
|
96
|
+
- lib/fabrication/generator/active_record.rb
|
97
|
+
- lib/fabrication/generator/base.rb
|
98
|
+
- lib/fabrication/version.rb
|
99
|
+
- lib/fabrication.rb
|
100
|
+
- spec/block_generated_fields_spec.rb
|
101
|
+
- spec/fabrication_spec.rb
|
102
|
+
- spec/fabricator_spec.rb
|
103
|
+
- spec/generator/active_record_spec.rb
|
104
|
+
- spec/generator/base_spec.rb
|
105
|
+
- spec/multiple_instance_spec.rb
|
106
|
+
- spec/simple_object_spec.rb
|
107
|
+
- spec/spec.opts
|
108
|
+
- spec/spec_helper.rb
|
109
|
+
- spec/support/database_setup.rb
|
110
|
+
- spec/support/helper_objects.rb
|
111
|
+
- README.markdown
|
112
|
+
has_rdoc: true
|
113
|
+
homepage: http://github.com/paulelliott/fabrication
|
114
|
+
licenses: []
|
115
|
+
|
116
|
+
post_install_message:
|
117
|
+
rdoc_options: []
|
118
|
+
|
119
|
+
require_paths:
|
120
|
+
- lib
|
121
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
hash: 3
|
127
|
+
segments:
|
128
|
+
- 0
|
129
|
+
version: "0"
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
none: false
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
hash: 3
|
136
|
+
segments:
|
137
|
+
- 0
|
138
|
+
version: "0"
|
139
|
+
requirements: []
|
140
|
+
|
141
|
+
rubyforge_project:
|
142
|
+
rubygems_version: 1.3.7
|
143
|
+
signing_key:
|
144
|
+
specification_version: 3
|
145
|
+
summary: Fabrication aims to provide a fast and simple solution for test object generation
|
146
|
+
test_files: []
|
147
|
+
|