ramlstyle 0.2.3
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.
- 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 %>
|