rapidoc 0.0.4

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.
Files changed (96) hide show
  1. data/.gitignore +21 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.rdoc +152 -0
  5. data/Rakefile +1 -0
  6. data/lib/rapidoc.rb +62 -0
  7. data/lib/rapidoc/action_doc.rb +86 -0
  8. data/lib/rapidoc/config.rb +127 -0
  9. data/lib/rapidoc/config/rapidoc.yml +4 -0
  10. data/lib/rapidoc/controller_extractor.rb +54 -0
  11. data/lib/rapidoc/http_response.rb +61 -0
  12. data/lib/rapidoc/param_errors.rb +43 -0
  13. data/lib/rapidoc/resource_doc.rb +66 -0
  14. data/lib/rapidoc/resources_extractor.rb +42 -0
  15. data/lib/rapidoc/routes_doc.rb +96 -0
  16. data/lib/rapidoc/templates/action.html.hbs +170 -0
  17. data/lib/rapidoc/templates/assets/css/bootstrap-responsive.min.css +9 -0
  18. data/lib/rapidoc/templates/assets/css/bootstrap.min.css +9 -0
  19. data/lib/rapidoc/templates/assets/css/rapidoc.css +43 -0
  20. data/lib/rapidoc/templates/assets/img/glyphicons-halflings.png +0 -0
  21. data/lib/rapidoc/templates/assets/js/bootstrap.min.js +6 -0
  22. data/lib/rapidoc/templates/assets/js/jquery-1.9.0.min.js +4 -0
  23. data/lib/rapidoc/templates/assets/js/json2.js +486 -0
  24. data/lib/rapidoc/templates/index.html.hbs +85 -0
  25. data/lib/rapidoc/templates_generator.rb +65 -0
  26. data/lib/rapidoc/version.rb +3 -0
  27. data/lib/rapidoc/yaml_parser.rb +49 -0
  28. data/lib/tasks/railtie.rb +7 -0
  29. data/lib/tasks/rapidoc.rake +18 -0
  30. data/rapidoc.gemspec +26 -0
  31. data/spec/dummy/.gitignore +15 -0
  32. data/spec/dummy/Gemfile +42 -0
  33. data/spec/dummy/README.rdoc +261 -0
  34. data/spec/dummy/Rakefile +7 -0
  35. data/spec/dummy/app/assets/images/rails.png +0 -0
  36. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  37. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  38. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  39. data/spec/dummy/app/controllers/users_controller.rb +114 -0
  40. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  41. data/spec/dummy/app/mailers/.gitkeep +0 -0
  42. data/spec/dummy/app/models/.gitkeep +0 -0
  43. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  44. data/spec/dummy/config.ru +4 -0
  45. data/spec/dummy/config/application.rb +62 -0
  46. data/spec/dummy/config/boot.rb +6 -0
  47. data/spec/dummy/config/database.yml +25 -0
  48. data/spec/dummy/config/environment.rb +5 -0
  49. data/spec/dummy/config/environments/development.rb +37 -0
  50. data/spec/dummy/config/environments/production.rb +67 -0
  51. data/spec/dummy/config/environments/test.rb +37 -0
  52. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  53. data/spec/dummy/config/initializers/inflections.rb +15 -0
  54. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  55. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  56. data/spec/dummy/config/initializers/session_store.rb +8 -0
  57. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  58. data/spec/dummy/config/locales/en.yml +5 -0
  59. data/spec/dummy/config/routes.rb +9 -0
  60. data/spec/dummy/db/seeds.rb +7 -0
  61. data/spec/dummy/lib/assets/.gitkeep +0 -0
  62. data/spec/dummy/lib/tasks/.gitkeep +0 -0
  63. data/spec/dummy/log/.gitkeep +0 -0
  64. data/spec/dummy/public/404.html +26 -0
  65. data/spec/dummy/public/422.html +26 -0
  66. data/spec/dummy/public/500.html +25 -0
  67. data/spec/dummy/public/favicon.ico +0 -0
  68. data/spec/dummy/public/index.html +241 -0
  69. data/spec/dummy/public/robots.txt +5 -0
  70. data/spec/dummy/salida/users_create_response.json +12 -0
  71. data/spec/dummy/script/rails +6 -0
  72. data/spec/dummy/test/fixtures/.gitkeep +0 -0
  73. data/spec/dummy/test/functional/.gitkeep +0 -0
  74. data/spec/dummy/test/integration/.gitkeep +0 -0
  75. data/spec/dummy/test/performance/browsing_test.rb +12 -0
  76. data/spec/dummy/test/test_helper.rb +13 -0
  77. data/spec/dummy/test/unit/.gitkeep +0 -0
  78. data/spec/dummy/vendor/assets/javascripts/.gitkeep +0 -0
  79. data/spec/dummy/vendor/assets/stylesheets/.gitkeep +0 -0
  80. data/spec/dummy/vendor/plugins/.gitkeep +0 -0
  81. data/spec/features/action_spec.rb +212 -0
  82. data/spec/features/index_spec.rb +64 -0
  83. data/spec/lib/action_doc_spec.rb +202 -0
  84. data/spec/lib/config_spec.rb +186 -0
  85. data/spec/lib/controller_extractor_spec.rb +77 -0
  86. data/spec/lib/http_response_spec.rb +63 -0
  87. data/spec/lib/param_errors_spec.rb +69 -0
  88. data/spec/lib/rake_spec.rb +25 -0
  89. data/spec/lib/rapidoc_spec.rb +39 -0
  90. data/spec/lib/resource_doc_spec.rb +131 -0
  91. data/spec/lib/resources_extractor_spec.rb +105 -0
  92. data/spec/lib/routes_doc_spec.rb +150 -0
  93. data/spec/lib/templates_generator_spec.rb +90 -0
  94. data/spec/lib/yard_parser_spec.rb +55 -0
  95. data/spec/spec_helper.rb +10 -0
  96. metadata +307 -0
