rspec-api-blueprint-formatter 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/api_blueprint.rb +10 -28
- data/lib/api_blueprint/action_formatter.rb +93 -0
- data/lib/api_blueprint/base_formatter.rb +20 -0
- data/lib/api_blueprint/example_formatter.rb +47 -0
- data/lib/api_blueprint/version.rb +3 -0
- data/spec/api_blueprint/action_formatter_spec.rb +123 -0
- data/spec/api_blueprint/example_formatter_spec.rb +87 -0
- data/spec/rspec/api/blueprint/formatter_spec.rb +2 -2
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e639084209b7c2eb7969f4bf4472bde50b48b7ca
|
4
|
+
data.tar.gz: d3498d9b1ee41bcbaf92b0345b1700bc8749db04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7e79fc9af3465c1bc7fc329d440fa8635b56445a83c0a9e3f8cc9f0c19fdefffba87f006dbfa4e4ff0972ab9cbe477ebfa660ab929cebe7dfce61e5f5d4ee0ea
|
7
|
+
data.tar.gz: 871449a2bc0e3d2f8a22e47dc260e4a4b720bb4261dc53dfeed9e1b90db9ea98f8ad0a1f4f0fcf82bf4c71001f2d500a9c15470c6789d4245a166dca0b8791ba
|
data/lib/api_blueprint.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
require 'rspec'
|
2
2
|
require 'rspec/core/formatters/base_formatter'
|
3
3
|
|
4
|
+
require 'api_blueprint/version'
|
5
|
+
require 'api_blueprint/base_formatter'
|
6
|
+
require 'api_blueprint/example_formatter'
|
7
|
+
require 'api_blueprint/action_formatter'
|
8
|
+
|
4
9
|
class ApiBlueprint < RSpec::Core::Formatters::BaseFormatter
|
5
|
-
VERSION = "0.1.3"
|
6
10
|
RSpec::Core::Formatters.register self, :example_passed, :example_started, :stop
|
7
11
|
|
8
12
|
def initialize(output)
|
@@ -34,6 +38,7 @@ class ApiBlueprint < RSpec::Core::Formatters::BaseFormatter
|
|
34
38
|
metadata[:resource] => {
|
35
39
|
metadata[:action] => {
|
36
40
|
description: metadata[:action_description],
|
41
|
+
parameters: metadata[:action_parameters],
|
37
42
|
examples: {
|
38
43
|
description => {
|
39
44
|
request: {
|
@@ -84,30 +89,14 @@ class ApiBlueprint < RSpec::Core::Formatters::BaseFormatter
|
|
84
89
|
actions.each &method(:print_action)
|
85
90
|
end
|
86
91
|
|
87
|
-
def print_action(action_name,
|
88
|
-
output.puts
|
89
|
-
"\n" \
|
90
|
-
"#{action_meta_data[:description]}\n" \
|
91
|
-
"\n" \
|
92
|
+
def print_action(action_name, action_metadata)
|
93
|
+
output.puts ApiBlueprintFormatter::ActionFormatter.new(action_name, action_metadata).format
|
92
94
|
|
93
|
-
|
95
|
+
action_metadata[:examples].each &method(:print_example)
|
94
96
|
end
|
95
97
|
|
96
98
|
def print_example(example_description, example_metadata)
|
97
|
-
output.puts
|
98
|
-
"\n" \
|
99
|
-
" #{example_metadata[:request][:parameters]}\n" \
|
100
|
-
" \n" \
|
101
|
-
" Location: #{example_metadata[:location]}\n" \
|
102
|
-
" Source code:\n" \
|
103
|
-
" \n" \
|
104
|
-
"#{indent_lines(8, example_metadata[:source])}\n" \
|
105
|
-
"\n"
|
106
|
-
|
107
|
-
output.puts "+ Response #{example_metadata[:response][:status]} (#{example_metadata[:request][:format]})\n" \
|
108
|
-
"\n" \
|
109
|
-
" #{example_metadata[:response][:body]}\n" \
|
110
|
-
"\n"
|
99
|
+
output.puts ApiBlueprintFormatter::ExampleFormatter.new(example_description, example_metadata).format
|
111
100
|
end
|
112
101
|
|
113
102
|
# To include the descriptions of all the contexts that are below the action
|
@@ -121,11 +110,4 @@ class ApiBlueprint < RSpec::Core::Formatters::BaseFormatter
|
|
121
110
|
[example_metadata[:description]] + description_array_from(parent)
|
122
111
|
end
|
123
112
|
end
|
124
|
-
|
125
|
-
def indent_lines(number_of_spaces, string)
|
126
|
-
string
|
127
|
-
.split("\n")
|
128
|
-
.map { |a| a.prepend(' ' * number_of_spaces) }
|
129
|
-
.join("\n")
|
130
|
-
end
|
131
113
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module ApiBlueprintFormatter
|
2
|
+
# Parses example metadata for Actions and outputs markdown in
|
3
|
+
# accordance with the API Blueprint spec.
|
4
|
+
#
|
5
|
+
# Spec: https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md#def-action-section
|
6
|
+
class ActionFormatter < BaseFormatter
|
7
|
+
attr_reader :action_metadata, :action_name
|
8
|
+
|
9
|
+
def initialize(action_name, action_metadata)
|
10
|
+
@action_name = action_name
|
11
|
+
@action_metadata = action_metadata
|
12
|
+
@parameters = action_metadata[:parameters] || []
|
13
|
+
end
|
14
|
+
|
15
|
+
def format
|
16
|
+
output = []
|
17
|
+
output << "## #{action_name}"
|
18
|
+
output << ''
|
19
|
+
output << action_metadata[:description].to_s
|
20
|
+
output << ''
|
21
|
+
output += format_parameters
|
22
|
+
output << ''
|
23
|
+
|
24
|
+
output.join("\n")
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def format_parameters
|
30
|
+
return [] if @parameters.empty?
|
31
|
+
|
32
|
+
output = ['']
|
33
|
+
output << '+ Parameters'
|
34
|
+
@parameters.each_pair do |param, data|
|
35
|
+
output += format_param(param, data)
|
36
|
+
end
|
37
|
+
output << ''
|
38
|
+
|
39
|
+
output
|
40
|
+
end
|
41
|
+
|
42
|
+
def format_param(param, data)
|
43
|
+
out = []
|
44
|
+
out << indent_lines(4, action_header(param, data))
|
45
|
+
|
46
|
+
if multiline_description(param)
|
47
|
+
out << ''
|
48
|
+
out << indent_lines(8, data[:description])
|
49
|
+
out << ''
|
50
|
+
end
|
51
|
+
|
52
|
+
out << indent_lines(8, "+ Default: #{data[:default]}") if data[:default]
|
53
|
+
out += format_members(param)
|
54
|
+
|
55
|
+
out
|
56
|
+
end
|
57
|
+
|
58
|
+
def multiline_description(param)
|
59
|
+
members(param).size > 0
|
60
|
+
end
|
61
|
+
|
62
|
+
def action_header(param, data)
|
63
|
+
param_signature = "#{param}#{param_attributes_string(data)}"
|
64
|
+
multiline_description = !members(param).empty?
|
65
|
+
|
66
|
+
header = "+ #{param_signature}"
|
67
|
+
header += " - #{data[:description]}" unless multiline_description
|
68
|
+
header
|
69
|
+
end
|
70
|
+
|
71
|
+
def param_attributes_string(data)
|
72
|
+
optional = data[:optional] ? 'optional' : nil
|
73
|
+
param_attributes = [data[:type], optional].compact
|
74
|
+
|
75
|
+
" (#{param_attributes.join(', ')})" unless param_attributes.empty?
|
76
|
+
end
|
77
|
+
|
78
|
+
def members(param)
|
79
|
+
@action_metadata[:parameters][param].fetch(:members, [])
|
80
|
+
end
|
81
|
+
|
82
|
+
def format_members(param)
|
83
|
+
out = []
|
84
|
+
unless members(param).empty?
|
85
|
+
out << indent_lines(8, '+ Members')
|
86
|
+
members(param).each do |member|
|
87
|
+
out << indent_lines(12, "+ `#{member}`")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
out
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ApiBlueprintFormatter
|
2
|
+
# Base for other formatters, providing utility methods
|
3
|
+
class BaseFormatter
|
4
|
+
protected
|
5
|
+
|
6
|
+
def indent_lines(number_of_spaces, string)
|
7
|
+
string
|
8
|
+
.split("\n")
|
9
|
+
.map { |a| a.prepend(' ' * number_of_spaces) }
|
10
|
+
.join("\n")
|
11
|
+
end
|
12
|
+
|
13
|
+
# Change certain characters that might come up in example names
|
14
|
+
# but do not play well with the API specs.
|
15
|
+
# Example: 'Test for [value]' -> 'Test for {value}'
|
16
|
+
def sanitize_api_identifier(name)
|
17
|
+
name.gsub(/[\[\]]/, '[' => '{', ']' => '}')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module ApiBlueprintFormatter
|
2
|
+
# Parses example metadata for Examples (Request+Response) and outputs
|
3
|
+
# markdown in accordance with the API Blueprint spec.
|
4
|
+
#
|
5
|
+
# Specs:
|
6
|
+
# - https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md#def-request-section
|
7
|
+
# - https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md#response-section
|
8
|
+
class ExampleFormatter < BaseFormatter
|
9
|
+
attr_reader :example_metadata
|
10
|
+
|
11
|
+
def initialize(example_description, example_metadata)
|
12
|
+
@example_description = example_description
|
13
|
+
@example_metadata = example_metadata
|
14
|
+
end
|
15
|
+
|
16
|
+
def format
|
17
|
+
out = ''
|
18
|
+
out << format_request
|
19
|
+
out << format_response
|
20
|
+
end
|
21
|
+
|
22
|
+
def example_description
|
23
|
+
sanitize_api_identifier(@example_description)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def format_request
|
29
|
+
"+ Request #{example_description}\n" \
|
30
|
+
"\n" \
|
31
|
+
" #{example_metadata[:request][:parameters]}\n" \
|
32
|
+
"\n" \
|
33
|
+
" Location: #{example_metadata[:location]}\n" \
|
34
|
+
" Source code:\n" \
|
35
|
+
"\n" \
|
36
|
+
"#{indent_lines(8, example_metadata[:source])}\n" \
|
37
|
+
"\n"
|
38
|
+
end
|
39
|
+
|
40
|
+
def format_response
|
41
|
+
"+ Response #{example_metadata[:response][:status]} (#{example_metadata[:request][:format]})\n" \
|
42
|
+
"\n" \
|
43
|
+
" #{example_metadata[:response][:body]}\n" \
|
44
|
+
"\n"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
RSpec.describe ApiBlueprintFormatter::ActionFormatter do
|
6
|
+
subject { described_class.new(action_name, action_metadata).format }
|
7
|
+
|
8
|
+
let(:action_name) { 'Standard Action [GET /api/v0/resource]' }
|
9
|
+
let(:action_metadata) { { description: action_description, parameters: action_parameters } }
|
10
|
+
|
11
|
+
let(:action_description) { 'Lorem ipsum et dolor' }
|
12
|
+
let(:action_parameters) { {} }
|
13
|
+
|
14
|
+
describe '#format' do
|
15
|
+
context 'with standard meta-data' do
|
16
|
+
it 'formats properly' do
|
17
|
+
is_expected.to eq "## Standard Action [GET /api/v0/resource]\n\nLorem ipsum et dolor\n\n"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with parameters' do
|
22
|
+
let(:action_header) { "## #{action_name}\n\n#{action_description}\n" }
|
23
|
+
|
24
|
+
context 'only descriptive params' do
|
25
|
+
let(:action_parameters) do
|
26
|
+
{
|
27
|
+
id: { description: 'Id of a post' }
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
it do
|
32
|
+
is_expected.to eq <<-EOF
|
33
|
+
#{action_header}
|
34
|
+
|
35
|
+
+ Parameters
|
36
|
+
+ id - Id of a post
|
37
|
+
|
38
|
+
EOF
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'descriptive param with type' do
|
43
|
+
let(:action_parameters) do
|
44
|
+
{
|
45
|
+
id: { description: 'Id of a post', type: :number }
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
it do
|
50
|
+
is_expected.to eq <<-EOF
|
51
|
+
#{action_header}
|
52
|
+
|
53
|
+
+ Parameters
|
54
|
+
+ id (number) - Id of a post
|
55
|
+
|
56
|
+
EOF
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'descriptive param with type and optionality' do
|
61
|
+
let(:action_parameters) do
|
62
|
+
{
|
63
|
+
amount: { description: 'Id of a post', type: :number, optional: true }
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
it do
|
68
|
+
is_expected.to eq <<-EOF
|
69
|
+
#{action_header}
|
70
|
+
|
71
|
+
+ Parameters
|
72
|
+
+ amount (number, optional) - Id of a post
|
73
|
+
|
74
|
+
EOF
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'descriptive param with: type, optionality, default value' do
|
79
|
+
let(:action_parameters) do
|
80
|
+
{
|
81
|
+
amount: { description: 'Id of a post', type: :number, optional: true, default: 0 }
|
82
|
+
}
|
83
|
+
end
|
84
|
+
|
85
|
+
it do
|
86
|
+
is_expected.to eq <<-EOF
|
87
|
+
#{action_header}
|
88
|
+
|
89
|
+
+ Parameters
|
90
|
+
+ amount (number, optional) - Id of a post
|
91
|
+
+ Default: 0
|
92
|
+
|
93
|
+
EOF
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'descriptive param with: enum and members' do
|
98
|
+
let(:action_parameters) do
|
99
|
+
{
|
100
|
+
id: { description: 'Id of a post', type: 'enum[string]', members: %w(A B C) }
|
101
|
+
}
|
102
|
+
end
|
103
|
+
|
104
|
+
it do
|
105
|
+
is_expected.to eq <<-EOF
|
106
|
+
#{action_header}
|
107
|
+
|
108
|
+
+ Parameters
|
109
|
+
+ id (enum[string])
|
110
|
+
|
111
|
+
Id of a post
|
112
|
+
|
113
|
+
+ Members
|
114
|
+
+ `A`
|
115
|
+
+ `B`
|
116
|
+
+ `C`
|
117
|
+
|
118
|
+
EOF
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
RSpec.describe ApiBlueprintFormatter::ExampleFormatter do
|
6
|
+
subject { described_class.new(example_description, example_metadata).format }
|
7
|
+
|
8
|
+
let(:example_description) { "Standard Request" }
|
9
|
+
let(:example_metadata) do
|
10
|
+
{
|
11
|
+
request: request_metadata,
|
12
|
+
response: response_metadata,
|
13
|
+
location: location,
|
14
|
+
source: source
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:request_metadata) { { parameters: {}, format: 'application/json' } }
|
19
|
+
let(:response_metadata) { { status: 200, body: JSON.generate({a:1, b:2, c:3}) } }
|
20
|
+
let(:location) { "spec/api_blueprint/example_formatter_spec.rb" }
|
21
|
+
let(:source) { "it 'returns standard APi Blueprint format' do\n ;\nend" }
|
22
|
+
|
23
|
+
|
24
|
+
describe '#format' do
|
25
|
+
context 'with standard meta-data' do
|
26
|
+
it 'formats properly' do
|
27
|
+
is_expected.to eq <<EOF
|
28
|
+
+ Request Standard Request
|
29
|
+
|
30
|
+
{}
|
31
|
+
|
32
|
+
Location: spec/api_blueprint/example_formatter_spec.rb
|
33
|
+
Source code:
|
34
|
+
|
35
|
+
it 'returns standard APi Blueprint format' do
|
36
|
+
;
|
37
|
+
end
|
38
|
+
|
39
|
+
+ Response 200 (application/json)
|
40
|
+
|
41
|
+
{"a":1,"b":2,"c":3}
|
42
|
+
|
43
|
+
EOF
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'and with parameters' do
|
47
|
+
context 'from request data' do
|
48
|
+
let(:request_metadata) { { parameters: {'p1': 'v1', 'p2': 'v2'}, format: 'application/json' } }
|
49
|
+
|
50
|
+
it 'formats properly' do
|
51
|
+
is_expected.to eq <<EOF
|
52
|
+
+ Request Standard Request
|
53
|
+
|
54
|
+
{:p1=>"v1", :p2=>"v2"}
|
55
|
+
|
56
|
+
Location: spec/api_blueprint/example_formatter_spec.rb
|
57
|
+
Source code:
|
58
|
+
|
59
|
+
it 'returns standard APi Blueprint format' do
|
60
|
+
;
|
61
|
+
end
|
62
|
+
|
63
|
+
+ Response 200 (application/json)
|
64
|
+
|
65
|
+
{"a":1,"b":2,"c":3}
|
66
|
+
|
67
|
+
EOF
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe '#example_description' do
|
76
|
+
subject { described_class.new(example_description, example_metadata).example_description }
|
77
|
+
|
78
|
+
context 'when description has non-compliant characters' do
|
79
|
+
let(:example_description) { 'Standard Request for [company]' }
|
80
|
+
|
81
|
+
it 'changes [] to {}' do
|
82
|
+
expect(subject).to eq 'Standard Request for {company}'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-api-blueprint-formatter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nam Chu Hoai
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-12-
|
11
|
+
date: 2016-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -64,6 +64,12 @@ files:
|
|
64
64
|
- bin/console
|
65
65
|
- bin/setup
|
66
66
|
- lib/api_blueprint.rb
|
67
|
+
- lib/api_blueprint/action_formatter.rb
|
68
|
+
- lib/api_blueprint/base_formatter.rb
|
69
|
+
- lib/api_blueprint/example_formatter.rb
|
70
|
+
- lib/api_blueprint/version.rb
|
71
|
+
- spec/api_blueprint/action_formatter_spec.rb
|
72
|
+
- spec/api_blueprint/example_formatter_spec.rb
|
67
73
|
- spec/rspec/api/blueprint/formatter_spec.rb
|
68
74
|
- spec/spec_helper.rb
|
69
75
|
homepage: https://github.com/nambrot/rspec-api-blueprint-formatter
|
@@ -92,6 +98,8 @@ signing_key:
|
|
92
98
|
specification_version: 4
|
93
99
|
summary: Use your Rspec tests to build your API documentation
|
94
100
|
test_files:
|
101
|
+
- spec/api_blueprint/action_formatter_spec.rb
|
102
|
+
- spec/api_blueprint/example_formatter_spec.rb
|
95
103
|
- spec/rspec/api/blueprint/formatter_spec.rb
|
96
104
|
- spec/spec_helper.rb
|
97
105
|
has_rdoc:
|