prmd 0.3.2 → 0.4.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.
@@ -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
+ }