jeffrafter-factory_girl 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/CONTRIBUTION_GUIDELINES.rdoc +9 -0
  2. data/Changelog +29 -0
  3. data/LICENSE +19 -0
  4. data/README.rdoc +265 -0
  5. data/Rakefile +81 -0
  6. data/lib/factory_girl.rb +35 -0
  7. data/lib/factory_girl/aliases.rb +50 -0
  8. data/lib/factory_girl/attribute.rb +29 -0
  9. data/lib/factory_girl/attribute/association.rb +20 -0
  10. data/lib/factory_girl/attribute/callback.rb +16 -0
  11. data/lib/factory_girl/attribute/dynamic.rb +20 -0
  12. data/lib/factory_girl/attribute/static.rb +17 -0
  13. data/lib/factory_girl/factory.rb +430 -0
  14. data/lib/factory_girl/proxy.rb +79 -0
  15. data/lib/factory_girl/proxy/attributes_for.rb +21 -0
  16. data/lib/factory_girl/proxy/build.rb +30 -0
  17. data/lib/factory_girl/proxy/create.rb +12 -0
  18. data/lib/factory_girl/proxy/stub.rb +50 -0
  19. data/lib/factory_girl/sequence.rb +63 -0
  20. data/lib/factory_girl/step_definitions.rb +54 -0
  21. data/lib/factory_girl/syntax.rb +12 -0
  22. data/lib/factory_girl/syntax/blueprint.rb +42 -0
  23. data/lib/factory_girl/syntax/generate.rb +68 -0
  24. data/lib/factory_girl/syntax/make.rb +39 -0
  25. data/lib/factory_girl/syntax/sham.rb +42 -0
  26. data/spec/factory_girl/aliases_spec.rb +29 -0
  27. data/spec/factory_girl/attribute/association_spec.rb +29 -0
  28. data/spec/factory_girl/attribute/callback_spec.rb +23 -0
  29. data/spec/factory_girl/attribute/dynamic_spec.rb +49 -0
  30. data/spec/factory_girl/attribute/static_spec.rb +29 -0
  31. data/spec/factory_girl/attribute_spec.rb +30 -0
  32. data/spec/factory_girl/factory_spec.rb +605 -0
  33. data/spec/factory_girl/proxy/attributes_for_spec.rb +52 -0
  34. data/spec/factory_girl/proxy/build_spec.rb +81 -0
  35. data/spec/factory_girl/proxy/create_spec.rb +94 -0
  36. data/spec/factory_girl/proxy/stub_spec.rb +79 -0
  37. data/spec/factory_girl/proxy_spec.rb +84 -0
  38. data/spec/factory_girl/sequence_spec.rb +66 -0
  39. data/spec/factory_girl/syntax/blueprint_spec.rb +34 -0
  40. data/spec/factory_girl/syntax/generate_spec.rb +57 -0
  41. data/spec/factory_girl/syntax/make_spec.rb +35 -0
  42. data/spec/factory_girl/syntax/sham_spec.rb +35 -0
  43. data/spec/integration_spec.rb +304 -0
  44. data/spec/models.rb +43 -0
  45. data/spec/spec_helper.rb +18 -0
  46. metadata +128 -0
