prmd 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YWJmODRjMTMyNjBmNGE5N2JmZTk4ZmI2MzZiZTM3NDBkZmEyNTI5Yw==
5
+ data.tar.gz: !binary |-
6
+ MjJiNjE4ZjA0ODUzNjlhNGZkZmVhZmY3MmRhMzY1MDFkYTM0M2QxMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ MThmMTQ3ODhhNDMwNTliZjk4NWY0N2JiOWU3MDk4ZjI1YzE2NDJhNjQ3YjIy
10
+ ZGU3OGVjYzBiNjZhNmVhNzljMjY5ZWE0YTJlMjg4NmMyN2JiOWQ1ZDM4N2E0
11
+ M2FjNDdjMmNmYzBlZjBiZjk1ZWQ4NWM3MDhiYmVmYTQ3MTYwMDA=
12
+ data.tar.gz: !binary |-
13
+ ZDMzZWZjMzAyZDYxNjg5NTRmZjRjODJjMDNkOTZmNmNhM2QzNzRjN2M2OGVi
14
+ Yjg3NWE1ZWE2Njk5M2Y5ODg4NDQ1NzlmNjZmZTQxY2E4ZWY0YTJmMzI0NGUz
15
+ MjM5ZjljNDMxZGNjNGQ3MTI1MmQ3Mjk5MWYyMjM2OGRjMjJkMmI=
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .ruby-version
4
+ .bundle
5
+ .config
6
+ coverage
7
+ InstalledFiles
8
+ lib/bundler/man
9
+ pkg
10
+ rdoc
11
+ spec/reports
12
+ test/tmp
13
+ test/version_tmp
14
+ tmp
15
+
16
+ # YARD artifacts
17
+ .yardoc
18
+ _yardoc
19
+ doc/
@@ -0,0 +1,2 @@
1
+ language: ruby
2
+ script: "bundle exec rake"
@@ -0,0 +1,6 @@
1
+ * Brandur <brandur@mutelight.org>
2
+ * Chris Continanza <christopher.continanza@gmail.com>
3
+ * Mark McGranaghan <mmcgrana@gmail.com>
4
+ * Timothée Peignier <timothee.peignier@tryphon.org>
5
+ * Wesley Beary <geemus+github@gmail.com>
6
+ * geemus <geemus@gmail.com>
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in prmd.gemspec
4
+ gemspec
@@ -0,0 +1,23 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ prmd (0.0.1)
5
+ diff-lcs
6
+ erubis
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ diff-lcs (1.2.5)
12
+ erubis (2.7.0)
13
+ minitest (4.7.5)
14
+ rake (10.1.0)
15
+
16
+ PLATFORMS
17
+ ruby
18
+
19
+ DEPENDENCIES
20
+ bundler (~> 1.3)
21
+ minitest
22
+ prmd!
23
+ rake
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013-2014 [CONTRIBUTORS.md](https://github.com/heroku/prmd/blob/master/CONTRIBUTORS.md)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,72 @@
1
+ # Prmd
2
+
3
+ schema to rule them all
4
+
5
+ ## Introduction
6
+
7
+ JSON-Schema provides a great way to describe an API. prmd provides tools for bootstrapping a description like this, verifying it's completeness and generating documentation from the specification.
8
+
9
+ The expectations for json-schema usage that are expected by prmd are described in [/docs/schemata.md](/docs/schemata.md).
10
+
11
+ To learn more about json-schema in general, start with [this excellent guide](http://spacetelescope.github.io/understanding-json-schema/) and supplement with the [specification](http://json-schema.org/documentation.html).
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ gem 'prmd'
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install prmd
26
+
27
+ ## Usage
28
+
29
+ Combine takes the path to a directory of schemas and combines them onto stdout. If -m or --meta is supplied, it will override defaults/metadata.
30
+
31
+ ```
32
+ prmd combine <directory>
33
+ ```
34
+
35
+ Doc takes the path to a directory of schemas and outputs their documentation onto stdout. If -m or --meta is supplied, it will override defaults/metadata.
36
+
37
+ ```
38
+ prmd doc <directory_or_schema>
39
+ ```
40
+
41
+ Prepend file to the documentation output.
42
+
43
+ ```
44
+ prmd doc -p header.md,overview.md <directory or schema>
45
+ ```
46
+
47
+ Init optionally takes a resource as it's first argument and generates a new schema file to stdout (generically or using the resource name provided). If -m or --meta is supplied, it will override defaults/metadata.
48
+
49
+ ```
50
+ prmd init
51
+ prmd init <resource_name>
52
+ ```
53
+
54
+ Verify takes a path to a directory of schemas or a particular schema file and checks to see if it matches expectations.
55
+
56
+ ```
57
+ prmd verify <directory_or_schema>
58
+ ```
59
+
60
+ Combining commands works too.
61
+
62
+ ```
63
+ prmd combine <directory> | prmd verify | prmd doc > schema.md
64
+ ```
65
+
66
+ ## Contributing
67
+
68
+ 1. Fork it
69
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
70
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
71
+ 4. Push to the branch (`git push origin my-new-feature`)
72
+ 5. Create new Pull Request
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = "test/*_test.rb"
6
+ end
7
+
8
+ task :default => :test
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'prmd')))
4
+
5
+ options = {}
6
+
7
+ commands = {
8
+ combine: OptionParser.new do |opts|
9
+ opts.banner = "prmd combine [options] <directory>"
10
+ opts.on("-m", "--meta meta.json", "Set defaults for schemata") do |m|
11
+ options[:meta] = m
12
+ end
13
+ end,
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
19
+ opts.on("-p", "--prepend header,overview", Array, "Prepend files to output") do |p|
20
+ options[:prepend] = p
21
+ end
22
+ opts.banner = "prmd doc [options] <directory>"
23
+ end,
24
+ init: OptionParser.new do |opts|
25
+ opts.banner = "prmd init [options] <directory> <resource>"
26
+ opts.on("-m", "--meta meta.json", "Set defaults for schemata") do |m|
27
+ options[:meta] = m
28
+ end
29
+ end,
30
+ verify: OptionParser.new do |opts|
31
+ opts.banner = "prmd verify [options] <directory or schema>"
32
+ end
33
+ }
34
+
35
+ help_text = commands.values.map do |command|
36
+ " #{command.banner}"
37
+ end.join("\n")
38
+
39
+ global = OptionParser.new do |opts|
40
+ opts.banner = "Usage: prmd [options] [command [options]]"
41
+ opts.separator "\nAvailable options:"
42
+ opts.on("--version", "Return version") do |opts|
43
+ puts "prmd #{Prmd::VERSION}"
44
+ exit(0)
45
+ end
46
+ opts.separator "\nAvailable commands:"
47
+ opts.separator help_text
48
+ end
49
+
50
+ if ARGV.empty?
51
+ puts global
52
+ exit(1)
53
+ end
54
+ global.order!
55
+
56
+ command = ARGV.shift.to_sym
57
+ option = commands[command]
58
+ if option.nil?
59
+ puts global
60
+ exit(1)
61
+ end
62
+
63
+ if ARGV.empty? && $stdin.tty?
64
+ puts option
65
+ exit(1)
66
+ end
67
+ option.order!
68
+
69
+ case command
70
+ when :combine
71
+ puts Prmd.combine(ARGV[0], options)
72
+ when :doc
73
+ if ARGV.empty?
74
+ data = JSON.parse($stdin.read)
75
+ schema = Prmd::Schema.new(data, options)
76
+ puts Prmd.doc(schema, options)
77
+ else
78
+ schema = Prmd::Schema.load(ARGV[0])
79
+ puts Prmd.doc(schema, options)
80
+ end
81
+ when :init
82
+ puts Prmd.init(ARGV[0], options)
83
+ when :verify
84
+ errors = []
85
+ if ARGV.empty?
86
+ data = $stdin.read
87
+ errors = Prmd.verify(JSON.parse(data))
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
95
+ else
96
+ Prmd.verify(JSON.parse(File.read(ARGV[0]))).each do |error|
97
+ errors << "#{ARGV[0]}: #{error}"
98
+ end
99
+ end
100
+ errors.each do |error|
101
+ $stderr.puts error
102
+ end
103
+ exit(1) unless errors.empty?
104
+ end
@@ -0,0 +1,162 @@
1
+ # schemata
2
+ This document seeks to explain JSON schema in practice as well as our usage and associated implications. Everything described must be followed unless otherwise noted (or it is a bug). Unless otherwise noted (as in meta-data) keys should be alphabetized for ease of modification/review/updating. A great example in-the-wild is available for the Heroku Platform API, see [Heroku Devcenter](https://devcenter.heroku.com/articles/platform-api-reference#schema) for details.
3
+
4
+ ## json-schema
5
+
6
+ JSON Schema provides a way to describe the resources, attributes and links of an API using JSON. This document will contain many examples and explanation, but going to the source can also be useful. There are three relevant specs, which are additive. You can read through them, ideally in this order:
7
+
8
+ 1. [JSON Schema Core](http://tools.ietf.org/html/draft-zyp-json-schema-04) - defines the basic foundation of JSON Schema - you probably will not need this often
9
+ 2. [JSON Schema Validation](http://tools.ietf.org/html/draft-fge-json-schema-validation-00) - defines the validation keywords of JSON Schema - covers most attributes
10
+ 3. [JSON Hyper-Schema](http://tools.ietf.org/html/draft-luff-json-hyper-schema-00) - defines the hyper-media keywords of JSON Schema - covers remaining links-specific attributes
11
+
12
+ ## structure
13
+
14
+ We have opted to split apart the schema into individual resource schema and a root schema which references all of them. These individual schema are named based on the singular form of the resource in question.
15
+
16
+ ### meta-data
17
+
18
+ Each schema MUST include some meta-data, which we cluster at the top of the file, including:
19
+
20
+ * `description` - a description of the resource described by the schema
21
+ * `id` - an id for this schema, it MUST be in the form `"schema/#{lower_case_singular_resource}"`
22
+ * `$schema` - defines what meta-schema is in use, it MUST be `http://json-schema.org/draft-04/hyper-schema`
23
+ * `title` - title for this resource, it MUST be in the form `"Heroku Platform API - #{title_case_plural_resource}"`
24
+ * `type` - the type(s) of this schema, it MUST be `["object"]`
25
+
26
+ ### `definitions`
27
+
28
+ We make heavy usage of the `definitions` attribute in each resource to provide a centralized collection of attributes related to each resource. By doing so we are able to refer to the same attribute in links, properties and even as foreign keys.
29
+
30
+ The definitions object MUST include every attribute related directly to this resource, including:
31
+
32
+ * all properties that are present in the serialization of the object
33
+ * an `identity` property to provide an easy way to find what unique identifier(s) can be used with this object as well as what to use for foreign keys
34
+ * all transient properties which may be passed into links related to the object, even if they are not serialized
35
+
36
+ Each attribute MUST include the following properties:
37
+
38
+ * `description` - a description of the attribute and how it relates to the resource
39
+ * `example` - an example of the attributes value, useful for documentation and tests
40
+ * `type` - an array of type(s) for this attribute, values MUST be one of `["array", "boolean", "integer", "number", "null", "object", "string"]`
41
+
42
+ Each attribute MAY include the following properties:
43
+
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
+ * `format` - format of the value. MUST be one of spec defined `["date-time", "email", "hostname", "ipv4", "ipv6", "uri"]` or defined by us `["uuid"]`
47
+
48
+ Examples:
49
+
50
+ ```javascript
51
+ {
52
+ "definitions": {
53
+ "id": {
54
+ "description": "unique identifier of resource",
55
+ "example": "01234567-89ab-cdef-0123-456789abcdef",
56
+ "format": "uuid",
57
+ "readOnly": true,
58
+ "type": ["string"]
59
+ },
60
+ "url": {
61
+ "description": "URL of resource",
62
+ "example": "http://example.com",
63
+ "format": "uri",
64
+ "pattern": "^http://[a-z][a-z0-9-]{3,30}\\.com$",
65
+ "type": ["null", "string"]
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ### `links`
72
+
73
+ Links define the actions available on a given resource. They are listed as an array, which should be alphabetized by title.
74
+
75
+ The links array MUST include an object defining each action available. Each action MUST include the following attributes:
76
+
77
+ * `description` - a description of the action to perform
78
+ * `href` - the path associated with this action, use [URI templates](http://tools.ietf.org/html/rfc6570) as needed, CGI escaping any JSON pointer values used for identity
79
+ * `method` - the http method to be used with this actio
80
+ * `rel` - describes relation of link to resource, SHOULD be one of `["create", "destroy", "self", "instances", "update"]`
81
+ * `title` - title for the link
82
+
83
+ Links that expect a json-encoded body as input MUST also include the following attributes:
84
+ * `schema` - an object with a `properties` object that MUST include JSON pointers to the definitions for each associated attribute
85
+
86
+ Schema properties MAY also include a `required` boolean to indicate if an attribute must be present, which is assumed to be false when omitted.
87
+
88
+ ```javascript
89
+ {
90
+ "links": [
91
+ {
92
+ "description": "Create a new resource.",
93
+ "href": "/resources",
94
+ "method": "POST",
95
+ "rel": "create",
96
+ "schema": {
97
+ "properties": {
98
+ "owner": { "$ref": "/schema/user#/definitions/identity" },
99
+ "url": { "$ref": "/schema/resource/definitions/url" }
100
+ }
101
+ },
102
+ "title": "Create"
103
+ },
104
+ {
105
+ "description": "Delete an existing resource.",
106
+ "href": "/resources/{(%2Fschema%2Fresources%23%2Fdefinitions%2Fidentity)}",
107
+ "method": "DELETE",
108
+ "rel": "destroy",
109
+ "title": "Delete"
110
+ },
111
+ {
112
+ "description": "Info for existing resource.",
113
+ "href": "/resources/{(%2Fschema%2Fresources%23%2Fdefinitions%2Fidentity)}",
114
+ "method": "GET",
115
+ "rel": "self",
116
+ "title": "Info"
117
+ },
118
+ {
119
+ "description": "List existing resources.",
120
+ "href": "/resources",
121
+ "method": "GET",
122
+ "rel": "instances",
123
+ "title": "List"
124
+ },
125
+ {
126
+ "description": "Update an existing resource.",
127
+ "href": "/resources/{(%2Fschema%2Fresource%23%2Fdefinitions%2Fidentity)}",
128
+ "method": "PATCH",
129
+ "rel": "update",
130
+ "schema": {
131
+ "properties": {
132
+ "url": { "$ref": "/schema/resource/definitions/url" }
133
+ }
134
+ },
135
+ "title": "Update"
136
+ }
137
+ }
138
+ ```
139
+
140
+ ### `properties`
141
+
142
+ Properties defines the attributes that exist in the serialization of the object.
143
+
144
+ The properties object MUST contain all the serialized attributes for the object. Each attribute MUST provide a [JSON pointer](http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07) to the attribute in appropriate `definitions`, we have opted to always use absolute pointers for consistency. Properties MUST also add any data which overrides the values in definitions and SHOULD add any additional, relevant data.
145
+
146
+ ```javascript
147
+ {
148
+ "properties": {
149
+ "id": { "$ref": "/schema/resource#/definitions/id" },
150
+ "owner": {
151
+ "description": "unique identifier of the user who owns this resource",
152
+ "properties": {
153
+ "id": { "$ref": "/schema/user#/definitions/id" }
154
+ },
155
+ "type": ["object"]
156
+ },
157
+ "url": { "$ref": "/schema/resource#/definitions/url" }
158
+ }
159
+ }
160
+ ```
161
+
162
+ Note: this assumes that schema/user will also be available and will have id defined in the definitions. If/when you need to refer to a foreign key, you MUST add a new schema and/or add the appropriate attribute to the foreign resource definitions unless it already exists.