gabrielg-factory_girl 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog ADDED
@@ -0,0 +1,19 @@
1
+ 1.1.3 (September 12, 2008)
2
+ Automatically pull in definitions from factories.rb, test/factories.rb, or
3
+ spec/factories.rb
4
+ 1.1.2 (July 30, 2008)
5
+ Improved error handling for invalid and undefined factories/attributes
6
+ Improved handling of strings vs symbols vs classes
7
+ Added a prettier syntax for handling associations
8
+ Updated documentation and fixed compatibility with Rails 2.1
9
+
10
+ 1.1.1 (June 23, 2008)
11
+ The attribute "name" no longer requires using #add_attribute
12
+
13
+ 1.1.0 (June 3, 2008)
14
+ Added support for dependent attributes
15
+ Fixed the attributes_for build strategy to not build associations
16
+ Added support for sequences
17
+
18
+ 1.0.0 (May 31, 208)
19
+ First version
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2008 Joe Ferris and thoughtbot, inc.
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,154 @@
1
+ h1. factory_girl
2
+
3
+ Written by "Joe Ferris":mailto:jferris@thoughtbot.com.
4
+
5
+ Thanks to Tammer Saleh, Dan Croak, and Jon Yurek of thoughtbot, inc.
6
+
7
+ Copyright 2008 Joe Ferris and thoughtbot, inc.
8
+
9
+ h2. Download
10
+
11
+ Github: "Page":http://github.com/thoughtbot/factory_girl/tree/master "Clone":git://github.com/thoughtbot/factory_girl.git
12
+
13
+ Gem: <pre>gem install thoughtbot-factory_girl --source http://gems.github.com</pre>
14
+
15
+ Note: if you install factory_girl using the gem from Github, you'll need this
16
+ in your environment.rb if you want to use Rails 2.1's dependency manager:
17
+
18
+ config.gem "thoughtbot-factory_girl",
19
+ :lib => "factory_girl",
20
+ :source => "http://gems.github.com"
21
+
22
+ h2. Defining factories
23
+
24
+ <pre><code># This will guess the User class
25
+ Factory.define :user do |u|
26
+ u.first_name 'John'
27
+ u.last_name 'Doe'
28
+ u.admin false
29
+ end
30
+
31
+ # This will use the User class (Admin would have been guessed)
32
+ Factory.define :admin, :class => User do |u|
33
+ u.first_name 'Admin'
34
+ u.last_name 'User'
35
+ u.admin true
36
+ end
37
+
38
+ # This will create an admin factory that will inherit the user factory attributes
39
+ # and override them with whatever you pass in
40
+ # The first name would be John and the last name would be Doe
41
+ Factory.define :admin, :inherit => :user, :class => User do |u|
42
+ u.admin true
43
+ end</code></pre>
44
+
45
+
46
+ It is recommended that you create a test/factories.rb file and define your
47
+ factories there. This file can be included from test_helper or directly from
48
+ your test files. Don't forget:
49
+ <pre><code>require 'factory_girl'</code></pre>
50
+
51
+
52
+ h2. Lazy Attributes
53
+
54
+ Most attributes can be added using static values that are evaluated when the
55
+ factory is defined, but some attributes (such as associations and other
56
+ attributes that must be dynamically generated) will need values assigned each
57
+ time an instance is generated. These "lazy" attributes can be added by passing
58
+ a block instead of a parameter:
59
+
60
+ <pre><code>Factory.define :user do |u|
61
+ # ...
62
+ u.activation_code { User.generate_activation_code }
63
+ end</code></pre>
64
+
65
+
66
+ h2. Dependent Attributes
67
+
68
+ Some attributes may need to be generated based on the values of other
69
+ attributes. This can be done by calling the attribute name on
70
+ Factory::AttributeProxy, which is yielded to lazy attribute blocks:
71
+
72
+ <pre><code>Factory.define :user do |u|
73
+ u.first_name 'Joe'
74
+ u.last_name 'Blow'
75
+ u.email {|a| "#{a.first_name}.#{a.last_name}@example.com".downcase }
76
+ end
77
+
78
+ Factory(:user, :last_name => 'Doe').email
79
+ # => "joe.doe@example.com"</code></pre>
80
+
81
+
82
+ h2. Associations
83
+
84
+ Associated instances can be generated by using the association method when
85
+ defining a lazy attribute:
86
+
87
+ <pre><code>Factory.define :post do |p|
88
+ # ...
89
+ p.author {|author| author.association(:user, :last_name => 'Writely') }
90
+ end</code></pre>
91
+
92
+
93
+ When using the association method, the same build strategy (build, create, or attributes_for) will be used for all generated instances:
94
+
95
+ <pre><code># Builds and saves a User and a Post
96
+ post = Factory(:post)
97
+ post.new_record? # => false
98
+ post.author.new_record # => false
99
+
100
+ # Builds but does not save a User and a Post
101
+ Factory.build(:post)
102
+ post.new_record? # => true
103
+ post.author.new_record # => true</code></pre>
104
+
105
+ Because this pattern is so common, a prettier syntax is available for defining
106
+ associations:
107
+
108
+ <pre><code># The following definitions are equivilent:
109
+ Factory.define :post do |p|
110
+ p.author {|a| a.association(:user) }
111
+ end
112
+
113
+ Factory.define :post do |p|
114
+ p.association :author, :factory => :user
115
+ end</code></pre>
116
+
117
+ If the factory name is the same as the association name, the factory name can
118
+ be left out.
119
+
120
+
121
+ h2. Sequences
122
+
123
+ Unique values in a specific format (for example, e-mail addresses) can be
124
+ generated using sequences. Sequences are defined by calling Factory.sequence,
125
+ and values in a sequence are generated by calling Factory.next:
126
+
127
+ <pre><code># Defines a new sequence
128
+ Factory.sequence :email do |n|
129
+ "person#{n}@example.com"
130
+ end
131
+
132
+ Factory.next :email
133
+ # => "person1@example.com"
134
+
135
+ Factory.next :email
136
+ # => "person2@example.com"</code></pre>
137
+
138
+
139
+ h2. Using factories
140
+
141
+ <pre><code># Build and save a User instance
142
+ Factory(:user)
143
+
144
+ # Build a User instance and override the first_name property
145
+ Factory.build(:user, :first_name => 'Joe')
146
+
147
+ # Return an attributes Hash that can be used to build a User instance
148
+ attrs = Factory.attributes_for(:user)</code></pre>
149
+
150
+ h2. More Information
151
+
152
+ "Our blog":http://giantrobots.thoughtbot.com
153
+
154
+ "factory_girl rdoc":http://dev.thoughtbot.com/factory_girl
data/Rakefile ADDED
@@ -0,0 +1,69 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/gempackagetask'
6
+ require 'date'
7
+
8
+ desc 'Default: run unit tests.'
9
+ task :default => :test
10
+
11
+ desc 'Test the factory_girl plugin.'
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << 'lib'
14
+ t.pattern = 'test/**/*_test.rb'
15
+ t.verbose = true
16
+ end
17
+
18
+ desc 'Generate documentation for the factory_girl plugin.'
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'Factory Girl'
22
+ rdoc.options << '--line-numbers' << '--inline-source' << "--main" << "README.textile"
23
+ rdoc.rdoc_files.include('README.textile')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
26
+
27
+ desc 'Update documentation on website'
28
+ task :sync_docs => 'rdoc' do
29
+ `rsync -ave ssh rdoc/ dev@dev.thoughtbot.com:/home/dev/www/dev.thoughtbot.com/factory_girl`
30
+ end
31
+
32
+ spec = Gem::Specification.new do |s|
33
+ s.name = %q{factory_girl}
34
+ s.version = "1.1.3"
35
+ s.summary = %q{factory_girl provides a framework and DSL for defining and
36
+ using model instance factories.}
37
+ s.description = %q{factory_girl provides a framework and DSL for defining and
38
+ using factories - less error-prone, more explicit, and
39
+ all-around easier to work with than fixtures.}
40
+
41
+ s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'test/**/*.rb']
42
+ s.require_path = 'lib'
43
+ s.test_files = Dir[*['test/**/*_test.rb']]
44
+
45
+ s.has_rdoc = true
46
+ s.extra_rdoc_files = ["README.textile"]
47
+ s.rdoc_options = ['--line-numbers', '--inline-source', "--main", "README.textile"]
48
+
49
+ s.authors = ["Joe Ferris"]
50
+ s.email = %q{jferris@thoughtbot.com}
51
+
52
+ s.platform = Gem::Platform::RUBY
53
+ s.add_dependency(%q<activesupport>, [">= 1.0"])
54
+ end
55
+
56
+ Rake::GemPackageTask.new spec do |pkg|
57
+ pkg.need_tar = true
58
+ pkg.need_zip = true
59
+ end
60
+
61
+ desc "Clean files generated by rake tasks"
62
+ task :clobber => [:clobber_rdoc, :clobber_package]
63
+
64
+ desc "Generate a gemspec file"
65
+ task :gemspec do
66
+ File.open("#{spec.name}.gemspec", 'w') do |f|
67
+ f.write spec.to_ruby
68
+ end
69
+ end
@@ -0,0 +1,37 @@
1
+ class Factory
2
+
3
+ cattr_accessor :aliases #:nodoc:
4
+ self.aliases = [
5
+ [/(.*)_id/, '\1'],
6
+ [/(.*)/, '\1_id']
7
+ ]
8
+
9
+ # Defines a new alias for attributes
10
+ #
11
+ # Arguments:
12
+ # pattern: (Regexp)
13
+ # A pattern that will be matched against attributes when looking for
14
+ # aliases. Contents captured in the pattern can be used in the alias.
15
+ # replace: (String)
16
+ # The alias that results from the matched pattern. Captured strings can
17
+ # be insert like String#sub.
18
+ #
19
+ # Example:
20
+ #
21
+ # Factory.alias /(.*)_confirmation/, '\1'
22
+ def self.alias (pattern, replace)
23
+ self.aliases << [pattern, replace]
24
+ end
25
+
26
+ def self.aliases_for (attribute) #:nodoc:
27
+ aliases.collect do |params|
28
+ pattern, replace = *params
29
+ if pattern.match(attribute.to_s)
30
+ attribute.to_s.sub(pattern, replace).to_sym
31
+ else
32
+ nil
33
+ end
34
+ end.compact << attribute
35
+ end
36
+
37
+ end
@@ -0,0 +1,38 @@
1
+ class Factory
2
+
3
+ class AttributeDefinitionError < RuntimeError
4
+ end
5
+
6
+ class Attribute #:nodoc:
7
+
8
+ attr_reader :name
9
+
10
+ def initialize (name, static_value, lazy_block)
11
+ name = name.to_sym
12
+
13
+ if name.to_s =~ /=$/
14
+ raise AttributeDefinitionError,
15
+ "factory_girl uses 'f.#{name.to_s.chop} value' syntax " +
16
+ "rather than 'f.#{name} = value'"
17
+ end
18
+
19
+ unless static_value.nil? || lazy_block.nil?
20
+ raise AttributeDefinitionError, "Both value and block given"
21
+ end
22
+
23
+ @name = name
24
+ @static_value = static_value
25
+ @lazy_block = lazy_block
26
+ end
27
+
28
+ def value (proxy)
29
+ if @lazy_block.nil?
30
+ @static_value
31
+ else
32
+ @lazy_block.call(proxy)
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,97 @@
1
+ class Factory
2
+
3
+ class AttributeProxy
4
+
5
+ attr_accessor :factory, :attribute_name, :strategy, :current_values #:nodoc:
6
+
7
+ def initialize (factory, attr, strategy, values) #:nodoc:
8
+ @factory = factory
9
+ @attribute_name = attr
10
+ @strategy = strategy
11
+ @current_values = values
12
+ end
13
+
14
+ # Generates an association using the current build strategy.
15
+ #
16
+ # Arguments:
17
+ # name: (Symbol)
18
+ # The name of the factory that should be used to generate this
19
+ # association.
20
+ # attributes: (Hash)
21
+ # A hash of attributes that should be overridden for this association.
22
+ #
23
+ # Returns:
24
+ # The generated association for the current build strategy. Note that
25
+ # assocaitions are not generated for the attributes_for strategy. Returns
26
+ # nil in this case.
27
+ #
28
+ # Example:
29
+ #
30
+ # Factory.define :user do |f|
31
+ # # ...
32
+ # end
33
+ #
34
+ # Factory.define :post do |f|
35
+ # # ...
36
+ # f.author {|a| a.association :user, :name => 'Joe' }
37
+ # end
38
+ #
39
+ # # Builds (but doesn't save) a Post and a User
40
+ # Factory.build(:post)
41
+ #
42
+ # # Builds and saves a User, builds a Post, assigns the User to the
43
+ # # author association, and saves the User.
44
+ # Factory.create(:post)
45
+ #
46
+ def association(name, attributes = {}, options = {})
47
+ return nil if strategy == :attributes_for
48
+ if options[:count] && strategy == :create
49
+ create_has_many_association(name, options[:count])
50
+ else
51
+ Factory.send(strategy, name, attributes)
52
+ end
53
+ end
54
+
55
+ def create_has_many_association(name, count)
56
+ (1..count).map { Factory.build(name) }
57
+ end
58
+
59
+ # Returns the value for specified attribute. A value will only be available
60
+ # if it was overridden when calling the factory, or if a value is added
61
+ # earlier in the definition of the factory.
62
+ #
63
+ # Arguments:
64
+ # attribute: (Symbol)
65
+ # The attribute whose value should be returned.
66
+ #
67
+ # Returns:
68
+ # The value of the requested attribute. (Object)
69
+ def value_for (attribute)
70
+ unless current_values.key?(attribute)
71
+ raise ArgumentError, "No such attribute: #{attribute.inspect}"
72
+ end
73
+ current_values[attribute]
74
+ end
75
+
76
+ # Undefined methods are delegated to value_for, which means that:
77
+ #
78
+ # Factory.define :user do |f|
79
+ # f.first_name 'Ben'
80
+ # f.last_name {|a| a.value_for(:first_name) }
81
+ # end
82
+ #
83
+ # and:
84
+ #
85
+ # Factory.define :user do |f|
86
+ # f.first_name 'Ben'
87
+ # f.last_name {|a| a.first_name }
88
+ # end
89
+ #
90
+ # are equivilent.
91
+ def method_missing (name, *args, &block)
92
+ current_values[name]
93
+ end
94
+
95
+ end
96
+
97
+ end