factory_girl_kibiz0r 2.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
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