machinist_redux 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +17 -0
  3. data/.gitignore +24 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +60 -0
  6. data/.rubocop_todo.yml +92 -0
  7. data/.travis.yml +23 -0
  8. data/Appraisals +11 -0
  9. data/Gemfile +32 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +307 -0
  12. data/Rakefile +20 -0
  13. data/gemfiles/rails_4.2.gemfile +38 -0
  14. data/gemfiles/rails_4.2.gemfile.lock +232 -0
  15. data/gemfiles/rails_5.0.gemfile +38 -0
  16. data/gemfiles/rails_5.0.gemfile.lock +232 -0
  17. data/gemfiles/rails_5.1.gemfile +34 -0
  18. data/gemfiles/rails_5.1.gemfile.lock +231 -0
  19. data/lib/generators/machinist/install/USAGE +2 -0
  20. data/lib/generators/machinist/install/install_generator.rb +46 -0
  21. data/lib/generators/machinist/install/templates/blueprints.rb +9 -0
  22. data/lib/generators/machinist/install/templates/machinist.rb.erb +7 -0
  23. data/lib/generators/machinist/model/model_generator.rb +11 -0
  24. data/lib/machinist.rb +5 -0
  25. data/lib/machinist/active_record.rb +14 -0
  26. data/lib/machinist/active_record/blueprint.rb +14 -0
  27. data/lib/machinist/active_record/lathe.rb +21 -0
  28. data/lib/machinist/blueprint.rb +84 -0
  29. data/lib/machinist/exceptions.rb +30 -0
  30. data/lib/machinist/lathe.rb +65 -0
  31. data/lib/machinist/machinable.rb +100 -0
  32. data/lib/machinist/version.rb +3 -0
  33. data/machinist.gemspec +23 -0
  34. data/spec/machinist/active_record_spec.rb +106 -0
  35. data/spec/machinist/blueprint_inheritance_spec.rb +101 -0
  36. data/spec/machinist/blueprint_spec.rb +76 -0
  37. data/spec/machinist/exceptions_spec.rb +16 -0
  38. data/spec/machinist/machinable_spec.rb +91 -0
  39. data/spec/spec_helper.rb +110 -0
  40. data/spec/support/active_record_environment.rb +62 -0
  41. metadata +94 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a6975277474c2f278dd63f6ebaf01e930e4e830b
