{"id":13595967,"url":"https://github.com/zombocom/rundoc","last_synced_at":"2025-04-08T12:31:54.379Z","repository":{"id":11281049,"uuid":"13689915","full_name":"zombocom/rundoc","owner":"zombocom","description":"RunDOC generates documentation by running scripts and embedding their results in the doc","archived":false,"fork":false,"pushed_at":"2024-05-17T16:22:41.000Z","size":327,"stargazers_count":70,"open_issues_count":3,"forks_count":9,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-05-17T17:28:01.809Z","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":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zombocom.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"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":"2013-10-18T21:03:21.000Z","updated_at":"2024-05-17T17:28:03.068Z","dependencies_parsed_at":"2024-05-06T16:29:56.361Z","dependency_job_id":null,"html_url":"https://github.com/zombocom/rundoc","commit_stats":null,"previous_names":["schneems/rundoc"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zombocom%2Frundoc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zombocom%2Frundoc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zombocom%2Frundoc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zombocom%2Frundoc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zombocom","download_url":"https://codeload.github.com/zombocom/rundoc/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247842683,"owners_count":21005325,"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-08-01T16:02:02.803Z","updated_at":"2025-04-08T12:31:54.372Z","avatar_url":"https://github.com/zombocom.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# RunDOC\n\n![](https://www.dropbox.com/s/u354td51brynr4h/Screenshot%202017-05-09%2009.36.33.png?raw=1)\n\n## What\n\nTurn your tutorials into tests and never let your docs be out of date again.\n\nStart off by writing your tutorial in modified-markdown, then execute it with `rundoc`. If there's a problem with following the directions, then your tutorial will fail to build. When it succeeds, the  real world output is embedded in the output markdown file. That means your tutorials will have the EXACT output that your readers will see.\n\n## Quickstart\n\nInstall the Ruby library:\n\n    $ gem install rundoc\n\nMake a rundoc file:\n\n    $ mkdir /tmp/rundoc-demo\n    $ cd /tmp/rundoc-demo\n    $ cat \u003c\u003c'EOF' \u003e ./RUNDOC.md\n    ```\n    :::\u003e\u003e $ echo Hello World\n    ```\n    EOF\n\nRun it:\n\n    $ rundoc --on-success-dir=rundoc_output ./RUNDOC.md\n\nView the output\n\n    $ cat rundoc_output/README.md\n    ```\n    $ echo Hello World\n    Hello World\n    ```\n\n## Install\n\nThis software is distributed as a Rubygem. Install it manually:\n\n```\n$ gem install rundoc\n```\n\nor add it to your Gemfile:\n\n```\ngem 'rundoc'\n```\n\n## Use It\n\nRun the `rundoc` command on any rundoc-flavored markdown file:\n\n```sh\n$ rundoc \u003ctest/fixtures/rails_7/rundoc.md\u003e\n```\n\n\u003e Note: This command will create and manipulate directories in the working directory of your source markdown file. Best practice is to have your source markdown file in its own empty directory.\n\nThis will generate a project folder with your project in it, and a markdown `README.md` with the parsed output of the markdown docs. See `rundoc --help` for more configuration options.\n\n## Quick docs\n\n- [Understanding the Syntax](#rundoc-syntax)\n- [Dotenv support](#dotenv-support)\n- [Rendering cheat sheet](#rendering-cheat-sheet)\n\n### Commands\n\n- Execute Bash Commands\n  - [$](#shell-commands)\n  - [fail.$](#shell-commands)\n- Dynamic command templating\n  - [pre.erb](#preerb)\n- Printing\n  - [print.text](#print)\n  - [print.erb](#print)\n- Chain commands\n  - [pipe](#pipe)\n  - [|](#pipe)\n- Manipulate Files\n  - [file.write](#file-commands)\n  - [file.append](#file-commands)\n  - [file.remove](#file-commands)\n- Boot background processes such as a local server\n  - [background.start](#background)\n  - [background.stop](#background)\n  - [background.stdin_write](#background)\n  - [background.wait](#background)\n  - [background.log.read](#background)\n  - [background.log.clear](#background)\n- Take screenshots\n  - [website.visit](#screenshots)\n  - [website.nav](#screenshots)\n  - [website.screenshot](#screenshots)\n- Configure RunDOC\n  - [rundoc.configure](#configure)\n- Import and compose documents\n  - [rundoc.require](#compose-multiple-rundoc-documents)\n\n## RunDOC Syntax\n\nRunDOC uses GitHub flavored markdown. This means you write like normal but in your code sections\nyou can add special annotations that when run through RunDOC can\ngenerate a project.\n\nAll RunDOC commands are prefixed with three colons `:::` and are inclosed in a code block a\ncommand such as `$` which is an alias for `bash` commands like this:\n\n    ```\n    :::\u003e- $ git init .\n    ```\n\nNothing before the three colons matters. The space between the colons\nand the command is optional.\n\nIf you don't want the command to output to your markdown document you\ncan add a minus symbol `-` to the end to prevent it from being\nrendered.\n\n    ```\n    :::-- $ git init .\n    ```\n\n\u003e Note: If all commands inside of a code block are hidden, the entire codeblock will not be rendered.\n\nIf you want the output of the actual command to be rendered to\nthe screen you can use two arrows so that:\n\n    ```\n    :::\u003e\u003e $ ls\n    ```\n\nThis code block might generate an output something like this to your markdown doc:\n\n    ```\n    $ ls\n        Gemfile   README.rdoc app   config.ru doc   log   script    tmp\n        Gemfile.lock  Rakefile  config    db    lib   public    test    vendor\n    ```\n\nAny items below the command will be passed into the stdin of the command. For example using a `$` command you can effectively pipe contents to stdin:\n\n    ```\n    :::\u003e\u003e $ tail -n 2\n    foo\n    bar\n    baz\n    bahz\n    ```\n\nWould output:\n\n   ```\n   $ tail -n 2\n   baz\n   bahz\n   ```\n\nThis STDIN feature could be useful if you are running an interactive command such as `play new` which requires user input.\n\nDifferent commands will do different things with this input. For example the `rundoc` command executes Ruby configuration code:\n\n    ```\n    :::-- rundoc\n    Rundoc.configure do |config|\n      config.after_build do\n        puts \"you could push to GitHub here\"\n        puts \"You could do anything here\"\n        puts \"This code will run after the docs are done building\"\n      end\n    end\n    ```\n\nAnd the `website.visit` command allows you to navigate and manipulate a webpage via a Capybara API:\n\n    ```\n    :::\u003e\u003e website.visit(name: \"localhost\", url: \"http://localhost:3000\", scroll: 100)\n    session.execute_script \"window.scrollBy(0,100)\"\n    session.click(\"sign up\")\n    ```\n\n### Exact output\n\nRunDOC only cares about things that come after a `:::` section. If you have a \"regular\" code section, it will be rendered as as normal:\n\n    ```\n    $ echo \"I won't run since i'm missing the :::\u003e\u003e at the front\"\n    ```\n\nYou can mix non-command code and commands, as long as the things that aren't rendering come first. This can be used to \"fake\" a command, for example:\n\n```\n$ rails new myapp # Not a command since it's missing the \":::\u003e\u003e\"\n:::-\u003e $ rails new myapp --skip-test --skip-yarn --skip-sprockets\n:::\u003e\u003e | $ head -n 5\n```\n\nThis will render as:\n\n```\n$ rails new myapp # Not a command since it's missing the \":::\u003e\u003e\"\"\n      create\n      create  README.md\n      create  Rakefile\n      create  .ruby-version\n      create  config.ru\n```\n\nIn this example it looks like the command was run without any flags, but in reality `rails new myapp --skip-test --skip-yarn --skip-sprockets | head -n 5` was executed. Though it's more explicit to use a `print.text` block, see [#print.text](#print) for more info.\n\n## Rendering Cheat Sheet\n\nAn arrow `\u003e` is shorthand for \"render this\" and a dash `-` is shorthand for skip this section. The two positions are **command** first and **result** second.\n\n- `:::\u003e-` (YES command output, not result output)\n- `:::\u003e\u003e` (YES command output, YES result output)\n- `:::--` (not command output, not result output)\n- `:::-\u003e` (not command output, YES result output)\n\n## Shell Commands\n\nCurrent Commands:\n\n- `$`\n- `fail.$`\n\nAnything you pass to `$` will be run in a shell. If a shell command returns a non-zero exit status an error will be raised. If you expect a non-zero exit status use `fail.$` instead:\n\n    ```\n    :::\u003e\u003e fail.$ cat /dev/null/foo\n    ```\n\nEven though this command returns a non zero exit status, the contents of the command will be written since we're stating that we don't care if the command fails. This would be the output:\n\n    ```\n    $ cat /dev/null/foo\n    cat: /dev/null/foo: Not a directory\n    ```\n\nSome commands may be custom, for example when running `cd` you likely want to change the working directory that your script is running in. To do this we need to run `Dir.chdir` instead of shelling out. So this works as you would expect:\n\n    ```\n    :::\u003e\u003e $ cd myapp/config\n    :::\u003e\u003e $ cat database.yml\n    ```\n\nHowever this command would fall on its face:\n\n    ```\n    :::\u003e\u003e $ cd myapp \u0026\u0026 cat config/database.yml\n    :::\u003e\u003e $ rails g scaffold users # \u003c=== This command would be in the wrong directory, not `myapp`\n    ```\n\nThese custom commands are kept to a minimum, and for the most part behave as you would expect them to. Write your docs as you normally would and check the output frequently.\n\nRunning shell commands like this can be very powerful, you'll likely want more control of how you manipulate files in your project. To do this you can use the `file.` namespace:\n\n## Dynamic command templating\n\nMeta commands that produce no output but instead allow for generating commands via dynamic templates.\n\nCurrent Commands:\n\n- `pre.erb`\n\n### pre.erb\n\nPlacing `pre.erb` in-front of another command will allow dynmaic templating via Ruby's [ERB](https://rubyapi.org/3.3/o/erb) syntax.\n\nFor example:\n\n  ```\n  :::\u003e\u003e pre.erb $ echo \"The answer to everything is \u003c%= 6*7 %\u003e\"\n  ```\n\nWhen this runs, it will first replace the template with the result of the ERB. It would be the same as this:\n\n    ```\n    :::\u003e\u003e $ echo \"The answer to everything is 42\"\n    ```\n\nThe binding (variable and method scope) for `pre.erb` is shared across all executions and the default `print.erb` command. That means you can use it to persist data or logic and re-use it:\n\n    ```ruby\n    :::-- print.erb \u003c%\n      # Won't be rendered because it's using `--` visibility\n      def lol\n        \"haha\"\n      end\n\n      user = \"Schneems\"\n    %\u003e\n    ```\n\n    ```\n    :::\u003e\u003e pre.erb $ echo \u003c%= user %\u003e said \u003c%= lol() %\u003e | tr '[:lower:]' '[:upper:]'\n    ```\n\nWhen run, this would produce:\n\n    ```\n    $ echo Schneems said haha | tr '[:lower:]' '[:upper:]'\n    SCHNEEMS SAID HAHA\n    ```\n\nMulti-line commands are also supported\n\n    ```\n    :::\u003e\u003e pre.erb file.write \"lol.txt\"\n    Super secret key:\n      \u003c%= \"#{key}\" %\u003e\n    ```\n\nThe only thing to watch out for is if the resulting template contains a `:::\u003e\u003e` (or similar) rundoc marker at the beginning of the line; Rundoc will think it is a new command rather than a part of `pre.erb` template.\n\nThe visibility of the `pre.erb` is forwarded to whatever command is run.\n\n## Print\n\nCurrent commands:\n\n- `print.text`\n- `print.erb`\n\nBehaves slightly differently than other commands. The \"command\" portion of the control character i.e. `:::\u003e` controls whether the contents will be rendered inside the block or before the block (versus usually this is used to control if the command such as `$ cd` is shown).\n\n- `:::\u003e\u003e` Print inside the code block\n- `:::-\u003e` Print BEFORE the code block, if multiple calls are made, they will be displayed in order.\n- `:::--` Nothing will be rendered, can be used to pass data to another rundoc command via the pipe operator.\n- `:::\u003e-` Same behavior as `:::--`.\n\nThis functionality is present to allow body text to be generated (versus only allowing generated text in code blocks).\n\nUse the `print.text` keyword followed by what you want to print:\n\n    ```\n    :::-\u003e print.text\n    I will render BEFORE the code block, use :::\u003e\u003e to render in it.\n\n    It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness,\n    it was the epoch of belief, it was the epoch ...\n    ```\n\nSpecifying `:::-\u003e` with `print.text` will render text without a code block (or before the code block if there are other rundoc commands). If you want to render text with a code block you can do it via `:::\u003e\u003e`.\n\nTo dynamically change the contents of the thing you're printing you can use `print.erb`:\n\n    ```\n    :::-\u003e print.erb\n    I will render BEFORE the code block, use :::\u003e\u003e to render in it.\n\n    What a week!\n    Captain it's only \u003c%= Time.now.strftime(\"%A\") %\u003e!\n    ```\n\nThis will evaluate the context of ERB and write it to the file. Like `print.text` use `:::-\u003e` to write the contents without a code block (or before the code block if there are other rundoc commands). If you want to render text with a code block you can do it via `:::\u003e\u003e`.\n\nERB commands share a default context. That means you can set a value in one `print.erb` section and view it from another. If you want to isolate your erb blocks you can provide a custom name via the `binding:` keyword:\n\n    ```\n    :::\u003e\u003e print.erb(binding: \"mc_hammer\")\n    I will render IN a code block, use `:::-\u003e` to render before.\n\n    \u003c%= @stop = true %\u003e\n\n    :::\u003e\u003e print.erb(binding: \"different\")\n    \u003c% if @stop %\u003e\n    Hammer time\n    \u003c% else %\u003e\n    Can't touch this\n    \u003c% end %\u003e\n    ```\n\nIn this example setting `@stop` in one `print.erb` will have no effect on the other.\n\n## File Commands\n\nCurrent Commands:\n\n- `file.write`\n- `file.append`\n- `file.remove`\n\nUse the `file.write` keyword followed by a filename, on the next line(s) put the contents of the file:\n\n    ```\n    :::\u003e- file.write config/routes.rb\n\n    Example::Application.routes.draw do\n      root        :to =\u003e \"pages#index\"\n\n      namespace :users do\n        resources :after_signup\n      end\n    end\n    ```\n\n\u003e If the exact filename is not known you can use a [file glob (\\*)](https://GitHub.com/schneems/rundoc/pull/6).\n\nIf you wanted to change `users` to `products` you could write to the same file again.\n\n    ```\n    :::\u003e- file.write config/routes.rb\n    Example::Application.routes.draw do\n      root        :to =\u003e \"pages#index\"\n\n      namespace :products do\n        resources :after_signup\n      end\n    end\n    ```\n\nTo fully delete files use bash `$` command such as `::: $ rm foo.rb`.\n\nTo add contents to a file you can use `file.append`\n\n    ```\n    :::\u003e\u003e file.append myapp/Gemfile\n    gem 'pg'\n    gem 'sextant', group: :development\n    gem 'wicked'\n    gem 'opro'\n    ```\n\nThe contents of the file (in this example a file named `Gemfile`) will remain unchanged, but the contents of the `file.append` block will now appear in the bottom of the file. If you want to append the contents to a specific part of the file instead of the end of the file you can specify line number by putting a hash (`#`) then a number following it.\n\n    ```\n    :::\u003e\u003e file.append myapp/Gemfile#22\n    gem 'rails_12factor'\n    ```\nThis will add the `gem 'rails_12factor'` on line 22 of the file `myapp/Gemfile`. If line 22 has existing contents, they will be bumped down to line 23.\n\nSome times you may want to remove a small amount of text from an existing file. You can do this using `file.remove`, you pass in the contents you want removed:\n\n    ```\n    :::\u003e\u003e file.remove myapp/Gemfile\n    gem 'sqlite3'\n    ```\n\nWhen this is run, the file `Gemfile` will be modified to not include `gem 'sqlite3'`.\n\nNote: `file.remove` currently requires a very explicit match so things like double versus single quotes, whitespace, and letter case all matter. Current best practice is to only use it for single line removals.\n\n## Pipe\n\nCommands:\n- `|`\n- `pipe` (aliased `|`)\n\nSometimes you need to need to pass data from one command to another. To do this there is a provided pipe command `|`.\n\nLet's say you want to output the first 23 lines of a file but you don't want to confuse your users with an additional pipe command in your shell line you could write something like this:\n\n```sh\n:::\u003e  $ cat config/database.yml\n:::\u003e\u003e | $ head -n 23\n```\n\nAnything after the pipe `|` will generate a new command with the output of the previous command passed to it. The pipe command will only ouput its result, so the user will not know it was even executed.\n\nThis command is currently hacked together, and needs a refactor. Use it, but if something does not behave as you would expected open an issue and explain it.\n\n## Background\n\nSometimes you want to start a long lived process like a server in the background. In that case, the `background` namespace has your, well, back.\n\nTo start a process, pass in the command as the first arg, and give it a name (so it can be referenced later):\n\n```\n:::\u003e\u003e background.start(\"rails server\", name: \"server\")\n```\n\n- Arguments\n  - name: Identifier of the background process, used in later invocations.\n  - wait (Optional): A string to wait for before continuing. This is useful to block moving on until an event happend such as a server was booted or web request was received. Also see `background.wait`\n  - timeout (Optional): A number of seconds to wait for a given string to be found in the logs.\n  - out (Optional): A bash redirect. Defaults to `2\u003e\u00261` to merge stderr and stdout together.\n  - allow_fail (Optional): Set to `true` if the command exiting shouldn't halt doc generation. Poorly named, may be renamed in the future.\n\nYou can make the background process wait until it receives a certain string in the logs. For instance to make sure that the server is fully booted:\n\n```\n:::\u003e\u003e background.start(\"rails server\", name: \"server\", wait: \"Listening on\")\n```\n\nYou can send strings to the STDIN of the process:\n\n```\n:::\u003e\u003e background.start(\"heroku run bash\", name: \"heroku_run\", wait: \"$\")\n:::-- background.stdin_write(\"ls\", name: \"heroku_run\")\n```\n\n- Arguments\n  - contents: Positional. The string to write to stdin\n  - ending: A string to append to the end of the contents, defaults to a newline\n            you could set it to something like \";\" or an empty newline \"\"\n  - name\n  - wait\n  - timeout\n\nYou can stop the process by referencing the name:\n\n```\n:::-- background.stop(name: \"server\")\n```\n\n- Arguments\n  - name\n\n\nYou can also get the log contents:\n\n```\n:::\u003e\u003e background.log.read(name: \"server\")\n```\n\n- Arguments\n  - name\n\nYou can also truncate the logs:\n\n```\n:::\u003e\u003e background.log.clear(name: \"server\")\n```\n\n- Arguments\n  - name\n\nYou can also wait for a given string to appear in the logs:\n\n```\n:::\u003e\u003e background.wait(name: \"server\", wait: \"method=GET\")\n```\n\n- Arguments\n  - name\n  - wait: Same as `background.start` a string value to look for before continuing.\n  - timeout: Maximum number of seconds to wait\n\n## Screenshots\n\nYou'll need selenium and `chromedriver` installed on your system to make screenshots work. On a mac you can run:\n\n```\n$ brew cask install chromedriver\n```\n\nTo take a screenshot first \"visit\" a website. The values you pass in to stdin can be used to further navigate. For more information see the [Capybara DSL](https://www.rubydoc.info/GitHub/teamcapybara/capybara/master#the-dsl). Use the keyword `session`\n\nOnce you're on the page you want to capture you can execute `website.screenshot`:\n\n```\n:::\u003e\u003e website.visit(name: \"localhost\", url: \"http://localhost:3000\", scroll: 100)\nsession.execute_script \"window.scrollBy(0,100)\"\nsession.first(:link, \"sign up\").click\n\n:::\u003e\u003e website.screenshot(name: \"localhost\")\n```\n\nThe result of the screenshot command will be to replace the code section with a markdown link to a relative path of the screenshot.\n\nOnce you've visited a website you can further navigate using `website.nav` or `website.navigate`:\n\n```\n:::\u003e\u003e website.visit(name: \"localhost\", url: \"http://localhost:3000\")\n:::\u003e\u003e website.navigate(name: \"localhost\")\nsession.execute_script \"window.scrollBy(0,100)\"\nsession.first(:link, \"sign up\").click\n\n:::\u003e\u003e website.screenshot(name: \"localhost\")\n```\n\n## Upload Screenshots\n\nYou can specify that you want to upload files to S3 instead of hosting them locally by passing in `upload: \"s3\"` to the screenshot command:\n\n```\n:::\u003e\u003e website.visit(name: \"localhost\", url: \"http://localhost:3000\", scroll: 100)\n:::\u003e\u003e website.screenshot(name: \"localhost\", upload: \"s3\")\n```\n\nTo authorize, you'll need to set these environment variables:\n\n```\nAWS_ACCESS_KEY_ID\nAWS_REGION\nAWS_SECRET_ACCESS_KEY\nAWS_BUCKET_NAME\n```\n\nThe bucketeer addon on Heroku is supported out of the box. To specify project specific environment variables see the \"dotenv\" section below.\n\n## Compose multiple RunDOC documents\n\nYou can also break up your document into smaller components using `rundoc.require`:\n\n```\n:::\u003e\u003e rundoc.require \"../day_one/rundoc.md\"\n```\n\nThis will prepend the code section with the generated contents of `rundoc.require`.\n\nIf you want to execute another tutorial as a pre-requisite but not embed the results you can use `:::--`:\n\n```\n:::-- rundoc.require \"../day_one/rundoc.md\"\n```\n\n## Dotenv support\n\nIf you need to specify project specific environment variables create a file called `.env` at the same directory as your `rundoc.md` and it will be imported. Add this file to your `.gitignore` so you don't accidentally share with the world\n\n## Configure\n\nYou can configure your docs in your docs use the `RunDOC` command\n\n    ```\n    :::-- rundoc.configure\n    ```\n\nNote: Make sure you run this as a hidden command (with `-`).\n\n**After Build**\n\nThis will eval any code you put under that line (in Ruby) when the build was successful but before the contents are finalized on disk. If you want to run some code after you're done building your docs you could use `Rundoc.configure` block and call the `after_build` method like this:\n\n    ```\n    :::-- rundoc.configure\n    Rundoc.configure do |config|\n      config.after_build do |context|\n        puts \"you could push to GitHub here\"\n        puts \"You could do anything here\"\n        puts \"This code will run after the docs are done building\"\n      end\n    end\n    ```\n\nThe `context` object will have details about the structure of the output directory structure. The stable API is:\n\n- `context.output_dir`: A [Pathname](https://rubyapi.org/3.3/o/pathname) containing the absolute path to the top level directory where all commands are were executed. If your script runs `rails new myapp` then this directory would contain another directory named `myapp`. Only modifications to this directory will be persisted to the final `--output-dir`.\n- `context.screenshots_dir`: A [Pathname](https://rubyapi.org/3.3/o/pathname) containing the absolute path to the directory where screenshots were saved. It is guaranteed to be somewhere within the `context.output_dir`\n- `context.output_markdown_path`: A [Pathname](https://rubyapi.org/3.3/o/pathname) containing the absolute path to the final markdown file. This is guaranteed to be in the `context.output_dir`\n\n**Filter Sensitive Info**\n\nSometimes sensitive info like usernames, email addresses, or passwords may be introduced to the output readme. Let's say that your email address was `schneems@example.com` you could filter this out of your final document and replace it with `developer@example.com` instead like this:\n\n    ```\n    :::-- rundoc.configure\n    Rundoc.configure do |config|\n      config.filter_sensitive(\"schneems@example.com\" =\u003e \"developer@example.com\")\n    end\n    ```\n\nThis command `filter_sensitive` can be called multiple times with different values. Since the config is in Ruby you could iterate over an array of sensitive data\n\n## Writing a new command\n\nRundoc does not have a stable internal command interface. You can define your own commands, but unless it is committed in this repo, it may break on a minor version change.\n\nTo add a new command it needs to be parsed and called. Examples of commands being implemented are seen in `lib/rundoc/code_command`.\n\nA new command needs to be registered:\n\n```\nRundoc.register_code_command(:lol, Rundoc::CodeCommand::Lol)\n```\n\nThey should inherit from Rundoc::CodeCommand:\n\n```\nclass Rundoc::CodeCommand::Lol \u003c Rundoc::CodeCommand\n  def initialize(line)\n  end\nend\n```\n\nThe initialize method is called with input from the document. The command is rendered (`:::\u003e-`) by the output of the `def call` method. The contents produced by the command (`:::-\u003e`) are rendered by the `def to_md` method.\n\nThe syntax for commands is ruby-ish but it is a custom grammar implemented in `lib/peg_parser.rb` for more info on manipulating the grammar see this tutorial on how I added keword-like/hash-like syntax https://github.com/schneems/implement_ruby_hash_syntax_with_parslet_example.\n\nCommand initialize methods natively support:\n\n- Barewords as a single string input\n- Keyword arguments\n- A combination of the two\n\nAnything that is passed to the command via \"stdin\" is available via a method `self.contents`. The interplay between the input and `self.contents` is not strongly defined.\n\n## Copyright\n\nAll content Copyright Richard Schneeman © 2020\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzombocom%2Frundoc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzombocom%2Frundoc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzombocom%2Frundoc/lists"}