fabrication 0.6.0 → 0.6.2

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 CHANGED
@@ -118,18 +118,3 @@ To run rake successfully:
118
118
  3. Install bundler
119
119
  4. Run `bundle install` from the project root
120
120
  5. Run `rake` and the test suite should be all green!
121
-
122
-
123
- look into: Object.reflect_on_associations
124
-
125
- Fabricator(:atlanta_hub, :from => :hub) do
126
- city "Atlanta"
127
- state "GA"
128
- location [33.755, -84.39]
129
- hardwares(:hardware, :as => :headend, :count => 4) do |hub, index|
130
- name 'something'
131
- end
132
- end
133
-
134
-
135
- build option cascades down to associations
data/lib/fabrication.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  module Fabrication
2
2
 
3
- require 'fabrication/errors'
3
+ autoload :DuplicateFabricatorError, 'fabrication/errors'
4
+ autoload :UnfabricatableError, 'fabrication/errors'
4
5
 
5
6
  autoload :Fabricator, 'fabrication/fabricator'
7
+ autoload :Sequencer, 'fabrication/sequencer'
6
8
  autoload :Schematic, 'fabrication/schematic'
7
9
  autoload :Support, 'fabrication/support'
8
10
 
@@ -14,36 +16,6 @@ module Fabrication
14
16
 
15
17
  class << self
16
18
 
17
- def schematic(name, options, &block)
18
- raise DuplicateFabricatorError if fabricators.has_key?(name)
19
- parent = fabricators[options[:from]]
20
- if options[:class_name]
21
- class_name = options[:class_name]
22
- elsif parent
23
- class_name = parent.class_name
24
- elsif options[:from]
25
- class_name = options[:from]
26
- else
27
- class_name = name
28
- end
29
- fabricators[name] = Fabricator.new(class_name, parent, &block)
30
- end
31
-
32
- def generate(name, options, overrides, &block)
33
- find_definitions if @@fabricators.nil?
34
- raise UnknownFabricatorError unless Fabrication::Support.fabricatable?(name)
35
- schematic(name, {}) unless fabricators.has_key?(name)
36
- fabricators[name].fabricate(options, overrides, &block)
37
- end
38
-
39
- def sequence(name, start=0)
40
- idx = sequences[name] ||= start
41
-
42
- (block_given? ? yield(idx) : idx).tap do
43
- sequences[name] += 1
44
- end
45
- end
46
-
47
19
  def attributes_for(name, options)
48
20
  hash = defined?(HashWithIndifferentAccess) ? HashWithIndifferentAccess.new : {}
49
21
  fetch_schematic(name).attributes.inject(hash) do |hash, attribute|
@@ -52,50 +24,15 @@ module Fabrication
52
24
  end.merge(options)
53
25
  end
54
26
 
55
- def find_definitions
56
- fabricator_file_paths = [
57
- File.join('test', 'fabricators'),
58
- File.join('spec', 'fabricators')
59
- ]
60
- fabricator_file_paths.each do |path|
61
- if File.exists?("#{path}.rb")
62
- require("#{path}.rb")
63
- end
64
-
65
- if File.directory? path
66
- Dir[File.join(path, '*.rb')].each do |file|
67
- require file
68
- end
69
- end
70
- end
71
- end
72
-
73
27
  def clear_definitions
74
- fabricators.clear
75
- sequences.clear
76
- end
77
-
78
- def fabricators
79
- @@fabricators ||= {}
80
- end
81
-
82
- def sequences
83
- @@sequences ||= {}
28
+ Fabricator.schematics.clear
29
+ Sequencer.sequences.clear
84
30
  end
85
31
 
86
32
  private
87
33
 
88
- @@fabricators = nil
89
-
90
34
  def fetch_schematic(name)
