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 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,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,4 @@
1
+ require_relative 'api_blueprint/rspec_formatter'
2
+
3
+ # keeping reference for backwards compatibility
4
+ ApiBlueprint = APIBlueprint::RspecFormatter
@@ -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,5 @@
1
+ module APIBlueprint
2
+ class Configuration
3
+ attr_accessor :output_source
4
+ end
5
+ 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
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApiBlueprint do
4
+ it 'has a version number' do
5
+ expect(ApiBlueprint::VERSION).not_to be nil
6
+ end
7
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'api_blueprint'
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