@@ -0,0 +1,4 @@
1
+ project_name: "Project Name"
2
+ base_url: "http://api.mydomain.com"
3
+ company: "My company"
4
+ year: 2013
@@ -0,0 +1,54 @@
1
+ module Rapidoc
2
+
3
+ ##
4
+ # This class open controller file and get all documentation blocks.
5
+ # Lets us check if any of this blocks is a `rapidoc` block
6
+ # and return it using `json` format.
7
+ #
8
+ # Rapidoc blocks must:
9
+ # - have YAML format
10
+ # - begin with `#=begin action` for actions description
11
+ # - begin with `#=begin resource` for resource description
12
+ # - end with `#=end`
13
+ #
14
+ class ControllerExtractor
15
+
16
+ def initialize( controller_file )
17
+ lines = IO.readlines( controller_dir( controller_file ) )
18
+ blocks = extract_blocks( lines )
19
+
20
+ @resource_info = YamlParser.extract_resource_info( lines, blocks )
21
+ @actions_info = YamlParser.extract_actions_info( lines, blocks )
22
+ end
23
+
24
+ def get_actions_info
25
+ @actions_info
26
+ end
27
+
28
+ def get_action_info( action )
29
+ @actions_info.select{ |info| info['action'] == action.to_s }.first
30
+ end
31
+
32
+ def get_resource_info
33
+ @resource_info
34
+ end
35
+
36
+ def get_controller_info
37
+ { "description" => @resource_info["description"], "actions" => @actions_info }
38
+ end
39
+
40
+ private
41
+
42
+ ##
43
+ # Gets init and end lines of each comment block
44
+ #
45
+ def extract_blocks( lines )
46
+ init_doc_lines = lines.each_index.select{ |i| lines[i].include? "=begin" }
47
+ end_doc_lines = lines.each_index.select{ |i| lines[i].include? "=end" }
48
+
49
+ blocks = init_doc_lines.each_index.map do |i|
50
+ { :init => init_doc_lines[i], :end => end_doc_lines[i] }
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+
3
+ module Rapidoc
4
+
5
+ ##
6
+ # Represent http status code with code and description.
7
+ # Also include bootstrap label for code.
8
+ #
9
+ class HttpResponse
10
+
11
+ attr_reader :code, :description, :label
12
+
13
+ def initialize( code )
14
+ @code = code
15
+ @description = get_description
16
+ @label = get_label
17
+ end
18
+
19
+ def get_description
20
+ case @code
21
+ when 200
22
+ 'OK'
23
+ when 201
24
+ 'Created'
25
+ when 204
26
+ 'No content'
27
+ when 401
28
+ 'Unauthorized'
29
+ when 403
30
+ 'Forbidden'
31
+ when 404
32
+ 'Not found'
33
+ when 422
34
+ 'Unprocessable Entity'
35
+ else
36
+ ''
37
+ end
38
+ end
39
+
40
+ def get_label
41
+ case @code
42
+ when 200
43
+ 'label label-info'
44
+ when 201
45
+ 'label label-success'
46
+ when 204
47
+ 'label label-info2'
48
+ when 401
49
+ 'label label-warning'
50
+ when 403
51
+ 'label label-warning2'
52
+ when 422
53
+ 'label label-important'
54
+ when 404
55
+ 'label label-inverse'
56
+ else
57
+ 'label'
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,43 @@
1
+ module Rapidoc
2
+
3
+ module ParamErrors
4
+
5
+ def get_error_info( object, type )
6
+ case type
7
+ when 'required'
8
+ get_required_error_info object
9
+ when 'inclusion'
10
+ get_inclusion_error_info object
11
+ else
12
+ nil
13
+ end
14
+ end
15
+
16
+ def get_required_error_info( object )
17
+ if default_errors and default_errors.include? "required"
18
+ get_default_error_info( object, "required" )
19
+ else
20
+ { "object" => object,
21
+ "message" => "blank",
22
+ "description" => "This parameter is mandatory" }
23
+ end
24
+ end
25
+
26
+ def get_inclusion_error_info( object )
27
+ if default_errors and default_errors.include? "inclusion"
28
+ get_default_error_info( object, "inclusion" )
29
+ else
30
+ { "object" => object,
31
+ "message" => "inclusion",
32
+ "description" => "This parameter is not in the collection" }
33
+ end
34
+ end
35
+
36
+ def get_default_error_info( object, type )
37
+ { 'object' => object,
38
+ 'message' => default_errors[type]['message'], # config function
39
+ 'description' => default_errors[type]['description']
40
+ }
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+
3
+ module Rapidoc
4
+
5
+ ##
6
+ # This class includes all info about a resource
7
+ # To extract info from controller file uses ControllerExtractor
8
+ # It includes an array of ActionDoc with each action information
9
+ #
10
+ class ResourceDoc
11
+ attr_reader :name, :description, :controller_file, :actions_doc
12
+
13
+ ##
14
+ # @param resource_name [String] resource name
15
+ # @param routes_doc [RoutesDoc] routes documentation
16
+ #
17
+ def initialize( resource_name, routes_actions_info )
18
+ @name = resource_name.to_s
19
+ @controller_file = name.to_s.pluralize + '_controller.rb'
20
+
21
+ generate_info routes_actions_info
22
+ end
23
+
24
+ ##
25
+ # Names with '/' caracter produce problems in html ids
26
+ #
27
+ def simple_name
28
+ return self.name.delete '/'
29
+ end
30
+
31
+ private
32
+
33
+ ##
34
+ # Create description and actions_doc
35
+ #
36
+ def generate_info( routes_info )
37
+ if routes_info
38
+ extractor = get_controller_extractor
39
+ @description = extractor.get_resource_info['description'] if extractor
40
+ @actions_doc = get_actions_doc( routes_info, extractor )
41
+ end
42
+ end
43
+
44
+ ##
45
+ # @return [ControllerExtractor] extractor that allow read controller files
46
+ # and extract action and resource info from them
47
+ #
48
+ def get_controller_extractor
49
+ if File.exists? controller_dir( @controller_file )
50
+ ControllerExtractor.new @controller_file
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ ##
57
+ # @return [Array] all the resource ActionDoc
58
+ #
59
+ def get_actions_doc( routes_actions_info, extractor )
60
+ routes_actions_info.map do |route_info|
61
+ controller_info = extractor ? extractor.get_action_info( route_info[:action] ) : nil
62
+ ActionDoc.new( route_info, controller_info, examples_dir )
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,42 @@
1
+ module Rapidoc
2
+
3
+ ##
4
+ # This module get resources info.
5
+ #
6
+ # Info of each route include:
7
+ # - method
8
+ # - action
9
+ # - url
10
+ # - controller_file
11
+ #
12
+ module ResourcesExtractor
13
+
14
+ ##
15
+ # Reads 'rake routes' output and gets the routes info
16
+ # @return [RoutesDoc] class with routes info
17
+ #
18
+ def get_routes_doc
19
+ routes_doc = RoutesDoc.new
20
+ routes = Dir.chdir( ::Rails.root.to_s ) { `rake routes` }
21
+
22
+ routes.split("\n").each do |entry|
23
+ routes_doc.add_route( entry )
24
+ end
25
+
26
+ routes_doc
27
+ end
28
+
29
+ ##
30
+ # Create new ResourceDoc for each resource extracted from RoutesDoc
31
+ # @return [Array] ResourceDoc array
32
+ #
33
+ def get_resources
34
+ routes_doc = get_routes_doc
35
+ resources_names = routes_doc.get_resources_names - resources_black_list
36
+
37
+ resources_names.map do |resource|
38
+ ResourceDoc.new( resource, routes_doc.get_actions_route_info( resource ) )
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,96 @@
1
+ # encoding: utf-8
2
+
3
+ module Rapidoc
4
+
5
+ ##
6
+ # This class let us manage resources and actions extracted from 'rake routes'
7
+ #
8
+ class RoutesDoc
9
+ def initialize
10
+ @resources_routes = {}
11
+ end
12
+
13
+ def add_route( route )
14
+ if route.split.size == 4
15
+ method, url, controller_action = route.split.slice(1, 3)
16
+ else
17
+ method, url, controller_action = route.split
18
+ end
19
+
20
+ add_resource_route( method, url, controller_action )
21
+ end
22
+
23
+ def get_resources_names
24
+ @resources_routes.keys.sort
25
+ end
26
+
27
+ def get_resource_actions_names( resource )
28
+ @resources_routes[resource.to_sym].map{ |route| route[:action] }.uniq
29
+ end
30
+
31
+ def get_actions_route_info( resource )
32
+ get_resource_actions_names( resource ).map do |action|
33
+ get_action_route_info( resource, action )
34
+ end
35
+ end
36
+
37
+ def get_action_route_info( resource, action )
38
+ urls = []
39
+ controllers = []
40
+ methods = []
41
+
42
+ # compact and generate action info from all routes info of resource
43
+ @resources_routes[resource.to_sym].each do |route|
44
+ if route[:action] == action.to_s
45
+ urls.push route[:url]
46
+ controllers.push route[:controller]
47
+ methods.push route[:method]
48
+ end
49
+ end
50
+
51
+ return {
52
+ resource: resource.to_s,
53
+ action: action.to_s,
54
+ method: methods.uniq.first,
55
+ urls: urls.uniq,
56
+ controllers: controllers.uniq
57
+ }
58
+ end
59
+
60
+ private
61
+
62
+ ##
63
+ # Add new route info to resource routes array with correct format
64
+ #
65
+ def add_resource_route( method, url, controller_action )
66
+ #resource = get_resource_name( url )
67
+ resource = controller_action.split('#').first
68
+ info = {
69
+ resource: resource,
70
+ action: controller_action.split('#').last,
71
+ method: method,
72
+ url: url ,
73
+ controller: controller_action.split('#').first
74
+ }
75
+
76
+ @resources_routes[resource.to_sym] ||= []
77
+ @resources_routes[resource.to_sym].push( info )
78
+ end
79
+
80
+ ##
81
+ # Extract resource name from url
82
+ #
83
+ def get_resource_name( url )
84
+ new_url = url.gsub( '(.:format)', '' )
85
+
86
+ return $1 if new_url =~ /\/(\w+)\/:id$/ # /users/:id (users)
87
+ return $1 if new_url =~ /\/(\w+)\/:id\/edit$/ # /users/:id/edit (users)
88
+ return $1 if new_url =~ /^\/(\w+)$/ # /users (users)
89
+ return $1 if new_url =~ /\/:\w*id\/(\w+)$/ # /users/:id/images (images)
90
+ return $1 if new_url =~ /\/:\w*id\/(\w+)\/\w+$/ # /users/:id/config/edit (users)
91
+ return $1 if new_url =~ /^\/(\w+)\/\w+$/ # /users/edit (users)
92
+ return $1 if new_url =~ /\/(\w+)\/\w+\/\w+$/ # /users/password/edit (users)
93
+ return url
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,170 @@
1
+ <!DOCTYPE html>
2
+ <html lang="es">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Rapidoc - Action</title>
6
+ <meta name="description" content="Artículo en GenbetaDev sobre Bootstrap 2.0">
7
+ <meta name="author" content="Rafael Jurado González" >
8
+ <link href="../assets/css/bootstrap.min.css" rel="stylesheet">
9
+ <link href="../assets/css/rapidoc.css" rel="stylesheet">
10
+ <link href="../assets/css/bootstrap-responsive.min.css" rel="stylesheet">
11
+ <script src="../assets/js/jquery-1.9.0.min.js"></script>
12
+ <script src="../assets/js/bootstrap.min.js"></script>
13
+ <script src="../assets/js/json2.js"></script>
14
+ <style>
15
+ body { padding-top: 60px; }
16
+ </style>
17
+ </head>
18
+ <body onload="prueba()">
19
+
20
+ <div class="navbar navbar-fixed-top">
21
+ <div class="navbar-inner">
22
+ <div class="container">
23
+ <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
24
+ <span class="icon-bar"></span>
25
+ <span class="icon-bar"></span>
26
+ <span class="icon-bar"></span>
27
+ </a>
28
+ <a class="brand" href="#">{{info.project_name}}</a>
29
+ <div class="nav-collapse">
30
+ <ul class="nav">
31
+ <li><a href="../index.html">Resources</a></li>
32
+ <li class="active"><a href="#">Action</a></li>
33
+ <li><a target="_blank" href="https://github.com/drinor/rapidoc.git">Contact</a></li>
34
+ </ul>
35
+ </div>
36
+ </div>
37
+ </div>
38
+ </div>
39
+
40
+ <div class="container">
41
+ <div class="page-header">
42
+ <h1>{{action.resource}}</h1>
43
+ </div>
44
+
45
+ <ul class="nav nav-tabs" id="myTab">
46
+ <li class="active"><a href="#home">Home</a></li>
47
+ {{#if action.params}}<li><a href="#params">Params</a></li>{{/if}}
48
+ {{#if action.errors}}<li><a href="#errors">Errors</a></li>{{/if}}
49
+ {{#if action.example_req}}<li><a href="#request">Request</a></li>{{/if}}
50
+ {{#if action.example_res}}<li><a href="#response">Response</a></li>{{/if}}
51
+ </ul>
52
+
53
+ <div class="tab-content">
54
+ <div class="tab-pane active my_tab" id="home">
55
+ <p>
56
+ {{action.description}}
57
+ </p>
58
+ <table class="table table-hover action-options">
59
+ <tr>
60
+ <td>Action</td><td>{{action.action}}</td>
61
+ </tr>
62
+ <tr>
63
+ <td>Method</td><td>{{action.action_method}}</td>
64
+ </tr>
65
+ <tr>
66
+ <td class="routes">Required authentication</td>
67
+ <td>
68
+ {{#if action.authentication}}
69
+ <i class="icon-ok"></i>
70
+ {{else}}
71
+ <i class="icon-remove"></i>
72
+ {{/if}}
73
+ </td>
74
+ </tr>
75
+ <tr>
76
+ <td>Response formats</td><td>{{action.response_formats}}</td>
77
+ </tr>
78
+ </table>
79
+
80
+
81
+ <h4 class="pad_top">Resource URL</h4>
82
+ <pre>{{action.urls}}</pre>
83
+
84
+ <h4 class="pad_top">Response Status</h4>
85
+ <table class="table table-hover">
86
+ {{#each action.http_responses}}
87
+ <tr>
88
+ <td class="routes"><span class="{{this.label}}">{{this.code}}</span></td>
89
+ <td>{{this.description}}</td>
90
+ </tr>
91
+ {{/each}}
92
+ </table>
93
+ </div>
94
+
95
+ {{#if action.params}}
96
+ <div class="tab-pane my_tab" id="params">
97
+ <table class="table table-hover" id="table-params">
98
+ {{#each action.params}}
99
+ <tr>
100
+ <td>
101
+ <strong>{{this.name}}</strong></br>
102
+ {{#if this.required}}
103
+ <span class="small">required</span>
104
+ {{else}}
105
+ <span class="small">optional</span>
106
+ {{/if}}
107
+ </td>
108
+ <td>
109
+ {{#if this.inclusion}}
110
+ [ {{this.inclusion}} ]
111
+ {{else}}
112
+ {{this.type}}
113
+ {{/if}}
114
+ </td>
115
+ <td>{{this.description}}</td>
116
+ </tr>
117
+ {{/each}}
118
+ <tr><td></td><td><td></td></tr>
119
+ </table>
120
+ </div>
121
+ {{/if}}
122
+
123
+ {{#if action.errors}}
124
+ <div class="tab-pane my_tab" id="errors">
125
+ <table class="table table-hover" id="table-errors">
126
+ <tr>
127
+ <th>Object</th>
128
+ <th>Message</th>
129
+ <th>Description</th>
130
+ </tr>
131
+ {{#each action.errors}}
132
+ <tr>
133
+ <td>{{this.object}}</td>
134
+ <td>{{this.message}}</td>
135
+ <td>{{this.description}}</td>
136
+ </tr>
137
+ {{/each}}
138
+ </table>
139
+ </div>
140
+ {{/if}}
141
+
142
+ {{#if action.example_req}}
143
+ <div class="tab-pane my_tab" id="request">
144
+ <pre>{{action.example_req }}</pre>
145
+ </div>
146
+ {{/if}}
147
+
148
+ {{#if action.example_res}}
149
+ <div class="tab-pane my_tab" id="response">
150
+ <pre>{{action.example_res }}</pre>
151
+ </div>
152
+ {{/if}}
153
+ </div>
154
+
155
+ <script>
156
+ $(function () {
157
+ $('#myTab a:first').tab('show');
158
+ })
159
+
160
+ $('#myTab a').click(function (e) {
161
+ e.preventDefault();
162
+ $(this).tab('show');
163
+ })
164
+ </script>
165
+ <footer>
166
+ <p>{{info.company}} {{info.year}}</p>
167
+ </footer>
168
+ </div>
169
+ </body>
170
+ </html>