91
- if fabricator = fabricators[name]
92
- fabricator.schematic
93
- else
94
- # force finding definitions after setting @@fabricators to an empty array
95
- Fabrication.send(:class_variable_set, :@@fabricators, nil) if Fabrication.fabricators.empty?
96
- build(name)
97
- fetch_schematic(name)
98
- end
35
+ Fabricator.schematics[name] || Fabricator.define(name)
99
36
  end
100
37
 
101
38
  end
@@ -103,11 +40,11 @@ module Fabrication
103
40
  end
104
41
 
105
42
  def Fabricator(name, options={}, &block)
106
- Fabrication.schematic(name, options, &block)
43
+ Fabrication::Fabricator.define(name, options, &block)
107
44
  end
108
45
 
109
- def Fabricate(name, options={}, &block)
110
- Fabrication.generate(name, {:save => true}, options, &block)
46
+ def Fabricate(name, overrides={}, &block)
47
+ Fabrication::Fabricator.generate(name, {:save => true}, overrides, &block)
111
48
  end
112
49
 
113
50
  class Fabricate
@@ -115,11 +52,11 @@ class Fabricate
115
52
  class << self
116
53
 
117
54
  def build(name, options={}, &block)
118
- Fabrication.generate(name, {:save => false}, options, &block)
55
+ Fabrication::Fabricator.generate(name, {:save => false}, options, &block)
119
56
  end
120
57
 
121
58
  def sequence(name, start=0, &block)
122
- Fabrication.sequence(name, start, &block)
59
+ Fabrication::Sequencer.sequence(name, start, &block)
123
60
  end
124
61
 
125
62
  def attributes_for(name, options={})
@@ -2,6 +2,6 @@ module Fabrication
2
2
 
3
3
  class DuplicateFabricatorError < StandardError; end
4
4
 
5
- class UnknownFabricatorError < StandardError; end
5
+ class UnfabricatableError < StandardError; end
6
6
 
7
7
  end
@@ -1,28 +1,48 @@
1
1
  class Fabrication::Fabricator
2
2
 
3
- GENERATORS = [
4
- Fabrication::Generator::ActiveRecord,
5
- Fabrication::Generator::Mongoid,
6
- Fabrication::Generator::Base
7
- ]
8
-
9
- attr_accessor :class_name, :schematic
10
-
11
- def initialize(class_name, parent=nil, &block)
12
- self.class_name = class_name
13
- klass = Fabrication::Support.class_for(class_name)
14
- self.schematic = parent ? parent.schematic.clone.merge!(&block) : Fabrication::Schematic.new(&block)
15
- self.generator = GENERATORS.detect do |gen|
16
- gen.supports?(klass)
17
- end.new(klass, schematic)
18
- end
3
+ class << self
19
4
 
20
- def fabricate(options={}, overrides={}, &block)
21
- generator.generate(options, overrides, &block)
22
- end
5
+ def define(name, options={}, &block)
6
+ raise Fabrication::DuplicateFabricatorError if schematics.include?(name)
7
+ schematics[name] = schematic_for(name, options, &block)
8
+ end
9
+
10
+ def generate(name, options={}, overrides={}, &block)
11
+ Fabrication::Support.find_definitions if schematics.empty?
12
+ (schematics[name] || define(name)).generate(options, overrides, &block)
13
+ end
14
+
15
+ def schematics
16
+ @@schematics ||= {}
17
+ end
23
18
 
24
- private
19
+ private
25
20
 
26
- attr_accessor :generator
21
+ def class_name_for(name, parent, options)
22
+ if options[:class_name]
23
+ class_name = options[:class_name]
24
+ elsif parent
25
+ class_name = parent.klass.name
26
+ elsif options[:from]
27
+ class_name = options[:from]
28
+ else
29
+ class_name = name
30
+ end
31
+ class_name
32
+ end
33
+
34
+ def schematic_for(name, options, &block)
35
+ parent = schematics[options[:from]]
36
+ class_name = class_name_for(name, parent, options)
37
+ klass = Fabrication::Support.class_for(class_name)
38
+ raise Fabrication::UnfabricatableError unless klass
39
+ if parent
40
+ parent.merge(&block).tap { |s| s.klass = klass }
41
+ else
42
+ Fabrication::Schematic.new(klass, &block)
43
+ end
44
+ end
45
+
46
+ end
27
47
 
