factory_girl_kibiz0r 2.0.0.beta2

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.
Files changed (83) hide show
  1. data/Appraisals +12 -0
  2. data/CONTRIBUTION_GUIDELINES.md +9 -0
  3. data/Changelog +29 -0
  4. data/GETTING_STARTED.md +246 -0
  5. data/Gemfile +12 -0
  6. data/Gemfile.lock +62 -0
  7. data/LICENSE +19 -0
  8. data/README.md +64 -0
  9. data/Rakefile +54 -0
  10. data/features/factory_girl_steps.feature +151 -0
  11. data/features/step_definitions/database_steps.rb +20 -0
  12. data/features/support/env.rb +6 -0
  13. data/features/support/factories.rb +84 -0
  14. data/lib/factory_girl/aliases.rb +21 -0
  15. data/lib/factory_girl/attribute/association.rb +24 -0
  16. data/lib/factory_girl/attribute/callback.rb +16 -0
  17. data/lib/factory_girl/attribute/dynamic.rb +21 -0
  18. data/lib/factory_girl/attribute/implicit.rb +36 -0
  19. data/lib/factory_girl/attribute/list.rb +19 -0
  20. data/lib/factory_girl/attribute/sequence.rb +16 -0
  21. data/lib/factory_girl/attribute/static.rb +18 -0
  22. data/lib/factory_girl/attribute.rb +42 -0
  23. data/lib/factory_girl/definition_proxy.rb +147 -0
  24. data/lib/factory_girl/deprecated.rb +18 -0
  25. data/lib/factory_girl/factory.rb +196 -0
  26. data/lib/factory_girl/find_definitions.rb +23 -0
  27. data/lib/factory_girl/proxy/attributes_for.rb +21 -0
  28. data/lib/factory_girl/proxy/build.rb +36 -0
  29. data/lib/factory_girl/proxy/create.rb +16 -0
  30. data/lib/factory_girl/proxy/stub.rb +64 -0
  31. data/lib/factory_girl/proxy.rb +87 -0
  32. data/lib/factory_girl/rails2.rb +1 -0
  33. data/lib/factory_girl/registry.rb +45 -0
  34. data/lib/factory_girl/sequence.rb +31 -0
  35. data/lib/factory_girl/step_definitions.rb +60 -0
  36. data/lib/factory_girl/syntax/blueprint.rb +42 -0
  37. data/lib/factory_girl/syntax/default.rb +33 -0
  38. data/lib/factory_girl/syntax/generate.rb +73 -0
  39. data/lib/factory_girl/syntax/make.rb +41 -0
  40. data/lib/factory_girl/syntax/methods.rb +86 -0
  41. data/lib/factory_girl/syntax/sham.rb +45 -0
  42. data/lib/factory_girl/syntax/vintage.rb +152 -0
  43. data/lib/factory_girl/syntax.rb +12 -0
  44. data/lib/factory_girl/version.rb +4 -0
  45. data/lib/factory_girl.rb +54 -0
  46. data/spec/acceptance/acceptance_helper.rb +11 -0
  47. data/spec/acceptance/attribute_aliases_spec.rb +26 -0
  48. data/spec/acceptance/attributes_for_spec.rb +48 -0
  49. data/spec/acceptance/build_spec.rb +35 -0
  50. data/spec/acceptance/build_stubbed_spec.rb +79 -0
  51. data/spec/acceptance/callbacks_spec.rb +53 -0
  52. data/spec/acceptance/create_spec.rb +67 -0
  53. data/spec/acceptance/default_strategy_spec.rb +27 -0
  54. data/spec/acceptance/definition_spec.rb +28 -0
  55. data/spec/acceptance/parent_spec.rb +39 -0
  56. data/spec/acceptance/sequence_spec.rb +34 -0
  57. data/spec/acceptance/syntax/blueprint_spec.rb +32 -0
  58. data/spec/acceptance/syntax/generate_spec.rb +60 -0
  59. data/spec/acceptance/syntax/make_spec.rb +35 -0
  60. data/spec/acceptance/syntax/sham_spec.rb +44 -0
  61. data/spec/acceptance/syntax/vintage_spec.rb +224 -0
  62. data/spec/factory_girl/aliases_spec.rb +33 -0
  63. data/spec/factory_girl/attribute/association_spec.rb +33 -0
  64. data/spec/factory_girl/attribute/callback_spec.rb +23 -0
  65. data/spec/factory_girl/attribute/dynamic_spec.rb +60 -0
  66. data/spec/factory_girl/attribute/implicit_spec.rb +50 -0
  67. data/spec/factory_girl/attribute/sequence_spec.rb +21 -0
  68. data/spec/factory_girl/attribute/static_spec.rb +29 -0
  69. data/spec/factory_girl/attribute_spec.rb +39 -0
  70. data/spec/factory_girl/definition_proxy_spec.rb +129 -0
  71. data/spec/factory_girl/deprecated_spec.rb +66 -0
  72. data/spec/factory_girl/factory_spec.rb +374 -0
  73. data/spec/factory_girl/find_definitions_spec.rb +100 -0
  74. data/spec/factory_girl/proxy/attributes_for_spec.rb +52 -0
  75. data/spec/factory_girl/proxy/build_spec.rb +86 -0
  76. data/spec/factory_girl/proxy/create_spec.rb +107 -0
  77. data/spec/factory_girl/proxy/stub_spec.rb +80 -0
  78. data/spec/factory_girl/proxy_spec.rb +102 -0
  79. data/spec/factory_girl/registry_spec.rb +83 -0
  80. data/spec/factory_girl/sequence_spec.rb +96 -0
  81. data/spec/factory_girl_spec.rb +17 -0
  82. data/spec/spec_helper.rb +93 -0
  83. metadata +294 -0
