{"id":18103854,"url":"https://github.com/sandro/assembly_line","last_synced_at":"2025-04-13T19:26:49.985Z","repository":{"id":799299,"uuid":"499900","full_name":"sandro/assembly_line","owner":"sandro","description":"Organize your test suite's object graphs in semantic blocks","archived":false,"fork":false,"pushed_at":"2010-03-05T22:33:13.000Z","size":109,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-10T10:40:50.023Z","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/sandro.png","metadata":{"files":{"readme":"README.markdown","changelog":"History.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2010-02-03T00:32:38.000Z","updated_at":"2013-11-17T10:10:10.000Z","dependencies_parsed_at":"2022-08-16T10:55:19.649Z","dependency_job_id":null,"html_url":"https://github.com/sandro/assembly_line","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandro%2Fassembly_line","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandro%2Fassembly_line/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandro%2Fassembly_line/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sandro%2Fassembly_line/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sandro","download_url":"https://codeload.github.com/sandro/assembly_line/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248767052,"owners_count":21158374,"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-10-31T22:13:18.097Z","updated_at":"2025-04-13T19:26:49.964Z","avatar_url":"https://github.com/sandro.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"Assembly Line\n=============\n\nAssembly Line allows you to group together a series of rspec `let` statements which can later be evaluated to set up a specific state for your specs. It's an excellent compliment to factory_girl because you can use your factories to build up each component, then use AssemblyLine to bring them all together.\n\nAs a system grows in complexity, more objects are required to set up the necessary state to write tests. Sometimes you'll need to write a test that requires access to the beginning, middle, and end of a very large hierarchy, and AssemblyLine can expose each part of the hierarchy that you care about.\n\nInstallation\n------------\n    gem install assembly_line\n\nEdit your *spec/spec_helper.rb*\n\n    # unnecessary if you used config.gem 'assembly_line'\n    require 'assembly_line'\n\n    # I put my definitions inside of spec/support/ because my spec_helper loads everything in that directory\n    require 'your_assembly_line_definitions'\n\n    # remember to extend the module in your Rspec configuration block\n    Spec::Runner.configure do |config|\n      config.extend AssemblyLine\n    end\n\nExample\n-------\n\n### Assuming you have the following class\n\n    class Party \u003c Struct.new(:host, :attendees)\n      attr_writer :drinks\n      def drinks\n        @drinks ||= []\n      end\n    end\n\n### Place your AssemblyLine definitions in *spec/support/assemblies/party_assembly.rb*\n\n    AssemblyLine.define(:drinks) do\n      let(:drinks) { [:gin, :vodka] }\n    end\n\n    AssemblyLine.define(:party) do\n      depends_on :drinks\n\n      let(:host) { :rochelle }\n      let(:attendees) { [:nick, :ellis, :coach] }\n      let(:party) { @party = Party.new(host, attendees) }\n      let(:party_crasher) { attendees \u003c\u003c :crasher; :crasher }\n    end\n\n### Use your AssemblyLine in a test\n\n    describe Party do\n      Assemble(:party)\n      before do\n        puts \"simple before block\"\n      end\n\n      context \"attendees\" do\n        it \"does not count the host as an attendee\" do\n          party.attendees.should_not include(host)\n        end\n      end\n\n      context \"party crasher\" do\n        Assemble(:party).invoke(:party_crasher)\n\n        it \"exemplifies method invocation after assembly\" do\n          party.attendees.should include(:crasher)\n        end\n      end\n\n      context \"drinks\" do\n        it \"does not include the list of standard drinks\" do\n          party.drinks.should_not include(drinks)\n        end\n      end\n    end\n\n### Use your AssemblyLine in an irb session\n\nAssemblyLine works a little differently when using it in irb. Your `let` definitions will not be defined globally (see [e26a903](http://github.com/sandro/assembly_line/commit/e26a903)), instead you'll have to prefix all defined methods with `AssemblyLine`.\n\n    \u003e\u003e require 'spec/support/assemblies'\n    \u003e\u003e Assemble(:drinks)\n    =\u003e #\u003cAssemblyLine::Constructor:0x10049e958 @code_block=#\u003cProc:0x000000010049ea98@(irb):1\u003e, @name=:drinks, @rspec_context=AssemblyLine::GlobalContext, @options={}\u003e\n    \u003e\u003e\n    \u003e\u003e AssemblyLine.drinks # the `drinks` method is prefixed with AssemblyLine\n    =\u003e [:gin, :vodka]\n\nUsage\n-----\n### let\n    AssemblyLine.define(:drinks) do\n      let(:drinks) { [:gin, :vodka] }\n    end\n\nThis is the main usage of AssemblyLine. Let defines a method named after the first parameter and returns the return value of the provided block. Let memoizes the results so subsequent calls to the method will return the same result without re-running the block. Let delegates to rspec's implementation of let.\n\n\n### before\n    AssemblyLine.define(:killer_feature) do\n      let(:killer_feature) { KillerFeature.new }\n      before do\n        KillerFeature.delete_all\n        killer_feature.save!\n      end\n    end\n\nYou can use rspec's before blocks within an AssemblyLine definition. This is a simple delegate so `before`, `before(:each)`, and `before(:all)` are all supported. You can even reference your `let` definitions within a before block.\n\n### depends_on\n    AssemblyLine.define(:user_with_expired_cc) do\n      let(:user) do\n        Factory(:confirmed_user).tap do |u|\n          u.credit_card.update_attribute :expiration_date, 1.year.ago\n        end\n      end\n    end\n\n    AssemblyLine.define(:subscription_with_invalid_cc) do\n      depends_on :user_with_expired_cc\n      let(:subscription) { Factory(:subscription, :user =\u003e user) }\n    end\n\nYou can utilize other AssemblyLine definitions with `depends_on`. It takes a list of AssemblyLine definitions to load. This allows you to make modular AssemblyLines which can be used throughout your spec suite.\n\n### invoke\n    AssemblyLine.define(:drinks) do\n      let(:drinks) do\n        [ Factory(:drink, :name =\u003e :gin), Factory(:drink, :name =\u003e :vodka) ]\n      end\n    end\n\n    describe \"Drinks#index\" do\n      Assemble(:drinks).invoke\n      it \"lists the drinks\" do\n        visit drinks_path\n        response.should contain(drinks.first.name)\n        response.should contain(drinks.last.name)\n      end\n    end\n\nInvoke takes a list of method names to call after assembly. If no arguments are provided, AssemblyLine will call a method named after the AssemblyLine itself, in this case `drinks` will be called. Note, these methods are called in a `before(:all)` block.\n\nLet definitions are lazily evaluated which means sometimes the expected data isn't available until it's too late. In the above example, if I didn't call `invoke` the drinks index page would be empty.\n\nThanks!\n-------\n\n- l4rk     (initial spike declaring modules and including them in the rspec context)\n- veezus   (code contributions, introduced modular design / dependencies)\n- bigtiger (named the project, contributor)\n- leshill  (support and testing, suggested irb support)\n- wgibbs   (suggested irb support)\n\n\nNote on Patches/Pull Requests\n-----------------------------\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\nCopyright\n---------\n\nCopyright (c) 2010 Sandro Turriate. See MIT_LICENSE for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandro%2Fassembly_line","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsandro%2Fassembly_line","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsandro%2Fassembly_line/lists"}