28
48
  end
@@ -6,21 +6,19 @@ class Fabrication::Generator::Base
6
6
  self.after_create_block = block if block_given?
7
7
  end
8
8
 
9
- def generate(options={:save => true}, overrides={}, &block)
10
- self.instance = klass.new
11
- process_attributes(overrides, &block)
9
+ def generate(options={:save => true}, attributes=[])
10
+ process_attributes(attributes)
12
11
  after_generation(options)
13
12
  after_create_block.call(instance) if after_create_block
14
13
  instance
15
14
  end
16
15
 
17
- def initialize(klass, schematic=nil)
18
- self.klass = klass
19
- self.schematic = schematic
16
+ def initialize(klass)
17
+ self.instance = klass.new
20
18
  end
21
19
 
22
20
  def method_missing(method_name, *args, &block)
23
- assign(method_name.to_s, args.first, &block)
21
+ assign(method_name, args.first, &block)
24
22
  end
25
23
 
26
24
  protected
@@ -29,11 +27,11 @@ class Fabrication::Generator::Base
29
27
 
30
28
  private
31
29
 
32
- attr_accessor :after_create_block, :instance, :klass, :schematic
30
+ attr_accessor :after_create_block, :instance
33
31
 
34
32
  def assign(method_name, param)
35
33
  value = nil
36
- if param.is_a?(Hash) && param[:count] && param[:count] > 1
34
+ if param.is_a?(Hash) && param.has_key?(:count) && param[:count] > 1
37
35
  value = (1..param[:count]).map do |i|
38
36
  block_given? ? yield(instance, i) : param
39
37
  end
@@ -43,8 +41,8 @@ class Fabrication::Generator::Base
43
41
  instance.send("#{method_name.to_s}=", value)
44
42
  end
45
43
 
46
- def process_attributes(options, &block)
47
- schematic.merge(options, &block).attributes.each do |attribute|
44
+ def process_attributes(attributes)
45
+ attributes.each do |attribute|
48
46
  if attribute.name == :after_create
49
47
  after_create(&attribute.value)
50
48
  else
@@ -1,11 +1,11 @@
1
1
  class Fabrication::Generator::Mongoid < Fabrication::Generator::Base
2
2
 
3
- def after_generation(options)
4
- instance.save if options[:save]
5
- end
6
-
7
3
  def self.supports?(klass)
8
4
  defined?(Mongoid) && klass.ancestors.include?(Mongoid::Document)
9
5
  end
10
6
 
7
+ def after_generation(options)
8
+ instance.save if options[:save]
9
+ end
10
+
11
11
  end
@@ -1,6 +1,15 @@
1
1
  class Fabrication::Schematic
2
2
 
3
- def initialize(&block)
3
+ GENERATORS = [
4
+ Fabrication::Generator::ActiveRecord,
5
+ Fabrication::Generator::Mongoid,
6
+ Fabrication::Generator::Base
7
+ ]
8
+
9
+ attr_accessor :generator, :klass
10
+ def initialize(klass, &block)
11
+ self.klass = klass
12
+ self.generator = GENERATORS.detect { |gen| gen.supports?(klass) }
4
13
  instance_eval(&block) if block_given?
5
14
  end
6
15
 
@@ -8,16 +17,26 @@ class Fabrication::Schematic
8
17
  attributes.select { |a| a.name == name }.first
9
18
  end
10
19
 
20
+ attr_writer :attributes
21
+ def attributes
22
+ @attributes ||= []
23
+ end
24
+
25
+ def generate(options={}, overrides={}, &block)
26
+ attributes = merge(overrides, &block).attributes
27
+ generator.new(klass).generate(options, attributes)
28
+ end
29
+
11
30
  def initialize_copy(original)
