{"id":13513921,"url":"https://github.com/p0deje/yard-doctest","last_synced_at":"2025-04-04T22:07:24.414Z","repository":{"id":56899026,"uuid":"20852905","full_name":"p0deje/yard-doctest","owner":"p0deje","description":"Doctests from YARD examples","archived":false,"fork":false,"pushed_at":"2023-04-24T23:45:07.000Z","size":80,"stargazers_count":113,"open_issues_count":4,"forks_count":16,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-03T18:50:24.730Z","etag":null,"topics":["doctest","ruby","yard"],"latest_commit_sha":null,"homepage":"","language":"Gherkin","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/p0deje.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2014-06-15T10:18:21.000Z","updated_at":"2025-01-12T14:54:05.000Z","dependencies_parsed_at":"2024-06-18T16:44:14.861Z","dependency_job_id":null,"html_url":"https://github.com/p0deje/yard-doctest","commit_stats":{"total_commits":73,"total_committers":7,"mean_commits":"10.428571428571429","dds":0.1643835616438356,"last_synced_commit":"68edd1d5908f3c6016f9bf030fbcac449bf8bf5c"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p0deje%2Fyard-doctest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p0deje%2Fyard-doctest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p0deje%2Fyard-doctest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/p0deje%2Fyard-doctest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/p0deje","download_url":"https://codeload.github.com/p0deje/yard-doctest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247256112,"owners_count":20909240,"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":["doctest","ruby","yard"],"created_at":"2024-08-01T05:00:40.226Z","updated_at":"2025-04-04T22:07:24.395Z","avatar_url":"https://github.com/p0deje.png","language":"Gherkin","funding_links":[],"categories":["Gherkin"],"sub_categories":[],"readme":"# yard-doctest [![Gem Version](https://badge.fury.io/rb/yard-doctest.svg)](http://badge.fury.io/rb/yard-doctest) ![CI status](https://github.com/p0deje/yard-doctest/actions/workflows/ci.yml/badge.svg)\n\n\nHave you ever wanted to turn your amazing code examples into something that really make sense, is always up-to-date and bullet-proof? Were looking at an amazing [Python doctest](https://docs.python.org/3/library/doctest.html)? Well, look no longer!\n\nMeet `YARD::Doctest` - simple and magical gem, which automatically parses your `@example` tags and turn them into tests!\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'yard-doctest'\n```\n\nAnd then execute:\n\n```bash\n$ bundle install\n```\n\nOr install it yourself as:\n\n```bash\n$ gem install yard-doctest\n```\n\n## Basic usage\n\nLet's imagine you have the following library:\n\n```\nlib/\n  cat.rb\n  dog.rb\n```\n\nEach file contains some class and methods:\n\n```ruby\n# cat.rb\nclass Cat\n  # @example\n  #   Cat.word #=\u003e 'meow'\n  def self.word\n    'meow'\n  end\n\n  def initialize(can_hunt_dogs = false)\n    @can_hunt_dogs = can_hunt_dogs\n  end\n\n  # @example Usual cat cannot hunt dogs\n  #   cat = Cat.new\n  #   cat.can_hunt_dogs? #=\u003e false\n  #\n  # @example Lion can hunt dogs\n  #   cat = Cat.new(true)\n  #   cat.can_hunt_dogs? #=\u003e true\n  #\n  # @example Mutated cat can hunt dogs too\n  #   cat = Cat.new\n  #   cat.instance_variable_set(:@can_hunt_dogs, true) # not part of public API\n  #   cat.can_hunt_dogs? #=\u003e true\n  def can_hunt_dogs?\n    @can_hunt_dogs\n  end\nend\n```\n\n```ruby\n# dog.rb\nclass Dog\n  # @example\n  #   Dog.word #=\u003e 'meow'\n  def self.word\n    'woof'\n  end\n\n  # @example Dogs never hunt dogs\n  #   dog = Dog.new\n  #   dog.can_hunt_dogs? #=\u003e false\n  def can_hunt_dogs?\n    false\n  end\nend\n```\n\nYou can run tests for all the examples you've documented.\n\nFirst of all, you need to tell YARD to automatically load `yard-doctest` (as well as other plugins).\nTo do so, add yard-doctest as an automatically loaded plugin in your `.yardops`:\n\n```bash\n# .yardopts\n--plugin yard-doctest\n```\n\nNext, you'll need to create test helper, which will be required before each of your test. Think about it as `spec_helper.rb` in RSpec, `test_helper.rb` in Minitest, or `env.rb` in Cucumber. You should require everything necessary for your examples to run there.\n\n```bash\n$ touch doctest_helper.rb\n# or move it into the `support`, `spec`, or `test` directory\n```\n\n```ruby\n# doctest_helper.rb\nrequire 'lib/cat'\nrequire 'lib/dog'\n```\n\nThat's pretty much it, you can now run your examples:\n\n```bash\n$ bundle exec yard doctest\nRun options: --seed 5974\n\n# Running:\n\n..F...\n\nFinished in 0.015488s, 387.3967 runs/s, 387.3967 assertions/s.\n\n  1) Failure:\nDog.word#test_0001_ [lib/dog.rb:5]:\nExpected: \"meow\"\n  Actual: \"woof\"\n\n6 runs, 6 assertions, 1 failures, 0 errors, 0 skips\n```\n\nOops, let's go back and fix the example by change \"meow\" to \"woof\" in `Dog.word` and re-run the examples:\n\n```bash\n$ sed -i.bak s/meow/woof/g lib/dog.rb\n$ bundle exec yard doctest\nRun options: --seed 51966\n\n# Running:\n\n......\n\nFinished in 0.002712s, 2212.3894 runs/s, 2212.3894 assertions/s.\n\n6 runs, 6 assertions, 0 failures, 0 errors, 0 skips\n```\n\nPretty simple, ain't it? Need more details about the way it parses examples?\n\nThink about `#=\u003e` as equality assertion: everything before is actual result, everything after is expected result and they are asserted using `#==`.\n\nYou can use as many assertions as you want in a single example:\n\n```ruby\nclass Cat\n  # @example\n  #   cat = Cat.new\n  #   cat.can_hunt_dogs? #=\u003e false\n  #   cat = Cat.new(true)\n  #   cat.can_hunt_dogs? #=\u003e true\n  def can_hunt_dogs?\n    @can_hunt_dogs\n  end\nend\n```\n\nIn this case, example will be run as a single test but with multiple assertions:\n\n```bash\n$ bundle exec yard doctest lib/cat.rb\n# ...\n1 runs, 2 assertions, 0 failures, 0 errors, 0 skips\n```\n\nIf your example has no assertions, it will still be evaluated to ensure nothing is raised at least:\n\n```ruby\nclass Cat\n  # @example\n  #   cat = Cat.new\n  #   cat.can_hunt_dogs?\n  def can_hunt_dogs?\n    @can_hunt_dogs\n  end\nend\n```\n\n```bash\n$ bundle exec yard doctest lib/cat.rb\n# ...\n1 runs, 0 assertions, 0 failures, 0 errors, 0 skips\n```\n\nPretty simple, ain't it? Need more details about the way it runs the tests?\n\nIt is actually delegated to amazing [minitest](https://github.com/seattlerb/minitest) and each example is an instance of `Minitest::Spec`.\n\n## Advanced usage\n\n### Exceptions\n\nIf you want to use example that raises exception, this can be achieved by specifying the correct expected value:\n\n```ruby\nclass Calculator\n  # @example\n  #   divide(1, 0) #=\u003e raise ZeroDivisionError, \"divided by 0\"\n  def divide(one, two)\n    one / two\n  end\nend\n```\n\nThe comparison of raised exceptions is being done by string containing the class and message of exceptions. With that said, you have to use the same message in expected value as the one that is used in actual.\n\n### Test helper\n\nYou can define any methods and instance variables in test helper and they will be available in examples.\n\nFor example, if we change the examples for `Cat#can_hunt_dogs?` like that:\n\n```ruby\n# cat.rb\nclass Cat\n  # @example Usual cat cannot hunt dogs\n  #   cat.can_hunt_dogs? #=\u003e false\n  def can_hunt_dogs?\n    @can_hunt_dogs\n  end\nend\n```\n\nAnd run the examples - it will fail because `cat is undefined`:\n\n```bash\n$ bundle exec yard doctest\n  # ...\n  1) Error:\nCat#can_hunt_dogs?#test_0001_Usual cat cannot hunt dogs:\nNameError: undefined local variable or method `cat' for Object:Class\n  # ...\n```\n\nIf you don't want to create new instance of class each time (or include module if you're testing it), you can fix this by defining a method in test helper:\n\n```ruby\n# doctest_helper.rb\nrequire 'lib/cat'\nrequire 'lib/dog'\n\ndef cat\n  @cat ||= Cat.new\nend\n```\n\n### Hooks\n\nIn case you need to do some preparations/cleanup between tests, hooks are at your service to be defined in test helper:\n\n```ruby\nYARD::Doctest.configure do |doctest|\n  doctest.before do\n    # this is called before each example and\n    # evaluated in the same context as example\n    # (i.e. has access to the same instance variables)\n  end\n\n  doctest.after do\n    # same as `before`, but runs after each example\n  end\n\n  doctest.after_run do\n    # runs after all the examples and\n    # has different context\n    # (i.e. no access to instance variables)\n  end\nend\n```\n\nThere is also a way to limit hooks to specific tests based on class/method name:\n\n```ruby\nYARD::Doctest.configure do |doctest|\n  doctest.before('MyClass') do\n    # this will only be called for doctests of `MyClass` class\n    # and all its methods (i.e. `MyClass.foo`, `MyClass#bar`)\n  end\n\n  doctest.after('MyClass#foo') do\n    # this will only be called for doctests of `MyClass#foo`\n  end\n\n  doctest.before('MyClass#foo@Example one') do\n    # this will only be called for example `Example one` of `MyClass#foo`\n  end\nend\n```\n\n### Skip\n\nYou can skip running some of the tests:\n\n```ruby\nYARD::Doctest.configure do |doctest|\n  doctest.skip 'MyClass' # will skip doctests for `MyClass` and all its methods\n  doctest.skip 'MyClass#foo' # will skip doctests for `MyClass#foo`\nend\n```\n\n### Rake\n\nThere is also a Rake task for you:\n\n```ruby\n# Rakefile\nrequire 'yard/doctest/rake'\n\nYARD::Doctest::RakeTask.new do |task|\n  task.doctest_opts = %w[-v]\n  task.pattern = 'lib/**/*.rb'\nend\n```\n\n```bash\n$ bundle exec rake yard:doctest\n```\n\n## Is it really used?\n\nWell, yeah. A great example of using yard-doctest is [watir-webdriver](https://github.com/watir/watir-webdriver).\n\n## Testing\n\nThere are some system tests implemented with [Aruba](https://github.com/cucumber/aruba):\n\n```bash\n$ bundle install\n$ bundle exec rake cucumber\n```\n\n## Contributing\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 future version unintentionally.\n* Commit, do not mess with Rakefile, version, or history. (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","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp0deje%2Fyard-doctest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fp0deje%2Fyard-doctest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fp0deje%2Fyard-doctest/lists"}