ramlstyle 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,35 @@
1
+ module Raml
2
+ class Root
3
+ def path_name
4
+ ""
5
+ end
6
+
7
+ def name
8
+ "/"
9
+ end
10
+
11
+ def recursive_resources(resource)
12
+ resource.resources.values.inject(resource.resources.values) do |memo, sub_resource|
13
+ memo << recursive_resources(sub_resource)
14
+ end.flatten
15
+ end
16
+
17
+ def all_resources
18
+ recursive_resources(self)
19
+ end
20
+
21
+ def all_methods(method_filter = %w(get put post delete head options patch))
22
+ all_resources.collect do|r|
23
+ r.methods.values.select do |m|
24
+ method_filter.include?(m.name)
25
+ end
26
+ end.flatten
27
+ end
28
+
29
+ def all_responses
30
+ all_methods.collect do|m|
31
+ m.responses.values
32
+ end.flatten
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ module Ramlstyle
2
+ class RamlParser
3
+ def initialize(file_name)
4
+ @file_name = file_name
5
+ end
6
+
7
+ # this expands out the resource_types, traits, and inline schemas
8
+ def parse
9
+ @raml ||= Raml.parse_file(@file_name)
10
+ @raml.expand
11
+ @raml
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,68 @@
1
+ module Ramlstyle
2
+ class Review
3
+ def initialize(raml)
4
+ @raml = raml
5
+ end
6
+
7
+ def review
8
+ # Root
9
+
10
+ lint(:error, "API Version (version) is required", @raml, &:version)
11
+
12
+ # Resources
13
+
14
+ lint(:warning, "Resource description is missing", @raml.all_resources, &:description)
15
+
16
+ lint(:warning, "Resource name should match standards", @raml.all_resources) do |resource|
17
+ resource.name =~ %r(^\/([a-z]+(\-[a-z]+)*|{[a-z]+([A-Z][a-z]+)*})$)
18
+ end
19
+
20
+ # Methods
21
+
22
+ lint(:warning, "Method should have description", @raml.all_methods, &:description)
23
+
24
+ lint(
25
+ :warning,
26
+ "Patch, Post, and Put Methods should have JSON bodies",
27
+ @raml.all_methods(%w(put post patch))) do |method|
28
+ method.bodies.keys.include?("application/json")
29
+ end
30
+
31
+ lint(
32
+ :warning,
33
+ "Patch, Post, and Put Methods should have JSON examples",
34
+ @raml.all_methods(%w(put post patch))) do |method|
35
+ method.bodies.keys.include?("application/json") &&
36
+ method.bodies["application/json"].example
37
+ end
38
+
39
+ lint(
40
+ :warning,
41
+ "Patch, Post, and Put Methods should have JSON schema",
42
+ @raml.all_methods(%w(put post patch))) do |method|
43
+ method.bodies.keys.include?("application/json") &&
44
+ method.bodies["application/json"].schema
45
+ end
46
+
47
+ # Responses
48
+
49
+ lint(:warning, "Response should have description", @raml.all_responses, &:description)
50
+
51
+ lint(:warning, "Responses should have JSON examples", @raml.all_responses) do |response|
52
+ response.bodies.keys.include?("application/json") &&
53
+ response.bodies["application/json"].example
54
+ end
55
+
56
+ lint(:warning, "Responses should have JSON schema", @raml.all_responses) do |response|
57
+ response.bodies.keys.include?("application/json") &&
58
+ response.bodies["application/json"].schema
59
+ end
60
+ end
61
+
62
+ def lint(severity, rule_name, nodes, &test)
63
+ Array(nodes).each do |node|
64
+ puts "#{severity.to_s.upcase}: #{rule_name} at #{node.path_name}" unless test.call(node)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ module Ramlstyle
2
+ VERSION = "0.2.3"
3
+ end
data/lib/ramlstyle.rb ADDED
@@ -0,0 +1,33 @@
1
+ require "erb"
2
+ require "redcarpet"
3
+ require "raml"
4
+
5
+ require "ramlstyle/version"
6
+ require "ramlstyle/patch/node"
7
+ require "ramlstyle/patch/root"
8
+
9
+ module Ramlstyle
10
+ module Command
11
+ autoload :CommandChain, 'ramlstyle/command/command_chain'
12
+ autoload :DocumentCommand, 'ramlstyle/command/document_command'
13
+ autoload :EndChain, 'ramlstyle/command/end_chain'
14
+ autoload :FileCommand, 'ramlstyle/command/file_command'
15
+ autoload :Options, 'ramlstyle/command/options'
16
+ autoload :ParseCommand, 'ramlstyle/command/parse_command'
17
+ autoload :ReviewCommand, 'ramlstyle/command/review_command'
18
+ autoload :Settings, 'ramlstyle/command/settings'
19
+ end
20
+
21
+ module Documentation
22
+ autoload :ERBContext, 'ramlstyle/documentation/erb_context'
23
+ autoload :Renderer, 'ramlstyle/documentation/renderer'
24
+ autoload :RendererFactory, 'ramlstyle/documentation/renderer_factory'
25
+ end
26
+
27
+ autoload :CLICommand, 'ramlstyle/cli_command'
28
+ autoload :Document, 'ramlstyle/document'
29
+ autoload :RamlParser, 'ramlstyle/raml_parser'
30
+ autoload :Review, 'ramlstyle/review'
31
+
32
+ TEMPLATES_PATH = File.join(File.dirname(File.expand_path(__FILE__)), '..', 'templates')
33
+ end
data/ramlstyle.gemspec ADDED
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ramlstyle/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ramlstyle"
8
+ spec.version = Ramlstyle::VERSION
9
+ spec.authors = ["Mark Morga"]
10
+ spec.email = ["markmorga@gmail.com"]
11
+
12
+ spec.summary = "Cmd line tool to validate, lint, and document a RAML API."
13
+ spec.description =
14
+ "Validates RAML file (and JSON schema), runs a configurable set of linting rules, and produces HTML documentation."
15
+ spec.homepage = "http://github.com/rackerlabs/ramlstyle"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_runtime_dependency "redcarpet"
23
+ spec.add_runtime_dependency "raml_ruby"
24
+
25
+ spec.add_development_dependency "pry"
26
+ spec.add_development_dependency "simplecov"
27
+ spec.add_development_dependency "rubocop"
28
+ spec.add_development_dependency "rubycritic"
29
+ spec.add_development_dependency "sandi_meter"
30
+ spec.add_development_dependency "bundler"
31
+ spec.add_development_dependency "rake"
32
+ spec.add_development_dependency "minitest"
33
+ spec.add_development_dependency "guard"
34
+ spec.add_development_dependency "guard-minitest"
35
+ spec.add_development_dependency "mocha"
36
+ end
@@ -0,0 +1,2 @@
1
+ vendor
2
+ test
@@ -0,0 +1,40 @@
1
+ <li>
2
+ <% if @item.display_name %>
3
+ <strong><%= @item.display_name %></strong>:
4
+ <% else %>
5
+ <strong><%= @key %></strong>:
6
+ <% end %>
7
+
8
+ <em>
9
+ <% if @item.required %>required <% end %>
10
+ (
11
+ <% if @item.enum %>
12
+ one of <%= @item.enum.join(', ') %>
13
+ <% else %>
14
+ <%= @item.type %>
15
+ <% end %>
16
+
17
+ <% if @item.default %> - default: <%= @item.default %><% end %>
18
+ <% if @item.repeat %> - repeat: <%= @item.repeat %><% end %>
19
+ <% if @item.type == 'string' %>
20
+ <% if @item.min_length %> - min_length: <%= @item.min_length %><% end %>
21
+ <% if @item.max_length %> - max_length: <%= @item.max_length %><% end %>
22
+ <% else %>
23
+ <% if @item.minimum %> - minimum: <%= @item.minimum %><% end %>
24
+ <% if @item.maximum %> - maximum: <%= @item.maximum %><% end %>
25
+ <% end %>
26
+ <% if @item.pattern %> - pattern: <%= @item.pattern %><% end %>
27
+ )
28
+ </em>
29
+
30
+ <%= markdown(@item.description) %>
31
+
32
+ <% if @item.example %>
33
+ <p><strong>Example</strong>:</p>
34
+ <% if @item.type == 'string' %>
35
+ <pre><%= h(@item.example) %></pre>
36
+ <% else %>
37
+ <pre><code><%= h(@item.example) %></code></pre>
38
+ <% end %>
39
+ <% end %>
40
+ </li>
@@ -0,0 +1,184 @@
1
+ <% if (@resource.methods || (@resource.description && @resource.parent_url)) %>
2
+ <div class="panel panel-white">
3
+ <div class="panel-heading">
4
+ <h4 class="panel-title">
5
+ <a class="collapsed" data-toggle="collapse" href="#panel_<%= @resource.unique_id %>">
6
+ <span class="parent"><%= @resource.parent_url %></span><%= @resource.name %>
7
+ </a>
8
+
9
+ <span class="methods">
10
+ <% for method in @resource.methods.values %>
11
+ <a class="collapsed" href="#panel_<%= @resource.unique_id %>" data-toggle="collapse" aria-expanded="false" aria-controls="panel_<%= @resource.unique_id %>">
12
+ <span class="badge badge_<%= method.name %>"><%= method.name %><% if secured?(method) %> <span class="glyphicon glyphicon-lock" title="Authentication required"></span><% end %></span>
13
+ </a>
14
+ <% end %>
15
+ </span>
16
+ </h4>
17
+ </div>
18
+
19
+ <div id="panel_<%= @resource.unique_id %>" class="panel-collapse collapse">
20
+ <div class="panel-body">
21
+ <% if @resource.parent_url %>
22
+ <% if @resource.description %>
23
+ <div class="@resource-description">
24
+ <%= markdown(@resource.description) %>
25
+ </div>
26
+ <% end %>
27
+ <% end %>
28
+
29
+ <div class="list-group">
30
+ <% for method in @resource.methods.values %>
31
+ <div onclick="window.location.href = '#<%= @resource.unique_id %>_<%= method.name %>'" data-toggle="collapse" href="#<%= @resource.unique_id %>_<%= method.name %>" aria-expanded="false" aria-controls="<%= @resource.unique_id %>_<%= method.name %>" class="list-group-item">
32
+ <span class="badge badge_<%= method.name %>"><%= method.name %><% if secured?(method) %> <span class="glyphicon glyphicon-lock" title="Authentication required"></span><% end %></span>
33
+ <div class="method_description">
34
+ <%= markdown method.description%>
35
+ </div>
36
+ <div class="clearfix"></div>
37
+ </div>
38
+ <div class="collapse" tabindex="0" id="<%= @resource.unique_id %>_<%= method.name %>">
39
+ <div class="panel panel-default">
40
+ <div class="panel-body">
41
+ <% if secured?(method) %>
42
+ <div class="alert alert-warning">
43
+ <span class="glyphicon glyphicon-lock" title="Authentication required"></span> Secured by <%= security_scheme_names(method).join(", ") %>
44
+ </div>
45
+ <% end %>
46
+
47
+ <!-- Nav tabs -->
48
+ <ul class="nav nav-tabs">
49
+ <% if method.all_uri_parameters.length || method.query_parameters || method.headers || method.body %>
50
+ <li class="active">
51
+ <a href="#<%= @resource.unique_id %>_<%= method.name %>_request" data-toggle="tab">Request</a>
52
+ </li>
53
+ <% end %>
54
+
55
+ <% if method.responses %>
56
+ <li>
57
+ <a href="#<%= @resource.unique_id %>_<%= method.name %>_response" data-toggle="tab">Response</a>
58
+ </li>
59
+ <% end %>
60
+ </ul>
61
+
62
+ <!-- Tab panes -->
63
+ <div class="tab-content">
64
+ <% if method.all_uri_parameters.length || method.query_parameters || method.headers || method.body %>
65
+ <div class="tab-pane active" id="<%= @resource.unique_id %>_<%= method.name %>_request">
66
+ <% if @resource.all_uri_parameters.length %>
67
+ <h3>URI Parameters</h3>
68
+ <ul>
69
+ <% for uri_parameter in @resource.all_uri_parameters %>
70
+ <%= render_parameter(uri_parameter) %>
71
+ <% end %>
72
+ </ul>
73
+ <% end %>
74
+
75
+ <% if method.headers %>
76
+ <h3>Headers</h3>
77
+ <ul>
78
+ <% for header_name, header in method.headers %>
79
+ <%= render_parameter(header) %>
80
+ <% end %>
81
+ </ul>
82
+ <% end %>
83
+
84
+ <% if method.query_parameters %>
85
+ <h3>Query Parameters</h3>
86
+ <ul>
87
+ <% for query_parameter in method.query_parameters.values %>
88
+ <%= render_parameter(query_parameter) %>
89
+ <% end %>
90
+ </ul>
91
+ <% end %>
92
+
93
+ <% if method.bodies.count > 0 %>
94
+ <h3>Body</h3>
95
+ <% for method_type, method_body in method.bodies %>
96
+ <p><strong>Type: <%= method_type %></strong></p>
97
+ <% if method_body.form_parameters %>
98
+ <strong>Form Parameters</strong>
99
+ <ul>
100
+ <% for form_param_name, form_param in method_body.form_parameters %>
101
+ <%= render_parameter(form_param) %>
102
+ <% end %>
103
+ </ul>
104
+ <% end %>
105
+
106
+ <% if method_body.schema %>
107
+ <p><strong>Schema</strong>:
108
+ <span class="methods">
109
+ <a href="#<%= @resource.unique_id %>_<%= method.name %>_request_schema" data-toggle="collapse" aria-expanded="true" aria-controls="<%= @resource.unique_id %>_<%= method.name %>_request_schema"><span class="glyphicon glyphicon-collapse-down" title="collapse"></span></a>
110
+ </span>
111
+ </p>
112
+
113
+ <pre class="collapse" id="<%= @resource.unique_id %>_<%= method.name %>_request_schema"><code class="json-schema"><%= h(method_body.schema.value) %></code></pre>
114
+ <% end %>
115
+
116
+ <% if method_body.example %>
117
+ <p><strong>Example</strong>:
118
+ <span class="methods">
119
+ <a href="#<%= @resource.unique_id %>_<%= method.name %>_request_example" data-toggle="collapse" aria-expanded="true" aria-controls="<%= @resource.unique_id %>_<%= method.name %>_request_example"><span class="glyphicon glyphicon-collapse-down" title="collapse"></span></a>
120
+ </span>
121
+ </p>
122
+ <pre class="collapse" id="<%= @resource.unique_id %>_<%= method.name %>_request_example"><code class="json example"><%= h(method_body.example) %></code></pre>
123
+ <% end %>
124
+ <% end %>
125
+ <% end %>
126
+ </div>
127
+ <% end %>
128
+
129
+ <% if method.responses %>
130
+ <div class="tab-pane" id="<%= @resource.unique_id %>_<%= method.name %>_response">
131
+ <% for status_code, response in method.responses %>
132
+ <h2>HTTP status code <a href="http://httpstatus.es/<%= status_code %>" target="_blank"><%= status_code %></a></h2>
133
+ <%= markdown response.description%>
134
+
135
+ <% if response.headers %>
136
+ <h3>Headers</h3>
137
+ <ul>
138
+ <% for header_name, header in response.headers %>
139
+ <%= render_parameter(header) %>
140
+ <% end %>
141
+ </ul>
142
+ <% end %>
143
+
144
+ <% if response.bodies.count > 0 %>
145
+ <h3>Body</h3>
146
+ <% for response_key, response_body in response.bodies %>
147
+ <p><strong>Type: <%= response_key %></strong></p>
148
+
149
+ <% if response_body.schema %>
150
+ <p><strong>Schema</strong>:
151
+ <span class="methods">
152
+ <a href="#<%= @resource.unique_id %>_<%= method.name %>_response_schema" data-toggle="collapse" aria-expanded="true" aria-controls="<%= @resource.unique_id %>_<%= method.name %>_response_schema"><span class="glyphicon glyphicon-collapse-down" title="collapse"></span></a>
153
+ </span>
154
+ </p>
155
+ <pre class="collapse" id="<%= @resource.unique_id %>_<%= method.name %>_response_schema"><code class="json-schema"><%= h(response_body.schema.value) %></code></pre>
156
+ <% end %>
157
+
158
+ <% if response_body.example %>
159
+ <p><strong>Example</strong>:
160
+ <span class="methods">
161
+ <a href="#<%= @resource.unique_id %>_<%= method.name %>_response_example" data-toggle="collapse" aria-expanded="true" aria-controls="<%= @resource.unique_id %>_<%= method.name %>_response_example"><span class="glyphicon glyphicon-collapse-down" title="collapse"></span></a>
162
+ </span>
163
+ </p>
164
+ <pre id="<%= @resource.unique_id %>_<%= method.name %>_response_example" class="collapse"><code class="json example"><%= h(response_body.example) %></code></pre>
165
+ <% end %>
166
+ <% end %>
167
+ <% end %>
168
+ <% end %>
169
+ </div>
170
+ <% end %>
171
+ </div>
172
+ </div>
173
+ </div>
174
+ </div>
175
+ <% end %>
176
+ </div>
177
+ </div>
178
+ </div>
179
+ </div>
180
+ <% end %>
181
+
182
+ <% for sub_resource in @resource.resources.values %>
183
+ <%= render_resource sub_resource %>
184
+ <% end %>