12
31
  self.attributes = original.attributes.map do |a|
13
32
  Attribute.new(a.name, a.params, a.value)
14
33
  end
15
34
  end
16
35
 
17
- def merge(options, &block)
36
+ def merge(overrides={}, &block)
18
37
  clone.tap do |schematic|
19
38
  schematic.instance_eval(&block) if block_given?
20
- options.each do |name, value|
39
+ overrides.each do |name, value|
21
40
  if attribute = schematic.attribute(name)
22
41
  attribute.params = nil
23
42
  attribute.value = value
@@ -28,11 +47,6 @@ class Fabrication::Schematic
28
47
  end
29
48
  end
30
49
 
31
- def merge!(&block)
32
- instance_eval(&block)
33
- self
34
- end
35
-
36
50
  def method_missing(method_name, *args, &block)
37
51
  method_name = parse_method_name(method_name, args)
38
52
  if (attr = attribute(method_name))
@@ -71,9 +85,4 @@ class Fabrication::Schematic
71
85
  end
72
86
  end
73
87
 
74
- attr_writer :attributes
75
- def attributes
76
- @attributes ||= []
77
- end
78
-
79
88
  end
@@ -0,0 +1,19 @@
1
+ class Fabrication::Sequencer
2
+
3
+ class << self
4
+
5
+ def sequence(name, start=0)
6
+ idx = sequences[name] ||= start
7
+
8
+ (block_given? ? yield(idx) : idx).tap do
9
+ sequences[name] += 1
10
+ end
11
+ end
12
+
13
+ def sequences
14
+ @@sequences ||= {}
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -3,7 +3,7 @@ class Fabrication::Support
3
3
  class << self
4
4
 
5
5
  def fabricatable?(name)
6
- Fabrication.fabricators.has_key?(name) || class_for(name)
6
+ Fabrication::Fabricator.schematics.include?(name) || class_for(name)
7
7
  end
8
8
 
9
9
  def class_for(class_or_to_s)
@@ -22,6 +22,18 @@ class Fabrication::Support
22
22
  name.to_s.gsub(/\/(.?)/){"::#{$1.upcase}"}.gsub(/(?:^|_)(.)/){$1.upcase}
23
23
  end
24
24
 
25
+ def find_definitions
26
+ ['test', 'spec'].map do |folder|
27
+ path = File.expand_path(File.join(folder, 'fabricators'))
28
+
29
+ require("#{path}.rb") if File.exists?("#{path}.rb")
30
+
31
+ File.directory? path and Dir[File.join(path, '*.rb')].each do |file|
32
+ require file
33
+ end
34
+ end
35
+ end
36
+
25
37
  end
26
38
 
27
39
  end
@@ -1,3 +1,3 @@
1
1
  module Fabrication
2
- VERSION = '0.6.0'
2
+ VERSION = '0.6.2'
3
3
  end
@@ -4,30 +4,16 @@ describe Fabrication do
4
4
 
5
5
  context 'static fields' do
6
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
7
+ let(:person) { Fabricate(:person, :last_name => 'Awesome') }
18
8
 
19
9
  it 'has the default first name' do
20
- person.first_name.should == 'Joe'
10
+ person.first_name.should == 'John'
21
11
  end
22
12
 
23
13
  it 'has an overridden last name' do
24
14
  person.last_name.should == 'Awesome'
25
15
  end
26
16
 
27
- it 'has the default age' do
28
- person.age.should == 78
29
- end
30
-
31
17
  it 'generates a fresh object every time' do
32
18
  Fabricate(:person).should_not == person
33
19
  end
@@ -36,22 +22,7 @@ describe Fabrication do
36
22
 
37
23
  context 'block generated fields' do
38
24
 
