{"id":15022432,"url":"https://github.com/wilsonsilva/xavier","last_synced_at":"2025-10-24T01:30:33.155Z","repository":{"id":56898643,"uuid":"124574588","full_name":"wilsonsilva/xavier","owner":"wilsonsilva","description":"Imagine DatabaseCleaner for objects in memory.","archived":false,"fork":false,"pushed_at":"2020-06-08T20:03:43.000Z","size":61,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2024-03-15T01:55:42.985Z","etag":null,"topics":["rspec","ruby","test"],"latest_commit_sha":null,"homepage":"https://www.rubydoc.info/gems/xavier","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/wilsonsilva.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-03-09T17:50:48.000Z","updated_at":"2024-01-25T13:14:32.000Z","dependencies_parsed_at":"2022-08-20T17:40:27.487Z","dependency_job_id":null,"html_url":"https://github.com/wilsonsilva/xavier","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilsonsilva%2Fxavier","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilsonsilva%2Fxavier/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilsonsilva%2Fxavier/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wilsonsilva%2Fxavier/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wilsonsilva","download_url":"https://codeload.github.com/wilsonsilva/xavier/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219867198,"owners_count":16555821,"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":["rspec","ruby","test"],"created_at":"2024-09-24T19:57:56.579Z","updated_at":"2025-10-24T01:30:32.823Z","avatar_url":"https://github.com/wilsonsilva.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/wilsonsilva/xavier/raw/master/logo.png\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eXavier\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"http://badge.fury.io/rb/xavier\"\u003e\n    \u003cimg src=\"https://badge.fury.io/rb/xavier.svg\" alt=\"Gem Version\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://travis-ci.org/wilsonsilva/xavier\"\u003e\n    \u003cimg src=\"https://travis-ci.org/wilsonsilva/xavier.svg?branch=master\" alt=\"Build Status\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codeclimate.com/github/wilsonsilva/xavier/maintainability\"\u003e\n    \u003cimg src=\"https://api.codeclimate.com/v1/badges/7473cd7cdcf12b4bb453/maintainability\" alt=\"Maintainability\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codeclimate.com/github/wilsonsilva/xavier/test_coverage\"\u003e\n    \u003cimg src=\"https://api.codeclimate.com/v1/badges/7473cd7cdcf12b4bb453/test_coverage\" alt=\"Test Coverage\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"http://inch-ci.org/github/wilsonsilva/xavier\"\u003e\n    \u003cimg src=\"http://inch-ci.org/github/wilsonsilva/xavier.svg?branch=master\" alt=\"Inline docs\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\nTracks and reverts objects internal state mutations (changes in `instance`, `class`, and `class instance` variables).\n\n## Table of contents\n\n* [Motivation](#motivation)\n* [Installation](#installation)\n* [Usage](#usage)\n  * [TL;DR](#tldr)\n  * [With object instances](#with-object-instances)\n* [Development](#development)\n* [Contributing](#contributing)\n\n## Motivation\n\nIn X-men, one of Xavier's goals is to protect society from antagonistic mutants. In Ruby, Xavier's goal is to protect\ntest cases from failures caused by global state mutations.\n\nGlobal state can easily lead to interference between test cases and cause random failures. These issues are called\n__mystery guests__, because they affect the behavior of the code being tested however the test method fails to show\nthat relationship.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'xavier'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install xavier\n\n## Usage\n\n### TL;DR\n\nCall `Xavier.observe` with an object (observable) and a block. Modify the state of the observable inside the block.\nWhen the block finishes executing, all the state mutations on the observable are reverted:\n\n```ruby\nXavier.observe(observable) do\n  # mutate the state of observable inside of this block\nend\n\n# all mutations on the observable are reverted outside of the block\n```\n\n### With object instances\n\nConsider [Jean Grey](https://en.wikipedia.org/wiki/Jean_Grey), a caring, nurturing human:\n\n```ruby\nclass JeanGrey\n  attr_reader :traits\n  \n  def initialize\n    @traits = ['caring', 'nurturing']\n  end\nend\n\njean_grey = JeanGrey.new\njean_grey.traits # =\u003e ['caring', 'nurturing']\n````\n\nJean's mutant power of telepathy first manifest when her best friend is hit by a car and killed. The event leaves her\ncomatose:\n\n```ruby\nclass JeanGrey\n  attr_reader :powers, :traits\n  \n  def initialize\n    @powers = []\n    @traits = ['caring', 'nurturing']\n  end\n  \n  def witness_friend_die!\n    powers \u003c\u003c 'telepathy'\n    traits \u003c\u003c 'comatose'\n  end\nend\n\njean_grey = JeanGrey.new\njean_grey.powers # =\u003e []\njean_grey.traits # =\u003e ['caring', 'nurturing']\njean_grey.witness_friend_die!\njean_grey.powers # =\u003e ['telepathy']\njean_grey.traits # =\u003e ['caring', 'nurturing', 'comatose']\n````\n\nShe is brought back to consciousness when her parents seek the help of powerful mutant telepath, Charles Xavier. Xavier\nblocks her telepathy until she is old enough to be able to control it:\n\n```ruby\nclass JeanGrey\n  attr_reader :powers, :traits\n  \n  def initialize\n    @powers = []\n    @traits = ['caring', 'nurturing']\n  end\n  \n  def witness_friend_die!\n    powers \u003c\u003c 'telepathy'\n    traits \u003c\u003c 'comatose'\n  end\nend\n\njean_grey = JeanGrey.new\njean_grey.powers # =\u003e []\njean_grey.traits # =\u003e ['caring', 'nurturing']\n\nXavier.observe(jean_grey) do\n  jean_grey.witness_friend_die!\n  jean_grey.powers # =\u003e ['telepathy']\n  jean_grey.traits # =\u003e ['caring', 'nurturing', 'comatose']\nend\n\njean_grey.powers # =\u003e []\njean_grey.traits # =\u003e ['caring', 'nurturing']\n````\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive\nprompt that will allow you to experiment. The health and maintainability of the codebase is ensured through a set of\nRake tasks to test, lint and audit the gem for security vulnerabilities and documentation:\n\n```\nrake rubocop               # Lint the codebase with RuboCop\nrake rubocop:auto_correct  # Auto-correct RuboCop offenses\nrake spec                  # Run RSpec code examples\nrake verify_measurements   # Verify that yardstick coverage is at least 100%\nrake yard                  # Generate YARD Documentation\nrake yard:junk             # Check the junk in your YARD Documentation\nrake yardstick_measure     # Measure docs in lib/**/*.rb with yardstick\n```\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the\nversion number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,\npush git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at https://github.com/wilsonsilva/xavier.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilsonsilva%2Fxavier","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwilsonsilva%2Fxavier","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilsonsilva%2Fxavier/lists"}