api_docs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Jack Neto, The Working Group
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # API docs
2
+
3
+ A tool to help you generate documentation for you API
4
+
5
+
6
+ ## Installation
7
+
8
+ Add gem definition to your Gemfile:
9
+
10
+ ``` ruby
11
+ gem 'api_docs'
12
+ ```
13
+
14
+ Bundle it:
15
+
16
+ bundle install
17
+
18
+ Add [Twitter bootstrap](http://twitter.github.com/bootstrap) and [Google code pretifyer](http://google-code-prettify.googlecode.com/svn/trunk/README.html) to you CSS manifest file
19
+
20
+ ``` js
21
+ //= require bootstrap
22
+ //= require prettify
23
+ ```
24
+
25
+ Here's what you Javascript manifest file should look like
26
+
27
+ ``` js
28
+ //= require jquery
29
+ //= require jquery_ujs
30
+ //= require bootstrap
31
+ //= require prettify
32
+ //= require api_docs
33
+ ```
34
+
35
+ Add your API documentation files to the /doc/api folder and in your view do:
36
+
37
+ ``` ruby
38
+ = render_api_docs %w{login users overview}
39
+ ```
40
+
41
+ ## The API documentation files
42
+
43
+ Here's a sample API for users
44
+
45
+ ``` yaml
46
+ 'List':
47
+ url: '/users'
48
+ method: GET
49
+ description: Returns a list of users
50
+ params:
51
+ api_key:
52
+ keyword: "a string of one or more words used to filter the users by first_name, last_name and email (optional)"
53
+ success:
54
+ response: 'HTTP/1.1 200 OK'
55
+ data: |
56
+ {
57
+ "users": [
58
+ {
59
+ "id": 27,
60
+ "first_name": "John",
61
+ "last_name": "Smith",
62
+ "created_at": "2011-06-13T00:28:36-04:00",
63
+ "updated_at": "2012-04-26T20:21:43-04:00"
64
+ },
65
+ {
66
+ "id": 3,
67
+ "first_name": "Anna",
68
+ "last_name": "Brown",
69
+ "created_at": "2011-06-13T00:28:36-04:00",
70
+ "updated_at": "2012-04-26T20:21:43-04:00"
71
+ },
72
+ ...
73
+ ]
74
+ }
75
+ fail:
76
+ response: 'HTTP/1.1 422 Unprocessable Entity'
77
+ data: |
78
+ {
79
+ "message": "Failed to create User",
80
+ "errors" : {
81
+ "email": "Email is invalid",
82
+ ...
83
+ }
84
+ }
85
+
86
+ curl: curl -i :api_url/v1/users?api_key=7gR9hZt3DBqcuzi2mZKN
87
+
88
+ # ------------------------------
89
+
90
+ 'Show':
91
+ url: '/users/:id'
92
+ method: GET
93
+ description: |
94
+ Returns profile details for a specified user.
95
+ <span class=label>NOTE</span> If showing details of another user the email is ommited
96
+ params:
97
+ api_key:
98
+ id: the id of a user
99
+ success:
100
+ response: 'HTTP/1.1 200 OK'
101
+ data: |
102
+ {
103
+ "user": {
104
+ "id": 917,
105
+ "api_key": "7gR9hZt3DBqcuzi2mZKN",
106
+ "email": "john_smith@gmail.com",
107
+ "first_name": "John",
108
+ "last_name": "Smith",
109
+ "created_at": "2011-06-13T00:28:36-04:00",
110
+ "updated_at": "2012-04-26T20:21:43-04:00"
111
+ }
112
+ }
113
+ fail:
114
+ response: 'HTTP/1.1 404 Not Found'
115
+ data: |
116
+ {
117
+ "message": "User not found"
118
+ }
119
+ curl: curl -i :api_url/v1/users/197?api_key=2a10K5ipBd2qapJsPvCso90kMO
120
+
121
+ # ------------------------------
122
+
123
+ 'Create':
124
+ url: '/users'
125
+ method: POST
126
+ description: Create a user
127
+ params:
128
+ user[first_name]:
129
+ user[last_name]:
130
+ user[email]:
131
+ user[password]:
132
+ success:
133
+ response: 'HTTP/1.1 201 Created'
134
+ data: |
135
+ {
136
+ "user": {
137
+ "id": 917,
138
+ "api_key": "7gR9hZt3DBqcuzi2mZKN",
139
+ "email": "john_smith@gmail.com",
140
+ "first_name": "John",
141
+ "last_name": "Smith",
142
+ "created_at": "2011-06-13T00:28:36-04:00",
143
+ "updated_at": "2012-04-26T20:21:43-04:00"
144
+ }
145
+ }
146
+ fail:
147
+ response: 'HTTP/1.1 422 Unprocessable Entity'
148
+ data: |
149
+ {
150
+ "message": "Failed to create User",
151
+ "errors" : {
152
+ "email": "Email is invalid",
153
+ ...
154
+ }
155
+ }
156
+ curl: |
157
+ curl -i :api_url/v1/users \
158
+ -d "user[first_name]=John" \
159
+ -d "user[last_name]=Smith" \
160
+ -d "user[email]=john_smith@twg.ca" \
161
+ -d "user[password]=passpass"
162
+ ```
163
+
164
+
165
+ ## Configuration
166
+
167
+ You can change the default configuration of this gem by adding the following code to your initializers folder:
168
+
169
+ ``` ruby
170
+ ApiDocs.configure do |config|
171
+ config.yaml_docs_folder = '/some/other/folder ' # the default folder is /doc/api
172
+ end
173
+ ```
174
+
175
+
176
+ ---
177
+
178
+ Copyright 2012 Jack Neto, [The Working Group, Inc](http://www.theworkinggroup.ca)
179
+
data/Rakefile ADDED
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'jeweler'
4
+
5
+ Jeweler::Tasks.new do |gem|
6
+ gem.name = "api_docs"
7
+ gem.homepage = "http://github.com/twg/api_docs"
8
+ gem.license = "MIT"
9
+ gem.summary = "A tool to help you generate documentation for you API"
10
+ gem.description = ''
11
+ gem.email = "jack@twg.ca"
12
+ gem.authors = ["Jack Neto", 'The Working Group Inc.']
13
+ gem.add_dependency('rails', '>=3.1.0')
14
+ gem.add_dependency('bootstrap_builder', '>=0.2.6')
15
+ end
16
+ Jeweler::RubygemsDotOrgTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/api_docs.gemspec ADDED
@@ -0,0 +1,61 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{api_docs}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Jack Neto", "The Working Group Inc."]
12
+ s.date = %q{2012-05-02}
13
+ s.description = %q{}
14
+ s.email = %q{jack@twg.ca}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.md"
18
+ ]
19
+ s.files = [
20
+ "LICENSE.txt",
21
+ "README.md",
22
+ "Rakefile",
23
+ "VERSION",
24
+ "api_docs.gemspec",
25
+ "app/assets/javascripts/api_docs.js.coffee",
26
+ "app/assets/javascripts/prettify.js",
27
+ "app/assets/stylesheets/prettify.css",
28
+ "app/views/api_docs/_api_docs.html.haml",
29
+ "app/views/api_docs/_curl.html.haml",
30
+ "app/views/api_docs/_form.html.haml",
31
+ "app/views/api_docs/_panel.html.haml",
32
+ "app/views/api_docs/_params.html.haml",
33
+ "app/views/api_docs/_response.html.haml",
34
+ "lib/api_docs.rb",
35
+ "lib/api_docs/configuration.rb",
36
+ "lib/api_docs/engine.rb",
37
+ "lib/api_docs/railtie.rb"
38
+ ]
39
+ s.homepage = %q{http://github.com/twg/api_docs}
40
+ s.licenses = ["MIT"]
41
+ s.require_paths = ["lib"]
42
+ s.rubygems_version = %q{1.3.7}
43
+ s.summary = %q{A tool to help you generate documentation for you API}
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ s.add_runtime_dependency(%q<rails>, [">= 3.1.0"])
51
+ s.add_runtime_dependency(%q<bootstrap_builder>, [">= 0.2.6"])
52
+ else
53
+ s.add_dependency(%q<rails>, [">= 3.1.0"])
54
+ s.add_dependency(%q<bootstrap_builder>, [">= 0.2.6"])
55
+ end
56
+ else
57
+ s.add_dependency(%q<rails>, [">= 3.1.0"])
58
+ s.add_dependency(%q<bootstrap_builder>, [">= 0.2.6"])
59
+ end
60
+ end
61
+
@@ -0,0 +1,37 @@
1
+ $ ->
2
+ prettyPrint()
3
+
4
+ # Select the first panel
5
+ $('ul.main-tabs li:first').removeClass('active') # wheir hack
6
+ $('ul.main-tabs a:first').tab('show')
7
+
8
+ # Select the first sub-panel of each tab
9
+ $('ul.sub-tabs').each ->
10
+ $(this).find('a:first').tab('show')
11
+
12
+ # Select a tab based on the URL
13
+ selectPanel window.location.hash
14
+
15
+
16
+ # --- Clicking on a tab link ---
17
+ $('ul.main-tabs li a, ul.sub-tabs li a').click (event) ->
18
+ window.location.hash = $(this).attr('href')
19
+
20
+
21
+ # --- Submitting the form ---
22
+ $('.tab-pane form').live 'submit', (event) ->
23
+ url = $(this).data('url')
24
+ ids = url.match(/\/(:\w*)/g)
25
+ for id in ids
26
+ input_field = $(this).find('input[name=' + id.substring(2) + ']')
27
+ url = url.replace(id, '/' + input_field.attr('value'))
28
+
29
+
30
+
31
+ selectPanel = (url)->
32
+ if url != ''
33
+ url_parts = window.location.hash.substring(1).split('-')
34
+ $('ul.main-tabs a[href="#' + url_parts[0] + '"]').tab('show')
35
+
36
+ if url_parts.length > 1
37
+ $('ul.sub-tabs a[href="' + url + '"]').tab('show')
@@ -0,0 +1,28 @@
1
+ var q=null;window.PR_SHOULD_USE_CONTINUATION=!0;
2
+ (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a=
3
+ [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c<i;++c){var j=f[c];if(/\\[bdsw]/i.test(j))a.push(j);else{var j=m(j),d;c+2<i&&"-"===f[c+1]?(d=m(f[c+2]),c+=2):d=j;b.push([j,d]);d<65||j>122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;c<b.length;++c)i=b[c],i[0]<=j[1]+1?j[1]=Math.max(j[1],i[1]):f.push(j=i);b=["["];o&&b.push("^");b.push.apply(b,a);for(c=0;c<
4
+ f.length;++c)i=f[c],b.push(e(i[0])),i[1]>i[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c<b;++c){var j=f[c];j==="("?++i:"\\"===j.charAt(0)&&(j=+j.substring(1))&&j<=i&&(d[j]=-1)}for(c=1;c<d.length;++c)-1===d[c]&&(d[c]=++t);for(i=c=0;c<b;++c)j=f[c],j==="("?(++i,d[i]===void 0&&(f[c]="(?:")):"\\"===j.charAt(0)&&
5
+ (j=+j.substring(1))&&j<=i&&(f[c]="\\"+d[i]);for(i=c=0;c<b;++c)"^"===f[c]&&"^"!==f[c+1]&&(f[c]="");if(a.ignoreCase&&s)for(c=0;c<b;++c)j=f[c],a=j.charAt(0),j.length>=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p<d;++p){var g=a[p];if(g.ignoreCase)l=!0;else if(/[a-z]/i.test(g.source.replace(/\\u[\da-f]{4}|\\x[\da-f]{2}|\\[^UXux]/gi,""))){s=!0;l=!1;break}}for(var r=
6
+ {b:8,t:9,n:10,v:11,f:12,r:13},n=[],p=0,d=a.length;p<d;++p){g=a[p];if(g.global||g.multiline)throw Error(""+g);n.push("(?:"+y(g)+")")}return RegExp(n.join("|"),l?"gi":"g")}function M(a){function m(a){switch(a.nodeType){case 1:if(e.test(a.className))break;for(var g=a.firstChild;g;g=g.nextSibling)m(g);g=a.nodeName;if("BR"===g||"LI"===g)h[s]="\n",t[s<<1]=y++,t[s++<<1|1]=a;break;case 3:case 4:g=a.nodeValue,g.length&&(g=p?g.replace(/\r\n?/g,"\n"):g.replace(/[\t\n\r ]+/g," "),h[s]=g,t[s<<1]=y,y+=g.length,
7
+ t[s++<<1|1]=a)}}var e=/(?:^|\s)nocode(?:\s|$)/,h=[],y=0,t=[],s=0,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=document.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);m(a);return{a:h.join("").replace(/\n$/,""),c:t}}function B(a,m,e,h){m&&(a={a:m,d:a},e(a),h.push.apply(h,a.e))}function x(a,m){function e(a){for(var l=a.d,p=[l,"pln"],d=0,g=a.a.match(y)||[],r={},n=0,z=g.length;n<z;++n){var f=g[n],b=r[f],o=void 0,c;if(typeof b===
8
+ "string")c=!1;else{var i=h[f.charAt(0)];if(i)o=f.match(i[1]),b=i[0];else{for(c=0;c<t;++c)if(i=m[c],o=f.match(i[1])){b=i[0];break}o||(b="pln")}if((c=b.length>=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m),
9
+ l=[],p={},d=0,g=e.length;d<g;++d){var r=e[d],n=r[3];if(n)for(var k=n.length;--k>=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/,
10
+ q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/,
11
+ q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g,
12
+ "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a),
13
+ a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e}
14
+ for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g<d.length;++g)e(d[g]);m===(m|0)&&d[0].setAttribute("value",
15
+ m);var r=s.createElement("OL");r.className="linenums";for(var n=Math.max(0,m-1|0)||0,g=0,z=d.length;g<z;++g)l=d[g],l.className="L"+(g+n)%10,l.firstChild||l.appendChild(s.createTextNode("\xa0")),r.appendChild(l);a.appendChild(r)}function k(a,m){for(var e=m.length;--e>=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*</.test(m)?"default-markup":"default-code";return A[a]}function E(a){var m=
16
+ a.g;try{var e=M(a.h),h=e.a;a.a=h;a.c=e.c;a.d=0;C(m,h)(a);var k=/\bMSIE\b/.test(navigator.userAgent),m=/\n/g,t=a.a,s=t.length,e=0,l=a.c,p=l.length,h=0,d=a.e,g=d.length,a=0;d[g]=s;var r,n;for(n=r=0;n<g;)d[n]!==d[n+2]?(d[r++]=d[n++],d[r++]=d[n++]):n+=2;g=r;for(n=r=0;n<g;){for(var z=d[n],f=d[n+1],b=n+2;b+2<=g&&d[b+1]===f;)b+=2;d[r++]=z;d[r++]=f;n=b}for(d.length=r;h<p;){var o=l[h+2]||s,c=d[a+2]||s,b=Math.min(o,c),i=l[h+1],j;if(i.nodeType!==1&&(j=t.substring(e,b))){k&&(j=j.replace(m,"\r"));i.nodeValue=
17
+ j;var u=i.ownerDocument,v=u.createElement("SPAN");v.className=d[a+1];var x=i.parentNode;x.replaceChild(v,i);v.appendChild(i);e<o&&(l[h+1]=i=u.createTextNode(t.substring(b,o)),x.insertBefore(i,v.nextSibling))}e=b;e>=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"],
18
+ "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"],
19
+ H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"],
20
+ J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+
21
+ I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^<?]+/],["dec",/^<!\w[^>]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^<xmp\b[^>]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^<script\b[^>]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^<style\b[^>]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),
22
+ ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css",
23
+ /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}),
24
+ ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes",
25
+ hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p<h.length&&l.now()<e;p++){var n=h[p],k=n.className;if(k.indexOf("prettyprint")>=0){var k=k.match(g),f,b;if(b=
26
+ !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p<h.length?setTimeout(m,
27
+ 250):a&&a()}for(var e=[document.getElementsByTagName("pre"),document.getElementsByTagName("code"),document.getElementsByTagName("xmp")],h=[],k=0;k<e.length;++k)for(var t=0,s=e[k].length;t<s;++t)h.push(e[k][t]);var e=q,l=Date;l.now||(l={now:function(){return+new Date}});var p=0,d,g=/\blang(?:uage)?-([\w.]+)(?!\S)/;m()};window.PR={createSimpleLexer:x,registerLangHandler:k,sourceDecorator:u,PR_ATTRIB_NAME:"atn",PR_ATTRIB_VALUE:"atv",PR_COMMENT:"com",PR_DECLARATION:"dec",PR_KEYWORD:"kwd",PR_LITERAL:"lit",
28
+ PR_NOCODE:"nocode",PR_PLAIN:"pln",PR_PUNCTUATION:"pun",PR_SOURCE:"src",PR_STRING:"str",PR_TAG:"tag",PR_TYPE:"typ"}})();
@@ -0,0 +1,53 @@
1
+ .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
2
+
3
+ /* Pretty printing styles. Used with prettify.js. */
4
+ /* Vim sunburst theme by David Leibovic */
5
+
6
+ pre .str, code .str { color: #65B042; } /* string - green */
7
+ pre .kwd, code .kwd { color: #E28964; } /* keyword - dark pink */
8
+ pre .com, code .com { color: #AEAEAE; font-style: italic; } /* comment - gray */
9
+ pre .typ, code .typ { color: #89bdff; } /* type - light blue */
10
+ pre .lit, code .lit { color: #3387CC; } /* literal - blue */
11
+ pre .pun, code .pun { color: #fff; } /* punctuation - white */
12
+ pre .pln, code .pln { color: #fff; } /* plaintext - white */
13
+ pre .tag, code .tag { color: #89bdff; } /* html/xml tag - light blue */
14
+ pre .atn, code .atn { color: #bdb76b; } /* html/xml attribute name - khaki */
15
+ pre .atv, code .atv { color: #65B042; } /* html/xml attribute value - green */
16
+ pre .dec, code .dec { color: #3387CC; } /* decimal - blue */
17
+
18
+ pre.prettyprint, code.prettyprint {
19
+ background-color: rgba(20, 20,20, .8);
20
+ -moz-border-radius: 8px;
21
+ -webkit-border-radius: 8px;
22
+ -o-border-radius: 8px;
23
+ -ms-border-radius: 8px;
24
+ -khtml-border-radius: 8px;
25
+ border-radius: 8px;
26
+ }
27
+
28
+ pre.prettyprint {
29
+ width: 95%;
30
+ margin: 1em auto;
31
+ padding: 1em;
32
+ white-space: pre-wrap;
33
+ }
34
+
35
+
36
+ /* Specify class=linenums on a pre to get line numbering */
37
+ ol.linenums { margin-top: 0; margin-bottom: 0; color: #AEAEAE; } /* IE indents via margin-left */
38
+ li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8 { list-style-type: none }
39
+ /* Alternate shading for lines */
40
+ li.L1,li.L3,li.L5,li.L7,li.L9 { }
41
+
42
+ @media print {
43
+ pre .str, code .str { color: #060; }
44
+ pre .kwd, code .kwd { color: #006; font-weight: bold; }
45
+ pre .com, code .com { color: #600; font-style: italic; }
46
+ pre .typ, code .typ { color: #404; font-weight: bold; }
47
+ pre .lit, code .lit { color: #044; }
48
+ pre .pun, code .pun { color: #440; }
49
+ pre .pln, code .pln { color: #000; }
50
+ pre .tag, code .tag { color: #006; font-weight: bold; }
51
+ pre .atn, code .atn { color: #404; }
52
+ pre .atv, code .atv { color: #060; }
53
+ }
@@ -0,0 +1,11 @@
1
+ .tabbable
2
+ %ul.nav.nav-tabs.main-tabs
3
+ - @api_docs.keys.each_with_index do |api_tab_label, i|
4
+ %li{:class => (:active if i == 0)}
5
+ = link_to api_tab_label.humanize.capitalize, "##{api_tab_label.underscore}", "data-toggle" => "tab"
6
+
7
+ .tab-content
8
+ - @api_docs.each do |api_tab_label, api|
9
+ .tab-pane{:id => api_tab_label.underscore}
10
+ - unless api.blank?
11
+ = render :partial => 'panel', :locals => {:label => api_tab_label, :api => api}
@@ -0,0 +1,4 @@
1
+ - if api_details['curl']
2
+ %p
3
+ %strong Sample cURL request
4
+ %pre.prettyprint= api_details['curl'].to_s.gsub(':api_url', ApiDocs.config.api_url)
@@ -0,0 +1,17 @@
1
+ - if api_details['method'].present? && %{post get}.include?(api_details['method'].downcase)
2
+ %hr/
3
+ %p
4
+ %strong Try it out:
5
+ %em #{api_details['method']} #{ApiDocs.config.api_url}/v1#{api_details['url']}
6
+ = bootstrap_form_for '', :url => "#{ApiDocs.config.api_url}/v1#{api_details['url']}", :html => {:method => api_details['method'], :target => '_blank', :class => 'form-horizontal', 'data-url' => "#{ApiDocs.config.api_url}/v1#{api_details['url']}"} do |f|
7
+ - case params
8
+ - when Array
9
+ - api_details['params'].each do |param|
10
+ = f.text_field param, :label => param, :name => param
11
+ - when Hash
12
+ - api_details['params'].each do |param, description|
13
+ = f.text_field param, :label => param, :name => param, :help_block => description
14
+
15
+ .form-actions
16
+ = f.submit :send, :class => 'btn-primary'
17
+
@@ -0,0 +1,33 @@
1
+ .tabbable.tabs-left
2
+ .row
3
+ - if api.length > 1
4
+ .span2
5
+ %ul.nav.nav-tabs.sub-tabs
6
+ - api.each do |api_path, api_details|
7
+ %li
8
+ = link_to "##{label}-#{api_path.gsub(/[\/\: ]/, '')}".downcase, "data-toggle" => "tab" do
9
+ = api_path
10
+
11
+ %div{:class => (api.length > 1 ? 'span10' : 'span12')}
12
+ %div{:class => ('tab-content' if api.length > 1)}
13
+ - api.each do |api_path, api_details|
14
+ .tab-pane{:id => "#{label}-#{api_path.gsub(/[\/\: ]/, '')}".downcase}
15
+ %h3
16
+ = api_path
17
+ - if api_details['method']
18
+ %span.label.label-important= api_details['method']
19
+ %small #{ApiDocs.config.api_url}/v1#{api_details['url']}
20
+
21
+ - if api_details['description']
22
+ %pre= api_details['description'].html_safe
23
+
24
+ = render :partial => 'params', :object => api_details['params']
25
+
26
+ .row
27
+ = render :partial => 'response', :object => api_details, :locals => {:response_type => 'success'}
28
+ = render :partial => 'response', :object => api_details, :locals => {:response_type => 'fail'}
29
+
30
+ = render :partial => 'curl', :locals => {:api_details => api_details}
31
+
32
+ = render :partial => 'form', :locals => {:api_details => api_details}
33
+
@@ -0,0 +1,15 @@
1
+ - if params
2
+ %p
3
+ %strong Parameters:
4
+ - case params
5
+ - when Array
6
+ %pre= params.join("\n")
7
+ - when Hash
8
+ %table.table.table-striped.table-bordered.table-condensed
9
+ %tr
10
+ %th Param
11
+ %th Description
12
+ - params.each do |param, description|
13
+ %tr
14
+ %td= param
15
+ %td= description
@@ -0,0 +1,16 @@
1
+ - case response[response_type]
2
+ - when Hash
3
+ .span5
4
+ %strong= "#{response_type.capitalize} response:"
5
+ %pre.prettyprint= response[response_type].dig('response')
6
+ - if response[response_type].dig('data')
7
+ %pre.prettyprint= response[response_type].dig('data')
8
+
9
+ - when Array
10
+ .span5
11
+ %strong= "#{response_type.capitalize} responses:"
12
+ - response[response_type].each do |res|
13
+ %pre.prettyprint= res.dig('response')
14
+ - if res.dig('data')
15
+ %pre.prettyprint= res.dig('data')
16
+ %hr/
@@ -0,0 +1,14 @@
1
+ module ApiDocs
2
+ class Configuration
3
+
4
+ # Where to find the folder with the yaml docs
5
+ attr_accessor :yaml_docs_folder, :api_url
6
+
7
+ # Configuration defaults
8
+ def initialize
9
+ @yaml_docs_folder = '/doc'
10
+ @api_url = 'http://localhost:3000'
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,8 @@
1
+ require "api_docs"
2
+ require "rails"
3
+
4
+ module ApiDocs
5
+ class Engine < Rails::Engine
6
+
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # Configure Rails 3.0 to use public/javascripts/jquery et al
2
+ module Jquery
3
+ module Rails
4
+
5
+ class Railtie < ::Rails::Railtie
6
+ config.before_configuration do
7
+ config.action_view.javascript_expansions[:defaults] |= ['bootstrap']
8
+ end
9
+ end
10
+
11
+ end
12
+ end
data/lib/api_docs.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'api_docs/engine'
2
+ require 'api_docs/configuration'
3
+
4
+ module ApiDocs
5
+
6
+ class << self
7
+
8
+ def configure
9
+ yield configuration
10
+ end
11
+
12
+ def configuration
13
+ @configuration ||= Configuration.new
14
+ end
15
+ alias :config :configuration
16
+
17
+ end
18
+
19
+
20
+ module ApplicationExtensions
21
+
22
+ def self.included(base)
23
+ base.send(:include, ApiDocs::ApplicationExtensions::InstanceMethods)
24
+ base.send(:helper_method, :render_api_docs) if base.respond_to?(:helper_method)
25
+ end
26
+
27
+ module InstanceMethods
28
+
29
+ def render_api_docs(docs)
30
+ @api_docs = {}
31
+ docs.each do |section|
32
+ @api_docs[section] = YAML::load(File.open("#{Rails.root}#{ApiDocs.config.yaml_docs_folder}/#{section}.yml"))
33
+ end
34
+ render_to_string(:partial => 'api_docs').html_safe
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+
41
+ ActionController::Base.send(:include, ApiDocs::ApplicationExtensions)
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: api_docs
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jack Neto
14
+ - The Working Group Inc.
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2012-05-02 00:00:00 -04:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: rails
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 3
33
+ - 1
34
+ - 0
35
+ version: 3.1.0
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: bootstrap_builder
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ hash: 27
47
+ segments:
48
+ - 0
49
+ - 2
50
+ - 6
51
+ version: 0.2.6
52
+ type: :runtime
53
+ version_requirements: *id002
54
+ description: ""
55
+ email: jack@twg.ca
56
+ executables: []
57
+
58
+ extensions: []
59
+
60
+ extra_rdoc_files:
61
+ - LICENSE.txt
62
+ - README.md
63
+ files:
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - VERSION
68
+ - api_docs.gemspec
69
+ - app/assets/javascripts/api_docs.js.coffee
70
+ - app/assets/javascripts/prettify.js
71
+ - app/assets/stylesheets/prettify.css
72
+ - app/views/api_docs/_api_docs.html.haml
73
+ - app/views/api_docs/_curl.html.haml
74
+ - app/views/api_docs/_form.html.haml
75
+ - app/views/api_docs/_panel.html.haml
76
+ - app/views/api_docs/_params.html.haml
77
+ - app/views/api_docs/_response.html.haml
78
+ - lib/api_docs.rb
79
+ - lib/api_docs/configuration.rb
80
+ - lib/api_docs/engine.rb
81
+ - lib/api_docs/railtie.rb
82
+ has_rdoc: true
83
+ homepage: http://github.com/twg/api_docs
84
+ licenses:
85
+ - MIT
86
+ post_install_message:
87
+ rdoc_options: []
88
+
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ hash: 3
97
+ segments:
98
+ - 0
99
+ version: "0"
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ requirements: []
110
+
111
+ rubyforge_project:
112
+ rubygems_version: 1.3.7
113
+ signing_key:
114
+ specification_version: 3
115
+ summary: A tool to help you generate documentation for you API
116
+ test_files: []
117
+