prmd 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.travis.yml +2 -0
- data/Gemfile.lock +0 -2
- data/README.md +46 -26
- data/bin/prmd +16 -24
- data/docs/schemata.md +0 -2
- data/lib/prmd/commands/combine.rb +56 -2
- data/lib/prmd/commands/doc.rb +13 -9
- data/lib/prmd/commands/expand.rb +1 -6
- data/lib/prmd/commands/init.rb +47 -37
- data/lib/prmd/commands/verify.rb +24 -2
- data/lib/prmd/schema.rb +12 -53
- data/lib/prmd/version.rb +1 -1
- data/lib/prmd/views/endpoint.erb +48 -28
- data/lib/prmd.rb +1 -1
- data/prmd.gemspec +7 -8
- data/test/helpers.rb +2 -2
- data/test/schema_test.rb +26 -5
- data/test/schemas/input/meta.json +14 -0
- data/test/schemas/input/user.json +8 -11
- metadata +19 -31
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OTJiYjFkZjYwZTAxYWExOTJmYzAxMWZjYmJiNmQ1YzA3ZTdiMmY0Ng==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
Y2RmMDI2NTIyNzQxZTk4NjcxZmZhYzU5NTM2NDdlNmM4YWZhMTE4Mg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTE2N2FhODUzYjgxY2Y0YjJmOGUwYzRkYTQwYmY0Nzg2NDJhNDdjM2JhZGYy
|
10
|
+
ZjFjY2MxMGY5ZmNkYjM0OTVlMmUyNTYzMGJlYTdmYjk1MTczOTZiODI3ZjVh
|
11
|
+
MWZlYTQ2OTg2MWRlNjg3Yjc4ZmU2MThkMGVjNTc2Yjg5ZGZmMTA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZjIyMmNlZmI2NGJiMjY2OGE5NWM2ZTJmMzkxMzAyM2NjNTkyOWFmMDZiMTRk
|
14
|
+
MWEwOWUwYmY0YjM3Mzk1N2FhNDE1YTdkYWJiNTY1NmUxMTE0NmQ4YjBiOTVm
|
15
|
+
Mjk5NzNmODZiNTIwNWUzY2Q3MDIxMjM0ZTRmNTEyMDFjMWU0MWY=
|
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,66 +1,86 @@
|
|
1
1
|
# Prmd
|
2
2
|
|
3
|
-
|
3
|
+
JSON Schema tooling: scaffold, verify, and generate documentation
|
4
|
+
against JSON Schema documents.
|
5
|
+
|
4
6
|
|
5
7
|
## Introduction
|
6
8
|
|
7
|
-
JSON-
|
9
|
+
[JSON Schema](http://json-schema.org/) provides a great way to describe
|
10
|
+
an API. prmd provides tools for bootstrapping a description like this,
|
11
|
+
verifying its completeness, and generating documentation from the
|
12
|
+
specification.
|
8
13
|
|
9
|
-
The
|
14
|
+
The JSON Schema usage conventions expected by prmd are described in
|
15
|
+
[/docs/schemata.md](/docs/schemata.md).
|
10
16
|
|
11
|
-
To learn more about
|
17
|
+
To learn more about JSON Schema in general, start with
|
18
|
+
[this excellent guide](http://spacetelescope.github.io/understanding-json-schema/)
|
19
|
+
and supplement with the [specification](http://json-schema.org/documentation.html).
|
12
20
|
|
13
21
|
## Installation
|
14
22
|
|
15
23
|
Add this line to your application's Gemfile:
|
16
24
|
|
17
|
-
|
25
|
+
```ruby
|
26
|
+
gem 'prmd'
|
27
|
+
```
|
18
28
|
|
19
29
|
And then execute:
|
20
30
|
|
21
|
-
|
31
|
+
```console
|
32
|
+
$ bundle
|
33
|
+
```
|
22
34
|
|
23
35
|
Or install it yourself as:
|
24
36
|
|
25
|
-
|
37
|
+
```console
|
38
|
+
$ gem install prmd
|
39
|
+
```
|
26
40
|
|
27
41
|
## Usage
|
28
42
|
|
29
|
-
Combine takes the path to a
|
43
|
+
Combine takes the path to a schema file or directory of schema files and
|
44
|
+
combines them on to stdout. If -m or --meta is supplied, it will override
|
45
|
+
defaults/metadata:
|
30
46
|
|
31
|
-
```
|
32
|
-
prmd combine <directory>
|
47
|
+
```console
|
48
|
+
$ prmd combine <file or directory>
|
33
49
|
```
|
34
50
|
|
35
|
-
Doc takes the path to a
|
51
|
+
Doc takes the path to a combined schema and outputs documentation to stdout.
|
52
|
+
If -m or --meta is supplied, it will override defaults/metadata:
|
36
53
|
|
37
|
-
```
|
38
|
-
prmd doc <
|
54
|
+
```console
|
55
|
+
$ prmd doc <combined schema>
|
39
56
|
```
|
40
57
|
|
41
|
-
|
58
|
+
You can also prepend files to the documention with -p or --prepend:
|
42
59
|
|
43
|
-
```
|
44
|
-
prmd doc -p header.md,overview.md <directory or schema>
|
60
|
+
```console
|
61
|
+
$ prmd doc -p header.md,overview.md <directory or schema>
|
45
62
|
```
|
46
63
|
|
47
|
-
Init optionally takes a resource as it's first argument and generates a
|
64
|
+
Init optionally takes a resource as it's first argument and generates a
|
65
|
+
new schema file to stdout (generically or using the resource name
|
66
|
+
provided). If -m or --meta is supplied, it will override
|
67
|
+
defaults/metadata:
|
48
68
|
|
49
|
-
```
|
50
|
-
prmd init
|
51
|
-
prmd init <
|
69
|
+
```console
|
70
|
+
$ prmd init
|
71
|
+
$ prmd init <resource name>
|
52
72
|
```
|
53
73
|
|
54
|
-
Verify takes a path to a
|
74
|
+
Verify takes a path to a combined schema and warns about missing attributes.
|
55
75
|
|
56
|
-
```
|
57
|
-
prmd verify <
|
76
|
+
```console
|
77
|
+
$ prmd verify <combined schema>
|
58
78
|
```
|
59
79
|
|
60
|
-
|
80
|
+
You can also chain commands as needed:
|
61
81
|
|
62
|
-
```
|
63
|
-
prmd combine <directory> | prmd verify | prmd doc > schema.md
|
82
|
+
```console
|
83
|
+
$ prmd combine <directory> | prmd verify | prmd doc > schema.md
|
64
84
|
```
|
65
85
|
|
66
86
|
## Contributing
|
data/bin/prmd
CHANGED
@@ -6,29 +6,25 @@ options = {}
|
|
6
6
|
|
7
7
|
commands = {
|
8
8
|
combine: OptionParser.new do |opts|
|
9
|
-
opts.banner = "prmd combine [options] <directory>"
|
9
|
+
opts.banner = "prmd combine [options] <file or directory>"
|
10
10
|
opts.on("-m", "--meta meta.json", "Set defaults for schemata") do |m|
|
11
11
|
options[:meta] = m
|
12
12
|
end
|
13
13
|
end,
|
14
14
|
doc: OptionParser.new do |opts|
|
15
|
-
opts.banner = "prmd doc [options] <schema>"
|
16
|
-
opts.on("-m", "--meta meta.json", "Set defaults for schemata") do |m|
|
17
|
-
options[:meta] = m
|
18
|
-
end
|
15
|
+
opts.banner = "prmd doc [options] <combined schema>"
|
19
16
|
opts.on("-p", "--prepend header,overview", Array, "Prepend files to output") do |p|
|
20
17
|
options[:prepend] = p
|
21
18
|
end
|
22
|
-
opts.banner = "prmd doc [options] <directory>"
|
23
19
|
end,
|
24
20
|
init: OptionParser.new do |opts|
|
25
|
-
opts.banner = "prmd init [options] <
|
21
|
+
opts.banner = "prmd init [options] <resource name>"
|
26
22
|
opts.on("-m", "--meta meta.json", "Set defaults for schemata") do |m|
|
27
23
|
options[:meta] = m
|
28
24
|
end
|
29
25
|
end,
|
30
26
|
verify: OptionParser.new do |opts|
|
31
|
-
opts.banner = "prmd verify [options] <
|
27
|
+
opts.banner = "prmd verify [options] <combined schema>"
|
32
28
|
end
|
33
29
|
}
|
34
30
|
|
@@ -68,37 +64,33 @@ option.order!
|
|
68
64
|
|
69
65
|
case command
|
70
66
|
when :combine
|
71
|
-
puts Prmd.combine(ARGV[0], options)
|
67
|
+
puts Prmd.combine(ARGV[0], options).to_s
|
72
68
|
when :doc
|
73
|
-
|
69
|
+
unless $stdin.tty?
|
74
70
|
data = JSON.parse($stdin.read)
|
75
|
-
schema = Prmd::Schema.new(data
|
71
|
+
schema = Prmd::Schema.new(data)
|
76
72
|
puts Prmd.doc(schema, options)
|
77
73
|
else
|
78
|
-
|
74
|
+
data = JSON.parse(File.read(ARGV[0]))
|
75
|
+
schema = Prmd::Schema.new(data)
|
79
76
|
puts Prmd.doc(schema, options)
|
80
77
|
end
|
81
78
|
when :init
|
82
79
|
puts Prmd.init(ARGV[0], options)
|
83
80
|
when :verify
|
84
|
-
errors = []
|
85
|
-
|
81
|
+
data, errors = '', []
|
82
|
+
unless $stdin.tty?
|
86
83
|
data = $stdin.read
|
87
|
-
errors
|
88
|
-
puts data
|
89
|
-
elsif File.directory?(ARGV[0])
|
90
|
-
Dir.glob(File.join(ARGV[0], '**/*.json')).each do |path|
|
91
|
-
Prmd.verify(JSON.parse(File.read(path))).each do |error|
|
92
|
-
errors << "#{path}: #{error}"
|
93
|
-
end
|
94
|
-
end
|
84
|
+
errors.concat(Prmd.verify(JSON.parse(data)))
|
95
85
|
else
|
96
|
-
|
86
|
+
data = JSON.parse(File.read(ARGV[0]))
|
87
|
+
Prmd.verify(data).each do |error|
|
97
88
|
errors << "#{ARGV[0]}: #{error}"
|
98
89
|
end
|
99
90
|
end
|
100
91
|
errors.each do |error|
|
101
|
-
$stderr.puts
|
92
|
+
$stderr.puts(error)
|
102
93
|
end
|
103
94
|
exit(1) unless errors.empty?
|
95
|
+
puts(data) unless $stdout.tty?
|
104
96
|
end
|
data/docs/schemata.md
CHANGED
@@ -42,7 +42,6 @@ Each attribute MUST include the following properties:
|
|
42
42
|
Each attribute MAY include the following properties:
|
43
43
|
|
44
44
|
* `pattern` - a regex encoded in a string that the valid values MUST match
|
45
|
-
* `readOnly` - boolean value defining if the attribute can be modified, assumes `false` if omitted
|
46
45
|
* `format` - format of the value. MUST be one of spec defined `["date-time", "email", "hostname", "ipv4", "ipv6", "uri"]` or defined by us `["uuid"]`
|
47
46
|
|
48
47
|
Examples:
|
@@ -54,7 +53,6 @@ Examples:
|
|
54
53
|
"description": "unique identifier of resource",
|
55
54
|
"example": "01234567-89ab-cdef-0123-456789abcdef",
|
56
55
|
"format": "uuid",
|
57
|
-
"readOnly": true,
|
58
56
|
"type": ["string"]
|
59
57
|
},
|
60
58
|
"url": {
|
@@ -1,5 +1,59 @@
|
|
1
1
|
module Prmd
|
2
|
-
def self.combine(
|
3
|
-
|
2
|
+
def self.combine(path, options={})
|
3
|
+
files = if File.directory?(path)
|
4
|
+
Dir.glob(File.join(path, '**', '*.json')) - [options[:meta]]
|
5
|
+
else
|
6
|
+
[path]
|
7
|
+
end
|
8
|
+
schemas = files.map { |file| JSON.parse(File.read(file)) }
|
9
|
+
|
10
|
+
data = {
|
11
|
+
'$schema' => 'http://json-schema.org/draft-04/hyper-schema',
|
12
|
+
'definitions' => {},
|
13
|
+
'properties' => {},
|
14
|
+
'type' => ['object']
|
15
|
+
}
|
16
|
+
|
17
|
+
if options[:meta] && File.exists?(options[:meta])
|
18
|
+
data.merge!(JSON.parse(File.read(options[:meta])))
|
19
|
+
end
|
20
|
+
|
21
|
+
schemas.each do |schema_data|
|
22
|
+
id = if schema_data['id']
|
23
|
+
schema_data['id'].split('/').last
|
24
|
+
end
|
25
|
+
next if id.nil? || id[0..0] == '_' # FIXME: remove this exception?
|
26
|
+
|
27
|
+
data['definitions'][id] = schema_data
|
28
|
+
reference_localizer = lambda do |datum|
|
29
|
+
case datum
|
30
|
+
when Array
|
31
|
+
datum.map {|element| reference_localizer.call(element)}
|
32
|
+
when Hash
|
33
|
+
if datum.has_key?('$ref')
|
34
|
+
if datum['$ref'].include?('/schema/')
|
35
|
+
$stderr.puts("`#{schema_data['id']}` `/schema/` prefixed refs are deprecated, use `/schemata/` prefixes")
|
36
|
+
datum['$ref'] = datum['$ref'].gsub(%r{/schema/([^#]*)#}, '#/definitions/\1')
|
37
|
+
end
|
38
|
+
datum['$ref'] = datum['$ref'].gsub(%r{/schemata/([^#]*)#}, '#/definitions/\1')
|
39
|
+
end
|
40
|
+
if datum.has_key?('href')
|
41
|
+
if datum['href'].include?('%2Fschema%2F')
|
42
|
+
$stderr.puts("`#{id}` `%2Fschema%2F` prefixed hrefs are deprecated, use `%2Fschemata%2F` prefixes")
|
43
|
+
datum['href'] = datum['href'].gsub(%r{%2Fschema%2F([^%]*)%23%2F}, '%23%2Fdefinitions%2F\1%2F')
|
44
|
+
end
|
45
|
+
datum['href'] = datum['href'].gsub(%r{%2Fschemata%2F([^%]*)%23%2F}, '%23%2Fdefinitions%2F\1%2F')
|
46
|
+
end
|
47
|
+
datum.each { |k,v| datum[k] = reference_localizer.call(v) }
|
48
|
+
else
|
49
|
+
datum
|
50
|
+
end
|
51
|
+
end
|
52
|
+
reference_localizer.call(data['definitions'][id])
|
53
|
+
|
54
|
+
data['properties'][id] = { '$ref' => "#/definitions/#{id}" }
|
55
|
+
end
|
56
|
+
|
57
|
+
Prmd::Schema.new(data)
|
4
58
|
end
|
5
59
|
end
|
data/lib/prmd/commands/doc.rb
CHANGED
@@ -2,7 +2,7 @@ def extract_attributes(schema, properties)
|
|
2
2
|
attributes = []
|
3
3
|
properties.each do |key, value|
|
4
4
|
# found a reference to another element:
|
5
|
-
value = schema.dereference(value)
|
5
|
+
_, value = schema.dereference(value)
|
6
6
|
if value.has_key?('anyOf')
|
7
7
|
descriptions = []
|
8
8
|
examples = []
|
@@ -13,7 +13,7 @@ def extract_attributes(schema, properties)
|
|
13
13
|
end
|
14
14
|
|
15
15
|
anyof.each do |ref|
|
16
|
-
nested_field = schema.dereference(ref)
|
16
|
+
_, nested_field = schema.dereference(ref)
|
17
17
|
descriptions << nested_field['description']
|
18
18
|
examples << nested_field['example']
|
19
19
|
end
|
@@ -23,7 +23,10 @@ def extract_attributes(schema, properties)
|
|
23
23
|
descriptions.first.gsub!(/ of (this )?.*/, "")
|
24
24
|
descriptions[1..-1].map { |d| d.gsub!(/unique /, "") }
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
|
+
last = descriptions.pop
|
28
|
+
description = [descriptions.join(", "), last].join(" or ")
|
29
|
+
|
27
30
|
example = doc_example(*examples)
|
28
31
|
attributes << [key, "string", description, example]
|
29
32
|
|
@@ -59,7 +62,7 @@ end
|
|
59
62
|
|
60
63
|
module Prmd
|
61
64
|
def self.doc(schema, options={})
|
62
|
-
root_url = schema['links'].find{|l| l['rel'] == '
|
65
|
+
root_url = schema['links'].find{|l| l['rel'] == 'self'}['href']
|
63
66
|
|
64
67
|
doc = (options[:prepend] || []).map do |path|
|
65
68
|
File.open(path, 'r').read + "\n"
|
@@ -73,20 +76,21 @@ module Prmd
|
|
73
76
|
identifiers = if definition['definitions']['identity'].has_key?('anyOf')
|
74
77
|
definition['definitions']['identity']['anyOf']
|
75
78
|
else
|
76
|
-
[
|
79
|
+
[definition['definitions']['identity']]
|
77
80
|
end
|
78
81
|
|
79
82
|
identifiers = identifiers.map {|ref| ref['$ref'].split('/').last }
|
80
83
|
end
|
81
84
|
if definition['properties']
|
82
85
|
definition['properties'].each do |key, value|
|
83
|
-
|
84
|
-
|
85
|
-
else
|
86
|
+
_, value = schema.dereference(value)
|
87
|
+
if value.has_key?('properties')
|
86
88
|
serialization[key] = {}
|
87
89
|
value['properties'].each do |k,v|
|
88
|
-
serialization[key][k] = schema.dereference(v)['example']
|
90
|
+
serialization[key][k] = schema.dereference(v).last['example']
|
89
91
|
end
|
92
|
+
else
|
93
|
+
serialization[key] = value['example']
|
90
94
|
end
|
91
95
|
end
|
92
96
|
else
|
data/lib/prmd/commands/expand.rb
CHANGED
@@ -39,25 +39,20 @@ if original['definitions']
|
|
39
39
|
when 'uuid'
|
40
40
|
{
|
41
41
|
'example' => '01234567-89ab-cdef-0123-456789abcdef',
|
42
|
-
'readOnly' => true,
|
43
42
|
'type' => ['string']
|
44
43
|
}
|
45
44
|
when 'email'
|
46
45
|
{
|
47
46
|
'example' => 'username@example.com',
|
48
|
-
'readOnly' => false,
|
49
47
|
'type' => ['string']
|
50
48
|
}
|
51
49
|
when 'date-time'
|
52
50
|
{
|
53
51
|
'example' => '2012-01-01T12:00:00Z',
|
54
|
-
'readOnly' => true,
|
55
52
|
'type' => ['string']
|
56
53
|
}
|
57
54
|
else
|
58
|
-
{
|
59
|
-
'readOnly' => false
|
60
|
-
}
|
55
|
+
{}
|
61
56
|
end
|
62
57
|
expanded['definitions'][key] = default.merge!(value)
|
63
58
|
end
|
data/lib/prmd/commands/init.rb
CHANGED
@@ -3,10 +3,11 @@ module Prmd
|
|
3
3
|
data = {
|
4
4
|
'$schema' => 'http://json-schema.org/draft-04/hyper-schema',
|
5
5
|
'title' => 'FIXME',
|
6
|
-
'type' => ['object'],
|
7
6
|
'definitions' => {},
|
7
|
+
'description' => 'FIXME',
|
8
8
|
'links' => [],
|
9
|
-
'properties' => {}
|
9
|
+
'properties' => {},
|
10
|
+
'type' => ['object']
|
10
11
|
}
|
11
12
|
|
12
13
|
if options[:meta] && File.exists?(options[:meta])
|
@@ -16,83 +17,92 @@ module Prmd
|
|
16
17
|
schema = Prmd::Schema.new(data)
|
17
18
|
|
18
19
|
if resource
|
19
|
-
|
20
|
+
if resource.include?('/')
|
21
|
+
parent, resource = resource.split('/')
|
22
|
+
end
|
23
|
+
schema['id'] = "schemata/#{resource}"
|
20
24
|
schema['title'] = "#{schema['title']} - #{resource[0...1].upcase}#{resource[1..-1]}"
|
21
25
|
schema['definitions'] = {
|
22
26
|
"created_at" => {
|
23
27
|
"description" => "when #{resource} was created",
|
24
28
|
"example" => "2012-01-01T12:00:00Z",
|
25
29
|
"format" => "date-time",
|
26
|
-
"readOnly" => true,
|
27
30
|
"type" => ["string"]
|
28
31
|
},
|
29
32
|
"id" => {
|
30
33
|
"description" => "unique identifier of #{resource}",
|
31
34
|
"example" => "01234567-89ab-cdef-0123-456789abcdef",
|
32
35
|
"format" => "uuid",
|
33
|
-
"readOnly" => true,
|
34
36
|
"type" => ["string"]
|
35
37
|
},
|
36
38
|
"identity" => {
|
37
|
-
"$ref" => "/
|
39
|
+
"$ref" => "/schemata/#{resource}#/definitions/id"
|
38
40
|
},
|
39
41
|
"updated_at" => {
|
40
42
|
"description" => "when #{resource} was updated",
|
41
43
|
"example" => "2012-01-01T12:00:00Z",
|
42
44
|
"format" => "date-time",
|
43
|
-
"readOnly" => true,
|
44
45
|
"type" => ["string"]
|
45
46
|
}
|
46
47
|
}
|
47
48
|
schema['links'] = [
|
48
49
|
{
|
49
|
-
"description"
|
50
|
-
"href"
|
51
|
-
"method"
|
52
|
-
"rel"
|
53
|
-
"schema"
|
50
|
+
"description" => "Create a new #{resource}.",
|
51
|
+
"href" => "/#{resource}s",
|
52
|
+
"method" => "POST",
|
53
|
+
"rel" => "create",
|
54
|
+
"schema" => {
|
54
55
|
"properties" => {},
|
55
56
|
"type" => ["object"]
|
56
57
|
},
|
57
|
-
"title"
|
58
|
+
"title" => "Create"
|
58
59
|
},
|
59
60
|
{
|
60
|
-
"description"
|
61
|
-
"href"
|
62
|
-
"method"
|
63
|
-
"rel"
|
64
|
-
"title"
|
61
|
+
"description" => "Delete an existing #{resource}.",
|
62
|
+
"href" => "/#{resource}s/{(%2Fschemata%2F#{resource}%23%2Fdefinitions%2Fidentity)}",
|
63
|
+
"method" => "DELETE",
|
64
|
+
"rel" => "destroy",
|
65
|
+
"title" => "Delete"
|
65
66
|
},
|
66
67
|
{
|
67
|
-
"description"
|
68
|
-
"href"
|
69
|
-
"method"
|
70
|
-
"rel"
|
71
|
-
"title"
|
68
|
+
"description" => "Info for existing #{resource}.",
|
69
|
+
"href" => "/#{resource}s/{(%2Fschemata%2F#{resource}%23%2Fdefinitions%2Fidentity)}",
|
70
|
+
"method" => "GET",
|
71
|
+
"rel" => "self",
|
72
|
+
"title" => "Info"
|
72
73
|
},
|
73
74
|
{
|
74
|
-
"description"
|
75
|
-
"href"
|
76
|
-
"method"
|
77
|
-
"rel"
|
78
|
-
"title"
|
75
|
+
"description" => "List existing #{resource}s.",
|
76
|
+
"href" => "/#{resource}s",
|
77
|
+
"method" => "GET",
|
78
|
+
"rel" => "instances",
|
79
|
+
"title" => "List"
|
79
80
|
},
|
80
81
|
{
|
81
|
-
"description"
|
82
|
-
"href"
|
83
|
-
"method"
|
84
|
-
"rel"
|
85
|
-
"schema"
|
82
|
+
"description" => "Update an existing #{resource}.",
|
83
|
+
"href" => "/#{resource}s/{(%2Fschemata%2F#{resource}%23%2Fdefinitions%2Fidentity)}",
|
84
|
+
"method" => "PATCH",
|
85
|
+
"rel" => "update",
|
86
|
+
"schema" => {
|
86
87
|
"properties" => {},
|
87
88
|
"type" => ["object"]
|
88
89
|
},
|
89
|
-
"title"
|
90
|
+
"title" => "Update"
|
90
91
|
}
|
91
92
|
]
|
93
|
+
if parent
|
94
|
+
schema['links'] << {
|
95
|
+
"description" => "List existing #{resource}s for existing #{parent}.",
|
96
|
+
"href" => "/#{parent}s/{(%2Fschemata%2F#{parent}%23%2Fdefinitions%2Fidentity)}/#{resource}s",
|
97
|
+
"method" => "GET",
|
98
|
+
"rel" => "instances",
|
99
|
+
"title" => "List"
|
100
|
+
}
|
101
|
+
end
|
92
102
|
schema['properties'] = {
|
93
|
-
"created_at" => { "$ref" => "/
|
94
|
-
"id" => { "$ref" => "/
|
95
|
-
"updated_at" => { "$ref" => "/
|
103
|
+
"created_at" => { "$ref" => "/schemata/#{resource}#/definitions/created_at" },
|
104
|
+
"id" => { "$ref" => "/schemata/#{resource}#/definitions/id" },
|
105
|
+
"updated_at" => { "$ref" => "/schemata/#{resource}#/definitions/updated_at" }
|
96
106
|
}
|
97
107
|
end
|
98
108
|
|
data/lib/prmd/commands/verify.rb
CHANGED
@@ -1,11 +1,23 @@
|
|
1
1
|
module Prmd
|
2
2
|
def self.verify(schema)
|
3
3
|
errors = []
|
4
|
+
errors << verify_schema(schema)
|
5
|
+
if schema['definitions']
|
6
|
+
schema['definitions'].each do |key, value|
|
7
|
+
errors << verify_schema(value)
|
8
|
+
errors << verify_definitions_and_links(value)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
errors.flatten!
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.verify_schema(schema)
|
15
|
+
errors = []
|
4
16
|
|
5
17
|
id = schema['id']
|
6
18
|
|
7
19
|
missing_requirements = []
|
8
|
-
%w{
|
20
|
+
%w{$schema definitions description id links properties title type}.each do |requirement|
|
9
21
|
unless schema.has_key?(requirement)
|
10
22
|
missing_requirements << requirement
|
11
23
|
end
|
@@ -14,6 +26,14 @@ module Prmd
|
|
14
26
|
errors << "Missing `#{id}#/#{missing_requirement}`"
|
15
27
|
end
|
16
28
|
|
29
|
+
errors
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.verify_definitions_and_links(schema)
|
33
|
+
errors = []
|
34
|
+
|
35
|
+
id = schema['id']
|
36
|
+
|
17
37
|
if schema['definitions']
|
18
38
|
unless schema['definitions'].has_key?('identity')
|
19
39
|
errors << "Missing `#{id}#/definitions/identity`"
|
@@ -21,7 +41,7 @@ module Prmd
|
|
21
41
|
schema['definitions'].each do |key, value|
|
22
42
|
missing_requirements = []
|
23
43
|
unless key == 'identity'
|
24
|
-
%w{description
|
44
|
+
%w{description type}.each do |requirement|
|
25
45
|
unless schema['definitions'][key].has_key?(requirement)
|
26
46
|
missing_requirements << requirement
|
27
47
|
end
|
@@ -59,6 +79,8 @@ module Prmd
|
|
59
79
|
errors << "Missing #{missing_requirement} in `#{link}` link for `#{id}`"
|
60
80
|
end
|
61
81
|
end
|
82
|
+
else
|
83
|
+
errors << "Missing `#{id}/links`"
|
62
84
|
end
|
63
85
|
|
64
86
|
errors
|
data/lib/prmd/schema.rb
CHANGED
@@ -9,61 +9,13 @@ module Prmd
|
|
9
9
|
@data[key] = value
|
10
10
|
end
|
11
11
|
|
12
|
-
def self.load(path, options={})
|
13
|
-
unless File.directory?(path)
|
14
|
-
data = JSON.parse(File.read(path))
|
15
|
-
else
|
16
|
-
data = {
|
17
|
-
'$schema' => 'http://json-schema.org/draft-04/hyper-schema',
|
18
|
-
'definitions' => {},
|
19
|
-
'properties' => {},
|
20
|
-
'type' => ['object']
|
21
|
-
}
|
22
|
-
|
23
|
-
if options[:meta] && File.exists?(options[:meta])
|
24
|
-
data.merge!(JSON.parse(File.read(options[:meta])))
|
25
|
-
end
|
26
|
-
|
27
|
-
Dir.glob(File.join(path, '**', '*.json')).each do |schema|
|
28
|
-
schema_data = JSON.parse(File.read(schema))
|
29
|
-
id = if schema_data['id']
|
30
|
-
schema_data['id'].gsub('schema/', '')
|
31
|
-
end
|
32
|
-
next if id.nil? || id[0..0] == '_' # FIXME: remove this exception?
|
33
|
-
|
34
|
-
data['definitions'][id] = schema_data
|
35
|
-
reference_localizer = lambda do |datum|
|
36
|
-
case datum
|
37
|
-
when Array
|
38
|
-
datum.map {|element| reference_localizer.call(element)}
|
39
|
-
when Hash
|
40
|
-
if datum.has_key?('$ref')
|
41
|
-
datum['$ref'] = datum['$ref'].gsub(%r{/schema/([^#]*)#}, '#/definitions/\1')
|
42
|
-
end
|
43
|
-
if datum.has_key?('href')
|
44
|
-
datum['href'] = datum['href'].gsub(%r{%2Fschema%2F([^%]*)%23%2F}, '%23%2Fdefinitions%2F\1%2F')
|
45
|
-
end
|
46
|
-
datum.each { |k,v| datum[k] = reference_localizer.call(v) }
|
47
|
-
else
|
48
|
-
datum
|
49
|
-
end
|
50
|
-
end
|
51
|
-
reference_localizer.call(data['definitions'][id])
|
52
|
-
|
53
|
-
data['properties'][id] = { '$ref' => "#/definitions/#{id}" }
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
self.new(data)
|
58
|
-
end
|
59
|
-
|
60
12
|
def initialize(new_data = {})
|
61
13
|
convert_type_to_array = lambda do |datum|
|
62
14
|
case datum
|
63
15
|
when Array
|
64
16
|
datum.map { |element| convert_type_to_array.call(element) }
|
65
17
|
when Hash
|
66
|
-
if datum.has_key?('type')
|
18
|
+
if datum.has_key?('type') && datum['type'].is_a?(String)
|
67
19
|
datum['type'] = [*datum['type']]
|
68
20
|
end
|
69
21
|
datum.each { |k,v| datum[k] = convert_type_to_array.call(v) }
|
@@ -77,19 +29,26 @@ module Prmd
|
|
77
29
|
def dereference(reference)
|
78
30
|
if reference.is_a?(Hash)
|
79
31
|
if reference.has_key?('$ref')
|
80
|
-
|
32
|
+
value = reference.dup
|
33
|
+
key = value.delete('$ref')
|
81
34
|
else
|
82
|
-
return reference # no dereference needed
|
35
|
+
return [nil, reference] # no dereference needed
|
83
36
|
end
|
84
37
|
else
|
85
|
-
key = reference
|
38
|
+
key, value = reference, {}
|
86
39
|
end
|
87
40
|
begin
|
88
41
|
datum = @data
|
89
42
|
key.gsub(%r{[^#]*#/}, '').split('/').each do |fragment|
|
90
43
|
datum = datum[fragment]
|
91
44
|
end
|
92
|
-
|
45
|
+
# last dereference will have nil key, so compact it out
|
46
|
+
# [-2..-1] should be the final key reached before deref
|
47
|
+
dereferenced_key, dereferenced_value = dereference(datum)
|
48
|
+
[
|
49
|
+
[key, dereferenced_key].compact.last,
|
50
|
+
[dereferenced_value, value].inject({}) { |composite, element| composite.merge(element) }
|
51
|
+
]
|
93
52
|
rescue => error
|
94
53
|
$stderr.puts("Failed to dereference `#{key}`")
|
95
54
|
raise(error)
|
data/lib/prmd/version.rb
CHANGED
data/lib/prmd/views/endpoint.erb
CHANGED
@@ -24,8 +24,13 @@
|
|
24
24
|
<%- definition['links'].each do |link, datum| %>
|
25
25
|
<%- path = link['href'].gsub(%r|(\{\([^\)]+\)\})|) do |ref|
|
26
26
|
ref = ref.gsub('%2F', '/').gsub('%23', '#').gsub(%r|[\{\(\)\}]|, '')
|
27
|
-
resource = ref.
|
28
|
-
|
27
|
+
resource = ref.match(%r{^#/definitions/([^/]*)}).captures.first
|
28
|
+
identity_key, identity_value = schema.dereference(ref)
|
29
|
+
if identity_value.has_key?('anyOf')
|
30
|
+
'{' + resource + '_' + identity_value['anyOf'].map {|r| r['$ref'].split('/').last}.join('_or_') + '}'
|
31
|
+
else
|
32
|
+
'{' + resource + '_' + identity_key.split('/').last + '}'
|
33
|
+
end
|
29
34
|
end -%>
|
30
35
|
### <%= title %> <%= link['title'] %>
|
31
36
|
<%= link['description'] %>
|
@@ -53,31 +58,52 @@ end -%>
|
|
53
58
|
|
54
59
|
#### Curl Example
|
55
60
|
```term
|
56
|
-
|
57
|
-
|
58
|
-
<%-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
61
|
+
<%- path = path.gsub(/{([^}]*)}/) {|match| '$' + match.gsub(/[{}]/, '')} %>
|
62
|
+
<%- if link.has_key?('schema') && (link['schema'].has_key?('properties') || link['schema'].has_key?('example')) %>
|
63
|
+
<%-
|
64
|
+
data = {}
|
65
|
+
if link['schema']['properties']
|
66
|
+
link['schema']['properties'].each do |key, value|
|
67
|
+
if value.has_key?('anyOf')
|
68
|
+
id_ref = value['anyOf'].detect {|ref| ref['$ref'].split('/').last == 'id'}
|
69
|
+
data[key] = schema.dereference(id_ref).last['example']
|
70
|
+
elsif value.has_key?('properties')
|
71
|
+
data[key] = {}
|
72
|
+
value['properties'].each do |k,v|
|
73
|
+
data[key][k] = schema.dereference(v).last['example']
|
74
|
+
end
|
75
|
+
else
|
76
|
+
data[key] = schema.dereference(value).last['example']
|
69
77
|
end
|
70
|
-
else
|
71
|
-
data[key] = value['example']
|
72
78
|
end
|
79
|
+
else
|
80
|
+
data.merge!(link['schema']['example'])
|
73
81
|
end
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
82
|
+
%>
|
83
|
+
<%- if link['method'].upcase == 'GET' %>
|
84
|
+
<%-
|
85
|
+
unless data.empty?
|
86
|
+
path << '?'
|
87
|
+
data.sort_by {|k,_| k.to_s }.each do |key, values|
|
88
|
+
if values.nil?
|
89
|
+
path << key.to_s << '&'
|
90
|
+
else
|
91
|
+
[values].flatten.each do |value|
|
92
|
+
path << key.to_s << '=' << CGI.escape(value.to_s) << '&'
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
path.chop! # remove trailing '&'
|
97
|
+
end
|
98
|
+
%>
|
99
|
+
$ curl -n -X <%= link['method'] %> <%= root_url %><%= path %>
|
100
|
+
<%- else %>
|
101
|
+
$ curl -n -X <%= link['method'] %> <%= root_url %><%= path %> \
|
102
|
+
-H "Content-Type: application/json" \
|
78
103
|
-d '<%= data.to_json %>'
|
104
|
+
<%- end %>
|
79
105
|
<%- else %>
|
80
|
-
|
106
|
+
$ curl -n -X <%= link['method'] %> <%= root_url %><%= path %>
|
81
107
|
<%- end %>
|
82
108
|
```
|
83
109
|
|
@@ -89,12 +115,6 @@ when 'create'
|
|
89
115
|
else
|
90
116
|
'200 OK'
|
91
117
|
end %>
|
92
|
-
<%- if link['rel'] == 'instances' && identifiers %>
|
93
|
-
Accept-Range: <%= identifiers.join(', ') %>
|
94
|
-
Content-Range: id 01234567-89ab-cdef-0123-456789abcdef..01234567-89ab-cdef-0123-456789abcdef; max=200
|
95
|
-
<%- end %>
|
96
|
-
ETag: "0123456789abcdef0123456789abcdef"
|
97
|
-
RateLimit-Remaining: 1200
|
98
118
|
```
|
99
119
|
```javascript```
|
100
120
|
<%- if link['rel'] == 'instances' %>
|
data/lib/prmd.rb
CHANGED
data/prmd.gemspec
CHANGED
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Prmd::VERSION
|
9
9
|
spec.authors = ["geemus"]
|
10
10
|
spec.email = ["geemus@gmail.com"]
|
11
|
-
spec.description = %q{
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.homepage = ""
|
11
|
+
spec.description = %q{scaffold, verify and generate docs from JSON Schema}
|
12
|
+
spec.summary = %q{JSON Schema tooling}
|
13
|
+
spec.homepage = "https://github.com/heroku/prmd"
|
14
14
|
spec.license = "MIT"
|
15
15
|
|
16
16
|
spec.files = `git ls-files`.split($/)
|
@@ -18,10 +18,9 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "
|
22
|
-
spec.add_dependency "erubis"
|
21
|
+
spec.add_dependency "erubis", "~> 2.7"
|
23
22
|
|
24
|
-
spec.add_development_dependency "bundler",
|
25
|
-
spec.add_development_dependency "rake"
|
26
|
-
spec.add_development_dependency "minitest"
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.2"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.3"
|
27
26
|
end
|
data/test/helpers.rb
CHANGED
@@ -2,9 +2,9 @@ require "minitest/autorun"
|
|
2
2
|
require "prmd"
|
3
3
|
|
4
4
|
def input_schemas_path
|
5
|
-
|
5
|
+
@@data_path ||= File.join(File.dirname(__FILE__), 'schemas', 'input')
|
6
6
|
end
|
7
7
|
|
8
8
|
def user_input_schema
|
9
|
-
|
9
|
+
@@user_input_schema ||= Prmd.combine(File.join(input_schemas_path, 'user.json'))
|
10
10
|
end
|
data/test/schema_test.rb
CHANGED
@@ -1,13 +1,34 @@
|
|
1
|
-
require File.join(File.dirname(__FILE__), 'helpers')
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'helpers'))
|
2
2
|
|
3
3
|
class SchemaTest < Minitest::Unit::TestCase
|
4
4
|
def test_dereference_with_ref
|
5
|
-
|
6
|
-
|
5
|
+
key, value = user_input_schema.dereference({
|
6
|
+
'$ref' => '#/definitions/user/definitions/id'
|
7
|
+
})
|
8
|
+
assert_equal(key, '#/definitions/user/definitions/id')
|
9
|
+
assert_equal(value, user_input_schema['definitions']['user']['definitions']['id'])
|
7
10
|
end
|
8
11
|
|
9
12
|
def test_dereference_without_ref
|
10
|
-
|
11
|
-
assert_equal
|
13
|
+
key, value = user_input_schema.dereference('#/definitions/user/definitions/id')
|
14
|
+
assert_equal(key, '#/definitions/user/definitions/id')
|
15
|
+
assert_equal(value, user_input_schema['definitions']['user']['definitions']['id'])
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_dereference_with_nested_ref
|
19
|
+
key, value = user_input_schema.dereference({
|
20
|
+
'$ref' => '#/definitions/user/definitions/identity'
|
21
|
+
})
|
22
|
+
assert_equal(key, '#/definitions/user/definitions/id')
|
23
|
+
assert_equal(value, user_input_schema['definitions']['user']['definitions']['id'])
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_dereference_with_local_context
|
27
|
+
key, value = user_input_schema.dereference({
|
28
|
+
'$ref' => '#/definitions/user/properties/id',
|
29
|
+
'override' => true
|
30
|
+
})
|
31
|
+
assert_equal(key, '#/definitions/user/definitions/id')
|
32
|
+
assert_equal(value, {'override' => true}.merge(user_input_schema['definitions']['user']['definitions']['id']))
|
12
33
|
end
|
13
34
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-04/hyper-schema",
|
3
|
+
"definitions": {},
|
4
|
+
"description": "API lets you interact with service",
|
5
|
+
"links": [{
|
6
|
+
"href": "https://api.example.com",
|
7
|
+
"rel": "self"
|
8
|
+
}],
|
9
|
+
"properties": {},
|
10
|
+
"title": "API",
|
11
|
+
"type": [
|
12
|
+
"object"
|
13
|
+
]
|
14
|
+
}
|
@@ -9,7 +9,6 @@
|
|
9
9
|
"description": "when user was created",
|
10
10
|
"example": "2012-01-01T12:00:00Z",
|
11
11
|
"format": "date-time",
|
12
|
-
"readOnly": true,
|
13
12
|
"type": [
|
14
13
|
"string"
|
15
14
|
]
|
@@ -18,19 +17,17 @@
|
|
18
17
|
"description": "unique identifier of user",
|
19
18
|
"example": "01234567-89ab-cdef-0123-456789abcdef",
|
20
19
|
"format": "uuid",
|
21
|
-
"readOnly": true,
|
22
20
|
"type": [
|
23
21
|
"string"
|
24
22
|
]
|
25
23
|
},
|
26
24
|
"identity": {
|
27
|
-
"$ref": "/
|
25
|
+
"$ref": "/schemata/user#/definitions/id"
|
28
26
|
},
|
29
27
|
"updated_at": {
|
30
28
|
"description": "when user was updated",
|
31
29
|
"example": "2012-01-01T12:00:00Z",
|
32
30
|
"format": "date-time",
|
33
|
-
"readOnly": true,
|
34
31
|
"type": [
|
35
32
|
"string"
|
36
33
|
]
|
@@ -53,14 +50,14 @@
|
|
53
50
|
},
|
54
51
|
{
|
55
52
|
"description": "Delete an existing user.",
|
56
|
-
"href": "/users/{(%
|
53
|
+
"href": "/users/{(%2Fschemata%2Fuser%23%2Fdefinitions%2Fidentity)}",
|
57
54
|
"method": "DELETE",
|
58
55
|
"rel": "destroy",
|
59
56
|
"title": "Delete"
|
60
57
|
},
|
61
58
|
{
|
62
59
|
"description": "Info for existing user.",
|
63
|
-
"href": "/users/{(%
|
60
|
+
"href": "/users/{(%2Fschemata%2Fuser%23%2Fdefinitions%2Fidentity)}",
|
64
61
|
"method": "GET",
|
65
62
|
"rel": "self",
|
66
63
|
"title": "Info"
|
@@ -74,7 +71,7 @@
|
|
74
71
|
},
|
75
72
|
{
|
76
73
|
"description": "Update an existing user.",
|
77
|
-
"href": "/users/{(%
|
74
|
+
"href": "/users/{(%2Fschemata%2Fuser%23%2Fdefinitions%2Fidentity)}",
|
78
75
|
"method": "PATCH",
|
79
76
|
"rel": "update",
|
80
77
|
"schema": {
|
@@ -89,14 +86,14 @@
|
|
89
86
|
],
|
90
87
|
"properties": {
|
91
88
|
"created_at": {
|
92
|
-
"$ref": "/
|
89
|
+
"$ref": "/schemata/user#/definitions/created_at"
|
93
90
|
},
|
94
91
|
"id": {
|
95
|
-
"$ref": "/
|
92
|
+
"$ref": "/schemata/user#/definitions/id"
|
96
93
|
},
|
97
94
|
"updated_at": {
|
98
|
-
"$ref": "/
|
95
|
+
"$ref": "/schemata/user#/definitions/updated_at"
|
99
96
|
}
|
100
97
|
},
|
101
|
-
"id": "
|
98
|
+
"id": "schemata/user"
|
102
99
|
}
|
metadata
CHANGED
@@ -1,43 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prmd
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- geemus
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: diff-lcs
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ! '>='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ! '>='
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: erubis
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
|
-
- -
|
17
|
+
- - ~>
|
32
18
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
19
|
+
version: '2.7'
|
34
20
|
type: :runtime
|
35
21
|
prerelease: false
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
|
-
- -
|
24
|
+
- - ~>
|
39
25
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
26
|
+
version: '2.7'
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
28
|
name: bundler
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,31 +42,31 @@ dependencies:
|
|
56
42
|
name: rake
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
|
-
- -
|
45
|
+
- - ~>
|
60
46
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
47
|
+
version: '10.2'
|
62
48
|
type: :development
|
63
49
|
prerelease: false
|
64
50
|
version_requirements: !ruby/object:Gem::Requirement
|
65
51
|
requirements:
|
66
|
-
- -
|
52
|
+
- - ~>
|
67
53
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
54
|
+
version: '10.2'
|
69
55
|
- !ruby/object:Gem::Dependency
|
70
56
|
name: minitest
|
71
57
|
requirement: !ruby/object:Gem::Requirement
|
72
58
|
requirements:
|
73
|
-
- -
|
59
|
+
- - ~>
|
74
60
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
61
|
+
version: '5.3'
|
76
62
|
type: :development
|
77
63
|
prerelease: false
|
78
64
|
version_requirements: !ruby/object:Gem::Requirement
|
79
65
|
requirements:
|
80
|
-
- -
|
66
|
+
- - ~>
|
81
67
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
83
|
-
description:
|
68
|
+
version: '5.3'
|
69
|
+
description: scaffold, verify and generate docs from JSON Schema
|
84
70
|
email:
|
85
71
|
- geemus@gmail.com
|
86
72
|
executables:
|
@@ -111,8 +97,9 @@ files:
|
|
111
97
|
- prmd.gemspec
|
112
98
|
- test/helpers.rb
|
113
99
|
- test/schema_test.rb
|
100
|
+
- test/schemas/input/meta.json
|
114
101
|
- test/schemas/input/user.json
|
115
|
-
homepage:
|
102
|
+
homepage: https://github.com/heroku/prmd
|
116
103
|
licenses:
|
117
104
|
- MIT
|
118
105
|
metadata: {}
|
@@ -135,9 +122,10 @@ rubyforge_project:
|
|
135
122
|
rubygems_version: 2.2.2
|
136
123
|
signing_key:
|
137
124
|
specification_version: 4
|
138
|
-
summary:
|
125
|
+
summary: JSON Schema tooling
|
139
126
|
test_files:
|
140
127
|
- test/helpers.rb
|
141
128
|
- test/schema_test.rb
|
129
|
+
- test/schemas/input/meta.json
|
142
130
|
- test/schemas/input/user.json
|
143
131
|
has_rdoc:
|