prmd 0.3.2 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,80 @@
1
+ <%-
2
+ def extract_attributes(schema, properties)
3
+ attributes = []
4
+ properties = properties.sort_by {|k,v| k} # ensure consistent ordering
5
+
6
+ properties.each do |key, value|
7
+ # found a reference to another element:
8
+ _, value = schema.dereference(value)
9
+ if value.has_key?('anyOf')
10
+ descriptions = []
11
+ examples = []
12
+
13
+ # sort anyOf! always show unique identifier first
14
+ anyof = value['anyOf'].sort_by do |property|
15
+ property['$ref'].split('/').last.gsub('id', 'a')
16
+ end
17
+
18
+ anyof.each do |ref|
19
+ _, nested_field = schema.dereference(ref)
20
+ descriptions << nested_field['description']
21
+ examples << nested_field['example']
22
+ end
23
+
24
+ # avoid repetition :}
25
+ description = if descriptions.size > 1
26
+ descriptions.first.gsub!(/ of (this )?.*/, "")
27
+ descriptions[1..-1].map { |d| d.gsub!(/unique /, "") }
28
+ [descriptions[0...-1].join(", "), descriptions.last].join(" or ")
29
+ else
30
+ description = descriptions.last
31
+ end
32
+
33
+ example = [*examples].map { |e| "<code>#{e.to_json}</code>" }.join(" or ")
34
+ attributes << [key, "string", description, example]
35
+
36
+ # found a nested object
37
+ elsif value['type'] == ['object'] && value['properties']
38
+ nested = extract_attributes(schema, value['properties'])
39
+ nested.each do |attribute|
40
+ attribute[0] = "#{key}:#{attribute[0]}"
41
+ end
42
+ attributes.concat(nested)
43
+ # just a regular attribute
44
+ else
45
+ description = value['description']
46
+ if value['enum']
47
+ description += '<br/><b>one of:</b>' + [*value['enum']].map { |e| "<code>#{e.to_json}</code>" }.join(" or ")
48
+ end
49
+
50
+ if value.has_key?('example')
51
+ example = [*value['example']].map { |e| "<code>#{e.to_json}</code>" }.join(" or ")
52
+ elsif value['type'] == ['array'] && value.has_key?('items')
53
+ example = "<code>#{schema.schema_value_example(value)}</code>"
54
+ end
55
+
56
+ type = if value['type'].include?('null')
57
+ 'nullable '
58
+ else
59
+ ''
60
+ end
61
+ type += (value['format'] || (value['type'] - ['null']).first)
62
+ attributes << [key, type, description, example]
63
+ end
64
+ end
65
+ return attributes
66
+ end
67
+
68
+ def build_link_path(schema, link)
69
+ link['href'].gsub(%r|(\{\([^\)]+\)\})|) do |ref|
70
+ ref = ref.gsub('%2F', '/').gsub('%23', '#').gsub(%r|[\{\(\)\}]|, '')
71
+ ref_resource = ref.split('#/definitions/').last.split('/').first.gsub('-','_')
72
+ identity_key, identity_value = schema.dereference(ref)
73
+ if identity_value.has_key?('anyOf')
74
+ '{' + ref_resource + '_' + identity_value['anyOf'].map {|r| r['$ref'].split('/').last}.join('_or_') + '}'
75
+ else
76
+ '{' + ref_resource + '_' + identity_key.split('/').last + '}'
77
+ end
78
+ end
79
+ end
80
+ %>
@@ -0,0 +1,58 @@
1
+ <%-
2
+ path = build_link_path(schema, link)
3
+ link_schema_properties_template = Prmd::Template::load('link_schema_properties.erb', options[:template])
4
+ -%>
5
+ ### <%= title %> <%= link['title'] %>
6
+ <%= link['description'] %>
7
+
8
+ ```
9
+ <%= link['method'] %> <%= path %>
10
+ ```
11
+
12
+ <%- if link.has_key?('schema') && link['schema'].has_key?('properties') %>
13
+ <%-
14
+ required, optional = link['schema']['properties'].partition do |k, v|
15
+ (link['schema']['required'] || []).include?(k)
16
+ end.map { |partition| Hash[partition] }
17
+ %>
18
+ <%- unless required.empty? %>
19
+ #### Required Parameters
20
+ <%= Erubis::Eruby.new(link_schema_properties_template).result(params: required, schema: schema) %>
21
+
22
+ <%- end %>
23
+ <%- unless optional.empty? %>
24
+ #### Optional Parameters
25
+ <%= Erubis::Eruby.new(link_schema_properties_template).result(params: optional, schema: schema) %>
26
+ <%- end %>
27
+ <%- end %>
28
+
29
+ #### Curl Example
30
+ <%=
31
+ Prmd::Template::render(File.join('schemata', 'link_curl_example.erb'), File.dirname(options[:template]), {
32
+ options: options,
33
+ resource: resource,
34
+ schema: schema,
35
+ schemata: schemata,
36
+ link: link,
37
+ path: path
38
+ })
39
+ %>
40
+
41
+ #### Response Example
42
+ ```
43
+ HTTP/1.1 <%= case link['rel']
44
+ when 'create'
45
+ '201 Created'
46
+ else
47
+ '200 OK'
48
+ end %>
49
+ ```
50
+ ```json
51
+ <%- if link.has_key?('targetSchema') %>
52
+ <%= JSON.pretty_generate(schema.schema_example(link['targetSchema'])) %>
53
+ <%- elsif link['rel'] == 'instances' %>
54
+ <%= JSON.pretty_generate([schema.schemata_example(resource)]) %>
55
+ <%- else %>
56
+ <%= JSON.pretty_generate(schema.schemata_example(resource)) %>
57
+ <%- end %>
58
+ ```
@@ -0,0 +1,25 @@
1
+ ```term
2
+ <%-
3
+ data = {}
4
+ path = path.gsub(/{([^}]*)}/) {|match| '$' + match.gsub(/[{}]/, '').upcase}
5
+
6
+ if link.has_key?('schema')
7
+ data.merge!(schema.schema_example(link['schema']))
8
+
9
+ if link['method'].upcase == 'GET' && !data.empty?
10
+ path << '?'
11
+ data.sort_by {|k,_| k.to_s }.each do |key, values|
12
+ [values].flatten.each do |value|
13
+ path << [key.to_s, CGI.escape(value.to_s)].join('=') << '&'
14
+ end
15
+ end
16
+ path.chop! # remove trailing '&'
17
+ end
18
+ end
19
+ %>
20
+ $ curl -n -X <%= link['method'] %> <%= schema.href %><%= path %>
21
+ <%- unless data.empty? || link['method'].upcase == 'GET' %>
22
+ -H "Content-Type: <%= options[:content_type] %>" \
23
+ -d '<%= data.to_json %>'
24
+ <%- end %>
25
+ ```
@@ -1,3 +1,3 @@
1
1
  module Prmd