@@ -0,0 +1,79 @@
1
+ class Factory
2
+
3
+ class Proxy #:nodoc:
4
+
5
+ attr_reader :callbacks
6
+
7
+ def initialize(klass, args=[])
8
+ end
9
+
10
+ def get(attribute)
11
+ nil
12
+ end
13
+
14
+ def set(attribute, value)
15
+ end
16
+
17
+ def associate(name, factory, attributes)
18
+ end
19
+
20
+ def add_callback(name, block)
21
+ @callbacks ||= {}
22
+ @callbacks[name] ||= []
23
+ @callbacks[name] << block
24
+ end
25
+
26
+ def run_callbacks(name)
27
+ if @callbacks && @callbacks[name]
28
+ @callbacks[name].each do |block|
29
+ block.arity.zero? ? block.call : block.call(@instance)
30
+ end
31
+ end
32
+ end
33
+
34
+ # Generates an association using the current build strategy.
35
+ #
36
+ # Arguments:
37
+ # name: (Symbol)
38
+ # The name of the factory that should be used to generate this
39
+ # association.
40
+ # attributes: (Hash)
41
+ # A hash of attributes that should be overridden for this association.
42
+ #
43
+ # Returns:
44
+ # The generated association for the current build strategy. Note that
45
+ # assocaitions are not generated for the attributes_for strategy. Returns
46
+ # nil in this case.
47
+ #
48
+ # Example:
49
+ #
50
+ # Factory.define :user do |f|
51
+ # # ...
52
+ # end
53
+ #
54
+ # Factory.define :post do |f|
55
+ # # ...
56
+ # f.author {|a| a.association :user, :name => 'Joe' }
57
+ # end
58
+ #
59
+ # # Builds (but doesn't save) a Post and a User
60
+ # Factory.build(:post)
61
+ #
62
+ # # Builds and saves a User, builds a Post, assigns the User to the
63
+ # # author association, and saves the User.
64
+ # Factory.create(:post)
65
+ #
66
+ def association(name, overrides = {})
67
+ nil
68
+ end
69
+
70
+ def method_missing(method, *args, &block)
71
+ get(method)
72
+ end
73
+
74
+ def result
75
+ raise NotImplementedError, "Strategies must return a result"
76
+ end
77
+ end
78
+
79
+ end
@@ -0,0 +1,21 @@
1
+ class Factory
2
+ class Proxy #:nodoc:
3
+ class AttributesFor < Proxy #:nodoc:
4
+ def initialize(klass, args = [])
5
+ @hash = (args.size == 1 && args[0].is_a?(Hash) ? args[0] : {})
6
+ end
7
+
8
+ def get(attribute)
9
+ @hash[attribute]
10
+ end
11
+
12
+ def set(attribute, value)
13
+ @hash[attribute] = value
14
+ end
15
+
16
+ def result
17
+ @hash
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ class Factory
2
+ class Proxy #:nodoc:
3
+ class Build < Proxy #:nodoc:
4
+ def initialize(klass, args = [])
5
+ @instance = klass.new(*args)
6
+ end
7
+
8
+ def get(attribute)
9
+ @instance.send(attribute)
10
+ end
11
+
12
+ def set(attribute, value)
13
+ @instance.send(:"#{attribute}=", value)
14
+ end
15
+
16
+ def associate(name, factory, attributes)
17
+ set(name, Factory.create(factory, attributes))
18
+ end
19
+
20
+ def association(factory, overrides = {})
21
+ Factory.create(factory, overrides)
22
+ end
23
+
24
+ def result
25
+ run_callbacks(:after_build)
26
+ @instance
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ class Factory
2
+ class Proxy #:nodoc:
3
+ class Create < Build #:nodoc:
4
+ def result
5
+ run_callbacks(:after_build)
6
+ @instance.save!
7
+ run_callbacks(:after_create)
8
+ @instance
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,50 @@
1
+ class Factory
2
+ class Proxy
3
+ class Stub < Proxy #:nodoc:
4
+ @@next_id = 1000
5
+
6
+ def initialize(klass, args = [])
7
+ @instance = klass.new(*args)
8
+ @instance.id = next_id
9
+ @instance.instance_eval do
10
+ def new_record?
11
+ id.nil?
12
+ end
13
+
14
+ def connection
15
+ raise "stubbed models are not allowed to access the database"
16
+ end
17
+
18
+ def reload
19
+ raise "stubbed models are not allowed to access the database"
20
+ end
21
+ end
22
+ end
23
+
24
+ def next_id
25
+ @@next_id += 1
26
+ end
27
+
28
+ def get(attribute)
29
+ @instance.send(attribute)
30
+ end
31
+
32
+ def set(attribute, value)
33
+ @instance.send(:"#{attribute}=", value)
34
+ end
35
+
36
+ def associate(name, factory, attributes)
37
+ set(name, Factory.stub(factory, attributes))
38
+ end
39
+
40
+ def association(factory, overrides = {})
41
+ Factory.stub(factory, overrides)
42
+ end
43
+
44
+ def result
45
+ run_callbacks(:after_stub)
46
+ @instance
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,63 @@
1
+ class Factory
2
+
3
+ # Raised when calling Factory.sequence from a dynamic attribute block
4
+ class SequenceAbuseError < StandardError; end
5
+
6
+ # Sequences are defined using Factory.sequence. Sequence values are generated
7
+ # using next.
8
+ class Sequence
9
+
10
+ def initialize (&proc) #:nodoc:
11
+ @proc = proc
12
+ @value = 0
13
+ end
14
+
15
+ # Returns the next value for this sequence
16
+ def next
17
+ @value += 1
18
+ @proc.call(@value)
19
+ end
20
+
21
+ end
22
+
23
+ class << self
24
+ attr_accessor :sequences #:nodoc:
25
+ end
26
+ self.sequences = {}
27
+
28
+ # Defines a new sequence that can be used to generate unique values in a specific format.
29
+ #
30
+ # Arguments:
31
+ # name: (Symbol)
32
+ # A unique name for this sequence. This name will be referenced when
33
+ # calling next to generate new values from this sequence.
34
+ # block: (Proc)
35
+ # The code to generate each value in the sequence. This block will be
36
+ # called with a unique number each time a value in the sequence is to be
37
+ # generated. The block should return the generated value for the
38
+ # sequence.
39
+ #
40
+ # Example:
41
+ #
42
+ # Factory.sequence(:email) {|n| "somebody_#{n}@example.com" }
43
+ def self.sequence (name, &block)
44
+ self.sequences[name] = Sequence.new(&block)
45
+ end
46
+
47
+ # Generates and returns the next value in a sequence.
48
+ #
49
+ # Arguments:
50
+ # name: (Symbol)
51
+ # The name of the sequence that a value should be generated for.
52
+ #
53
+ # Returns:
54
+ # The next value in the sequence. (Object)
55
+ def self.next (sequence)
56
+ unless self.sequences.key?(sequence)
57
+ raise "No such sequence: #{sequence}"
58
+ end
59
+
60
+ self.sequences[sequence].next
61
+ end
62
+
63
+ end
@@ -0,0 +1,54 @@
1
+ module FactoryGirlStepHelpers
2
+ def convert_association_string_to_instance(factory_name, assignment)
3
+ attribute, value = assignment.split(':', 2)
4
+ attributes = convert_human_hash_to_attribute_hash(attribute => value.strip)
5
+ factory = Factory.factory_by_name(factory_name)
6
+ model_class = factory.build_class
7
+ model_class.find(:first, :conditions => attributes) or
8
+ Factory(factory_name, attributes)
9
+ end
10
+
11
+ def convert_human_hash_to_attribute_hash(human_hash, associations = [])
12
+ human_hash.inject({}) do |attribute_hash, (human_key, value)|
13
+ key = human_key.downcase.gsub(' ', '_').to_sym
14
+ if association = associations.detect {|association| association.name == key }
15
+ value = convert_association_string_to_instance(association.factory, value)
16
+ end
17
+ attribute_hash.merge(key => value)
18
+ end
19
+ end
20
+ end
21
+
22
+ World(FactoryGirlStepHelpers)
23
+
24
+ Factory.factories.values.each do |factory|
25
+ # TODO: support irregular pluralizations
26
+ Given /^the following #{factory.human_name}s? exists?:$/ do |table|
27
+ table.hashes.each do |human_hash|
28
+ attributes = convert_human_hash_to_attribute_hash(human_hash, factory.associations)
29
+ Factory.create(factory.factory_name, attributes)
30
+ end
31
+ end
32
+
33
+ Given /^an? #{factory.human_name} exists$/ do
34
+ Factory(factory.factory_name)
35
+ end
36
+
37
+ Given /^(\d+) #{factory.human_name}s exist$/ do |count|
38
+ count.to_i.times { Factory(factory.human_name) }
39
+ end
40
+
41
+ if factory.build_class.respond_to?(:columns)
42
+ factory.build_class.columns.each do |column|
43
+ human_column_name = column.name.downcase.gsub('_', ' ')
44
+ Given /^an? #{factory.human_name} exists with an? #{human_column_name} of "([^"]*)"$/i do |value|
45
+ Factory(factory.factory_name, column.name => value)
46
+ end
47
+
48
+ Given /^(\d+) #{factory.human_name}s exist with an? #{human_column_name} of "([^"]*)"$/i do |count, value|
49
+ count.to_i.times { Factory(factory.factory_name, column.name => value) }
50
+ end
51
+ end
52
+ end
53
+ end
54
+
@@ -0,0 +1,12 @@
1
+ class Factory
2
+ # Provides alternate syntaxes for factory_girl. If you don't like the default
3
+ # syntax for defining or using factories, look at one of the Factory::Syntax
4
+ # modules:
5
+ #
6
+ # * Factory::Syntax::Blueprint: definition syntax similar to Machinist
7
+ # * Factory::Syntax::Generate: usage syntax similar to Object Daddy
8
+ # * Factory::Syntax::Make: usage syntax similar to Machinist
9
+ # * Factory::Syntax::Sham: sequence syntax similar to Machinist
10
+ module Syntax
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ class Factory
2
+ module Syntax
3
+
4
+ # Extends ActiveRecord::Base to provide a make class method, which is an
5
+ # alternate syntax for defining factories.
6
+ #
7
+ # Usage:
8
+ #
9
+ # require 'factory_girl/syntax/blueprint'
10
+ #
11
+ # User.blueprint do
12
+ # name { 'Billy Bob' }
13
+ # email { 'billy@bob.example.com' }
14
+ # end
15
+ #
16
+ # Factory(:user, :name => 'Johnny')
17
+ #
18
+ # This syntax was derived from Pete Yandell's machinist.
19
+ module Blueprint
20
+ module ActiveRecord #:nodoc:
21
+
22
+ def self.included(base) # :nodoc:
23
+ base.extend ClassMethods
24
+ end
25
+
26
+ module ClassMethods #:nodoc:
27
+
28
+ def blueprint(&block)
29
+ instance = Factory.new(name.underscore, :class => self)
30
+ instance.instance_eval(&block)
31
+ Factory.factories[instance.factory_name] = instance
32
+ end
33
+
34
+ end
35
+
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ ActiveRecord::Base.send(:include, Factory::Syntax::Blueprint::ActiveRecord)
42
+
@@ -0,0 +1,68 @@
1
+ class Factory
2
+ module Syntax
3
+
4
+ # Extends ActiveRecord::Base to provide generation methods for factories.
5
+ #
6
+ # Usage:
7
+ #
8
+ # require 'factory_girl/syntax/generate'
9
+ #
10
+ # Factory.define :user do |factory|
11
+ # factory.name 'Billy Bob'
12
+ # factory.email 'billy@bob.example.com'
13
+ # end
14
+ #
15
+ # # Creates a saved instance without raising (same as saving the result
16
+ # # of Factory.build)
17
+ # User.generate(:name => 'Johnny')
18
+ #
19
+ # # Creates a saved instance and raises when invalid (same as
20
+ # # Factory.create)
21
+ # User.generate!
22
+ #
23
+ # # Creates an unsaved instance (same as Factory.build)
24
+ # User.spawn
25
+ #
26
+ # # Creates an instance and yields it to the passed block
27
+ # User.generate do |user|
28
+ # # ...do something with user...
29
+ # end
30
+ #
31
+ # This syntax was derived from Rick Bradley and Yossef Mendelssohn's
32
+ # object_daddy.
33
+ module Generate
34
+ module ActiveRecord #:nodoc:
35
+
36
+ def self.included(base) # :nodoc:
37
+ base.extend ClassMethods
38
+ end
39
+
40
+ module ClassMethods #:nodoc:
41
+
42
+ def generate(overrides = {}, &block)
43
+ instance = Factory.build(name.underscore, overrides)
44
+ instance.save
45
+ yield(instance) if block_given?
46
+ instance
47
+ end
48
+
49
+ def generate!(overrides = {}, &block)
50
+ instance = Factory.create(name.underscore, overrides)
51
+ yield(instance) if block_given?
52
+ instance
53
+ end
54
+
55
+ def spawn(overrides = {}, &block)
56
+ instance = Factory.build(name.underscore, overrides)
57
+ yield(instance) if block_given?
58
+ instance
59
+ end
60
+
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
67
+
68
+ ActiveRecord::Base.send(:include, Factory::Syntax::Generate::ActiveRecord)