/cabbage_doc

A lean and mean interactive API documentation generator.

Primary LanguageRubyMIT LicenseMIT

CabbageDoc

A lean and mean interactive API documentation generator.

Screenshot

Getting Started

CabbageDoc has been designed from the ground-up to be easy to configure and use.

Start by adding the gem to your Gemfile.

gem 'cabbage_doc'

Configuration

Before using CabbageDoc, it is necessary to configure a couple of basic settings.

CabbageDoc.configure do |config|
  config.root = Rails.root.join('doc')

  config.domain = 'example.com'

  config.authentication = proc do |auth, request|
    auth.type = :basic
    auth.username = request.params[:username]
    auth.password = request.params[:password]
    auth.configurable = [:username, :password]
  end

  config.controllers = proc do
    Dir.glob(Rails.root.join('app', 'controllers', 'api', 'v1', '*.rb')).sort
  end

  config.title = "Developer Documentation"
  config.welcome = <<-WELCOME
  Developer Documentation
  =======================
  Awesome developer documentation.
WELCOME
end

Task

Create a new .rake file in your project, usually within lib/tasks and add the following line:

CabbageDoc::Task.define do |config|
  config.name = :cabbagedoc
end

Run rake -T to see the newly defined rake tasks.

Web

The default UI is a mountable Sinatra application. It's perfectly fine to mount it within a Rails application, namely config/routes.rb.

mount CabbageDoc::Web, at: '/docs'

If you don't want your documentation to be public, fear not, CabbageDoc got you covered:

CabbageDoc::Web.use(Rack::Auth::Basic) do |username, password|
  username == 'cabbage' && password == 'doc'
end

By default, the documentation used by the UI is regenerated only by running the documentation generation rake task.

This behavior can be changed by setting the dev property to true in the configuration block.

CabbageDoc.configure do |config|
  config.dev = Rails.env.development?
end

When dev is set to true, the documentation will be regenerated on each request.

Customize

If you do not fancy the default UI, you can customize it to suit your own needs.

In order to do that, you will have to run the customize rake task.

rake cabbagedoc:customize

This will copy the internal web directory into the root directory you configured in your initializer.

When this alternate web directory exists, CabbageDoc will use it, instead of the internal web directory.

How to document?

CabbageDoc uses a simple and readable structured comment style inspired by Tomdoc.

# Public: Resources
#
# PATH: /resources
class ResourcesController # :cabbagedoc:
  # Public: List
  #
  # GET: /resources
  #
  # Parameters:
  #   detail (Enumeration) - level of detail (default: basic, values: full|basic)
  #   per_page (Numeric) - resources per page (default: 25)
  #   categories (Array) - filter by categories
  #   search (String) - filter by search string
  def index # :cabbagedoc:
  end

  # Public: Show
  #
  # GET: /resources/:id
  #
  # Parameters:
  #   id (String) [required] - resource id
  #   detail (Enumeration) - level of detail (default: basic, values: full|basic)
  def show # :cabbagedoc:
  end

  # Public: Create
  #
  # POST: /resources
  #
  # Parameters:
  #   title (String) [required] - resource title
  #   text (String) - resource text
  def create # :cabbagedoc:
  end

  # Public: Update
  #
  # PUT: /resources/:id
  #
  # Parameters:
  #   id (String) [required] - resource id
  #   title (String) - resource title
  #   text (String) - resource text
  def update # :cabbagedoc:
  end

  # Public: Delete
  #
  # DELETE: /resources/:id
  #
  # Parameters:
  #   id (String) [required] - resource id
  def destroy # :cabbagedoc:
  end
end

It is also possible to add a longer description like so:

# Public: Delete
#
# DELETE: /resources/:id
#
# Description: Deletes a resource.
#
# Parameters:
#   id (String) [required] - resource id
def destroy # :cabbagedoc:
end

Multline descriptions are also possible:

# Public: Delete
#
# DELETE: /resources/:id
#
# Description:
#   Deletes a resource.
#   And it also does something magical.
#
# Parameters:
#   id (String) [required] - resource id
def destroy # :cabbagedoc:
end

The description is processed via Markdown.

Parameters

Parameters in the URL (path components) should be prefixed with a : and then added to the list of parameters.

CabbageDoc is smart enough to detect this and make the necessary substitutions when interacting wit the action in question.

# Public: Delete
#
# DELETE: /resources/:parent_id/comments/:id
#
# Parameters:
#   parent_id (String) [required] - parent resource id
#   id (String) [required] - id
def destroy # :cabbagedoc:
end

These parameters should be marked as required.

Here is a list of all parameter types:

  • Number
  • Numeric
  • Decimal
  • Integer
  • String
  • Id
  • Enumeration
  • Array
  • Hash
  • Date
  • Time
  • Timestamp

An Enumeration represents a finite number of choices (think of it as a select box).