39
- let(:person) do
40
- Fabricate(:person)
41
- end
42
-
43
- before(:all) do
44
- Fabricator(:person) do
45
- first_name { Faker::Name.first_name }
46
- last_name { Faker::Name.last_name }
47
- age { rand(100) }
48
- shoes(:count => 10) { |person, i| "shoe #{i}" }
49
- end
50
- end
51
-
52
- it 'has a first name' do
53
- person.first_name.should be
54
- end
25
+ let(:person) { Fabricate(:person) }
55
26
 
56
27
  it 'has a last name' do
57
28
  person.last_name.should be
@@ -69,16 +40,13 @@ describe Fabrication do
69
40
 
70
41
  context 'with the generation parameter' do
71
42
 
72
- before(:all) do
73
- Fabricator(:person) do
43
+ let(:person) do
44
+ Fabricate(:person) do
74
45
  first_name "Paul"
75
46
  last_name { |person| "#{person.first_name}#{person.age}" }
76
- age 60
77
47
  end
78
48
  end
79
49
 
80
- let(:person) { Fabricate(:person) }
81
-
82
50
  it 'evaluates the fields in order of declaration' do
83
51
  person.last_name.should == "Paul"
84
52
  end
@@ -90,14 +58,6 @@ describe Fabrication do
90
58
  let(:person1) { Fabricate(:person, :first_name => 'Jane') }
91
59
  let(:person2) { Fabricate(:person, :first_name => 'John') }
92
60
 
93
- before(:all) do
94
- Fabricator(:person) do
95
- first_name { Faker::Name.first_name }
96
- last_name { Faker::Name.last_name }
97
- age { rand(100) }
98
- end
99
- end
100
-
101
61
  it 'person1 is named Jane' do
102
62
  person1.first_name.should == 'Jane'
103
63
  end
@@ -130,6 +90,9 @@ describe Fabrication do
130
90
 
131
91
  context 'with an active record object' do
132
92
 
93
+ before { TestMigration.up }
94
+ after { TestMigration.down }
95
+
133
96
  before(:all) do
134
97
  Fabricator(:company) do
135
98
  name { Faker::Company.name }
@@ -140,15 +103,8 @@ describe Fabrication do
140
103
  Fabricator(:other_company, :from => :company) do
141
104
  divisions(:count => 2) { Fabricate(:division) }
142
105
  end
143
-
144
- Fabricator(:division) do
145
- name "Awesome Division"
146
- end
147
106
  end
148
107
 
149
- before { TestMigration.up }
150
- after { TestMigration.down }
151
-
152
108
  let(:company) { Fabricate(:company, :name => "Hashrocket") }
153
109
 
154
110
  it 'generates field blocks immediately' do
@@ -176,19 +132,6 @@ describe Fabrication do
176
132
 
177
133
  context 'with a mongoid document' do
178
134
 
179
- before(:all) do
180
- Fabricator(:author) do
181
- name "George Orwell"
182
- books(:count => 4) do |author, i|
183
- Fabricate(:book, :title => "book title #{i}", :author => author)
184
- end
185
- end
186
-
187
- Fabricator(:book) do
188
- title "1984"
189
- end
190
- end
191
-
192
135
  let(:author) { Fabricate(:author) }
193
136
 
194
137
  it "sets the author name" do
@@ -206,20 +149,8 @@ describe Fabrication do
206
149
 
207
150
  let(:ernie) { Fabricate(:hemingway) }
208
151
 
209
- before(:all) do
210
- Fabricator(:book)
211
- Fabricator(:author) do
212
- name 'George Orwell'
213
- books { |author| [Fabricate(:book, :title => '1984', :author => author)] }
214
- end
215
-
216
- Fabricator(:hemingway, :from => :author) do
217
- name 'Ernest Hemingway'
218
- end
219
- end
220
-
221
152
  it 'has the values from the parent' do
222
- ernie.books.map(&:title).should == ['1984']
153
+ ernie.books.count.should == 4
223
154
  end
224
155
 
225
156
  it 'overrides specified values from the parent' do