@@ -0,0 +1,84 @@
1
+ ActiveRecord::Base.establish_connection(
2
+ :adapter => 'sqlite3',
3
+ :database => File.join(File.dirname(__FILE__), 'test.db')
4
+ )
5
+
6
+ class CreateSchema < ActiveRecord::Migration
7
+ def self.up
8
+ create_table :posts, :force => true do |t|
9
+ t.integer :author_id
10
+ t.integer :category_id
11
+ t.string :title
12
+ t.string :body
13
+ end
14
+
15
+ create_table :category_groups, :force => true do |t|
16
+ t.string :name
17
+ end
18
+
19
+ create_table :categories, :force => true do |t|
20
+ t.integer :category_group_id
21
+ t.string :name
22
+ end
23
+
24
+ create_table :users, :force => true do |t|
25
+ t.string :name
26
+ t.boolean :admin, :default => false, :null => false
27
+ end
28
+ end
29
+ end
30
+
31
+ CreateSchema.suppress_messages { CreateSchema.migrate(:up) }
32
+
33
+ class User < ActiveRecord::Base
34
+ end
35
+
36
+ class CategoryGroup < ActiveRecord::Base
37
+ end
38
+
39
+ class Category < ActiveRecord::Base
40
+ belongs_to :category_group
41
+ end
42
+
43
+ class Post < ActiveRecord::Base
44
+ belongs_to :author, :class_name => 'User'
45
+ belongs_to :category
46
+ end
47
+
48
+ class NonActiveRecord
49
+ end
50
+
51
+ FactoryGirl.define do
52
+ # To make sure the step defs work with an email
53
+ sequence :email do |n|
54
+ "email#{n}@example.com"
55
+ end
56
+
57
+ factory :user do
58
+ end
59
+
60
+ factory :admin_user, :parent => :user do
61
+ admin true
62
+ end
63
+
64
+ factory :category do
65
+ name "programming"
66
+ category_group
67
+ end
68
+
69
+ factory :category_group do
70
+ name "tecnhology"
71
+ end
72
+
73
+ factory :post do
74
+ association :author, :factory => :user
75
+ category
76
+ end
77
+
78
+ # This is here to ensure that factory step definitions don't raise for a non-AR factory
79
+ factory :non_active_record do
80
+ end
81
+ end
82
+
83
+ require 'factory_girl/step_definitions'
84
+
@@ -0,0 +1,21 @@
1
+ module FactoryGirl
2
+
3
+ class << self
4
+ attr_accessor :aliases #:nodoc:
5
+ end
6
+ self.aliases = [
7
+ [/(.+)_id/, '\1'],
8
+ [/(.*)/, '\1_id']
9
+ ]
10
+
11
+ def self.aliases_for(attribute) #:nodoc:
12
+ aliases.collect do |params|
13
+ pattern, replace = *params
14
+ if pattern.match(attribute.to_s)
15
+ attribute.to_s.sub(pattern, replace).to_sym
16
+ else
17
+ nil
18
+ end
19
+ end.compact << attribute
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module FactoryGirl
2
+ class Attribute #:nodoc:
3
+
4
+ class Association < Attribute #:nodoc:
5
+
6
+ attr_reader :factory
7
+
8
+ def initialize(name, factory, overrides)
9
+ super(name)
10
+ @factory = factory
11
+ @overrides = overrides
12
+ end
13
+
14
+ def add_to(proxy)
15
+ proxy.associate(name, @factory, @overrides)
16
+ end
17
+
18
+ def association?
19
+ true
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ module FactoryGirl
2
+ class Attribute #:nodoc:
3
+
4
+ class Callback < Attribute #:nodoc:
5
+ def initialize(name, block)
6
+ @name = name.to_sym
7
+ @block = block
8
+ end
9
+
10
+ def add_to(proxy)
11
+ proxy.add_callback(name, @block)
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module FactoryGirl
2
+ class Attribute #:nodoc:
3
+
4
+ class Dynamic < Attribute #:nodoc:
5
+ def initialize(name, block)
6
+ super(name)
7
+ @block = block
8
+ end
9
+
10
+ def add_to(proxy)
11
+ value = @block.arity == 1 ? @block.call(proxy) : proxy.instance_exec(&@block)
12
+ if FactoryGirl::Sequence === value
13
+ raise SequenceAbuseError
14
+ end
15
+ method = !ignored? ? :set : :ignore
16
+ proxy.send(method, name, value)
17
+ end
18
+ end
19
+
20
+ end
21
+ end
@@ -0,0 +1,36 @@
1
+ module FactoryGirl
2
+ class Attribute
3
+
4
+ class Implicit < Attribute
5
+ def initialize(name)
6
+ super(name)
7
+ end
8
+
9
+ def add_to(proxy)
10
+ implementation.add_to(proxy)
11
+ end
12
+
13
+ def association?
14
+ implementation.association?
15
+ end
16
+
17
+ def factory
18
+ name
19
+ end
20
+
21
+ private
22
+
23
+ def implementation
24
+ @implementation ||= resolve_name
25
+ end
26
+
27
+ def resolve_name
28
+ if FactoryGirl.factories.registered?(name)
29
+ Attribute::Association.new(name, name, {})
30
+ else
31
+ Attribute::Sequence.new(name, name)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ module FactoryGirl
2
+
3
+ class Attribute
4
+
5
+ class List < Array
6
+
7
+ def method_missing(method, *args, &block)
8
+ if empty?
9
+ super
10
+ else
11
+ last.send(method, *args, &block)
12
+ end
13
+ end
14
+
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,16 @@
1
+ module FactoryGirl
2
+ class Attribute
3
+
4
+ class Sequence < Attribute
5
+ def initialize(name, sequence)
6
+ super(name)
7
+ @sequence = sequence
8
+ end
9
+
10
+ def add_to(proxy)
11
+ proxy.set(name, FactoryGirl.generate(@sequence))
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module FactoryGirl
2
+ class Attribute #:nodoc:
3
+
4
+ class Static < Attribute #:nodoc:
5
+
6
+ def initialize(name, value)
7
+ super(name)
8
+ @value = value
9
+ end
10
+
11
+ def add_to(proxy)
12
+ method = !ignored? ? :set : :ignore
13
+ proxy.send(method, name, @value)
14
+ end
15
+ end
16
+
17
+ end
18
+ end
@@ -0,0 +1,42 @@
1
+ module FactoryGirl
2
+
3
+ # Raised when defining an invalid attribute:
4
+ # * Defining an attribute which has a name ending in "="
5
+ # * Defining an attribute with both a static and lazy value
6
+ # * Defining an attribute twice in the same factory
7
+ class AttributeDefinitionError < RuntimeError
8
+ end
9
+
10
+ class Attribute #:nodoc:
11
+
12
+ attr_reader :name
13
+
14
+ def initialize(name)
15
+ @name = name.to_sym
16
+
17
+ if @name.to_s =~ /=$/
18
+ attribute_name = $`
19
+ raise AttributeDefinitionError,
20
+ "factory_girl uses 'f.#{attribute_name} value' syntax " +
21
+ "rather than 'f.#{attribute_name} = value'"
22
+ end
23
+ end
24
+
25
+ def add_to(proxy)
26
+ end
27
+
28
+ def association?
29
+ false
30
+ end
31
+
32
+ def ignore
33
+ @ignored = true
34
+ self
35
+ end
36
+
37
+ def ignored?
38
+ @ignored
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,147 @@
1
+ module FactoryGirl
2
+ class DefinitionProxy
3
+ instance_methods.each do |method|
4
+ undef_method(method) unless method =~ /(^__|^nil\?$|^send$|^object_id$|^extend$|^instance_eval$)/
5
+ end
6
+
7
+ def initialize(factory)
8
+ @factory = factory
9
+ end
10
+
11
+ # Adds an attribute that should be assigned on generated instances for this
12
+ # factory.
13
+ #
14
+ # This method should be called with either a value or block, but not both. If
15
+ # called with a block, the attribute will be generated "lazily," whenever an
16
+ # instance is generated. Lazy attribute blocks will not be called if that
17
+ # attribute is overridden for a specific instance.
18
+ #
19
+ # When defining lazy attributes, an instance of FactoryGirl::Proxy will
20
+ # be yielded, allowing associations to be built using the correct build
21
+ # strategy.
22
+ #
23
+ # Arguments:
24
+ # * name: +Symbol+ or +String+
25
+ # The name of this attribute. This will be assigned using "name=" for
26
+ # generated instances.
27
+ # * value: +Object+
28
+ # If no block is given, this value will be used for this attribute.
29
+ def add_attribute(name, value = nil, &block)
30
+ if block_given?
31
+ if value
32
+ raise AttributeDefinitionError, "Both value and block given"
33
+ else
34
+ attribute = Attribute::Dynamic.new(name, block)
35
+ end
36
+ else
37
+ attribute = Attribute::Static.new(name, value)
38
+ end
39
+
40
+ @factory.define_attribute(attribute)
41
+ end
42
+
43
+ # Calls add_attribute using the missing method name as the name of the
44
+ # attribute, so that:
45
+ #
46
+ # factory :user do
47
+ # name 'Billy Idol'
48
+ # end
49
+ #
50
+ # and:
51
+ #
52
+ # factory :user do
53
+ # add_attribute :name, 'Billy Idol'
54
+ # end
55
+ #
56
+ # are equivilent.
57
+ #
58
+ # If no argument or block is given, factory_girl will look for a sequence
59
+ # or association with the same name. This means that:
60
+ #
61
+ # factory :user do
62
+ # email { create(:email) }
63
+ # association :account
64
+ # end
65
+ #
66
+ # and:
67
+ #
68
+ # factory :user do
69
+ # email
70
+ # account
71
+ # end
72
+ #
73
+ # are equivilent.
74
+ def method_missing(name, *args, &block)
75
+ if args.empty? && block.nil?
76
+ @factory.define_attribute(Attribute::Implicit.new(name))
77
+ else
78
+ add_attribute(name, *args, &block)
79
+ end
80
+ end
81
+
82
+ # Adds an attribute that will have unique values generated by a sequence with
83
+ # a specified format.
84
+ #
85
+ # The result of:
86
+ # factory :user do
87
+ # sequence(:email) { |n| "person#{n}@example.com" }
88
+ # end
89
+ #
90
+ # Is equal to:
91
+ # sequence(:email) { |n| "person#{n}@example.com" }
92
+ #
93
+ # factory :user do
94
+ # email { FactoryGirl.create(:email) }
95
+ # end
96
+ #
97
+ # Except that no globally available sequence will be defined.
98
+ def sequence(name, start_value = 1, &block)
99
+ sequence = Sequence.new(name, start_value, &block)
100
+ add_attribute(name) { sequence.next }
101
+ end
102
+
103
+ # Adds an attribute that builds an association. The associated instance will
104
+ # be built using the same build strategy as the parent instance.
105
+ #
106
+ # Example:
107
+ # factory :user do
108
+ # name 'Joey'
109
+ # end
110
+ #
111
+ # factory :post do
112
+ # association :author, :factory => :user
113
+ # end
114
+ #
115
+ # Arguments:
116
+ # * name: +Symbol+
117
+ # The name of this attribute.
118
+ # * options: +Hash+
119
+ #
120
+ # Options:
121
+ # * factory: +Symbol+ or +String+
122
+ # The name of the factory to use when building the associated instance.
123
+ # If no name is given, the name of the attribute is assumed to be the
124
+ # name of the factory. For example, a "user" association will by
125
+ # default use the "user" factory.
126
+ def association(name, options = {})
127
+ factory_name = options.delete(:factory) || name
128
+ @factory.define_attribute(Attribute::Association.new(name, factory_name, options))
129
+ end
130
+
131
+ def after_build(&block)
132
+ @factory.add_callback(:after_build, &block)
133
+ end
134
+
135
+ def after_create(&block)
136
+ @factory.add_callback(:after_create, &block)
137
+ end
138
+
139
+ def after_stub(&block)
140
+ @factory.add_callback(:after_stub, &block)
141
+ end
142
+
143
+ def to_create(&block)
144
+ @factory.to_create(&block)
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,18 @@
1
+ module Factory
2
+ def self.method_missing(name, *args, &block)
3
+ if FactoryGirl.respond_to?(name)
4
+ $stderr.puts "DEPRECATION WARNING: Change Factory.#{name} to FactoryGirl.#{name}"
5
+ FactoryGirl.send(name, *args, &block)
6
+ else
7
+ super(name, *args, &block)
8
+ end
9
+ end
10
+
11
+ def self.const_missing(name)
12
+ if FactoryGirl.const_defined?(name)
13
+ FactoryGirl.const_get(name)
14
+ else
15
+ super(name)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,196 @@
1
+ module FactoryGirl
2
+ # Raised when a factory is defined that attempts to instantiate itself.
3
+ class AssociationDefinitionError < RuntimeError
4
+ end
5
+
6
+ # Raised when a callback is defined that has an invalid name
7
+ class InvalidCallbackNameError < RuntimeError
8
+ end
9
+
10
+ # Raised when a factory is defined with the same name as a previously-defined factory.
11
+ class DuplicateDefinitionError < RuntimeError
12
+ end
13
+
14
+ class Factory
15
+ attr_reader :name #:nodoc:
16
+ attr_reader :attributes #:nodoc:
17
+
18
+ def factory_name
19
+ puts "WARNING: factory.factory_name is deprecated. Use factory.name instead."
20
+ name
21
+ end
22
+
23
+ def class_name #:nodoc:
24
+ @options[:class] || name
25
+ end
26
+
27
+ def build_class #:nodoc:
28
+ @build_class ||= class_for(class_name)
29
+ end
30
+
31
+ def default_strategy #:nodoc:
32
+ @options[:default_strategy] || :create
33
+ end
34
+
35
+ def initialize(name, options = {}) #:nodoc:
36
+ assert_valid_options(options)
37
+ @name = factory_name_for(name)
38
+ @options = options
39
+ @attributes = Attribute::List.new
40
+ end
41
+
42
+ def inherit_from(parent) #:nodoc:
43
+ @options[:class] ||= parent.class_name
44
+ @options[:default_strategy] ||= parent.default_strategy
45
+
46
+ new_attributes = []
47
+ parent.attributes.each do |attribute|
48
+ unless attribute_defined?(attribute.name)
49
+ new_attributes << attribute.clone
50
+ end
51
+ end
52
+ @attributes.unshift *new_attributes
53
+ end
54
+
55
+ def define_attribute(attribute)
56
+ name = attribute.name
57
+ # TODO: move these checks into Attribute
58
+ if attribute_defined?(name)
59
+ raise AttributeDefinitionError, "Attribute already defined: #{name}"
60
+ end
61
+ if attribute.respond_to?(:factory) && attribute.factory == self.name
62
+ raise AssociationDefinitionError, "Self-referencing association '#{name}' in factory '#{self.name}'"
63
+ end
64
+ @attributes << attribute
65
+ end
66
+
67
+ def add_callback(name, &block)
68
+ unless [:after_build, :after_create, :after_stub].include?(name.to_sym)
69
+ raise InvalidCallbackNameError, "#{name} is not a valid callback name. Valid callback names are :after_build, :after_create, and :after_stub"
70
+ end
71
+ @attributes << Attribute::Callback.new(name.to_sym, block)
72
+ end
73
+
74
+ def run(proxy_class, overrides) #:nodoc:
75
+ proxy = proxy_class.new(build_class)
76
+ overrides = symbolize_keys(overrides)
77
+ overrides.each {|attr, val| proxy.set(attr, val) }
78
+ passed_keys = overrides.keys.collect {|k| FactoryGirl.aliases_for(k) }.flatten
79
+ @attributes.each do |attribute|
80
+ unless passed_keys.include?(attribute.name)
81
+ attribute.add_to(proxy)
82
+ end
83
+ end
84
+ proxy.result(@to_create_block)
85
+ end
86
+
87
+ def human_name(*args, &block)
88
+ name.to_s.gsub('_', ' ')
89
+ end
90
+
91
+ def associations
92
+ attributes.select {|attribute| attribute.association? }
93
+ end
94
+
95
+ # Names for this factory, including aliases.
96
+ #
97
+ # Example:
98
+ #
99
+ # factory :user, :aliases => [:author] do
100
+ # # ...
101
+ # end
102
+ #
103
+ # FactoryGirl.create(:author).class
104
+ # # => User
105
+ #
106
+ # Because an attribute defined without a value or block will build an
107
+ # association with the same name, this allows associations to be defined
108
+ # without factories, such as:
109
+ #
110
+ # factory :user, :aliases => [:author] do
111
+ # # ...
112
+ # end
113
+ #
114
+ # factory :post do
115
+ # author
116
+ # end
117
+ #
118
+ # FactoryGirl.create(:post).author.class
119
+ # # => User
120
+ def names
121
+ [name] + (@options[:aliases] || [])
122
+ end
123
+
124
+ def to_create(&block)
125
+ @to_create_block = block
126
+ end
127
+
128
+ private
129
+
130
+ def class_for (class_or_to_s)
131
+ if class_or_to_s.respond_to?(:to_sym)
132
+ class_name = variable_name_to_class_name(class_or_to_s)
133
+ class_name.split('::').inject(Object) do |object, string|
134
+ object.const_get(string)
135
+ end
136
+ else
137
+ class_or_to_s
138
+ end
139
+ end
140
+
141
+ def factory_name_for(class_or_to_s)
142
+ if class_or_to_s.respond_to?(:to_sym)
143
+ class_or_to_s.to_sym
144
+ else
145
+ class_name_to_variable_name(class_or_to_s).to_sym
146
+ end
147
+ end
148
+
149
+ def attribute_defined? (name)
150
+ !@attributes.detect {|attr| attr.name == name && !attr.is_a?(Attribute::Callback) }.nil?
151
+ end
152
+
153
+ def assert_valid_options(options)
154
+ invalid_keys = options.keys - [:class, :parent, :default_strategy, :aliases]
155
+ unless invalid_keys == []
156
+ raise ArgumentError, "Unknown arguments: #{invalid_keys.inspect}"
157
+ end
158
+ if options[:default_strategy]
159
+ assert_valid_strategy(options[:default_strategy])
160
+ puts "WARNING: default_strategy is deprecated."
161
+ puts "Override to_create if you need to prevent a call to #save!."
162
+ end
163
+ end
164
+
165
+ def assert_valid_strategy(strategy)
166
+ unless Proxy.const_defined? variable_name_to_class_name(strategy)
167
+ raise ArgumentError, "Unknown strategy: #{strategy}"
168
+ end
169
+ end
170
+
171
+ # Based on ActiveSupport's underscore inflector
172
+ def class_name_to_variable_name(name)
173
+ name.to_s.gsub(/::/, '/').
174
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
175
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
176
+ tr("-", "_").
177
+ downcase
178
+ end
179
+
180
+ # Based on ActiveSupport's camelize inflector
181
+ def variable_name_to_class_name(name)
182
+ name.to_s.
183
+ gsub(/\/(.?)/) { "::#{$1.upcase}" }.
184
+ gsub(/(?:^|_)(.)/) { $1.upcase }
185
+ end
186
+
187
+ # From ActiveSupport
188
+ def symbolize_keys(hash)
189
+ hash.inject({}) do |options, (key, value)|
190
+ options[(key.to_sym rescue key) || key] = value
191
+ options
192
+ end
193
+ end
194
+
195
+ end
196
+ end
@@ -0,0 +1,23 @@
1
+ module FactoryGirl
2
+
3
+ class << self
4
+ # An Array of strings specifying locations that should be searched for
5
+ # factory definitions. By default, factory_girl will attempt to require
6
+ # "factories," "test/factories," and "spec/factories." Only the first
7
+ # existing file will be loaded.
8
+ attr_accessor :definition_file_paths
9
+ end
10
+ self.definition_file_paths = %w(factories test/factories spec/factories)
11
+
12
+ def self.find_definitions #:nodoc:
13
+ definition_file_paths.each do |path|
14
+ require("#{path}.rb") if File.exists?("#{path}.rb")
15
+
16
+ if File.directory? path
17
+ Dir[File.join(path, '*.rb')].sort.each do |file|
18
+ require file
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end