{"id":29272104,"url":"https://github.com/acook/impasta","last_synced_at":"2025-07-05T00:10:35.541Z","repository":{"id":13722450,"uuid":"16416605","full_name":"acook/impasta","owner":"acook","description":"IMPASTA!! A test spy for your Ruby app.","archived":false,"fork":false,"pushed_at":"2023-02-21T17:34:04.000Z","size":91,"stargazers_count":1,"open_issues_count":5,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2024-08-08T15:17:59.932Z","etag":null,"topics":["minimalist-library","mocking-framework","modular","ruby","spy","test-spies","testing-framework"],"latest_commit_sha":null,"homepage":null,"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/acook.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-01-31T18:34:20.000Z","updated_at":"2022-04-14T04:54:37.000Z","dependencies_parsed_at":"2022-09-23T14:31:36.497Z","dependency_job_id":null,"html_url":"https://github.com/acook/impasta","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/acook/impasta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acook%2Fimpasta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acook%2Fimpasta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acook%2Fimpasta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acook%2Fimpasta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/acook","download_url":"https://codeload.github.com/acook/impasta/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/acook%2Fimpasta/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263636825,"owners_count":23492312,"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":["minimalist-library","mocking-framework","modular","ruby","spy","test-spies","testing-framework"],"created_at":"2025-07-05T00:10:33.455Z","updated_at":"2025-07-05T00:10:35.534Z","avatar_url":"https://github.com/acook.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"Impasta\n=======\n\n\u003e **im-past-a** (noun)\n\u003e\n\u003e 1. A piece of pasta found with other pasta noodles that do not share its type.\n\u003e 2. A test spy that can impersonate a given class and/or track methods passed to it.\n\u003e\n\u003e **Origin:** portmanteau of *imposter* and *pasta*\n\n*protip: definition #2 is the one we're talking about*\n\n[![Gem Version](https://img.shields.io/gem/v/impasta.svg?style=for-the-badge)](https://rubygems.org/gems/impasta)\n[![Build Status](https://img.shields.io/circleci/build/github/acook/impasta/main.svg?style=for-the-badge)](https://circleci.com/gh/acook/impasta/tree/main)\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'impasta'\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install impasta\n\n## Usage\n\nIt's pretty easy, to create a new Impasta just do:\n\n~~~ruby\nimp = Impasta.decoy\n~~~\n\nYou can give it a name too:\n\n~~~ruby\naka_imp = Impasta.decoy aka: 'totally not an imposter'\n~~~\n\nBoth of those Impastas will accept any method and args you throw at them.\n\n~~~ruby\nimp.whatever                       #=\u003e self\naka_imp.lulz 2, 3, :slimpickins    #=\u003e self\n~~~\n\nBut you can also constrain the methods Impasta objects accept by passing in a target:\n\n~~~ruby\narray_imp = Impasta.infiltrate target: Array.new\n\narray_imp.first         #=\u003e self\narray_imp.johnnycarson  #=\u003e raises Impasta::MissingMethod\n~~~\n\nYou can also extract information from an instance of Impasta:\n\n~~~ruby\narray_imp.impasta.ledger            # will display all methods sent to it in this format: [[method_name, arguments_sent_to_method, block_passed_to_method], ...]\narray_imp.impasta.target            #=\u003e [] # (this is the same array passed in earlier)\narray_imp.impasta.origin            #=\u003e \"readme.rb line #54\" # this will display where the Impasta was instantiated\n~~~\n\n## Meet the Spies\n\n### Decoy\n\n- `Impasta.decoy aka: \"A type of dummy object\"`\n- It responds to any message with self! (ignores any target and does its own thing)\n- Excellent placeholder when you don't care about enforcing which methods can be called.\n\n### Wiretap\n\n- `Impasta.wiretap aka: \"A type of proxy object\"`\n- Passes method calls on to the target and returns exactly that.\n- Good to keep an eye on what your objects are talking about when you're not looking.\n\n### Infiltrate\n\n- `Impasta.infiltrate aka: \"A type of test double\"`\n- Responds with `self` (the Infiltate object) for any message the target recognizes, raises an exception for anything else.\n- Will raise for everything if no target provided!\n- Good for enforcing API integrity, if you can use this one instead of a Decoy, I highly recommend it.\n\n### Ghoul\n\n- `Impasta.ghoul aka: \"A type of null object\"`\n- Responds with `nil` for any message the target recognizes, raises an exception for anything else.\n- Like Infilitrate, but returns `nil` instead for situations where you need to test nil-resiliency or stop returning endless `self`s. \n\n### Forging Messages (AKA: Mocking \u0026 Stubbing Methods)\n\n- Decoy and Infiltrate Impastas will always return `self` for any method they accept (any for Decoy, only what the target does for Infiltrate).\n- Ghoul always returns `nil`.\n- Wiretap always returns the same thing as the target.\n\nBut what if they didn't?\n\nEnter: FORGERY\n\n~~~ruby\nimp.decoy\ntmp.identity                                     #=\u003e self\nimp.impasta.forge :identity, returns: \"fake id\"\nimp.identity                                     #=\u003e \"fake id\"\n~~~\n\nYou can use a single `returns` keyword as above or you can use a block instead to set the value it will respond with when it receives the message. \nArguments are ignored by the forgery, but you can check the ledger to make sure they are correct.\n\n### Secrets\n\nAll spies have secrets, you've already interacted with them above, obtained by calling the `Spy#impasta` method.\n\nBut they can do other things, here are a few more:\n\n- `secrets.inspect_target` to remind yourself about who this spy is targetting\n- `secrets.inspect_forgeries` to see the list of forgeries this spy is carrying\n- `secrets.codename` to get the spy to spill the beans on everything it knows\n- `secrets.within` accepts a block and executes in the context of the `Impasta::Secrets` instance, good for configuring a bunch of things all at once\n\n## Contributing\n\n1. Fork it ( http://github.com/acook/impasta/fork )\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Add some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facook%2Fimpasta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Facook%2Fimpasta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Facook%2Fimpasta/lists"}