4
+ data.tar.gz: 0f4f61f505cb8aa1dedc0abc7d55984d07fee225
5
+ SHA512:
6
+ metadata.gz: 6c1d8c9400d7ac81391d511c57dd655ac5d8f9c511e4a075c58178935c8360cd51af43a3610283cc742c93f27a0ab3a334685f0f9f0b00a43d464141d880dc66
7
+ data.tar.gz: 7efa8ffa828f5721186c24f1036d78b1523fa9a91a77d36ae763fad5995278c5516bbc3dedf0fe81561ddd27f03f8502bce7e4f0d27821c4f22691514351534b
data/.codeclimate.yml ADDED
@@ -0,0 +1,17 @@
1
+ ---
2
+ engines:
3
+ duplication:
4
+ enabled: true
5
+ config:
6
+ languages:
7
+ - ruby
8
+ fixme:
9
+ enabled: true
10
+ rubocop:
11
+ enabled: true
12
+ ratings:
13
+ paths:
14
+ - '**.rb'
15
+ exclude_paths:
16
+ - script/
17
+ - spec/
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .DS_Store
6
+ .rbenv-*
7
+ .rbx
8
+ .rbxpkg
9
+ .ruby-gemset
10
+ .ruby-version
11
+ .rvmrc
12
+ .yardoc
13
+ _yardoc
14
+ coverage
15
+ doc/
16
+ Gemfile.lock
17
+ InstalledFiles
18
+ lib/bundler/man
19
+ rdoc
20
+ spec/reports
21
+ tags
22
+ test/tmp
23
+ test/version_tmp
24
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,60 @@
1
+ ---
2
+ require: rubocop-rspec
3
+ inherit_from: .rubocop_todo.yml
4
+
5
+ AllCops:
6
+ TargetRubyVersion: 2.2
7
+ DisplayCopNames: true
8
+ Exclude:
9
+ - 'tmp/**/*'
10
+
11
+ Style/MixinGrouping:
12
+ Exclude:
13
+ - 'spec/**/*.rb'
14
+
15
+ Metrics/BlockLength:
16
+ CountComments: false # count full line comments?
17
+ Exclude:
18
+ - '**/*_spec.rb'
19
+
20
+ StringLiterals:
21
+ EnforcedStyle: single_quotes
22
+ Enabled: true
23
+
24
+ DotPosition:
25
+ EnforcedStyle: leading
26
+ Enabled: true
27
+
28
+ ClassAndModuleChildren:
29
+ EnforcedStyle: nested
30
+ Enabled: true
31
+
32
+ Documentation:
33
+ Enabled: false
34
+
35
+ FileName:
36
+ Enabled: true
37
+
38
+ LineLength:
39
+ Max: 120
40
+ Enabled: true
41
+
42
+ Style/ExtraSpacing:
43
+ Enabled: true
44
+
45
+ Lint/LiteralInInterpolation:
46
+ AutoCorrect: true
47
+
48
+ Style/ModuleFunction:
49
+ EnforcedStyle: extend_self # Allows us to have private methods too
50
+
51
+ Style/PercentLiteralDelimiters:
52
+ # Hound and CodeClimate are currently using an old version of Rubocop with
53
+ # different defaults, so we set them explicitly here.
54
+ PreferredDelimiters:
55
+ default: ()
56
+ '%i': '[]'
57
+ '%I': '[]'
58
+ '%r': '{}'
59
+ '%w': '[]'
60
+ '%W': '[]'
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,92 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2017-05-16 15:42:20 +0100 using RuboCop version 0.48.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ Metrics/AbcSize:
11
+ Max: 17
12
+
13
+ # Offense count: 1
14
+ Metrics/CyclomaticComplexity:
15
+ Max: 7
16
+
17
+ # Offense count: 1
18
+ # Configuration parameters: CountComments.
19
+ Metrics/MethodLength:
20
+ Max: 13
21
+
22
+ # Offense count: 1
23
+ Metrics/PerceivedComplexity:
24
+ Max: 8
25
+
26
+ # Offense count: 1
27
+ RSpec/DescribeMethod:
28
+ Exclude:
29
+ - 'spec/machinist/exceptions_spec.rb'
30
+
31
+ # Offense count: 17
32
+ # Configuration parameters: Max.
33
+ RSpec/ExampleLength:
34
+ Exclude:
35
+ - 'spec/machinist/active_record_spec.rb'
36
+ - 'spec/machinist/blueprint_inheritance_spec.rb'
37
+ - 'spec/machinist/blueprint_spec.rb'
38
+ - 'spec/machinist/machinable_spec.rb'
39
+
40
+ # Offense count: 2
41
+ RSpec/IteratedExpectation:
42
+ Exclude:
43
+ - 'spec/machinist/blueprint_spec.rb'
44
+ - 'spec/machinist/machinable_spec.rb'
45
+
46
+ # Offense count: 21
47
+ RSpec/MultipleExpectations:
48
+ Max: 6
49
+
50
+ # Offense count: 2
51
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
52
+ # SupportedStyles: nested, compact
53
+ Style/ClassAndModuleChildren:
54
+ Exclude:
55
+ - 'lib/machinist/active_record/blueprint.rb'
56
+ - 'lib/machinist/active_record/lathe.rb'
57
+
58
+ # Offense count: 1
59
+ # Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
60
+ # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
61
+ Style/FileName:
62
+ Exclude:
63
+ - 'Appraisals'
64
+
65
+ # Offense count: 1
66
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
67
+ # SupportedStyles: format, sprintf, percent
68
+ Style/FormatString:
69
+ Exclude:
70
+ - 'lib/machinist/blueprint.rb'
71
+
72
+ # Offense count: 3
73
+ # Configuration parameters: MinBodyLength.
74
+ Style/GuardClause:
75
+ Exclude:
76
+ - 'lib/generators/machinist/install/install_generator.rb'
77
+ - 'lib/machinist/lathe.rb'
78
+
79
+ # Offense count: 1
80
+ Style/MethodMissing:
81
+ Exclude:
82
+ - 'lib/machinist/lathe.rb'
83
+
84
+ # Offense count: 1
85
+ # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist.
86
+ # NamePrefix: is_, has_, have_
87
+ # NamePrefixBlacklist: is_, has_, have_
88
+ # NameWhitelist: is_a?
89
+ Style/PredicateName:
90
+ Exclude:
91
+ - 'spec/**/*'
92
+ - 'lib/machinist/blueprint.rb'
data/.travis.yml ADDED
@@ -0,0 +1,23 @@
1
+ ---
2
+ language: ruby
3
+
4
+ rvm:
5
+ - ruby-head
6
+ - 2.4.1
7
+ - 2.3.4
8
+ - 2.2.6
9
+
10
+ gemfile:
11
+ - gemfiles/rails_4.2.gemfile
12
+ - gemfiles/rails_5.0.gemfile
13
+ - gemfiles/rails_5.1.gemfile
14
+
15
+ matrix:
16
+ allow_failures:
17
+ - rvm: ruby-head
18
+
19
+ before_install:
20
+ - gem update bundler
21
+
22
+ after_success:
23
+ - bundle exec codeclimate-test-reporter
data/Appraisals ADDED
@@ -0,0 +1,11 @@
1
+ appraise 'rails-4.2' do
2
+ gem 'activerecord', '~> 4.2.8', group: :test, require: false
3
+ end
4
+
5
+ appraise 'rails-5.0' do
6
+ gem 'activerecord', '~> 5.0.3', group: :test, require: false
7
+ end
8
+
9
+ appraise 'rails-5.1' do
10
+ gem 'activerecord', '~> 5.1.1', group: :test, require: false
11
+ end
data/Gemfile ADDED
@@ -0,0 +1,32 @@
1
+ source 'http://rubygems.org'
2
+ gemspec
3
+ ruby RUBY_VERSION
4
+
5
+ group :development do
6
+ gem 'appraisal', require: false
7
+ gem 'gem-release', require: false
8
+ gem 'github_changelog_generator', require: false
9
+ gem 'guard', require: false
10
+ gem 'guard-rspec', require: false
11
+ gem 'guard-rubocop', require: false
12
+ gem 'guard-rubycritic', require: false
13
+ gem 'rdoc', require: false
14
+ gem 'rubocop-rspec', require: false
15
+ end
16
+
17
+ group :test do
18
+ gem 'codeclimate-test-reporter', require: false
19
+ gem 'coveralls', require: false
20
+ gem 'fuubar', require: false
21
+ gem 'rspec', require: false
22
+ gem 'rspec_junit_formatter', require: false
23
+ gem 'simplecov', '~> 0.14', require: false
24
+ end
25
+
26
+ platforms :ruby do
27
+ gem 'sqlite3'
28
+ end
29
+
30
+ platforms :jruby do
31
+ gem 'activerecord-jdbcsqlite3-adapter'
32
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2008-2017 Pete Yandell, Attila Györffy, Dominic Sayers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,307 @@
1
+ # Machinist 3
2
+
3
+ *Fixtures aren't fun. Machinist was.*
4
+
5
+ [![Gem version](https://badge.fury.io/rb/machinist_redux.svg)](https://rubygems.org/gems/machinist_redux)
6
+ [![Gem downloads](https://img.shields.io/gem/dt/machinist_redux.svg)](https://rubygems.org/gems/machinist_redux)
7
+ [![Build Status](https://travis-ci.org/dominicsayers/machinist.svg?branch=master)](https://travis-ci.org/dominicsayers/machinist)
8
+ [![Code Climate](https://codeclimate.com/github/dominicsayers/machinist/badges/gpa.svg)](https://codeclimate.com/github/dominicsayers/machinist)
9
+ [![Test Coverage](https://codeclimate.com/github/dominicsayers/machinist/badges/coverage.svg)](https://codeclimate.com/github/dominicsayers/machinist/coverage)
10
+ [![Dependency Status](https://gemnasium.com/badges/github.com/dominicsayers/machinist.svg)](https://gemnasium.com/github.com/dominicsayers/machinist)
11
+ [![Security](https://hakiri.io/github/dominicsayers/machinist/master.svg)](https://hakiri.io/github/dominicsayers/machinist/master)
12
+
13
+ - [Home page](https://github.com/dominicsayers/machinist)
14
+ - [Google group](https://groups.google.com/group/machinist-users), for support
15
+ - [Bug tracker](https://github.com/dominicsayers/machinist/issues), for reporting Machinist bugs
16
+
17
+ If you want Machinist 1, [go here](https://github.com/notahat/machinist/tree/1.0-maintenance).
18
+
19
+ If you want support for Rails 3 or Rubies prior to 2.2, [go here](https://github.com/attilagyorffy/machinist).
20
+
21
+ ## Status
22
+
23
+ This is a fork of [Pete Yandell's Machinist](http://github.com/notahat/machinist). The original gem was abandoned for the reasons given below, as are most of its forks. The purpose of this fork is to keep Machinist under maintenance for legacy projects that have upgraded to Ruby 2.2 or later and Rails 4.2 or later, but still have Machinist factories in the test environment.
24
+
25
+ I'm pleased to say that Pete's code runs fine under Ruby 2.2, 2.3 & 2.4 and Rails 4.2, 5.0 and 5.1. I have allowed [RuboCop](https://github.com/bbatsov/rubocop) and [RuboCop RSpec](https://github.com/backus/rubocop-rspec) to suggest some changes, and I have converted to the more up-to-date RSpec syntax using [Transpec](https://github.com/yujinakayama/transpec). Few if any manual changes were needed.
26
+
27
+ Pete Yandell's reason for abandoning Machinist is that he found himself with less and less need for factories in tests. He recommends Bo Jeanes' [excellent article on the topic](http://bjeanes.com/2012/02/factories-breed-complexity).
28
+
29
+ ## Introduction
30
+
31
+ Machinist makes it easy to create objects for use in tests. It generates data
32
+ for the attributes you don't care about, and constructs any necessary
33
+ associated objects, leaving you to specify only the fields you care about in
34
+ your test. For example:
35
+
36
+ ```ruby
37
+ describe Comment, 'without_spam scope' do
38
+ it "doesn't include spam" do
39
+ # This will make a Comment, a Post, and a User (the author of the
40
+ # Post), generate values for all their attributes, and save them:
41
+ spam = Comment.make!(spam: true)
42
+
43
+ Comment.without_spam.should_not include(spam)
44
+ end
45
+ end
46
+ ```
47
+
48
+ You tell Machinist how to do this with blueprints:
49
+
50
+ ```ruby
51
+ require 'machinist/active_record'
52
+
53
+ User.blueprint do
54
+ username { "user#{sn}" } # Each user gets a unique serial number.
55
+ end
56
+
57
+ Post.blueprint do
58
+ author
59
+ title { "Post #{sn}" }
60
+ body { 'Lorem ipsum...' }
61
+ end
62
+
63
+ Comment.blueprint do
64
+ post
65
+ email { "commenter#{sn}@example.com" }
66
+ body { 'Lorem ipsum...' }
67
+ end
68
+ ```
69
+
70
+ ## Installation
71
+
72
+ ### Upgrading from Machinist 1
73
+
74
+ See [the wiki](http://wiki.github.com/notahat/machinist/machinist-2).
75
+
76
+ ### Rails 4 and 5
77
+
78
+ In your app's `Gemfile`, in the `group :test` section, add:
79
+
80
+ ```ruby
81
+ gem 'machinist_redux'
82
+ ```
83
+
84
+ Then run:
85
+
86
+ ```ruby
87
+ bundle install
88
+ rails generate machinist:install
89
+ ```
90
+
91
+ If you want Machinist to automatically add a blueprint to your blueprints file
92
+ whenever you generate a model, add the following to your `config/application.rb` inside the Application class:
93
+
94
+ ```ruby
95
+ config.generators do |g|
96
+ g.fixture_replacement :machinist
97
+ end
98
+ ```
99
+
100
+ ## Usage
101
+
102
+ ### Blueprints
103
+
104
+ A blueprint describes how to generate an object. The blueprint takes care of
105
+ providing attributes that your test doesn't care about, leaving you to focus on
106
+ just the attributes that are important for the test.
107
+
108
+ A simple blueprint might look like this:
109
+
110
+ ```ruby
111
+ Post.blueprint do
112
+ title { 'A Post' }
113
+ body { 'Lorem ipsum...' }
114
+ end
115
+ ```
116
+
117
+ You can then construct a Post from this blueprint with:
118
+
119
+ ```ruby
120
+ Post.make!
121
+ ```
122
+
123
+ When you call `make!`, Machinist calls `Post.new`, then runs through the
124
+ attributes in your blueprint, calling the block for each attribute to generate
125
+ a value. It then saves and reloads the Post. (It throws an exception if the
126
+ Post can't be saved.)
127
+
128
+ You can override values defined in the blueprint by passing a hash to make:
129
+
130
+ ```ruby
131
+ Post.make!(title: 'A Specific Title')
132
+ ```
133
+
134
+ If you want to generate an object without saving it to the database, replace
135
+ `make!` with `make`.
136
+
137
+ ### Unique Attributes
138
+
139
+ For attributes that need to be unique, you can call the `sn` method from
140
+ within the attribute block to get a unique serial number for the object.
141
+
142
+ ```ruby
143
+ User.blueprint do
144
+ username { "user-#{sn}" }
145
+ end
146
+ ```
147
+
148
+ ### Associations
149
+
150
+ If your object needs associated objects, you can generate them like this:
151
+
152
+ ```ruby
153
+ Comment.blueprint do
154
+ post { Post.make }
155
+ end
156
+ ```
157
+
158
+ Calling `Comment.make!` will construct a Comment and its associated Post, and
159
+ save both.
160
+
161
+ Machinist is smart enough to look at the association and work out what sort of
162
+ object it needs to create, so you can shorten the above blueprint to:
163
+
164
+ ```ruby
165
+ Comment.blueprint do
166
+ post
167
+ end
168
+ ```
169
+
170
+ If you want to override the value for post when constructing the comment, you
171
+ can do this:
172
+
173
+ ```ruby
174
+ post = Post.make(title: 'A particular title')
175
+ comment = Comment.make(post: post)
176
+ ```
177
+
178
+ For `has_many` and `has_and_belongs_to_many` associations, you can create
179
+ multiple associated objects like this:
180
+
181
+ ```ruby
182
+ Post.blueprint do
183
+ comments(3) # Makes 3 comments.
184
+ end
185
+ ```
186
+
187
+ ### Named Blueprints
188
+
189
+ Named blueprints let you define variations on an object. For example, suppose
190
+ some of your Users are administrators:
191
+
192
+ ```ruby
193
+ User.blueprint do
194
+ name { "User #{sn}" }
195
+ email { "user-#{sn}@example.com" }
196
+ end
197
+
198
+ User.blueprint(:admin) do
199
+ name { "Admin User #{sn}" }
200
+ admin { true }
201
+ end
202
+ ```
203
+
204
+ Calling:
205
+
206
+ ```ruby
207
+ User.make!(:admin)
208
+ ```
209
+
210
+ will use the `:admin` blueprint.
211
+
212
+ Named blueprints call the default blueprint to set any attributes not
213
+ specifically provided, so in this example the `email` attribute will still be
214
+ generated even for an admin user.
215
+
216
+ You must define a default blueprint for any class that has a named blueprint,
217
+ even if the default blueprint is empty.
218
+
219
+ ### Blueprints on Plain Old Ruby Objects
220
+
221
+ Machinist also works with plain old Ruby objects. Let's say you have a class like:
222
+
223
+ ```ruby
224
+ class Post
225
+ extend Machinist::Machinable
226
+
227
+ attr_accessor :title
228
+ attr_accessor :body
229
+ end
230
+ ```
231
+
232
+ You can blueprint the Post class just like anything else:
233
+
234
+ ```ruby
235
+ Post.blueprint do
236
+ title { 'A title!' }
237
+ body { 'A body!' }
238
+ end
239
+ ```
240
+
241
+ And `Post.make` will construct a new Post.
242
+
243
+ ### Other Tricks
244
+
245
+ You can refer to already assigned attributes when constructing a new attribute:
246
+
247
+ ```ruby
248
+ Post.blueprint do
249
+ author { "Author #{sn}" }
250
+ body { "Post by #{object.author}" }
251
+ end
252
+ ```
253
+
254
+ ### More Details
255
+
256
+ Read the code! No, really. I wrote this code to be read.
257
+
258
+ Check out [the specs](https://github.com/dominicsayers/machinist/tree/master/spec), starting with [the spec for Machinable](https://github.com/dominicsayers/machinist/blob/master/spec/machinable_spec.rb).
259
+
260
+ ## Developing
261
+
262
+ The Machinist specs and source code were written to be read, and I'm pretty
263
+ happy with them. Don't be afraid to have a look under the hood!
264
+
265
+ If you want to submit a patch:
266
+
267
+ - Fork the project.
268
+ - Make your feature addition or bug fix.
269
+ - Add tests for it. This is important so I don't break it in a
270
+ future version unintentionally.
271
+ - Commit, do not mess with rakefile, version, or history.
272
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
273
+ - Send me a pull request. Bonus points for topic branches.
274
+
275
+ ## Contributors
276
+
277
+ Machinist was maintained by Pete Yandell ([pete@notahat.com](mailto:pete@notahat.com), [@notahat](http://twitter.com/notahat))
278
+
279
+ Other contributors include:
280
+
281
+ [Marcos Arias](http://github.com/yizzreel),
282
+ [Jack Dempsey](http://github.com/jackdempsey),
283
+ [Jeremy Durham](http://github.com/jeremydurham),
284
+ [Clinton Forbes](http://github.com/clinton),
285
+ [Perryn Fowler](http://github.com/perryn),
286
+ [Niels Ganser](http://github.com/Nielsomat),
287
+ [Jeremy Grant](http://github.com/jeremygrant),
288
+ [Jon Guymon](http://github.com/gnarg),
289
+ [James Healy](http://github.com/yob),
290
+ [Ben Hoskings](http://github.com/benhoskings),
291
+ [Evan David Light](http://github.com/elight),
292
+ [Chris Lloyd](http://github.com/chrislloyd),
293
+ [Adam Meehan](http://github.com/adzap),
294
+ [Kyle Neath](http://github.com/kneath),
295
+ [Lawrence Pit](http://github.com/lawrencepit),
296
+ [Xavier Shay](http://github.com/xaviershay),
297
+ [T.J. Sheehy](http://github.com/tjsheehy),
298
+ [Roland Swingler](http://github.com/knaveofdiamonds),
299
+ [Gareth Townsend](http://github.com/quamen),
300
+ [Matt Wastrodowski](http://github.com/towski),
301
+ [Ian White](http://github.com/ianwhite),
302
+ [Dominic Sayers](https://github.com/dominicsayers)
303
+
304
+ Thanks to Thoughtbot's [Factory
305
+ Girl](http://github.com/thoughtbot/factory_girl/tree/master). Machinist was
306
+ written because I loved the idea behind Factory Girl, but I thought the
307
+ philosophy wasn't quite right, and I hated the syntax.