auto-rswag 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7bd7f5d1bb6327a80a89497075356aafd2cdcba798b8d7258f2d31c682666a95
4
+ data.tar.gz: b509baea5844020859126427811398fa40e79496a0d5e66ef3a881c08c841c39
5
+ SHA512:
6
+ metadata.gz: db3929e25c816dcd3710c081eed70c089112149d1befb1570de3a84b9306dd4897191b6643a1c47e4c74e9391a4d1b150195172be6d2fbf05f50e33bbc5fdc2e
7
+ data.tar.gz: 4ba7b0c799057de66e6ed2c8cc852cd67e8c15053344da60a453c0aa3dfeae861e4bacf14e07161cfd876d8f2a138145234afff7efc31cec7d741afc000992ef
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ # Specify your gem's dependencies in auto-rswag.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,63 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ auto-rswag (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.0)
10
+ coderay (1.1.2)
11
+ coveralls (0.8.23)
12
+ json (>= 1.8, < 3)
13
+ simplecov (~> 0.16.1)
14
+ term-ansicolor (~> 1.3)
15
+ thor (>= 0.19.4, < 2.0)
16
+ tins (~> 1.6)
17
+ docile (1.3.2)
18
+ jaro_winkler (1.5.4)
19
+ json (2.3.0)
20
+ method_source (1.0.0)
21
+ parallel (1.19.1)
22
+ parser (2.7.0.5)
23
+ ast (~> 2.4.0)
24
+ pry (0.13.0)
25
+ coderay (~> 1.1)
26
+ method_source (~> 1.0)
27
+ rainbow (3.0.0)
28
+ rexml (3.2.4)
29
+ rspec (0.9.4)
30
+ rubocop (0.80.1)
31
+ jaro_winkler (~> 1.5.1)
32
+ parallel (~> 1.10)
33
+ parser (>= 2.7.0.1)
34
+ rainbow (>= 2.2.2, < 4.0)
35
+ rexml
36
+ ruby-progressbar (~> 1.7)
37
+ unicode-display_width (>= 1.4.0, < 1.7)
38
+ ruby-progressbar (1.10.1)
39
+ simplecov (0.16.1)
40
+ docile (~> 1.1)
41
+ json (>= 1.8, < 3)
42
+ simplecov-html (~> 0.10.0)
43
+ simplecov-html (0.10.2)
44
+ sync (0.5.0)
45
+ term-ansicolor (1.7.1)
46
+ tins (~> 1.0)
47
+ thor (1.0.1)
48
+ tins (1.24.1)
49
+ sync
50
+ unicode-display_width (1.6.1)
51
+
52
+ PLATFORMS
53
+ ruby
54
+
55
+ DEPENDENCIES
56
+ auto-rswag!
57
+ coveralls (>= 0.8.23)
58
+ pry (~> 0)
59
+ rspec (~> 0)
60
+ rubocop (>= 0.80.1)
61
+
62
+ BUNDLED WITH
63
+ 2.0.2
data/lib/auto_rswag.rb ADDED
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require_relative 'printer.rb'
5
+ require_relative 'auto_rswag_helper.rb'
6
+ require_relative 'doc_writer.rb'
7
+
8
+ # This module hooks into the Rspec test to retrieve useful
9
+ # metadata and submit it to AutoRswagHelper for conversion.
10
+ module AutoRswag
11
+ def update_documentation
12
+ $title = metadata[:response][:schema]['$ref'].split('/').last
13
+
14
+ after do
15
+ payload = AutoRswagHelper.convert_response(response)
16
+ AutoRswagHelper.map_fields(payload)
17
+ docs = SwaggerPrinter.print_swagger(payload, $title)
18
+ DocWriter.write_docs(docs, $title)
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class performs conversions of the response data
4
+ # based on test metadata.
5
+ class AutoRswagHelper
6
+ class << self
7
+ def convert_response(response)
8
+ return response if [Array, Hash].include?(response.class)
9
+
10
+ body = response.body
11
+ body = body.respond_to?(:read) ? body.read : body
12
+
13
+ JSON.parse(body)
14
+ rescue StandardError
15
+ body
16
+ end
17
+
18
+ def map_fields(object)
19
+ if object.is_a? Array
20
+ object = {
21
+ type: :array,
22
+ items: map_fields(object.first)
23
+ }
24
+ elsif object.is_a?(Hash)
25
+ object = {
26
+ type: :object,
27
+ properties: map_object_keys(object)
28
+ }
29
+ end
30
+ object
31
+ end
32
+
33
+ def map_object_keys(object)
34
+ object.keys.each do |key|
35
+ value = object.delete(key)
36
+ converted_key = convert(key)
37
+ if value.is_a? Hash
38
+ object[converted_key] = {
39
+ type: :object,
40
+ properties: value
41
+ }
42
+ map_fields(value)
43
+ elsif value.is_a? Array
44
+ object[converted_key] = {
45
+ type: :array,
46
+ items: [value.first]
47
+ }
48
+ map_fields(value)
49
+ else
50
+ object[converted_key] = parse_field(value)
51
+ end
52
+ end
53
+ end
54
+
55
+ def convert(key)
56
+ key.to_sym
57
+ end
58
+
59
+ def parse_field(value)
60
+ type = value.nil? ? :string : value.class.to_s.downcase.to_sym
61
+ {
62
+ type: type,
63
+ example: value,
64
+ 'x-nullable' => true
65
+ }
66
+ end
67
+ end
68
+ end
data/lib/doc_writer.rb ADDED
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class writes the parsed documenation to the swagger_helper file.
4
+ class DocWriter
5
+ class << self
6
+ def default_docs_path
7
+ Rails.root.join('spec', 'swagger_helper.rb').to_s
8
+ end
9
+
10
+ def write_docs(docs, fragment_title)
11
+ old_documentation = File.read(default_docs_path)
12
+ new_documentation_fragment = example_hash(fragment_title, old_documentation)
13
+ return if new_documentation_fragment.nil?
14
+
15
+ new_documentation = old_documentation.sub(new_documentation_fragment, docs)
16
+ File.open(default_docs_path, 'w') { |f| f.write(new_documentation) }
17
+ end
18
+
19
+ def example_hash(fragment_title, old_documentation)
20
+ match = ''
21
+ iterator = 1
22
+ while true do
23
+ regex = /(#{fragment_title})(.*?\}){#{iterator}}/
24
+ new_match_data = old_documentation.match(regex)
25
+ new_match = new_match_data.present? ? new_match_data[0] : nil
26
+ return unless new_match != match
27
+
28
+ match = new_match
29
+ begin
30
+ return match if eval("{#{match}}")
31
+ rescue SyntaxError
32
+ end
33
+
34
+ iterator += 1
35
+ end
36
+ end
37
+ end
38
+ end
data/lib/printer.rb ADDED
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This class walks through the payload object and
4
+ # builds a prettified representation in rswag format.
5
+ class SwaggerPrinter
6
+ class << self
7
+ def print_swagger(object, test_title)
8
+ @indent ||= 2
9
+ line = "#{test_title}: {\n"
10
+ line += print_values(object)
11
+ line + end_wrap
12
+ end
13
+
14
+ def wrap_hash
15
+ line = ' ' * @indent + "type: :object,\n"
16
+ line += ' ' * @indent + "properties: {\n"
17
+ @indent += 2
18
+ line
19
+ end
20
+
21
+ def wrap_array
22
+ line = ' ' * @indent + "type: :array,\n"
23
+ line += ' ' * @indent + "items: {\n"
24
+ @indent += 2
25
+ line
26
+ end
27
+
28
+ def end_wrap
29
+ line = ''
30
+ while @indent > 2
31
+ @indent -= 2
32
+ line += ' ' * @indent + "}\n"
33
+ end
34
+ line + '}'
35
+ end
36
+
37
+ def print_values(object)
38
+ return wrap_array + print_values(object.first) if object.is_a?(Array)
39
+
40
+ output = wrap_hash
41
+ object.each_with_index do |(key, val), i|
42
+ line = if val[:type] == :object
43
+ print_hash(key, val)
44
+ elsif val[:type] == :array
45
+ print_array(key, val)
46
+ else
47
+ print_line(key, val)
48
+ end
49
+ comma = i == object.keys.size - 1 ? '' : ','
50
+ line += "#{comma}\n"
51
+ output += line
52
+ end
53
+ output
54
+ end
55
+
56
+ def print_hash(key, val)
57
+ line = ' ' * @indent + "#{key}: {\n"
58
+ @indent += 2
59
+ line += print_values(val[:properties])
60
+ @indent -= 2
61
+ line += ' ' * @indent + "}\n"
62
+ @indent -= 2
63
+ line += ' ' * @indent + '}'
64
+ line
65
+ end
66
+
67
+ def print_array(key, val)
68
+ line = ' ' * @indent + "#{key}: {\n"
69
+ @indent += 2
70
+ line += wrap_array
71
+ line += print_values(val[:items].first)
72
+ @indent -= 2
73
+ line += ' ' * @indent + "}\n"
74
+ @indent -= 2
75
+ line += ' ' * @indent + '}'
76
+ line
77
+ end
78
+
79
+ def print_line(key, val)
80
+ line = ' ' * @indent + "#{key}: { "
81
+ val.each_with_index do |(val_key, val_val), j|
82
+ next if val_key == :type && val.any? { |k, v| k == :example && v == nil }
83
+ val_comma = j == val.keys.size - 1 ? '' : ','
84
+ line += "#{escape_key(val_key)}: #{prettify_value(val, val_key, val_val)}#{val_comma} "
85
+ end
86
+ line + '}'
87
+ end
88
+
89
+ def escape_key(key)
90
+ return key unless key.to_s.include?('-')
91
+
92
+ "'#{key.to_s}'"
93
+ end
94
+
95
+ def prettify_value(type, key, val)
96
+ return ':' + val.to_s if key == :type
97
+ return val if key != :example
98
+ return 'nil' if val.nil?
99
+
100
+ type[:type] == :string ? "'#{val}'" : val
101
+ end
102
+ end
103
+ end
data/rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ Metrics/MethodLength:
2
+ Max: 25
3
+
4
+ Metrics/AbcSize:
5
+ Max: 25
6
+
7
+ Metrics/LineLength:
8
+ Max: 99
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: auto-rswag
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Porter
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-03-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: coveralls
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.8.23
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 0.8.23
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '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.80.1
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 0.80.1
69
+ description: Convert raw JSON payloads to Rswag configuration to automate endpoint
70
+ documentation
71
+ email: tyler.b.porter@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - Gemfile
77
+ - Gemfile.lock
78
+ - lib/auto_rswag.rb
79
+ - lib/auto_rswag_helper.rb
80
+ - lib/doc_writer.rb
81
+ - lib/printer.rb
82
+ - rubocop.yml
83
+ homepage: https://rubygems.org/gems/auto-rswag
84
+ licenses:
85
+ - MIT
86
+ metadata:
87
+ source_code_uri: https://github.com/pawptart/auto-rswag
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubygems_version: 3.0.3
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: JSON to Rswag configuration
107
+ test_files: []