@@ -230,20 +161,14 @@ describe Fabrication do
230
161
 
231
162
  context 'and a class name as a parent' do
232
163
 
233
- before(:all) do
234
- Fabricator(:hemingway, :from => :author) do
235
- name 'Ernest Hemingway'
236
- end
237
- end
164
+ let(:greyhound) { Fabricate(:greyhound) }
238
165
 
239
- let(:ernie) { Fabricate(:hemingway) }
240
-
241
- it 'has the name defined' do
242
- ernie.name.should == 'Ernest Hemingway'
166
+ it 'has the breed defined' do
167
+ greyhound.breed.should == 'greyhound'
243
168
  end
244
169
 
245
- it 'not have any books' do
246
- ernie.books.should == []
170
+ it 'does not have a name' do
171
+ greyhound.name.should be_nil
247
172
  end
248
173
 
249
174
  end
@@ -253,12 +178,15 @@ describe Fabrication do
253
178
  describe '.clear_definitions' do
254
179
 
255
180
  before(:all) do
256
- Fabricator(:author) {}
257
181
  Fabrication.clear_definitions
258
182
  end
259
183
 
184
+ after(:all) do
185
+ Fabrication::Support.find_definitions
186
+ end
187
+
260
188
  it 'should not generate authors' do
261
- Fabrication.fabricators.has_key?(:author).should be_false
189
+ Fabrication::Fabricator.schematics.has_key?(:author).should be_false
262
190
  end
263
191
 
264
192
  end
@@ -278,17 +206,20 @@ describe Fabrication do
278
206
  context 'when generating from a non-existant fabricator' do
279
207
 
280
208
  it 'throws an error' do
281
- lambda { Fabricate(:your_mom) }.should raise_error(Fabrication::UnknownFabricatorError)
209
+ lambda { Fabricate(:your_mom) }.should raise_error(Fabrication::UnfabricatableError)
282
210
  end
283
211
 
284
212
  end
285
213
 
286
214
  context 'defining a fabricator without a block' do
287
215
 
288
- before(:all) { Fabricator(:author) }
216
+ before(:all) do
217
+ class Widget; end
218
+ Fabricator(:widget)
219
+ end
289
220
 
290
221
  it 'works fine' do
291
- Fabricate(:author).should be
222
+ Fabricate(:widget).should be
292
223
  end
293
224
 
294
225
  end
@@ -298,10 +229,17 @@ describe Fabrication do
298
229
  let(:author) { Fabricator(:author) }
299
230
  let(:book) { Fabricator(:book) }
300
231
 
301
- before(:all) { author; book }
232
+ before(:all) do
233
+ Fabrication.clear_definitions
234
+ author; book
235
+ end
236
+
237
+ after(:all) do
238
+ Fabrication::Support.find_definitions
239
+ end
302
240
 
303
241
  it "returns the two fabricators" do
304
- Fabrication.fabricators.should == {:author => author, :book => book}
242
+ Fabrication::Fabricator.schematics.should == {:author => author, :book => book}
305
243
  end
306
244
 
307
245
  end
@@ -335,21 +273,16 @@ describe Fabrication do
335
273
 
336
274
  describe "Fabricate.attributes_for" do
337
275
 
338
- before(:all) do
339
- Fabricator(:person) do
340
- first_name "Paul"
341
- last_name { "Elliott" }
342
- end
276
+ let(:person) do
277
+ Fabricate.attributes_for(:person, :first_name => "John", :last_name => "Smith")
343
278
  end
344
279
 
345
- let(:person) { Fabricate.attributes_for(:person) }
346
-
347
280
  it 'has the first name as a parameter' do
348
- person['first_name'].should == "Paul"
281
+ person['first_name'].should == "John"
349
282
  end
350
283
 
351
284
  it 'has the last name as a parameter' do
352
- person[:last_name].should == "Elliott"
285
+ person[:last_name].should == "Smith"
353
286
  end
354
287
 
355
288
  end