2
- VERSION = "0.3.2"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -19,6 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "erubis", "~> 2.7"
22
+ spec.add_dependency "json_schema", "~> 0.1"
22
23
 
23
24
  spec.add_development_dependency "bundler", "~> 1.3"
24
25
  spec.add_development_dependency "rake", "~> 10.2"
@@ -0,0 +1,168 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-04/hyper-schema#",
3
+ "id": "http://json-schema.org/draft-04/hyper-schema#",
4
+ "title": "JSON Hyper-Schema",
5
+ "allOf": [
6
+ {
7
+ "$ref": "http://json-schema.org/draft-04/schema#"
8
+ }
9
+ ],
10
+ "properties": {
11
+ "additionalItems": {
12
+ "anyOf": [
13
+ {
14
+ "type": "boolean"
15
+ },
16
+ {
17
+ "$ref": "#"
18
+ }
19
+ ]
20
+ },
21
+ "additionalProperties": {
22
+ "anyOf": [
23
+ {
24
+ "type": "boolean"
25
+ },
26
+ {
27
+ "$ref": "#"
28
+ }
29
+ ]
30
+ },
31
+ "dependencies": {
32
+ "additionalProperties": {
33
+ "anyOf": [
34
+ {
35
+ "$ref": "#"
36
+ },
37
+ {
38
+ "type": "array"
39
+ }
40
+ ]
41
+ }
42
+ },
43
+ "items": {
44
+ "anyOf": [
45
+ {
46
+ "$ref": "#"
47
+ },
48
+ {
49
+ "$ref": "#/definitions/schemaArray"
50
+ }
51
+ ]
52
+ },
53
+ "definitions": {
54
+ "additionalProperties": {
55
+ "$ref": "#"
56
+ }
57
+ },
58
+ "patternProperties": {
59
+ "additionalProperties": {
60
+ "$ref": "#"
61
+ }
62
+ },
63
+ "properties": {
64
+ "additionalProperties": {
65
+ "$ref": "#"
66
+ }
67
+ },
68
+ "allOf": {
69
+ "$ref": "#/definitions/schemaArray"
70
+ },
71
+ "anyOf": {
72
+ "$ref": "#/definitions/schemaArray"
73
+ },
74
+ "oneOf": {
75
+ "$ref": "#/definitions/schemaArray"
76
+ },
77
+ "not": {
78
+ "$ref": "#"
79
+ },
80
+
81
+ "links": {
82
+ "type": "array",
83
+ "items": {
84
+ "$ref": "#/definitions/linkDescription"
85
+ }
86
+ },
87
+ "fragmentResolution": {
88
+ "type": "string"
89
+ },
90
+ "media": {
91
+ "type": "object",
92
+ "properties": {
93
+ "type": {
94
+ "description": "A media type, as described in RFC 2046",
95
+ "type": "string"
96
+ },
97
+ "binaryEncoding": {
98
+ "description": "A content encoding scheme, as described in RFC 2045",
99
+ "type": "string"
100
+ }
101
+ }
102
+ },
103
+ "pathStart": {
104
+ "description": "Instances' URIs must start with this value for this schema to apply to them",
105
+ "type": "string",
106
+ "format": "uri"
107
+ }
108
+ },
109
+ "definitions": {
110
+ "schemaArray": {
111
+ "type": "array",
112
+ "items": {
113
+ "$ref": "#"
114
+ }
115
+ },
116
+ "linkDescription": {
117
+ "title": "Link Description Object",
118
+ "type": "object",
119
+ "required": [ "href", "rel" ],
120
+ "properties": {
121
+ "href": {
122
+ "description": "a URI template, as defined by RFC 6570, with the addition of the $, ( and ) characters for pre-processing",
123
+ "type": "string"
124
+ },
125
+ "rel": {
126
+ "description": "relation to the target resource of the link",
127
+ "type": "string"
128
+ },
129
+ "title": {
130
+ "description": "a title for the link",
131
+ "type": "string"
132
+ },
133
+ "targetSchema": {
134
+ "description": "JSON Schema describing the link target",
135
+ "$ref": "#"
136
+ },
137
+ "mediaType": {
138
+ "description": "media type (as defined by RFC 2046) describing the link target",
139
+ "type": "string"
140
+ },
141
+ "method": {
142
+ "description": "method for requesting the target of the link (e.g. for HTTP this might be \"GET\" or \"DELETE\")",
143
+ "type": "string"
144
+ },
145
+ "encType": {
146
+ "description": "The media type in which to submit data along with the request",
147
+ "type": "string",
148
+ "default": "application/json"
149
+ },
150
+ "schema": {
151
+ "description": "Schema describing the data to submit along with the request",
152
+ "$ref": "#"
153
+ }
154
+ }
155
+ }
156
+ },
157
+ "links": [
158
+ {
159
+ "rel": "self",
160
+ "href": "{+id}"
161
+ },
162
+ {
163
+ "rel": "full",
164
+ "href": "{+($ref)}"
165
+ }
166
+ ]
167
+ }
168
+
@@ -0,0 +1,175 @@
1
+ {
2
+ "$schema": "http://interagent.github.io/interagent-hyper-schema#",
3
+ "id": "http://interagent.github.io/interagent-hyper-schema#",
4
+ "title": "Heroku JSON Hyper-Schema",
5
+ "allOf": [
6
+ {
7
+ "$ref": "http://json-schema.org/draft-04/hyper-schema#"
8
+ }
9
+ ],
10
+ "definitions": {
11
+ "identity": {
12
+ "anyOf": [
13
+ {
14
+ "additionalProperties": false,
15
+ "properties": {
16
+ "anyOf": {
17
+ "additionalProperties": {
18
+ "$ref": "#/definitions/ref"
19
+ },
20
+ "minProperties": 1
21
+ }
22
+ },
23
+ "required": ["anyOf"]
24
+ },
25
+ {
26
+ "properties": {},
27
+ "strictProperties": true
28
+ }
29
+ ]
30
+ },
31
+ "ref": {
32
+ "additionalProperties": false,
33
+ "properties": {
34
+ "$ref": {
35
+ "type": "string"
36
+ }
37
+ },
38
+ "required": ["$ref"]
39
+ },
40
+ "resource": {
41
+ "dependencies": {
42
+ "properties": {
43
+ "properties": {
44
+ "definitions": {
45
+ "additionalProperties": {
46
+ "$ref": "#/definitions/resourceDefinition"
47
+ },
48
+ "properties": {
49
+ "identity": {
50
+ "$ref": "#/definitions/identity"
51
+ }
52
+ },
53
+ "required": ["identity"]
54
+ }
55
+ }
56
+ }
57
+ },
58
+ "properties": {
59
+ "links": {
60
+ "items": {
61
+ "$ref": "#/definitions/resourceLink"
62
+ }
63
+ },
64
+ "properties": {
65
+ "patternProperties": {
66
+ "^[a-z][a-z_]*[a-z]$": {
67
+ "$ref": "#/definitions/resourceProperty"
68
+ }
69
+ },
70
+ "strictProperties": true
71
+ },
72
+ "strictProperties": {
73
+ "enum": [true],
74
+ "type": "boolean"
75
+ }
76
+ },
77
+ "required": [
78
+ "definitions",
79
+ "description",
80
+ "links",
81
+ "title",
82
+ "type"
83
+ ]
84
+ },
85
+ "resourceDefinition": {
86
+ "anyOf": [
87
+ {
88
+ "required": ["example", "type"]
89
+ },
90
+ {
91
+ "required": ["type"],
92
+ "type": ["array"]
93
+ },
94
+ {
95
+ "required": ["type"],
96
+ "type": ["object"]
97
+ }
98
+ ],
99
+ "not": {
100
+ "required": ["links"]
101
+ },
102
+ "required": ["description"]
103
+ },
104
+ "resourceLink": {
105
+ "properties": {
106
+ "href": {
107
+ "pattern": "^(/([a-z][a-z\\-]*[a-z]|\\{\\(.*\\)\\}))+$"
108
+ },
109
+ "schema": {
110
+ "anyOf": [
111
+ {
112
+ "required": ["properties"]
113
+ },
114
+ {
115
+ "required": ["patternProperties"]
116
+ }
117
+ ],
118
+ "required": ["type"]
119
+ }
120
+ },
121
+ "required": ["description", "href", "method", "rel", "title"]
122
+ },
123
+ "resourceProperty": {
124
+ "anyOf": [
125
+ {
126
+ "$ref": "#/definitions/ref"
127
+ },
128
+ {
129
+ "properties": {
130
+ "properties": {
131
+ "additionalProperties": {
132
+ "$ref": "#/definitions/resourceProperty"
133
+ }
134
+ },
135
+ "strictProperties": {
136
+ "enum": [true],
137
+ "type": "boolean"
138
+ }
139
+ },
140
+ "required": ["description", "properties", "type"]
141
+ },
142
+ {
143
+ "properties": {
144
+ "items": {
145
+ "$ref": "#/definitions/ref"
146
+ }
147
+ },
148
+ "required": ["description", "items", "type"]
149
+ }
150
+ ]
151
+ }
152
+ },
153
+ "properties": {
154
+ "definitions": {
155
+ "additionalProperties": {
156
+ "$ref": "#/definitions/resource"
157
+ }
158
+ },
159
+ "properties": {
160
+ "additionalProperties": {
161
+ "$ref": "#/definitions/ref"
162
+ }
163
+ }
164
+ },
165
+ "required": [
166
+ "$schema",
167
+ "definitions",
168
+ "description",
169
+ "id",
170
+ "links",
171
+ "properties",
172
+ "title",
173
+ "type"
174
+ ]
175
+ }