{"id":13395156,"url":"https://github.com/notahat/machinist","last_synced_at":"2025-05-14T12:10:11.927Z","repository":{"id":438242,"uuid":"59997","full_name":"notahat/machinist","owner":"notahat","description":"Fixtures aren't fun. Machinist is.","archived":false,"fork":false,"pushed_at":"2023-06-23T10:00:40.000Z","size":2161,"stargazers_count":1116,"open_issues_count":31,"forks_count":134,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-11T04:58:33.907Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/notahat.png","metadata":{"files":{"readme":"README.markdown","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2008-10-06T11:43:46.000Z","updated_at":"2024-11-17T19:36:31.000Z","dependencies_parsed_at":"2023-07-05T14:55:11.790Z","dependency_job_id":null,"html_url":"https://github.com/notahat/machinist","commit_stats":{"total_commits":253,"total_committers":21,"mean_commits":"12.047619047619047","dds":"0.17786561264822132","last_synced_commit":"dba78a430cd67646a270393c4adfa19a5516f569"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/notahat%2Fmachinist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/notahat%2Fmachinist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/notahat%2Fmachinist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/notahat%2Fmachinist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/notahat","download_url":"https://codeload.github.com/notahat/machinist/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253534345,"owners_count":21923521,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-30T17:01:44.426Z","updated_at":"2025-05-14T12:10:06.908Z","avatar_url":"https://github.com/notahat.png","language":"Ruby","funding_links":[],"categories":["Ruby","Testing"],"sub_categories":[],"readme":"# Machinist 2\n\n*Fixtures aren't fun. Machinist is.*\n\n- [Home page](http://github.com/notahat/machinist)\n- [Google group](http://groups.google.com/group/machinist-users), for support\n- [Bug tracker](http://github.com/notahat/machinist/issues), for reporting Machinist bugs\n\nIf you want Machinist 1, [go here](http://github.com/notahat/machinist/tree/1.0-maintenance).\n\n\n## Introduction\n\n*Note: Machinist isn't under active development. See the Status section below for more info.*\n\nMachinist makes it easy to create objects for use in tests. It generates data\nfor the attributes you don't care about, and constructs any necessary\nassociated objects, leaving you to specify only the fields you care about in\nyour test. For example:\n\n    describe Comment, \"without_spam scope\" do\n      it \"doesn't include spam\" do\n        # This will make a Comment, a Post, and a User (the author of the\n        # Post), generate values for all their attributes, and save them:\n        spam = Comment.make!(:spam =\u003e true)\n\n        Comment.without_spam.should_not include(spam)\n      end\n    end\n\nYou tell Machinist how to do this with blueprints:\n\n    require 'machinist/active_record'\n\n    User.blueprint do\n      username { \"user#{sn}\" }  # Each user gets a unique serial number.\n    end\n\n    Post.blueprint do\n      author\n      title  { \"Post #{sn}\" }\n      body   { \"Lorem ipsum...\" }\n    end\n\n    Comment.blueprint do\n      post\n      email { \"commenter#{sn}@example.com\" }\n      body  { \"Lorem ipsum...\" }\n    end\n\n\n## Installation\n\n### Upgrading from Machinist 1\n\nSee [the wiki](http://wiki.github.com/notahat/machinist/machinist-2).\n\n### Rails 3\n\nIn your app's `Gemfile`, in the `group :test` section, add:\n\n    gem 'machinist', '\u003e= 2.0.0.beta2'\n\nThen run:\n\n    bundle\n    rails generate machinist:install\n\nIf you want Machinist to automatically add a blueprint to your blueprints file\nwhenever you generate a model, add the following to your `config/application.rb`\ninside the Application class:\n\n    config.generators do |g|\n      g.fixture_replacement :machinist\n    end\n\n### Rails 2\n\nSee [the wiki](http://wiki.github.com/notahat/machinist/rails-2).\n\n\n## Usage\n\n### Blueprints\n\nA blueprint describes how to generate an object. The blueprint takes care of\nproviding attributes that your test doesn't care about, leaving you to focus on\njust the attributes that are important for the test.\n\nA simple blueprint might look like this:\n\n    Post.blueprint do\n      title  { \"A Post\" }\n      body   { \"Lorem ipsum...\" }\n    end\n\nYou can then construct a Post from this blueprint with:\n\n    Post.make!\n\nWhen you call `make!`, Machinist calls `Post.new`, then runs through the\nattributes in your blueprint, calling the block for each attribute to generate\na value. It then saves and reloads the Post. (It throws an exception if the\nPost can't be saved.)\n\nYou can override values defined in the blueprint by passing a hash to make:\n\n    Post.make!(:title =\u003e \"A Specific Title\")\n\nIf you want to generate an object without saving it to the database, replace\n`make!` with `make`.\n\n\n### Unique Attributes\n\nFor attributes that need to be unique, you can call the `sn` method from\nwithin the attribute block to get a unique serial number for the object.\n\n    User.blueprint do\n      username { \"user-#{sn}\" }\n    end\n\n\n### Associations\n\nIf your object needs associated objects, you can generate them like this:\n\n    Comment.blueprint do\n      post { Post.make }\n    end\n\nCalling `Comment.make!` will construct a Comment and its associated Post, and\nsave both.\n\nMachinist is smart enough to look at the association and work out what sort of\nobject it needs to create, so you can shorten the above blueprint to:\n\n    Comment.blueprint do\n      post\n    end\n\nIf you want to override the value for post when constructing the comment, you\ncan do this:\n\n    post = Post.make(:title =\u003e \"A particular title)\n    comment = Comment.make(:post =\u003e post)\n\n\nFor `has_many` and `has_and_belongs_to_many` associations, you can create\nmultiple associated objects like this:\n\n    Post.blueprint do\n      comments(3)  # Makes 3 comments.\n    end\n\n\n### Named Blueprints\n\nNamed blueprints let you define variations on an object. For example, suppose\nsome of your Users are administrators:\n\n    User.blueprint do\n      name  { \"User #{sn}\" }\n      email { \"user-#{sn}@example.com\" }\n    end\n\n    User.blueprint(:admin) do\n      name  { \"Admin User #{sn}\" }\n      admin { true }\n    end\n\nCalling:\n\n    User.make!(:admin)\n\nwill use the `:admin` blueprint.\n\nNamed blueprints call the default blueprint to set any attributes not\nspecifically provided, so in this example the `email` attribute will still be\ngenerated even for an admin user.\n\nYou must define a default blueprint for any class that has a named blueprint,\neven if the default blueprint is empty.\n\n\n### Blueprints on Plain Old Ruby Objects\n\nMachinist also works with plain old Ruby objects. Let's say you have a class like:\n\n    class Post\n      extend Machinist::Machinable\n\n      attr_accessor :title\n      attr_accessor :body\n    end\n\nYou can blueprint the Post class just like anything else:\n\n    Post.blueprint do\n      title { \"A title!\" }\n      body  { \"A body!\" }\n    end\n\nAnd `Post.make` will construct a new Post.\n\n\n### Other Tricks\n\nYou can refer to already assigned attributes when constructing a new attribute:\n\n    Post.blueprint do\n      author { \"Author #{sn}\" }\n      body   { \"Post by #{object.author}\" }\n    end\n\n\n### More Details\n\nRead the code! No, really. I wrote this code to be read.\n\nCheck out [the specs](https://github.com/notahat/machinist/tree/master/spec),\nstarting with [the spec for\nMachinable](https://github.com/notahat/machinist/blob/master/spec/machinable_spec.rb).\n\n\n## Compatibility\n\nI've tested this with:\n\nRuby versions: 1.8.7, 1.9.2, 1.9.3, 2.0.0\nRails versions: 2.3, 3.0, 3.2\n\nIt may well be happy with other versions too, but I'm not promising anything.\nCompatibility patches are welcome.\n\n\n## Developing\n\nThe Machinist specs and source code were written to be read, and I'm pretty\nhappy with them. Don't be afraid to have a look under the hood!\n\nIf you want to submit a patch:\n\n- Fork the project.\n- Make your feature addition or bug fix.\n- Add tests for it. This is important so I don't break it in a\n  future version unintentionally.\n- Commit, do not mess with rakefile, version, or history.\n  (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)\n- Send me a pull request. Bonus points for topic branches.\n\n\n## Status\n\nIn active use in a number of large Rails 2 and 3 apps.\n\nDevelopment is sporadic at best, as I find myself with less and less need for\nfactories in tests. See Bo Jeanes'\n[excellent article on the topic](http://bjeanes.com/2012/02/factories-breed-complexity).\n\nIf anybody wants to take over maintenance, let me know.\n\n\n## Contributors\n\nMachinist is maintained by Pete Yandell ([pete@notahat.com](mailto:pete@notahat.com), [@notahat](http://twitter.com/notahat))\n\nOther contributors include:\n\n[Marcos Arias](http://github.com/yizzreel),\n[Jack Dempsey](http://github.com/jackdempsey),\n[Jeremy Durham](http://github.com/jeremydurham),\n[Clinton Forbes](http://github.com/clinton),\n[Perryn Fowler](http://github.com/perryn),\n[Niels Ganser](http://github.com/Nielsomat),\n[Jeremy Grant](http://github.com/jeremygrant),\n[Jon Guymon](http://github.com/gnarg),\n[James Healy](http://github.com/yob),\n[Ben Hoskings](http://github.com/benhoskings),\n[Evan David Light](http://github.com/elight),\n[Chris Lloyd](http://github.com/chrislloyd),\n[Adam Meehan](http://github.com/adzap),\n[Kyle Neath](http://github.com/kneath),\n[Lawrence Pit](http://github.com/lawrencepit),\n[Xavier Shay](http://github.com/xaviershay),\n[T.J. Sheehy](http://github.com/tjsheehy),\n[Roland Swingler](http://github.com/knaveofdiamonds),\n[Gareth Townsend](http://github.com/quamen),\n[Matt Wastrodowski](http://github.com/towski),\n[Ian White](http://github.com/ianwhite)\n\nThanks to Thoughtbot's [Factory\nGirl](http://github.com/thoughtbot/factory_girl/tree/master). Machinist was\nwritten because I loved the idea behind Factory Girl, but I thought the\nphilosophy wasn't quite right, and I hated the syntax.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnotahat%2Fmachinist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnotahat%2Fmachinist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnotahat%2Fmachinist/lists"}