# detail (Enumeration) - level of detail (default: basic, values: full|basic)

The values are separated by | and it is possible to provide a default value.

If there is no default value, then nothing will be selected by default. However if the parameter in question is required, a default value MUST be provided.

An Array represents a flat array of values and a Hash a group of key-value pairs.

Nested hashes are not supported at this point in time.

Visibility

In the examples above, we used the default Public visibility. Here is a list of all visibility options.

  • Public
  • Private
  • Internal
  • Beta
  • Unreleased

By default only controllers and actions marked as Public will show up in the generated documentation.

You can turn on additional visibility options in the initializer like so:

config.authentication = proc do |auth, request|
  auth.visibility += [:private, :internal, :beta, :unreleased]
end

Beta and Unreleased visibility will display a "warning" on each marked action.

Screenshot

Examples

It is also possible to provide examples for each action.

# Examples:
#   Example One - (detail: basic)

Screenshot

Templates

Often times it is needed to document a so called subresource which can be mounted under a number of parent resources.

To enable this, CabbageDoc offers templates. Templates can be inline or global.

Inline Templates

Inline templates are useful when there is a subresource which is specific to a given application and will only live within the context of that application.

# Public: {Post,Ideas} Resource
#
# PATH: /{posts,ideas}/:{post,idea}_id/resources
class ResourcesController # :cabbagedoc:
  # Public: List
  #
  # GET: /{posts,ideas}/:{post,idea}_id/resources
  #
  # Parameters:
  #   {post,idea}_id - {post,idea} ID
  #   detail (Enumeration) - level of detail (default: basic, values: full|basic)
  #   per_page (Numeric) - resources per page (default: 25)
  #   categories (Array) - filter by categories
  #   search (String) - filter by search string
  def index # :cabbagedoc:
  end
end

When CabbageDoc will process this, it will detect it uses inline templates and will generate two copies with the template values substituted.

Why two? Because each template string has two values, separated by ,.

Global Templates

Global templates are useful when there is a subresource that lives outside the context of a single application and will most likely be mounted within multiple applications.

The prime example of this would be a Rails Engine.

In this case, it is not desirable to litter the documentation with specific terminology, because the engine could be mounted in several applications.

This is where global templates come into play, by allowing us to use generic templates and then provide specific values in the CabbageDoc configuration.

  config.tags = %i[main_app secondary_app]
  config.controllers = proc
  {
    main_app: CabbageDoc.glob([
          ['..', 'main_app', 'app', 'controllers', 'api', 'v1', '*.rb'],
          ['..', 'racl', 'app', 'controllers', 'api', 'v1', '*.rb']
    ]),
    secondary_app: CabbageDoc.glob([
          ['..', 'secondary_app', 'app', 'controllers', 'api', 'v1', '*.rb'],
          ['..', 'racl', 'app', 'controllers', 'api', 'v1', '*.rb']
    ])
  }

The engine called racl is sourced into both apps as shown above.

# Public: {racl:collection} Resource
#
# PATH: /{racl:root}/{racl:resource}/:{racl:resource_id}/resources
module Racl
  class Resource # :cabbagedoc:
    # Public: List {racl:resource}
    #
    # GET: /{racl:root}/{racl:resource}/:{racl:resource_id}/resources
    #
    # Parameters:
    #   {racl:resource_id} - {racl:resource_name} ID
    #   detail (Enumeration) - level of detail (default: basic, values: full|basic)
    #   per_page (Numeric) - resources per page (default: 25)
    #   categories (Array) - filter by categories
    #   search (String) - filter by search string
    def index # :cabbagedoc:
    end
  end
end

These templates will be substituted with what it is defined in the global CabbageDoc configuration for each application.

  config.templates = {
    main_app: {
      '{racl:collection}' => [
        'Content',
        'Idea'
      ],
      '{racl:root}' => [
        'api/v1',
        'api/v1'
      ],
      '{racl:resource}' => [
        'content',
        'ideas'
      ],
      '{racl:resource_id}' => [
        'content_id',
        'idea_id'
      ],
      '{racl:resource_name}' => [
        'content',
        'idea'
      ]
    },
    secondary_app: {
      '{racl:collection}' => [
        'Dashboards'
      ],
      '{racl:root}' => [
        'api/v1'
      ],
      '{racl:resource}' => [
        'dashboards'
      ],
      '{racl:resource_id}' => [
        'dashboard_id'
      ],
      '{racl:resource_name}' => [
        'dashboard'
      ]
    }
  }

By running rake cabbagedoc, CabbageDoc parses all comments and generates the necessary metadata which is then used to render the documentation.

Contribute

  • Fork the project.
  • Make your feature addition or bug fix.
  • Do not bump the version number.
  • Send me a pull request. Bonus points for topic branches.

License

CabbageDoc is provided as-is under the MIT license. For more information see LICENSE.