fabrication 0.0.1
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/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
|
+
|