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.
@@ -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 %>