json-schema-docs 0.1.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/.gitignore +14 -0
- data/.rubocop.yml +10 -0
- data/.travis.yml +23 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +98 -0
- data/Rakefile +47 -0
- data/json-schema-docs.gemspec +35 -0
- data/lib/json-schema-docs/configuration.rb +29 -0
- data/lib/json-schema-docs/generator.rb +65 -0
- data/lib/json-schema-docs/helpers.rb +46 -0
- data/lib/json-schema-docs/layouts/endpoint.md.erb +39 -0
- data/lib/json-schema-docs/layouts/includes/example.md.erb +11 -0
- data/lib/json-schema-docs/layouts/includes/response.md.erb +11 -0
- data/lib/json-schema-docs/layouts/object.md.erb +17 -0
- data/lib/json-schema-docs/parser.rb +363 -0
- data/lib/json-schema-docs/version.rb +4 -0
- data/lib/json-schema-docs.rb +55 -0
- data/script/bootstrap +5 -0
- data/script/console +11 -0
- metadata +203 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: cd5892af89b1910f3b373a462c2fb4854cf1626b15031f44a7f3d5b6b7280c3d
|
4
|
+
data.tar.gz: 65c3110d0ab1e4397fafca814423daae4bc5bf3c5e34bdb087c9fa346e0615f5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b9dbb7897d5d73835f56ad12cdbacf9e0aa14ba97a6e7ee04c630ba0158bac274cc03b8216102b2034ba580d49b54352b3bfe7f65a3254c30a6814e5b6eeb94d
|
7
|
+
data.tar.gz: 98ba7a96d3e77c85d4ca35bf7f56254b35ad62cd6162978a3ce2d95bf20c35e3d9a2b17894a7457c1a8d625aa702ff255068eeaedfef5b71b6d601284c97b074
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
sudo: false
|
2
|
+
language: ruby
|
3
|
+
cache: bundler
|
4
|
+
|
5
|
+
rvm:
|
6
|
+
- 2.3.6
|
7
|
+
- 2.4.3
|
8
|
+
- 2.5.0
|
9
|
+
- 2.6.0
|
10
|
+
|
11
|
+
git:
|
12
|
+
depth: 10
|
13
|
+
|
14
|
+
before_install:
|
15
|
+
- gem update --system
|
16
|
+
- gem install bundler
|
17
|
+
|
18
|
+
matrix:
|
19
|
+
include:
|
20
|
+
- script: bundle exec rake rubocop
|
21
|
+
rvm: 2.6.0
|
22
|
+
- script: bundle exec rake html_proofer
|
23
|
+
rvm: 2.6.0
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2019 Garen Torikian
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
# json-schema-docs
|
2
|
+
|
3
|
+
Inspired by [prmd](https://github.com/interagent/prmd)'s doc generation, this is a stand-alone gem to generate Markdown files from a single JSON schema file. `prmd`'s doc generator is rather opinionated, and I did not like its opinions. 😅
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'json-schema-docs'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install json-schema-docs
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
``` ruby
|
24
|
+
# pass in a filename
|
25
|
+
JsonSchemaDocs.build(filename: filename)
|
26
|
+
|
27
|
+
# or pass in a string
|
28
|
+
JsonSchemaDocs.build(schema: contents)
|
29
|
+
|
30
|
+
# or a schema class
|
31
|
+
schema = Prmd::Schema.new(data)
|
32
|
+
JsonSchemaDocs.build(schema: schema)
|
33
|
+
```
|
34
|
+
|
35
|
+
|
36
|
+
## Breakdown
|
37
|
+
|
38
|
+
There are several phases going on the single `JsonSchemaDocs.build` call:
|
39
|
+
|
40
|
+
* The JSON schema file is read (if you passed `filename`) through `Prmd::Schema` (or simply consumed if you passed it through `schema`).
|
41
|
+
* `JsonSchemaDocs::Parser` manipulates the schema into a slightly saner format.
|
42
|
+
* `JsonSchemaDocs::Generator` takes that saner format and converts it into Markdown, via ERB templates.
|
43
|
+
|
44
|
+
If you wanted to, you could break these calls up individually. For example:
|
45
|
+
|
46
|
+
``` ruby
|
47
|
+
options = {}
|
48
|
+
options[:filename] = "#{File.dirname(__FILE__)}/../data/schema.json"
|
49
|
+
|
50
|
+
options = JsonSchemaDocs::Configuration::JSON_SCHEMA_DOCS.merge(options)
|
51
|
+
|
52
|
+
response = File.read(options[:filename])
|
53
|
+
|
54
|
+
parser = JsonSchemaDocs::Parser.new(response, options)
|
55
|
+
parsed_schema = parser.parse
|
56
|
+
|
57
|
+
generator = JsonSchemaDocs::Generator.new(parsed_schema, options)
|
58
|
+
|
59
|
+
generator.generate
|
60
|
+
```
|
61
|
+
|
62
|
+
## Generating output
|
63
|
+
|
64
|
+
By default, the generation process uses ERB to layout the content into Markdown.
|
65
|
+
|
66
|
+
### Helper methods
|
67
|
+
|
68
|
+
In your ERB layouts, there are several helper methods you can use. The helper methods are:
|
69
|
+
|
70
|
+
* `slugify(str)` - This slugifies the given string.
|
71
|
+
* `include(filename, opts)` - This embeds a template from your `includes` folder, passing along the local options provided.
|
72
|
+
|
73
|
+
## Configuration
|
74
|
+
|
75
|
+
The following options are available:
|
76
|
+
|
77
|
+
| Option | Description | Default |
|
78
|
+
| :----- | :---------- | :------ |
|
79
|
+
| `filename` | The location of your schema's IDL file. | `nil` |
|
80
|
+
| `schema` | A string representing a schema IDL file. | `nil` |
|
81
|
+
| `delete_output` | Deletes `output_dir` before generating content. | `false` |
|
82
|
+
| `output_dir` | The location of the output Markdown files. | `./output/` |
|
83
|
+
| `templates` | The templates to use when generating Markdown files. You may override any of the following keys: `endpoint`, `object`, `includes`. | The defaults are found in _lib/json-schema-docs/layouts/_.
|
84
|
+
| `prmd` | The options to pass into PRMD's parser. | The defaults are found in _lib/json-schema-docs/configuration.rb/_.
|
85
|
+
|
86
|
+
## Development
|
87
|
+
|
88
|
+
After checking out the repo, run `script/bootstrap` to install dependencies. Then, run `rake test` to run the tests. You can also run `bundle exec rake console` for an interactive prompt that will allow you to experiment.
|
89
|
+
|
90
|
+
## Sample site
|
91
|
+
|
92
|
+
Clone this repository and run:
|
93
|
+
|
94
|
+
```
|
95
|
+
bundle exec rake sample
|
96
|
+
```
|
97
|
+
|
98
|
+
to see some sample output.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
require 'rubocop/rake_task'
|
6
|
+
|
7
|
+
RuboCop::RakeTask.new(:rubocop)
|
8
|
+
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'test'
|
11
|
+
t.libs << 'lib'
|
12
|
+
t.warning = false
|
13
|
+
t.test_files = FileList['test/**/*_test.rb']
|
14
|
+
end
|
15
|
+
|
16
|
+
task default: :test
|
17
|
+
|
18
|
+
desc 'Generate the documentation'
|
19
|
+
task :generate_sample do
|
20
|
+
require 'pry'
|
21
|
+
require 'json-schema-docs'
|
22
|
+
|
23
|
+
options = {}
|
24
|
+
options[:delete_output] = true
|
25
|
+
options[:filename] = File.join(File.dirname(__FILE__), 'test', 'json-schema-docs', 'fixtures', 'heroku.json')
|
26
|
+
|
27
|
+
JsonSchemaDocs.build(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
desc 'Generate the documentation and run a web server'
|
31
|
+
task sample: [:generate_sample] do
|
32
|
+
require 'webrick'
|
33
|
+
|
34
|
+
puts 'Navigate to http://localhost:3000 to see the sample docs'
|
35
|
+
|
36
|
+
mime_types = WEBrick::HTTPUtils::DefaultMimeTypes
|
37
|
+
mime_types.store 'md', 'text/plain'
|
38
|
+
|
39
|
+
options = {
|
40
|
+
Port: 3000,
|
41
|
+
MimeTypes: mime_types
|
42
|
+
}
|
43
|
+
server = WEBrick::HTTPServer.new options
|
44
|
+
server.mount '/', WEBrick::HTTPServlet::FileHandler, 'output'
|
45
|
+
trap('INT') { server.stop }
|
46
|
+
server.start
|
47
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'json-schema-docs/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'json-schema-docs'
|
9
|
+
spec.version = JsonSchemaDocs::VERSION
|
10
|
+
spec.authors = ['Garen Torikian']
|
11
|
+
spec.email = ['gjtorikian@gmail.com']
|
12
|
+
|
13
|
+
spec.summary = 'Easily generate Markdown files from your JSON schema.'
|
14
|
+
spec.homepage = 'https://github.com/gjtorikian/json-schema-docs'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = 'bin'
|
21
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ['lib']
|
23
|
+
|
24
|
+
spec.add_dependency 'prmd', '~> 0.13'
|
25
|
+
|
26
|
+
spec.add_development_dependency 'awesome_print'
|
27
|
+
spec.add_development_dependency 'html-proofer', '~> 3.4'
|
28
|
+
spec.add_development_dependency 'minitest', '~> 5.0'
|
29
|
+
spec.add_development_dependency 'minitest-focus', '~> 1.1'
|
30
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.6'
|
31
|
+
spec.add_development_dependency 'rake'
|
32
|
+
spec.add_development_dependency 'rubocop'
|
33
|
+
spec.add_development_dependency 'rubocop-performance'
|
34
|
+
spec.add_development_dependency 'rubocop-standard'
|
35
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module JsonSchemaDocs
|
3
|
+
module Configuration
|
4
|
+
JSON_SCHEMA_DOCS_DEFAULTS = {
|
5
|
+
# initialize
|
6
|
+
filename: nil,
|
7
|
+
schema: nil,
|
8
|
+
|
9
|
+
# Generating
|
10
|
+
delete_output: false,
|
11
|
+
output_dir: './output/',
|
12
|
+
|
13
|
+
templates: {
|
14
|
+
endpoint: "#{File.dirname(__FILE__)}/layouts/endpoint.md.erb",
|
15
|
+
object: "#{File.dirname(__FILE__)}/layouts/object.md.erb",
|
16
|
+
|
17
|
+
includes: "#{File.dirname(__FILE__)}/layouts/includes",
|
18
|
+
},
|
19
|
+
|
20
|
+
prmd: {
|
21
|
+
http_header: {},
|
22
|
+
content_type: 'application/json',
|
23
|
+
doc: {
|
24
|
+
url_style: 'default'
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}.freeze
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'erb'
|
3
|
+
|
4
|
+
module JsonSchemaDocs
|
5
|
+
class Generator
|
6
|
+
include Helpers
|
7
|
+
|
8
|
+
attr_accessor :parsed_schema
|
9
|
+
|
10
|
+
def initialize(parsed_schema, options)
|
11
|
+
@parsed_schema = parsed_schema
|
12
|
+
@options = options
|
13
|
+
|
14
|
+
%i(endpoint object).each do |sym|
|
15
|
+
if !File.exist?(@options[:templates][sym])
|
16
|
+
raise IOError, "`#{sym}` template #{@options[:templates][sym]} was not found"
|
17
|
+
end
|
18
|
+
instance_variable_set("@json_schema_#{sym}_template", ERB.new(File.read(@options[:templates][sym]), nil, '-'))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def generate
|
23
|
+
FileUtils.rm_rf(@options[:output_dir]) if @options[:delete_output]
|
24
|
+
|
25
|
+
@parsed_schema.each_pair do |resource, schemata|
|
26
|
+
%i(endpoint object).each do |type|
|
27
|
+
contents = render(type, schemata)
|
28
|
+
write_file(type, resource, contents)
|
29
|
+
|
30
|
+
contents = render(type, schemata)
|
31
|
+
write_file(type, resource, contents)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def render(type, schemata)
|
39
|
+
layout = instance_variable_get("@json_schema_#{type}_template")
|
40
|
+
opts = @options.merge(helper_methods)
|
41
|
+
|
42
|
+
opts[:schemata] = schemata
|
43
|
+
layout.result(OpenStruct.new(opts).instance_eval { binding })
|
44
|
+
end
|
45
|
+
|
46
|
+
def write_file(type, name, contents, trim: true)
|
47
|
+
if type == :object
|
48
|
+
path = File.join(@options[:output_dir], 'objects', name.downcase)
|
49
|
+
FileUtils.mkdir_p(path)
|
50
|
+
elsif type == :endpoint
|
51
|
+
path = File.join(@options[:output_dir], 'objects', name.downcase, 'endpoints')
|
52
|
+
FileUtils.mkdir_p(path)
|
53
|
+
end
|
54
|
+
|
55
|
+
if trim
|
56
|
+
# normalize spacing so that CommonMarker doesn't treat it as `pre`
|
57
|
+
contents = contents.gsub(/^\s+$/, '')
|
58
|
+
contents = contents.gsub(/^\s{4}/m, ' ')
|
59
|
+
end
|
60
|
+
|
61
|
+
filename = File.join(path, 'index.md')
|
62
|
+
File.write(filename, contents) unless contents.nil?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JsonSchemaDocs
|
4
|
+
module Helpers
|
5
|
+
SLUGIFY_PRETTY_REGEXP = Regexp.new("[^[:alnum:]._~!$&'()+,;=@]+").freeze
|
6
|
+
|
7
|
+
attr_accessor :templates
|
8
|
+
|
9
|
+
def slugify(str)
|
10
|
+
slug = str.gsub(SLUGIFY_PRETTY_REGEXP, '-')
|
11
|
+
slug.gsub!(%r!^\-|\-$!i, '')
|
12
|
+
slug.downcase
|
13
|
+
end
|
14
|
+
|
15
|
+
def include(filename, opts = {})
|
16
|
+
template = fetch_include(filename)
|
17
|
+
opts = @options.merge(opts)
|
18
|
+
template.result(OpenStruct.new(opts.merge(helper_methods)).instance_eval { binding })
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def fetch_include(filename)
|
24
|
+
@templates ||= {}
|
25
|
+
|
26
|
+
return @templates[filename] unless @templates[filename].nil?
|
27
|
+
|
28
|
+
contents = File.read(File.join(@options[:templates][:includes], filename))
|
29
|
+
|
30
|
+
@templates[filename] = ERB.new(contents, nil, '-')
|
31
|
+
end
|
32
|
+
|
33
|
+
def helper_methods
|
34
|
+
return @helper_methods if defined?(@helper_methods)
|
35
|
+
|
36
|
+
@helper_methods = {}
|
37
|
+
|
38
|
+
Helpers.instance_methods.each do |name|
|
39
|
+
next if name == :helper_methods
|
40
|
+
@helper_methods[name] = method(name)
|
41
|
+
end
|
42
|
+
|
43
|
+
@helper_methods
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# <a class="header-link" name="resource-<%= schemata['title'] %>"><%= schemata['title'] %></a>
|
2
|
+
|
3
|
+
<% (schemata['links'] || []).each do |link, datum| %>
|
4
|
+
|
5
|
+
## <a class="header-link" name="link-<%= link['method'] %>-<%= resource %>-<%= link['href'] %>"><%= schemata['title'] %> <%= link['title'] %></a>
|
6
|
+
|
7
|
+
<%= link['description'] %>
|
8
|
+
|
9
|
+
```
|
10
|
+
<%= link['method'] %> <%= link['link_path'] %>
|
11
|
+
```
|
12
|
+
|
13
|
+
<% if link['required_properties'] && !link['required_properties'].empty? %>
|
14
|
+
## Required Parameters
|
15
|
+
|
16
|
+
| Name | Type | Description | Example |
|
17
|
+
| ------- | ------- | ------- | ------- |
|
18
|
+
<%- link['required_properties'].each do |property_ref| -%>
|
19
|
+
| **<%= property_ref[:name] %>** | *<%= property_ref[:type] %>* | <%= property_ref[:description] %> | <%= property_ref[:example] %> |
|
20
|
+
<%- end -%>
|
21
|
+
|
22
|
+
<% end %>
|
23
|
+
|
24
|
+
<% if link['optional_properties'] && !link['optional_properties'].empty? %>
|
25
|
+
## Optional Parameters
|
26
|
+
|
27
|
+
| Name | Type | Description | Example |
|
28
|
+
| ------- | ------- | ------- | ------- |
|
29
|
+
<%- link['optional_properties'].each do |property_ref| -%>
|
30
|
+
| **<%= property_ref[:name] %>** | *<%= property_ref[:type] %>* | <%= property_ref[:description] %> | <%= property_ref[:example] %> |
|
31
|
+
<%- end -%>
|
32
|
+
|
33
|
+
<% end %>
|
34
|
+
|
35
|
+
<%= include.('example.md.erb', example: link['example']) %>
|
36
|
+
|
37
|
+
<%= include.('response.md.erb', response: link['response']) %>
|
38
|
+
|
39
|
+
<% end %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
## Curl Example
|
2
|
+
|
3
|
+
```bash
|
4
|
+
$ curl -n <%= example[:request] -%><%- unless example[:http_headers].empty? %> \<%- end -%>
|
5
|
+
<%- if !example[:data].nil? %>
|
6
|
+
<%= example[:data] -%>
|
7
|
+
<%- end -%>
|
8
|
+
<%- example[:http_headers].each do |key, value| %>
|
9
|
+
-H "<%= key %>: <%= value %>"<%- if key != example[:http_headers].keys.last %> \<%- end -%>
|
10
|
+
<%- end %>
|
11
|
+
```
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# <a class="header-link" name="resource-<%= schemata['title'].downcase %>"><%= schemata['title'] %></a>
|
2
|
+
|
3
|
+
<% if schemata['stability'] && !schemata['stability'].empty? %>
|
4
|
+
Stability: `<%= schemata['stability'] %>`
|
5
|
+
<% end %>
|
6
|
+
|
7
|
+
<%= schemata['description'] %>
|
8
|
+
|
9
|
+
<% if schemata['property_refs'] && !schemata['property_refs'].empty? %>
|
10
|
+
## Attributes
|
11
|
+
|
12
|
+
| Name | Type | Description | Example |
|
13
|
+
| ------- | ------- | ------- | ------- |
|
14
|
+
<%- schemata['property_refs'].each do |property_ref| -%>
|
15
|
+
| **<%= property_ref[:name] %>** | *<%= property_ref[:type] %>* | <%= property_ref[:description] %> | <%= property_ref[:example] %> |
|
16
|
+
<%- end -%>
|
17
|
+
<% end %>
|
@@ -0,0 +1,363 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'prmd'
|
3
|
+
|
4
|
+
module JsonSchemaDocs
|
5
|
+
class Parser
|
6
|
+
include Helpers
|
7
|
+
|
8
|
+
attr_reader :processed_schema
|
9
|
+
|
10
|
+
def initialize(schema, options)
|
11
|
+
@options = options
|
12
|
+
|
13
|
+
if schema.is_a?(Prmd::Schema)
|
14
|
+
@schema = schema
|
15
|
+
else
|
16
|
+
# FIXME: Multiloader has issues: https://github.com/interagent/prmd/issues/279
|
17
|
+
# for now just always assume a JSON file
|
18
|
+
data = Prmd::MultiLoader::Json.load_data(schema)
|
19
|
+
|
20
|
+
@schema = Prmd::Schema.new(data)
|
21
|
+
end
|
22
|
+
|
23
|
+
@processed_schema = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse
|
27
|
+
@schema['properties'].each_key do |key|
|
28
|
+
resource, property = key, @schema['properties'][key]
|
29
|
+
begin
|
30
|
+
_, schemata = @schema.dereference(property)
|
31
|
+
|
32
|
+
# establish condensed object description
|
33
|
+
if schemata['properties'] && !schemata['properties'].empty?
|
34
|
+
schemata['property_refs'] = []
|
35
|
+
refs = extract_schemata_refs(@schema, schemata['properties']).map { |v| v && v.split('/') }
|
36
|
+
extract_attributes(@schema, schemata['properties']).each_with_index do |(key, type, description, example), i|
|
37
|
+
property_ref = { type: type, description: description, example: example}
|
38
|
+
if refs[i] && refs[i][1] == 'definitions' && refs[i][2] != resource
|
39
|
+
property_ref[:name] = '[%s](#%s)' % [key, 'resource-' + refs[i][2]]
|
40
|
+
else
|
41
|
+
property_ref[:name] = key
|
42
|
+
end
|
43
|
+
schemata['property_refs'].push(property_ref)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# establish full link description
|
48
|
+
(schemata['links'] || []).each do |link, datum|
|
49
|
+
link_path = build_link_path(@schema, link)
|
50
|
+
response_example = link['response_example']
|
51
|
+
|
52
|
+
if link.has_key?('schema') && link['schema'].has_key?('properties')
|
53
|
+
required, optional = Prmd::Link.new(link).required_and_optional_parameters
|
54
|
+
|
55
|
+
unless required.empty?
|
56
|
+
link_schema_required_properties = extract_attributes(@schema, required).map do |(name, type, description, example)|
|
57
|
+
{ name: name, type: type, description: description, example: example}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
unless optional.empty?
|
62
|
+
link_schema_optional_properties = extract_attributes(@schema, optional).map do |(name, type, description, example)|
|
63
|
+
{ name: name, type: type, description: description, example: example}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
link['link_path'] = link_path
|
69
|
+
link['required_properties'] = link_schema_required_properties
|
70
|
+
link['optional_properties'] = link_schema_optional_properties
|
71
|
+
link['example'] = generate_example(link, link_path)
|
72
|
+
link['response'] = {
|
73
|
+
header: generate_response_header(response_example, link),
|
74
|
+
example: generate_response_example(response_example, link, resource)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
@processed_schema[resource] = schemata
|
79
|
+
rescue => e
|
80
|
+
$stdout.puts("Error in resource: #{resource}")
|
81
|
+
raise e
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
@processed_schema
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def extract_attributes(schema, properties)
|
91
|
+
attributes = []
|
92
|
+
|
93
|
+
_, properties = schema.dereference(properties)
|
94
|
+
|
95
|
+
properties.each do |key, value|
|
96
|
+
# found a reference to another element:
|
97
|
+
_, value = schema.dereference(value)
|
98
|
+
|
99
|
+
# include top level reference to nested things, when top level is nullable
|
100
|
+
if value.has_key?('type') && value['type'].include?('null') && (value.has_key?('items') || value.has_key?('properties'))
|
101
|
+
attributes << build_attribute(schema, key, value)
|
102
|
+
end
|
103
|
+
|
104
|
+
if value.has_key?('anyOf')
|
105
|
+
descriptions = []
|
106
|
+
examples = []
|
107
|
+
|
108
|
+
anyof = value['anyOf']
|
109
|
+
|
110
|
+
anyof.each do |ref|
|
111
|
+
_, nested_field = schema.dereference(ref)
|
112
|
+
descriptions << nested_field['description'] if nested_field['description']
|
113
|
+
examples << nested_field['example'] if nested_field['example']
|
114
|
+
end
|
115
|
+
|
116
|
+
# avoid repetition :}
|
117
|
+
description = if descriptions.size > 1
|
118
|
+
descriptions.first.gsub!(/ of (this )?.*/, '')
|
119
|
+
descriptions[1..-1].map { |d| d.gsub!(/unique /, '') }
|
120
|
+
[descriptions[0...-1].join(', '), descriptions.last].join(' or ')
|
121
|
+
else
|
122
|
+
description = descriptions.last
|
123
|
+
end
|
124
|
+
|
125
|
+
example = [*examples].map { |e| "`#{e.to_json}`" }.join(' or ')
|
126
|
+
attributes << [key, 'string', description, example]
|
127
|
+
|
128
|
+
# found a nested object
|
129
|
+
elsif value['properties']
|
130
|
+
nested = extract_attributes(schema, value['properties'])
|
131
|
+
nested.each do |attribute|
|
132
|
+
attribute[0] = "#{key}:#{attribute[0]}"
|
133
|
+
end
|
134
|
+
attributes.concat(nested)
|
135
|
+
|
136
|
+
elsif array_with_nested_objects?(value['items'])
|
137
|
+
if value['items']['properties']
|
138
|
+
nested = extract_attributes(schema, value['items']['properties'])
|
139
|
+
nested.each do |attribute|
|
140
|
+
attribute[0] = "#{key}/#{attribute[0]}"
|
141
|
+
end
|
142
|
+
attributes.concat(nested)
|
143
|
+
end
|
144
|
+
if value['items']['oneOf']
|
145
|
+
value['items']['oneOf'].each_with_index do |oneof, index|
|
146
|
+
ref, oneof_definition = schema.dereference(oneof)
|
147
|
+
oneof_name = ref ? ref.split('/').last : index
|
148
|
+
nested = extract_attributes(schema, oneof_definition['properties'])
|
149
|
+
nested.each do |attribute|
|
150
|
+
attribute[0] = "#{key}/[#{oneof_name.upcase}].#{attribute[0]}"
|
151
|
+
end
|
152
|
+
attributes.concat(nested)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# just a regular attribute
|
157
|
+
else
|
158
|
+
attributes << build_attribute(schema, key, value)
|
159
|
+
end
|
160
|
+
end
|
161
|
+
attributes.map! { |key, type, description, example|
|
162
|
+
if example.nil? && Prmd::DefaultExamples.key?(type)
|
163
|
+
example = '`%s`' % Prmd::DefaultExamples[type].to_json
|
164
|
+
end
|
165
|
+
[key, type, description, example]
|
166
|
+
}
|
167
|
+
return attributes.sort
|
168
|
+
end
|
169
|
+
|
170
|
+
def extract_schemata_refs(schema, properties)
|
171
|
+
ret = []
|
172
|
+
properties.keys.sort.each do |key|
|
173
|
+
value = properties[key]
|
174
|
+
ref, value = schema.dereference(value)
|
175
|
+
if value['properties']
|
176
|
+
refs = extract_schemata_refs(schema, value['properties'])
|
177
|
+
elsif value['items'] && value['items']['properties']
|
178
|
+
refs = extract_schemata_refs(schema, value['items']['properties'])
|
179
|
+
else
|
180
|
+
refs = [ref]
|
181
|
+
end
|
182
|
+
if value.has_key?('type') && value['type'].include?('null') && (value.has_key?('items') || value.has_key?('properties'))
|
183
|
+
# A nullable object usually isn't a reference to another schema. It's
|
184
|
+
# either not a reference at all, or it's a reference within the same
|
185
|
+
# schema. Instead, the definition of the nullable object might contain
|
186
|
+
# references to specific properties.
|
187
|
+
#
|
188
|
+
# If all properties refer to the same schema, we'll use that as the
|
189
|
+
# reference. This might even overwrite an actual, intra-schema
|
190
|
+
# reference.
|
191
|
+
|
192
|
+
l = refs.map { |v| v && v.split('/')[0..2] }
|
193
|
+
if l.uniq.size == 1 && l[0] != nil
|
194
|
+
ref = l[0].join('/')
|
195
|
+
end
|
196
|
+
ret << ref
|
197
|
+
end
|
198
|
+
ret.concat(refs)
|
199
|
+
end
|
200
|
+
ret
|
201
|
+
end
|
202
|
+
|
203
|
+
def build_attribute(schema, key, value)
|
204
|
+
description = value['description'] || ''
|
205
|
+
if value['default']
|
206
|
+
description += "<br/> **default:** `#{value['default'].to_json}`"
|
207
|
+
end
|
208
|
+
|
209
|
+
if value['minimum'] || value['maximum']
|
210
|
+
description += '<br/> **Range:** `'
|
211
|
+
if value['minimum']
|
212
|
+
comparator = value['exclusiveMinimum'] ? '<' : '<='
|
213
|
+
description += "#{value['minimum'].to_json} #{comparator} "
|
214
|
+
end
|
215
|
+
description += 'value'
|
216
|
+
if value['maximum']
|
217
|
+
comparator = value['exclusiveMaximum'] ? '<' : '<='
|
218
|
+
description += " #{comparator} #{value['maximum'].to_json}"
|
219
|
+
end
|
220
|
+
description += '`'
|
221
|
+
end
|
222
|
+
|
223
|
+
if value['enum']
|
224
|
+
description += '<br/> **one of:**' + [*value['enum']].map { |e| "`#{e.to_json}`" }.join(' or ')
|
225
|
+
end
|
226
|
+
|
227
|
+
if value['pattern']
|
228
|
+
description += "<br/> **pattern:** `#{value['pattern']}`"
|
229
|
+
end
|
230
|
+
|
231
|
+
if value['minLength'] || value['maxLength']
|
232
|
+
description += '<br/> **Length:** `'
|
233
|
+
if value['minLength']
|
234
|
+
description += "#{value['minLength'].to_json}"
|
235
|
+
end
|
236
|
+
unless value['minLength'] == value['maxLength']
|
237
|
+
if value['maxLength']
|
238
|
+
unless value['minLength']
|
239
|
+
description += '0'
|
240
|
+
end
|
241
|
+
description += "..#{value['maxLength'].to_json}"
|
242
|
+
else
|
243
|
+
description += '..∞'
|
244
|
+
end
|
245
|
+
end
|
246
|
+
description += '`'
|
247
|
+
end
|
248
|
+
|
249
|
+
if value.has_key?('example')
|
250
|
+
example = if value['example'].is_a?(Hash) && value['example'].has_key?('oneOf')
|
251
|
+
value['example']['oneOf'].map { |e| "`#{e.to_json}`" }.join(' or ')
|
252
|
+
else
|
253
|
+
"`#{value['example'].to_json}`"
|
254
|
+
end
|
255
|
+
elsif (value['type'] == ['array'] && value.has_key?('items')) || value.has_key?('enum')
|
256
|
+
example = "`#{schema.schema_value_example(value).to_json}`"
|
257
|
+
elsif value['type'].include?('null')
|
258
|
+
example = '`null`'
|
259
|
+
end
|
260
|
+
|
261
|
+
type = if value['type'].include?('null')
|
262
|
+
'nullable '
|
263
|
+
else
|
264
|
+
''
|
265
|
+
end
|
266
|
+
type += (value['format'] || (value['type'] - ['null']).first)
|
267
|
+
[key, type, description, example]
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
def build_link_path(schema, link)
|
272
|
+
link['href'].gsub(%r|(\{\([^\)]+\)\})|) do |ref|
|
273
|
+
ref = ref.gsub('%2F', '/').gsub('%23', '#').gsub(%r|[\{\(\)\}]|, '')
|
274
|
+
ref_resource = ref.split('#/definitions/').last.split('/').first.gsub('-', '_')
|
275
|
+
identity_key, identity_value = schema.dereference(ref)
|
276
|
+
if identity_value.has_key?('anyOf')
|
277
|
+
'{' + ref_resource + '_' + identity_value['anyOf'].map { |r| r['$ref'].split('/').last }.join('_or_') + '}'
|
278
|
+
else
|
279
|
+
'{' + ref_resource + '_' + identity_key.split('/').last + '}'
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def array_with_nested_objects?(items)
|
285
|
+
return unless items
|
286
|
+
items['properties'] || items['oneOf']
|
287
|
+
end
|
288
|
+
|
289
|
+
def generate_example(link, link_path)
|
290
|
+
request = {}
|
291
|
+
data = {}
|
292
|
+
headers = {}
|
293
|
+
|
294
|
+
path = link_path.gsub(/{([^}]*)}/) { |match| '$' + match.gsub(/[{}]/, '').upcase }
|
295
|
+
get_params = []
|
296
|
+
|
297
|
+
if link.has_key?('schema')
|
298
|
+
data = @schema.schema_example(link['schema'])
|
299
|
+
if link['method'].upcase == 'GET' && !data.nil?
|
300
|
+
get_params << Prmd::UrlGenerator.new({schema: @schema, link: link, options: @options[:prmd]}).url_params
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
data = nil if data.empty? # same thing
|
305
|
+
|
306
|
+
# fetch any headers
|
307
|
+
if link['method'].upcase != 'GET'
|
308
|
+
opts = @options[:prmd].dup
|
309
|
+
headers = { 'Content-Type' => opts[:content_type] }.merge(opts[:http_header])
|
310
|
+
end
|
311
|
+
|
312
|
+
# define initial request call
|
313
|
+
if link['method'].upcase != 'GET'
|
314
|
+
request = "-X #{link['method']} #{@schema.href}#{path}"
|
315
|
+
else
|
316
|
+
request = "#{@schema.href}#{path}"
|
317
|
+
end
|
318
|
+
|
319
|
+
# add data, if present
|
320
|
+
if !data.nil? && link['method'].upcase != 'GET'
|
321
|
+
data = "-d '#{JSON.pretty_generate(data)}' \\"
|
322
|
+
elsif !get_params.empty? && link['method'].upcase == 'GET'
|
323
|
+
data = "-G #{get_params.join(" ss\\\n -d ")} \\"
|
324
|
+
end
|
325
|
+
|
326
|
+
{ request: request, data: data, http_headers: headers }
|
327
|
+
end
|
328
|
+
|
329
|
+
def generate_response_header(response_example, link)
|
330
|
+
return response_example['head'] if response_example
|
331
|
+
|
332
|
+
header = 'HTTP/1.1'
|
333
|
+
code = case link['rel']
|
334
|
+
when 'create'
|
335
|
+
'201 Created'
|
336
|
+
when 'empty'
|
337
|
+
'202 Accepted'
|
338
|
+
else
|
339
|
+
'200 OK'
|
340
|
+
end
|
341
|
+
"#{header} #{code}"
|
342
|
+
end
|
343
|
+
|
344
|
+
def generate_response_example(response_example, link, resource)
|
345
|
+
if response_example || link['rel'] != 'empty'
|
346
|
+
if response_example
|
347
|
+
response_example['body']
|
348
|
+
else
|
349
|
+
if link['rel'] == 'empty'
|
350
|
+
elsif link.has_key?('targetSchema')
|
351
|
+
JSON.pretty_generate(@schema.schema_example(link['targetSchema']))
|
352
|
+
elsif link['rel'] == 'instances'
|
353
|
+
JSON.pretty_generate([@schema.schemata_example(resource)])
|
354
|
+
else
|
355
|
+
JSON.pretty_generate(@schema.schemata_example(resource))
|
356
|
+
end
|
357
|
+
end
|
358
|
+
else
|
359
|
+
nil
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'json-schema-docs/helpers'
|
3
|
+
require 'json-schema-docs/configuration'
|
4
|
+
require 'json-schema-docs/generator'
|
5
|
+
require 'json-schema-docs/parser'
|
6
|
+
require 'json-schema-docs/version'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'awesome_print'
|
10
|
+
require 'pry'
|
11
|
+
rescue LoadError; end
|
12
|
+
|
13
|
+
module JsonSchemaDocs
|
14
|
+
class << self
|
15
|
+
def build(options)
|
16
|
+
options = JsonSchemaDocs::Configuration::JSON_SCHEMA_DOCS_DEFAULTS.merge(options)
|
17
|
+
|
18
|
+
filename = options[:filename]
|
19
|
+
schema = options[:schema]
|
20
|
+
|
21
|
+
if !filename.nil? && !schema.nil?
|
22
|
+
raise ArgumentError, 'Pass in `filename` or `schema`, but not both!'
|
23
|
+
end
|
24
|
+
|
25
|
+
if filename.nil? && schema.nil?
|
26
|
+
raise ArgumentError, 'Pass in either `filename` or `schema`'
|
27
|
+
end
|
28
|
+
|
29
|
+
if filename
|
30
|
+
unless filename.is_a?(String)
|
31
|
+
raise TypeError, "Expected `String`, got `#{filename.class}`"
|
32
|
+
end
|
33
|
+
|
34
|
+
unless File.exist?(filename)
|
35
|
+
raise ArgumentError, "#{filename} does not exist!"
|
36
|
+
end
|
37
|
+
|
38
|
+
schema = File.read(filename)
|
39
|
+
else
|
40
|
+
if !schema.is_a?(String) && !schema.is_a?(Prmd::Schema)
|
41
|
+
raise TypeError, "Expected `String` or `Prmd::Schema`, got `#{schema.class}`"
|
42
|
+
end
|
43
|
+
|
44
|
+
schema = schema
|
45
|
+
end
|
46
|
+
|
47
|
+
parser = JsonSchemaDocs::Parser.new(schema, options)
|
48
|
+
parsed_schema = parser.parse
|
49
|
+
|
50
|
+
generator = JsonSchemaDocs::Generator.new(parsed_schema, options)
|
51
|
+
|
52
|
+
generator.generate
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/script/bootstrap
ADDED
data/script/console
ADDED
metadata
ADDED
@@ -0,0 +1,203 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json-schema-docs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Garen Torikian
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-09-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: prmd
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.13'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: awesome_print
|
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: html-proofer
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.4'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.4'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '5.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '5.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: minitest-focus
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry-byebug
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.6'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.6'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-performance
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-standard
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description:
|
154
|
+
email:
|
155
|
+
- gjtorikian@gmail.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- ".gitignore"
|
161
|
+
- ".rubocop.yml"
|
162
|
+
- ".travis.yml"
|
163
|
+
- Gemfile
|
164
|
+
- LICENSE.txt
|
165
|
+
- README.md
|
166
|
+
- Rakefile
|
167
|
+
- json-schema-docs.gemspec
|
168
|
+
- lib/json-schema-docs.rb
|
169
|
+
- lib/json-schema-docs/configuration.rb
|
170
|
+
- lib/json-schema-docs/generator.rb
|
171
|
+
- lib/json-schema-docs/helpers.rb
|
172
|
+
- lib/json-schema-docs/layouts/endpoint.md.erb
|
173
|
+
- lib/json-schema-docs/layouts/includes/example.md.erb
|
174
|
+
- lib/json-schema-docs/layouts/includes/response.md.erb
|
175
|
+
- lib/json-schema-docs/layouts/object.md.erb
|
176
|
+
- lib/json-schema-docs/parser.rb
|
177
|
+
- lib/json-schema-docs/version.rb
|
178
|
+
- script/bootstrap
|
179
|
+
- script/console
|
180
|
+
homepage: https://github.com/gjtorikian/json-schema-docs
|
181
|
+
licenses:
|
182
|
+
- MIT
|
183
|
+
metadata: {}
|
184
|
+
post_install_message:
|
185
|
+
rdoc_options: []
|
186
|
+
require_paths:
|
187
|
+
- lib
|
188
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
189
|
+
requirements:
|
190
|
+
- - ">="
|
191
|
+
- !ruby/object:Gem::Version
|
192
|
+
version: '0'
|
193
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - ">="
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: '0'
|
198
|
+
requirements: []
|
199
|
+
rubygems_version: 3.0.6
|
200
|
+
signing_key:
|
201
|
+
specification_version: 4
|
202
|
+
summary: Easily generate Markdown files from your JSON schema.
|
203
|
+
test_files: []
|