{"id":22909482,"url":"https://github.com/roschaefer/fabulist","last_synced_at":"2025-04-01T10:04:16.651Z","repository":{"id":150361334,"uuid":"9733069","full_name":"roschaefer/Fabulist","owner":"roschaefer","description":null,"archived":false,"fork":false,"pushed_at":"2013-08-22T08:33:01.000Z","size":388,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-02-07T05:29:22.407Z","etag":null,"topics":[],"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/roschaefer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-04-28T16:59:56.000Z","updated_at":"2014-10-28T11:55:26.000Z","dependencies_parsed_at":"2023-04-04T02:16:42.578Z","dependency_job_id":null,"html_url":"https://github.com/roschaefer/Fabulist","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roschaefer%2FFabulist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roschaefer%2FFabulist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roschaefer%2FFabulist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roschaefer%2FFabulist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/roschaefer","download_url":"https://codeload.github.com/roschaefer/Fabulist/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246620262,"owners_count":20806722,"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-12-14T03:39:10.955Z","updated_at":"2025-04-01T10:04:16.617Z","avatar_url":"https://github.com/roschaefer.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fabulist\n\nWrite declarative and vivid cucumber features by referencing shared state across multiple steps.\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n    gem 'fabulist', :git =\u003e 'https://github.com/teamaker/Fabulist.git'\n\nAnd then run:\n\n    $ bundle install\n\n## Usage\nIn situations where you write conjunctive steps (ie. share state across several step definitions) it's usual to assign instance variables used by the following steps. When doing so, your step definitions have to know implementation details of each other, thus become inflexible and tightly coupled.\n\nTherefore, this gem provides a simple api to memorize arbitrary ruby object and to reference them by:\n\n1. class\n2. any predicate\n3. insertion order\n\nLet's have a look at this sample scenario:\n\n```cucumber\nFeature: Reference shared objects between multiple step definitions\nAs a developer\nI want to show this minmal working example\nIn order to demonstrate the main pupose of this gem\n\nScenario: Call by a name\n  Given I am a user and my name is \"John\"\n  When someone asks for John\n  Then I will respond\n```\n\n```ruby\nclass User\n  attr_accessor :name\n\n  def initialize(name)\n    self.name = name\n  end\n\n  def called(name)\n    self.name == name\n  end\nend\n\n```\nYou can keep track of your domain models with ```memorize``` and ```recall```:\n\n```ruby\nGiven(/^I am a user and my name is \"(.*?)\"$/) do |name|\n  user = User.new(name)\n  memorize user\nend\n\nWhen(/^someone asks for (.*)$/) do |name|\n  recall Object, :called, name\nend\n```\n\nThat's it.\n\n```ruby\n#In this particular case, other ways to call the the user would be:\nrecall                         # =\u003e user\nrecall User, :called, \"John\"   # =\u003e user\n\n# only this will raise an exception\nrecall AnotherClass          # =\u003e raises NoObjectFound\nrecall User, :called, \"Karl\" # =\u003e raises NoObjectFound\nrecall User, :whatsoever     # =\u003e raises NoObjectFound, because the user doesn't respond to 'whatsoever'\n```\n## Hints\n\nYour objects lack the ability methods to say whether they have a particular feature or not? If you don't want to bloat your production code with test specific implementation, try to *wrap* your objects. In the [features](https://github.com/teamaker/Fabulist/tree/master/features) I use a [tagged object](https://github.com/teamaker/Fabulist/blob/master/features/support/tagged_object.rb) to mark arbitrary objects. The tagged object serves as a proxy for the original object.\nIf your objects encapsulate some state but lack the necessary methods, a proxy should check the underlying state of the object.\n\nAre your features first-person narrative? Give the [narrator](https://github.com/teamaker/Fabulist/blob/master/features/support/narrator.rb) his own representation. Then you can literally interact with the objects that occur in your story.\n\n## Configuration\nTo make the convenience methods ```memorize``` and ```recall``` available to your cucumber world, add this line:\n```ruby\n# features/support/fabulist.rb\nrequire 'fabulist/cucumber'\n```\n\nDo you use ActiveRecord and you always want updated models?\nYou can configure callbacks to define what happens before you memorize an object or recall it from memory.\n\n```ruby\n# features/support/fabulist.rb\nrequire 'fabulist'\nFabulist.configure do |config|\n  config.before_memorize do |object|\n    object.save!\n  end\n  config.after_recall  do |object|\n    object.reload\n  end\nend\n\n```\n## LoC\n```shell\n➜  Fabulist git:(master) ✗ git rev-parse HEAD\n8e528dba9100648c523cd4791bb865703a9fe2ae\n➜  Fabulist git:(master) ✗ find lib | grep \".rb$\" | xargs cat | wc -l  \n     117\n```\n## Contributing\n\n1. Fork it\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%2Froschaefer%2Ffabulist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froschaefer%2Ffabulist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froschaefer%2Ffabulist/lists"}