ramlstyle 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +44 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +162 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +13 -0
- data/README.md +49 -0
- data/Rakefile +28 -0
- data/bin/code_climate_reek +17 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/exe/ramlstyle +5 -0
- data/lib/ramlstyle/cli_command.rb +13 -0
- data/lib/ramlstyle/command/command_chain.rb +13 -0
- data/lib/ramlstyle/command/document_command.rb +17 -0
- data/lib/ramlstyle/command/end_chain.rb +8 -0
- data/lib/ramlstyle/command/file_command.rb +21 -0
- data/lib/ramlstyle/command/options.rb +33 -0
- data/lib/ramlstyle/command/parse_command.rb +9 -0
- data/lib/ramlstyle/command/review_command.rb +10 -0
- data/lib/ramlstyle/command/settings.rb +16 -0
- data/lib/ramlstyle/document.rb +15 -0
- data/lib/ramlstyle/documentation/erb_context.rb +52 -0
- data/lib/ramlstyle/documentation/renderer.rb +14 -0
- data/lib/ramlstyle/documentation/renderer_factory.rb +17 -0
- data/lib/ramlstyle/patch/node.rb +28 -0
- data/lib/ramlstyle/patch/root.rb +35 -0
- data/lib/ramlstyle/raml_parser.rb +14 -0
- data/lib/ramlstyle/review.rb +68 -0
- data/lib/ramlstyle/version.rb +3 -0
- data/lib/ramlstyle.rb +33 -0
- data/ramlstyle.gemspec +36 -0
- data/sandi_meter/.sandi_meter +2 -0
- data/templates/item.html.erb +40 -0
- data/templates/resource.html.erb +184 -0
- data/templates/template.html.erb +308 -0
- metadata +264 -0
@@ -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
|
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,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 %>
|