From 396a07bcc7d5aa3f6a345bb10620e4a8cab82cb0 Mon Sep 17 00:00:00 2001
From: Jan-Piet Mens <jpmens@gmail.com>
Date: Mon, 18 Feb 2013 15:31:38 +0100
Subject: [PATCH] Add support for additional EXAMPLES string in Ansible modules
 return DOC and EXAMPLES as a list add moduledev explanation more

---
 bin/ansible-doc                  |  8 ++++++--
 docsite/rst/moduledev.rst        | 13 +++++++++++++
 hacking/module_formatter.py      |  3 ++-
 hacking/templates/man.j2         |  7 +++++++
 hacking/templates/markdown.j2    |  6 +++++-
 hacking/templates/rst.j2         |  8 ++++++++
 lib/ansible/utils/module_docs.py | 12 +++++++++---
 7 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/bin/ansible-doc b/bin/ansible-doc
index cf75f07e44..c1d3243de0 100755
--- a/bin/ansible-doc
+++ b/bin/ansible-doc
@@ -91,6 +91,9 @@ def print_man(doc):
         for ex in doc['examples']:
             print "%s\n" % (ex['code'])
 
+    if 'plainexamples' in doc and doc['plainexamples'] is not None:
+        print doc['plainexamples']
+
 def print_snippet(doc):
 
     desc = tty_ify("".join(doc['short_description']))
@@ -153,7 +156,7 @@ def main():
 
             filename = utils.plugins.module_finder.find_plugin(module)
             try:
-                doc = module_docs.get_docstring(filename)
+                doc, plainexamples = module_docs.get_docstring(filename)
                 desc = tty_ify(doc.get('short_description', '?'))
                 if len(desc) > 55:
                     desc = desc + '...'
@@ -180,7 +183,7 @@ def main():
             continue
 
         try:
-            doc = module_docs.get_docstring(filename)
+            doc, plainexamples = module_docs.get_docstring(filename)
         except:
             traceback.print_exc()
             sys.stderr.write("ERROR: module %s has a documentation error formatting or is missing documentation\n" % module)
@@ -197,6 +200,7 @@ def main():
             doc['filename']         = filename
             doc['docuri']           = doc['module'].replace('_', '-')
             doc['now_date']         = datetime.date.today().strftime('%Y-%m-%d')
+            doc['plainexamples']    = plainexamples
 
             if options.show_snippet:
                 print_snippet(doc)
diff --git a/docsite/rst/moduledev.rst b/docsite/rst/moduledev.rst
index bd13d04aa3..223a556c8c 100644
--- a/docsite/rst/moduledev.rst
+++ b/docsite/rst/moduledev.rst
@@ -354,6 +354,19 @@ for URL, module, italic, and constant-width respectively. It is suggested
 to use ``C()`` for file and option names, and ``I()`` when referencing
 parameters; module names should be specifies as ``M(module)``.
 
+Examples (which typically contain colons, quotes, etc.) are difficult
+to format with YAML, so these can (alternatively, or additionally) be
+written in plain text in an ``EXAMPLES`` string within the module
+like this::
+
+    EXAMPLES = '''
+    - action: modulename opt1=arg1 opt2=arg2
+    '''
+
+The ``module_formatter.py`` script and ``ansible-doc(1)`` append the
+``EXAMPLES`` blob after any existing ``examples`` you may have in the
+YAML ``DOCUMENTATION`` string.
+
 Building & Testing
 ++++++++++++++++++
 
diff --git a/hacking/module_formatter.py b/hacking/module_formatter.py
index 71e8777a43..eb87e500c9 100755
--- a/hacking/module_formatter.py
+++ b/hacking/module_formatter.py
@@ -296,7 +296,7 @@ def main():
                 js_data.append(j)
             continue
 
-        doc = ansible.utils.module_docs.get_docstring(fname, verbose=options.verbose)
+        doc, examples = ansible.utils.module_docs.get_docstring(fname, verbose=options.verbose)
 
         if doc is None and module not in ansible.utils.module_docs.BLACKLIST_MODULES:
             sys.stderr.write("*** ERROR: CORE MODULE MISSING DOCUMENTATION: %s ***\n" % module)
@@ -314,6 +314,7 @@ def main():
             doc['docuri']           = doc['module'].replace('_', '-')
             doc['now_date']         = datetime.date.today().strftime('%Y-%m-%d')
             doc['ansible_version']  = options.ansible_version
+            doc['plainexamples']    = examples  #plain text
 
             if options.includes_file is not None and includefmt != "":
                 incfile.write(includefmt % module)
diff --git a/hacking/templates/man.j2 b/hacking/templates/man.j2
index 36764bd4e0..90e429742b 100644
--- a/hacking/templates/man.j2
+++ b/hacking/templates/man.j2
@@ -56,6 +56,13 @@
 .fi
 {% endfor %}
 {% endif %}
+." ------ PLAINEXAMPLES
+{% if plainexamples is defined %}
+.nf
+@{ plainexamples }@
+.fi
+{% endif %}
+
 ." ------- AUTHOR
 {% if author is defined %}
 .SH AUTHOR
diff --git a/hacking/templates/markdown.j2 b/hacking/templates/markdown.j2
index 2c65af0fa3..0cc8151fde 100644
--- a/hacking/templates/markdown.j2
+++ b/hacking/templates/markdown.j2
@@ -44,7 +44,11 @@ New in version @{ version_added }@.
 @{ example['code'] }@
 ```
 {% endfor %}
- 
+{% if plainexamples -%}
+```
+@{ plainexamples }@
+```
+{% endif %}
 
 {% if notes %}
 #### Notes
diff --git a/hacking/templates/rst.j2 b/hacking/templates/rst.j2
index a619f6a298..5952581426 100644
--- a/hacking/templates/rst.j2
+++ b/hacking/templates/rst.j2
@@ -54,6 +54,14 @@
 {% endfor %}
     <br/>
 
+{% if plainexamples %}
+.. raw:: html
+
+    <pre>
+@{ plainexamples | escape | indent(4, True) }@
+    </pre>
+{% endif %}
+
 {% if notes %}
 .. raw:: html
 
diff --git a/lib/ansible/utils/module_docs.py b/lib/ansible/utils/module_docs.py
index 221cb4ad4e..e8e5541716 100755
--- a/lib/ansible/utils/module_docs.py
+++ b/lib/ansible/utils/module_docs.py
@@ -30,11 +30,14 @@ BLACKLIST_MODULES = [
 
 def get_docstring(filename, verbose=False):
     """
-    Search for assignment of the DOCUMENTATION variable in the given file.
-    Parse that from YAML and return the YAML doc or None.
+    Search for assignment of the DOCUMENTATION and EXAMPLES variables
+    in the given file.
+    Parse DOCUMENTATION from YAML and return the YAML doc or None
+    together with EXAMPLES, as plain text.
     """
 
     doc = None
+    plainexamples = None
 
     try:
         # Thank you, Habbie, for this bit of code :-)
@@ -43,8 +46,11 @@ def get_docstring(filename, verbose=False):
             if isinstance(child, ast.Assign):
                 if 'DOCUMENTATION' in (t.id for t in child.targets):
                     doc = yaml.load(child.value.s)
+                if 'EXAMPLES' in (t.id for t in child.targets):
+                    plainexamples = child.value.s[1:]  # Skip first empty line
     except:
         if verbose == True:
             traceback.print_exc()
             print "unable to parse %s" % filename
-    return doc
+    return doc, plainexamples
+