rspec-api-blueprint-formatter 0.1.3 → 0.2.0
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 +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:
|