td_rspec-api-blueprint-formatter 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 +7 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/api_blueprint.rb +4 -0
- data/lib/api_blueprint/configurable.rb +21 -0
- data/lib/api_blueprint/configuration.rb +5 -0
- data/lib/api_blueprint/output_collector.rb +84 -0
- data/lib/api_blueprint/output_printer.rb +118 -0
- data/lib/api_blueprint/rspec_formatter.rb +60 -0
- data/spec/rspec/api/blueprint/formatter_spec.rb +7 -0
- data/spec/spec_helper.rb +2 -0
- metadata +115 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 59a8e91cd531a25b3b19452d5dce0beef7f3f22d
|
4
|
+
data.tar.gz: 49503ca3349755f31f1caf88a65c0c1c175db506
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2933fc8ed8472b06ffd1874537fd4771a2e1f8b0225469cf51d0657772479197db49a6770dda24ebe52ee53e40af5443c7be5f08c9353455e045a50ce4e7cb66
|
7
|
+
data.tar.gz: 2715f7b0116bad33ef7d8bdc189d812917d60e77cddb683ffc7237d375d36fb4ca8ee56759b081bc9d7007d8cc3538fa8b617e1bb1d769c1579fdc9b3e8e4817
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
require 'api_blueprint_formatter'
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require 'irb'
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module APIBlueprint
|
2
|
+
module Configurable
|
3
|
+
def configure
|
4
|
+
yield(configuration)
|
5
|
+
end
|
6
|
+
|
7
|
+
def configuration
|
8
|
+
@configuration ||= default_configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def reset_configuration!
|
12
|
+
@configuration = default_configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
def default_configuration
|
16
|
+
configuration = Configuration.new
|
17
|
+
configuration.output_source = true
|
18
|
+
configuration
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module APIBlueprint
|
2
|
+
# Collects example for API documentation
|
3
|
+
class OutputCollector
|
4
|
+
attr_accessor :resources, :resource_parameters, :configuration
|
5
|
+
|
6
|
+
def initialize(configuration)
|
7
|
+
@configuration = configuration
|
8
|
+
@resources = {}
|
9
|
+
@resource_parameters = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_example(metadata, example_block, request, response)
|
13
|
+
@resources.deep_merge!(
|
14
|
+
metadata[:resource_group] => build_resource(example_block, metadata,
|
15
|
+
request, response)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def build_resource(example_block, metadata, request, response)
|
22
|
+
@resource_parameters[metadata[:resource]] = metadata[:resource_parameters]
|
23
|
+
|
24
|
+
{
|
25
|
+
metadata[:resource] => {
|
26
|
+
metadata[:action] => build_action(example_block, metadata, request,
|
27
|
+
response)
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def build_action(example_block, metadata, request, response)
|
33
|
+
example_description = metadata[:example_description] ||
|
34
|
+
metadata[:description].tr('()', '/')
|
35
|
+
|
36
|
+
{
|
37
|
+
description: metadata[:action_description],
|
38
|
+
examples: {
|
39
|
+
example_description => build_example(example_block, metadata,
|
40
|
+
request, response)
|
41
|
+
}
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_example(example_block, metadata, request, response)
|
46
|
+
{
|
47
|
+
request: build_request(request),
|
48
|
+
source: example_block.source,
|
49
|
+
location: metadata[:location],
|
50
|
+
response: build_response(response)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
def build_request(request)
|
55
|
+
{
|
56
|
+
parameters: request_parameters(request),
|
57
|
+
format: request.format
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
def request_parameters(request)
|
62
|
+
path_params = request.path_parameters.keys.map(&:to_s)
|
63
|
+
request.parameters.except(*path_params).to_json
|
64
|
+
rescue Encoding::UndefinedConversionError
|
65
|
+
'binary'
|
66
|
+
end
|
67
|
+
|
68
|
+
def build_response(response)
|
69
|
+
{
|
70
|
+
status: response.status,
|
71
|
+
content_type: response.content_type.to_s,
|
72
|
+
body: response_body(response)
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def response_body(response)
|
77
|
+
if response['Content-Transfer-Encoding'] == 'binary'
|
78
|
+
'binary'
|
79
|
+
else
|
80
|
+
response.body
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module APIBlueprint
|
2
|
+
# Prints API blueprint output
|
3
|
+
class OutputPrinter
|
4
|
+
attr_accessor :configuration, :examples, :output
|
5
|
+
|
6
|
+
def initialize(configuration, output_collector, output)
|
7
|
+
@configuration = configuration
|
8
|
+
@output_collector = output_collector
|
9
|
+
@output = output
|
10
|
+
end
|
11
|
+
|
12
|
+
def print
|
13
|
+
sorted_examples.each do |resource_group_name, resource_group_resources|
|
14
|
+
print_resource_group(resource_group_name, resource_group_resources)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def print_resource_group(resource_group_name, resource_group_resources)
|
21
|
+
output.puts "# Group #{resource_group_name}"
|
22
|
+
resource_group_resources.each(&method(:print_resource))
|
23
|
+
end
|
24
|
+
|
25
|
+
def sorted_examples
|
26
|
+
@output_collector.resources.sort_by { |k, _v| k }
|
27
|
+
end
|
28
|
+
|
29
|
+
def print_resource(resource_name, actions)
|
30
|
+
validate_resource_name(resource_name)
|
31
|
+
|
32
|
+
output.puts "# #{resource_name}"
|
33
|
+
|
34
|
+
print_resource_parameters(resource_name)
|
35
|
+
|
36
|
+
validate_http_verbs(actions, resource_name)
|
37
|
+
|
38
|
+
actions.each(&method(:print_action))
|
39
|
+
end
|
40
|
+
|
41
|
+
def validate_http_verbs(actions, resource_name)
|
42
|
+
http_verbs = actions.keys.map do |action|
|
43
|
+
action.scan(/\[([A-Z]+)\]/).flatten[0]
|
44
|
+
end
|
45
|
+
|
46
|
+
return if http_verbs.length == http_verbs.uniq.length
|
47
|
+
|
48
|
+
raise "Action HTTP verbs are not unique #{actions.keys.inspect} for "\
|
49
|
+
"resource: '#{resource_name}'"
|
50
|
+
end
|
51
|
+
|
52
|
+
def validate_resource_name(resource_name)
|
53
|
+
return if resource_name =~ %r{^[^\[\]]*\[/[^\]]+\]}
|
54
|
+
raise "resource: '#{resource_name}' is invalid. :resource needs to be "\
|
55
|
+
'specified according to https://github.com/apiaryio/api-blueprint/blob/master/API%20Blueprint%20Specification.md#resource-section'
|
56
|
+
end
|
57
|
+
|
58
|
+
def print_action(action_name, action_meta_data)
|
59
|
+
output.puts "## #{action_name}\n" \
|
60
|
+
"\n" \
|
61
|
+
"#{action_meta_data[:description]}\n" \
|
62
|
+
"\n" \
|
63
|
+
|
64
|
+
action_meta_data[:examples].each(&method(:print_example))
|
65
|
+
end
|
66
|
+
|
67
|
+
def print_example(example_description, example_metadata)
|
68
|
+
print_request(example_description, example_metadata)
|
69
|
+
print_source(example_metadata)
|
70
|
+
print_response(example_metadata)
|
71
|
+
end
|
72
|
+
|
73
|
+
def print_resource_parameters(resource_name)
|
74
|
+
return unless @output_collector.resource_parameters[resource_name]
|
75
|
+
|
76
|
+
output.puts "\n"
|
77
|
+
output.puts '+ Parameters'
|
78
|
+
|
79
|
+
@output_collector.resource_parameters[resource_name].each do |param, desc|
|
80
|
+
output.puts " + #{param} #{desc}\n"
|
81
|
+
end
|
82
|
+
|
83
|
+
output.puts "\n"
|
84
|
+
end
|
85
|
+
|
86
|
+
def print_request(example_description, example_metadata)
|
87
|
+
output.puts "+ Request #{example_description}\n" \
|
88
|
+
"\n" \
|
89
|
+
" #{example_metadata[:request][:parameters]}\n" \
|
90
|
+
" \n"
|
91
|
+
end
|
92
|
+
|
93
|
+
def print_source(example_metadata)
|
94
|
+
return if @configuration.output_source
|
95
|
+
|
96
|
+
output.puts " Location: #{example_metadata[:location]}\n" \
|
97
|
+
" Source code:\n" \
|
98
|
+
" \n" \
|
99
|
+
"#{indent_lines(8, example_metadata[:source])}\n" \
|
100
|
+
"\n"
|
101
|
+
end
|
102
|
+
|
103
|
+
def print_response(example_metadata)
|
104
|
+
output.puts "+ Response #{example_metadata[:response][:status]} "\
|
105
|
+
"(#{example_metadata[:response][:content_type]})\n" \
|
106
|
+
"\n" \
|
107
|
+
" #{example_metadata[:response][:body]}\n" \
|
108
|
+
"\n"
|
109
|
+
end
|
110
|
+
|
111
|
+
def indent_lines(number_of_spaces, string)
|
112
|
+
string
|
113
|
+
.split("\n")
|
114
|
+
.map { |a| a.prepend(' ' * number_of_spaces) }
|
115
|
+
.join("\n")
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rspec/core/formatters'
|
2
|
+
require 'rspec/core/formatters/base_formatter'
|
3
|
+
|
4
|
+
require_relative 'output_collector'
|
5
|
+
require_relative 'output_printer'
|
6
|
+
require_relative 'configurable'
|
7
|
+
require_relative 'configuration'
|
8
|
+
|
9
|
+
module APIBlueprint
|
10
|
+
# RSpec formatter for API blueprint
|
11
|
+
class RspecFormatter < RSpec::Core::Formatters::BaseFormatter
|
12
|
+
VERSION = '0.1.0'.freeze
|
13
|
+
|
14
|
+
extend Configurable
|
15
|
+
|
16
|
+
RSpec::Core::Formatters.register self, :example_passed, :example_started,
|
17
|
+
:stop
|
18
|
+
|
19
|
+
def initialize(output)
|
20
|
+
super
|
21
|
+
|
22
|
+
configure_rspec
|
23
|
+
|
24
|
+
@output_collector = OutputCollector.new(configuration)
|
25
|
+
end
|
26
|
+
|
27
|
+
def example_started(notification)
|
28
|
+
@example_group_instance = notification.example.example_group_instance
|
29
|
+
end
|
30
|
+
|
31
|
+
def example_passed(passed)
|
32
|
+
metadata = passed.example.metadata
|
33
|
+
|
34
|
+
if metadata[:apidoc] && metadata[:resource_group] &&
|
35
|
+
metadata[:resource] && metadata[:action] &&
|
36
|
+
metadata[:action_description]
|
37
|
+
|
38
|
+
@output_collector
|
39
|
+
.add_example(metadata,
|
40
|
+
passed.example.instance_variable_get(:@example_block),
|
41
|
+
@example_group_instance.request,
|
42
|
+
@example_group_instance.response)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def stop(_notification)
|
47
|
+
OutputPrinter.new(configuration, @output_collector, output).print
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def configure_rspec
|
53
|
+
RSpec.configuration.silence_filter_announcements = true
|
54
|
+
end
|
55
|
+
|
56
|
+
def configuration
|
57
|
+
self.class.configuration
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: td_rspec-api-blueprint-formatter
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nam Chu Hoai
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-12-21 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.3'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.10'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.45'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.45'
|
69
|
+
description: Use your Rspec tests to build your API documentation
|
70
|
+
email:
|
71
|
+
- nambrot@googlemail.com
|
72
|
+
executables:
|
73
|
+
- console
|
74
|
+
- setup
|
75
|
+
extensions: []
|
76
|
+
extra_rdoc_files: []
|
77
|
+
files:
|
78
|
+
- bin/console
|
79
|
+
- bin/setup
|
80
|
+
- lib/api_blueprint.rb
|
81
|
+
- lib/api_blueprint/configurable.rb
|
82
|
+
- lib/api_blueprint/configuration.rb
|
83
|
+
- lib/api_blueprint/output_collector.rb
|
84
|
+
- lib/api_blueprint/output_printer.rb
|
85
|
+
- lib/api_blueprint/rspec_formatter.rb
|
86
|
+
- spec/rspec/api/blueprint/formatter_spec.rb
|
87
|
+
- spec/spec_helper.rb
|
88
|
+
homepage: https://github.com/nambrot/rspec-api-blueprint-formatter
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
metadata:
|
92
|
+
allowed_push_host: https://rubygems.org
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.4.5
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: Use your Rspec tests to build your API documentation
|
113
|
+
test_files:
|
114
|
+
- spec/rspec/api/blueprint/formatter_spec.rb
|
115
|
+
- spec/spec_helper.rb
|