fabrication 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown ADDED
File without changes
@@ -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,3 @@
1
+ module Fabrication
2
+ VERSION = '0.0.1'
3
+ 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
@@ -0,0 +1,2 @@
1
+ --colour
2
+ --format nested
@@ -0,0 +1,9 @@
1
+ $:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
2
+ $:.unshift(File.dirname(__FILE__))
3
+
4
+ require 'rubygems'
5
+ require 'spec'
6
+ require 'spec/autorun'
7
+ require 'fabrication'
8
+ require 'ffaker'
9
+ require 'active_record'
@@ -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
+