Documentation Formatting Guide
Keeping documentation relevant, concise and up to date is very important to us. As such, we have ensured that updating and writing documentation for Ably is a simple process for Ably staff and developers, and even our customers and partners. We welcome you to fork this documentation repository, update the documentation as you see fit, and send us your pull requests so we can incorporate your changes.
Please see this documentation repository’s README for details on how to fork this repo, make changes, and send pull requests back to Ably. From a high level, the documentation within this repository is used to generate a static site hosted at docs.ably.com, which is subsequently imported into the primary Ably website documentation periodically. All documentation is formatted using Textile markup. Please refer to Promptworks for a complete Textile reference. The Textile documentation is converted into HTML using Nanoc.
Detailed below are specific Ably layout techniques that you should be aware of when writing documentation. All standard Textile markup is supported in addition to what is documented below.
Metadata
At the top of each textile page, the following metadata can be included as follows:
---
title: "Enter a title that will appear in the navigation and HTML page title"
section: "Specify either rest|realtime|other|none to assign to nav on the left"
index: 0 # Optional integer position within the nav, 0 is reserved for index & home
api_separator: #This being specified will result in a seperator between docs and API docs
Section Title: #Title of a section in API separator
- External Link:/external/link #External link
- Internal Link#internal-link #auto-links to #internal-link
jump_to: # Optional YAML tag that will insert a "jump to" navigation based on YAML
"External Links": # surrounding quotes are not normally needed...
- External Link 1:/external/link #Separate with a ":" to link to /external/link
"Help with":
- "Item 1#anchor-link-id" # links to #anchor-link-id
"API methods":
- "Item 2" # auto-links to #item-2
- "Item 3" # auto-links to #item-3
- "Language specific content"#language-specific-content
---
CopyCopied!
View this page’s Textile markup for an example of the jump to navigation.
Note that if you have referenced an anchor that has language specific content, the jump to navigation will automatically update to reflect the new content for that anchor whenever a language is selected, and ignore the text you have provided. Also, if an anchor is longer visible because it is contained within a language block, the corresponding navigation item will be hidden.
SEO focussed metadata
The following metadata attributes are supported:
---
meta_description: "Description for this page rendeded in HTML meta description field"
meta_keywords: "Keywords for this page rendeded in HTML meta keywords field"
meta_image: "/images/path/to/file/in/assets/folder.png"
---
CopyCopied!
Special Metadata
Certain pages have additional pieces of metadata which can be used to help the website display unique information.
Compare pages metadata
Pages in the /compare
folder can have the following additional metadata:
---
published_date: January 3000
competitors:
- "competitor1 ID, which should match the ID used on the website"
- "competitor2 ID, which should match the ID used on the website"
---
CopyCopied!
Tutorial pages metadata
Pages in the /tutorials
folder require certain metadata to make them indexable at Ably’s website.
* denotes required meta fields, but isn’t valid yaml. If copy/pasting, don’t forget to remove them
---
alt_title: an alternative title to display on the website
excerpt: A small blurb introduction for your tutorial
category*: introduction | external-services | liberaries-integration
platform*: mobile | browser | mixed
authors*:
* author_name: Supports multiple authors
author_bio: but must be an array even if single author
author_profile_url: https://authors_website.com
author_image: hosted gravatar or an image present in websites images/tutorials/ folder
* author_name: Second Author
author_bio: ""
author_profile_url: ""
author_image: ""
level: String (suggestions: medium | easy | hard)
reading_time: Number in minutes
tags:
- ably-realtime
- ably-features
- example-apps
---
CopyCopied!
Markup fundamentals
Headings
The title of the page is automatically inserted into the page using a h1.
tag. A simple breadcrumb navigation will be shown if the page has an index other than zero, and a page with index 0 exists.
Use bq(definition).
for method definitions after h6.
method anchors. See blockquote definitions.
h1.
used to indicate a new section such as the API reference, the title will be used within the in-context navigation. The first paragraph that follows will always contain larger text. You can continue this larger style by using a p(larger).
tag.
h2.
used for the key secondary headings on a page, and will be used within the in-context navigation.
h3.
used for the key tertiary headings, all paragraph text that follows is indented
h4.
to h5.
used for further headings decreasing in emphasis used in a typical hierarchical fashion
h6.
used to designate a definition or reference, see REST history section in maroon for an example of how this is used
h[1-6](#anchor-id).
used with any heading tag to add an HTML ID that can be linked to using anchor tags
Documentation links
Absolute reference links such as <a href="http://www.google.com">Google</a>
can be used as normal.
All links to other documentation pages must follow the format <a href="/rest/channels">REST Channels</a>"
and must resolve to a relative path for this repository. When imported into the main Ably website, the links will be automatically modified to link to the correct page in the Ably webite documentation.
Anchor links can be used as follows <a href="/api/rest-sdk/statistics#stats">REST spec stats</a>
.
Links can also contain mono-spaced code references within the link using the format <a href="/rest/channels">
, which would appear as mono-spaced-link-text
mono-spaced-link-text
Code blocks
Simple code keywords inline within your content are used commonly by wrapping them the symbol. For example <notextile><code>
method</notextile> is presented as </code>[email protected]
For all code blocks, a language in lowercase must be specified. Languages currently supported are javascript
, java
, android
, kotlin
, python
, php
, ruby
, nodejs
, typescript
, objc
, swift
, go
, csharp
, cplusplus
, flutter
, c
, css
, appcelerator
, phonegap
, curl
, html
, json
, sh
, yaml
. A code block must be prefixed and suffixed with a line break, and must use the following syntax:
bc[javascript]. var a = 1;
a += 1;
CopyCopied!
Note, if multiple code blocks appear underneath each other with different languages, then a language selector will appear for the page. For example, the following Textile:
bc[javascript]. var a = 1;
a += 1;
// line break
bc[ruby,nodejs]. a = 1
a += 1
// line break
bc[csharp]. Integer a = 1;
a += 1;
CopyCopied!
generates the following where the code shown is governed by the language selected in the floating top nav
var a = 1;
a += 1;
CopyCopied!
Note that if you don’t include a full set of languages, or at least provide a default
language, then a language selector will appear. In the example below, no language has been specified for javascript
or nodejs
. Select JavaScript in the top nav to see what happens when a language is not available.
# this is ruby
CopyCopied!
Code blocks Github style
As an alternative, you can use Github styled code blocks using triple backticks however the language(s) must be specified comma separated after the backticks in square brackets, for consistency with normal textile language blocks. The advantage of Github blocks over traditional Textile blocks is that line breaks are supported. Please note that lowest level indentation is stripped from the code.
```[javascript]
var a = 1;
a = 2; // note this works in spite of the line break
```
```[ruby]
a = 1
a = 2
```
```[csharp]
int a = 1;
a = 2;
```
CopyCopied!
generates the following where the code shown is governed by the language selected in the floating top nav
var a = 1;
a = 2; // note this works in spite of the line break
CopyCopied!
Try it now code editor
In order to publish code examples to JSBin, your /config/jsbin_config.yaml must be set up with a valid JSBin API key.
Code examples that run in your browser can be included in this documentation repo within the /content/code folder. Every code example must contain JavaScript, HTML and CSS that will be launched in our custom Ably JSBin.
The following example shows how you can easily add a “Try it” button to your code example that will launch the code from the path you provide in our Ably JSBin code editor:
bc[javascript].
var ably = new Ably.Realtime('<loading API key, please wait>');
Demo OnlyCopyCopied!
generates the following:
var ably = new Ably.Realtime('<loading API key, please wait>');
Demo OnlyCopyCopied!
Linking to code examples
If you want to link to a code example without using a code block, you can use ERB to embed the link and specify a class of external
to ensure the link opens a new tab/window.
"Example":https://jsbin.ably.com:443/ekedis/latest_?javascript
CopyCopied!
generates the following:
Variables
In your code examples you can use handlebar like variables that are replaced with values at runtime. This is especially useful when you need to show examples that use a Token that may expire for example. When using the variables, please ensure that the case is matched exactly and that the variable is surrounded by single or double-quotes as CodeMirror colour coding can prevent the variables from being identified.
The following variables are supported:
- {{API_KEY_NAME}}
- {{API_KEY_SECRET}}
- {{API_KEY}}
- {{API_KEY_BASE64}}
- {{APP_ID}}
- {{TOKEN}}
- {{TOKEN_BASE64}}
- {{MS_SINCE_EPOCH}}
- {{SECONDS_SINCE_EPOCH}}
- {{RANDOM_CHANNEL_NAME}}
- {{SIGNED_TOKEN_REQUEST_EXAMPLE}}
Example of the above variables being used in a code block below:
API_KEY_NAME: "{{API_KEY_NAME}}"
API_KEY_NAME: "{{API_KEY_SECRET}}"
API_KEY: "<loading API key, please wait>"
API_KEY_BASE64: "{{API_KEY_BASE64}}"
TOKEN: "{{TOKEN}}"
TOKEN_BASE64: "{{TOKEN_BASE64}}"
MS_SINCE_EPOCH: "{{MS_SINCE_EPOCH}}"
SECONDS_SINCE_EPOCH: "{{SECONDS_SINCE_EPOCH}}"
RANDOM_CHANNEL_NAME: "ray-map-ash"
Demo OnlyCopyCopied!SIGNED_TOKEN_REQUEST_EXAMPLE: "{{SIGNED_TOKEN_REQUEST_EXAMPLE}}"
Special page variables
Certain pages have additional variable options.
Compare pages variables
In pages within the /compare
folder, it’s possible to make use of the following variables:
- {{COMPANY_0}}
- {{COMPANY_1}}
- {{COMPANY_URL_0}}
- {{COMPANY_URL_1}}
- {{COMPANY_ID_0}}
- {{COMPANY_ID_1}}
- {{PUBLISHED_DATE}}
The {{COMPANY_*}}
variables make use of the correlated company listed in the metadata of the page to insert the relevant piece of information.
Examples of the above variables being used are:
First company name: {{COMPANY_0}}
Second company's home page url: {{COMPANY_URL_1}}
First Company's docs ID, as used in '/data/compare.yaml': {{COMPANY_ID_0}}
CopyCopied!The date this article was published: {{PUBLISHED_DATE}}
Isolated language blocks (always present) versus grouped language blocks
For both code blocks, if a single language code block appears without another contiguous language block before or after it, then it will always be shown regardless of the current language selected by the viewer. This is to ensure that should you wish to show a simple HTML block or a JavaScript code block with formatting for example, this can be done without worrying it will be hidden. For example:
bc[html]. <html>
<body></body></html>
CopyCopied!
Will always be visible as follows:
<html>
<body></body></html>
CopyCopied!
Non-formatted mono-spaced code blocks
If you want to provide a non-formatted mono-spaced box with code, then use a pre. block instead without specifying a language. For example:
For example:
pre. this.code is('mono-spaced')
CopyCopied!
will generate a box styled as follows:
this.code is('mono-spaced')
Language specific (default)
Within this documentation repository’s static site, all language specific content is wrapped in light dotted lines for clarity. However, when imported into the main Ably website, content will not be wrapped in dotted lines. Unlike code blocks, if you specify a single language specific block of content, it will only be shown if the language matches. Single language code blocks in contrast will appear regardless of which language is selected.
You can specify multiple languages per language specific content block such as <span lang="ruby,java">
.
Whenever you need to vary the content based on the language selected by the user in the top language navigation, you have the following options available:
Consecutive lines with tag[lang].
Whenever the front end detects multiple consecutive tag.
markup with a language specified, the front end will automatically show the content related to the selected language, and hide all other languages. Note that the special language default
can be used to provide default copy in the absence of any specific language variation existing. For example:
p[default]. Default text to appear for all languages not specified
p[ruby]. Text to appear when Ruby is the chosen language
CopyCopied!
Will result in:
Default text to appear for all languages not specified
Large blocks using blang[lang].
When you need to vary large content blocks by language which can in turn contain any other HTML or Textile markup, you can use the custom blank
textile markup with the lang
attribute set within the square brackets. Indentation following the markup becomes significant and is used to indicate to the Textile parser that all text with indentation following the blang[lang].
markup is part of this large language block.
If a language block for the user’s currently selected language does not exist, nothing will be shown to the user.
blang[default].
p(#conditional-nav). This block will be shown by default and the nav will be visible
This second line is considered part of the default block because it's still indented.
blang[ruby].
This block will be shown when Ruby is selected and the conditional nav is not visible
This second line is considered part of the Ruby block because it's still indented.
CopyCopied!
Results in:
This second line is considered part of the default block because it’s still indented.
Note that if any navigation item references an anchor that is no longer visible, it will be hidden in the navigation.
In-line content with <span lang="[lang]">
When you need to vary the content by language inline within a paragraph or another element, you can use span
tags with the lang
attribute set. If a language tag is missing, nothing will be shown. For example:
The language currently being viewed is:
<span lang="javascript">javascript</span><span lang="ruby">ruby</span>
CopyCopied!
Results in:
The language currently being viewed is: javascript
Here is another examples using an additional default language tag in the format <span lang="default"></span>
:
The language of all is currently being viewed
Method or object reference / definitions with language variations h6(#request-token). definition
When you need to vary the reference or definition of a method or object property by language, you can use h6
tags with the language defined on the next line as follows:
h6(#method-anchor-example).
default: fooBar
ruby: foo_bar
CopyCopied!
will render as:
fooBar
Language definition lists
Please refer to Definition lists below for instructions on how to specify a language for definitions and lists.
Supported languages
The supported languages are as follows:
- language code
- language name <% Ably::DOCUMENTATION_LANGUAGES.each do |lang_code, lang| %>
- <=lang_code>
- <=html_escape(lang[:name])> <% end %>
If you wish to add support for more languages, please refer to /lib/documentation_languages.rb
Definition lists
Definition lists are used frequently to list out parameters to methods, object properties or return values. They are prefixed and sufficed with a line break, and used as follows:
- value := description<br><em class="italics">Type: @[email protected]</em>
- value 2 := _default description_ description<br><em class="italics">Type: @[email protected]</em>
CopyCopied!
and renders as:
- value
- description
- value 2
- default description descriptionType:
Type
Please note that:
- The definition term (left hand part) is never
wrappedcode
- Defaults are treated specially by placing
_default description_
at the start of the definition description (right hand part) - As a convention, types are placed after the definition description (right hand part) using the format
<br>
<em class="italics">Type:
Type
Column headers for your definition lists can be specified on the first line by surrounding the definitions with an asterix. For example:
- *id heading* := *value heading*
- id := description
CopyCopied!
will render as:
- id heading
- value heading
- id
- description
Language specific definitions
Unfortunately as definition lists do not natively support specifying a language, a “hack” is used to make this work. The following example:
- value := definition
- <div lang="ruby">ruby</div> := a Ruby specific definition
- <div lang="default">default</div> := a generic definition
- <div lang="ruby">ruby second</div> := a Ruby specific definition
- <div lang="javascript">javascript second</div> := a JavaScript specific definition
CopyCopied!
will render as:
- value
- definition
- default
- a generic definition
- javascript second
- a JavaScript specific definition
Code within definitions
bc[lang]
blocks cannot be used within definitions because they need to be surrounded by lines of white-space. Adding white-space would however terminate the definition list. As such, the following workaround can be used if you need to embed code in a definition:
- value := definition
- another value := definition with code block
<pre lang="json">@{
"name": "<event name>"
}@</pre>
CopyCopied!
will render as:
- value
- definition
- another value
- definition with code block
{ "name": "<event name>" }
CopyCopied!
Method definitions with blockquotes
The pattern within API sections is to define a method with an h6
such as h6(#method). method
, and then to define all method definitions (including any overloaded methods) with bq(definition).
bq(definition#anchor).
default: send(message, options)
javascript: send(message, options)
java: void send(Message message, Options options)
CopyCopied!
will render as:
send(message, options)
Inline Table of Contents
Inline Table of Contents are typically used at the start of a new section (such as API reference) to provide a form of navigation to the user. The Inline Table of Contents is also beneficial from a usability perspective as users can quickly get an overview of the content structure and scope. A custom textile tag has been created for this, inline-toc
. An inline-toc
tag can appear anywhere in a document as long as there is white space before it, the YAML within the tag appears directly after the tag, and the tag and YAML ends with white space. Here is example Textile markup:
inline-toc.
Channel Object Reference:
- Example:
- Metadata // the anchor link #meta-data will be used automatically
- Manually configured#code-blocks
- Language Specific Content#language-specific-content
- Conditional navigation shown when anchor is visible#conditional-nav
CopyCopied!
The above code produces the following element:
Note that if you have referenced an anchor that has language specific content, the Table of Contents will automatically update to reflect the new content for that anchor whenever a language is selected, and ignore the text you have provided.
Language conventions
JavaScript
Although JavaScript is not a typed language, to avoid ambiguity, types are preferred before the argument name in method definitions, and the type should be linked to the type definition where available. As argument names are irrelevant when invoking a function (only the order matters), it is better to use a meaningful name in method definitions. Example:
new Ably.Realtime(ClientOptions clientOptions)
Callbacks and their method signatures should be included in code definitions. Where possible, instead of simply naming the function callback, a meaningful name should be used. Example:
subscribe(listener(Message message))
Java
As Java is a typed language, types must be appear before variable name in method definitions, and the type should be linked to the type definition where available. The argument names should match the definition in the library. Example:
new io.ably.lib.AblyRealtime(ClientOptions clientOptions)
If the fully qualified name is too long to fit into the definition, and even more so within the navigation, then the unqualified class name can be used although it is preferable to mention the fully qualified namespace somewhere in the surrounding documentation. Example:
AblyRealtime(io.ably.lib.ClientOptions clientOptions)
Ruby
Although Ruby is not a typed language, to avoid ambiguity, types are preferred before the argument name in method definitions, and the type should be linked to the type definition where available. As argument names are irrelevant when invoking a method (unless using Hash method options), it is advised to use a meaningful name in method definitions. Example:
Ably::Realtime.new(ClientOptions client_options)
If the fully qualified name is too long to fit into the definition, and even more so within the navigation, then the unqualified class name can be used although it is preferable to mention the fully qualified namespace somewhere in the surrounding documentation. Example:
Realtime.new(ClientOptions client_options)
Where methods yield blocks and/or return valueas, the following syntax is the standard:
EventMachine::Deferrable connect → yields
Connection
If the block yields a number of variables and they need to be named for clarity, then the following is recommended:
foo → yields Object bacon, Object cheese
Minimizable/expandable content blocks
Sections of documentation are able to be minimized to help reduce the amount of content presented to developers reading the docs, whilst still allowing them to explore the detail where necessary. This is particularly useful for detailed code examples, for example. You can use this feature in one of two ways:
Minimize on the title
Click to see how to minimize by title
Minimize the content block
Click to see how to minimize by block
Other custom styles
Tips can be shown using the markup p(tip).
Page-specific options
Certain pages have styles and variables intended specifically for them.
Compare pages
Compare pages make use of the /data/compare.yaml
file to automatically generate content. This yaml contains company information, and comparison points between all the companies organized under certain categories (i.e. Interoperability).
Compare tables
It’s possible to automatically generate a comparison table for any two companies, through the use of:
compare_table(CATEGORY, OPTIONAL_COLUMN_TITLE).
This will check if there are any comparible points between the the companies specified in the metadata of the pages, within the specified CATEGORY
. If there are, a table will be generated to compare said points. The OPTIONAL_COLUMN_TITLE
, if specified, will check if the category has an extras
field, and if so will use that when creating the table as an additional column, using the title specified.
Tutorials pages
In order to build a stepped view mode of the tutorials, certain markup guidelines must be respected
- Each step is marked by an
h2
heading - Heading text will be used to create the TOC menu for navigation
- You should assign identifiable ids to each tutorial step: otherwise a generated id will be created, but it’s name won’t be humanized
- You can add additional piece of help at the end of a step busing the following custom block
CopyCopied!