prmd 0.7.0 → 0.7.1
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 +4 -4
- data/.gitignore +1 -0
- data/README.md +21 -4
- data/docs/schemata.md +4 -0
- data/lib/prmd/core/combiner.rb +4 -34
- data/lib/prmd/core/reference_localizer.rb +93 -0
- data/lib/prmd/load_schema_file.rb +3 -14
- data/lib/prmd/multi_loader.rb +2 -0
- data/lib/prmd/multi_loader/json.rb +19 -0
- data/lib/prmd/multi_loader/loader.rb +128 -0
- data/lib/prmd/multi_loader/toml.rb +19 -0
- data/lib/prmd/multi_loader/yajl.rb +19 -0
- data/lib/prmd/multi_loader/yaml.rb +19 -0
- data/lib/prmd/multi_loader/yml.rb +2 -0
- data/lib/prmd/rake_tasks/base.rb +33 -5
- data/lib/prmd/rake_tasks/combine.rb +20 -4
- data/lib/prmd/rake_tasks/doc.rb +24 -8
- data/lib/prmd/rake_tasks/verify.rb +17 -5
- data/lib/prmd/schema.rb +5 -1
- data/lib/prmd/templates/combine_head.json +3 -3
- data/lib/prmd/templates/init_default.json +5 -3
- data/lib/prmd/templates/init_resource.json.erb +18 -1
- data/lib/prmd/templates/schemata.md.erb +3 -0
- data/lib/prmd/templates/schemata/helper.erb +20 -0
- data/lib/prmd/templates/schemata/link.md.erb +11 -1
- data/lib/prmd/templates/schemata/link_curl_example.md.erb +8 -5
- data/lib/prmd/version.rb +1 -1
- data/test/commands/render_test.rb +60 -0
- data/test/core/reference_localizer_test.rb +65 -0
- data/test/helpers.rb +25 -3
- data/test/multi_loader/common.rb +35 -0
- data/test/multi_loader/json_test.rb +14 -0
- data/test/multi_loader/toml_test.rb +18 -0
- data/test/multi_loader/yajl_test.rb +18 -0
- data/test/multi_loader/yaml_test.rb +14 -0
- data/test/rake_tasks/combine_test.rb +38 -0
- data/test/rake_tasks/doc_test.rb +31 -0
- data/test/rake_tasks/verify_test.rb +23 -0
- data/test/schemata/data/test.json +6 -0
- data/test/schemata/data/test.toml +4 -0
- data/test/schemata/data/test.yaml +3 -0
- data/test/schemata/input/rake-meta.json +9 -0
- data/test/schemata/input/rake_combine/post.json +100 -0
- data/test/schemata/input/rake_combine/user.json +100 -0
- data/test/schemata/input/rake_doc.json +223 -0
- data/test/schemata/input/rake_verify.json +223 -0
- metadata +44 -3
- data/Gemfile.lock +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2d8980d47308e01724a4038226dcb44581cd4ad
|
4
|
+
data.tar.gz: 528abc2bf4b32d96469d27453bf011944a43e0fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af62a75a4a3cba5bec58e76be3ce9243697abbfec32fded14745a1f89cc29b32a7344b4fbd1fd2a3559b97a9b2ebce2eeb097f448a836353a52b52388e556587
|
7
|
+
data.tar.gz: e67e0d992a1ac14686565ddb53c071b46055ee8e57bb61fc149afb5c32fd458969cd080f87c5db1b57eb90d7f84c1f466250214eba8a22f1a61cc64508d22732
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -80,6 +80,21 @@ $ prmd verify schema.json
|
|
80
80
|
$ prmd doc schema.json > schema.md
|
81
81
|
```
|
82
82
|
|
83
|
+
### Using YAML instead of JSON as a resource and meta format
|
84
|
+
|
85
|
+
`init` and `combine` supports YAML format:
|
86
|
+
|
87
|
+
```bash
|
88
|
+
# Generate resources in YAML format
|
89
|
+
$ prmd init --yaml app > schemata/app.yml
|
90
|
+
$ prmd init --yaml user > schemata/user.yml
|
91
|
+
|
92
|
+
# Combine into a single schema
|
93
|
+
$ prmd combine --meta meta.json schemata/ > schema.json
|
94
|
+
```
|
95
|
+
|
96
|
+
`combine` can detect both `*.yml` and `*.json` and use them side by side. For example, if one have a lot of legacy JSON resources and wants to create new resources in YAML format - `combine` will be able to handle it properly.
|
97
|
+
|
83
98
|
# Render from schema
|
84
99
|
|
85
100
|
```bash
|
@@ -110,7 +125,7 @@ $ prmd doc --settings config.json schema.json > schema.md
|
|
110
125
|
```
|
111
126
|
|
112
127
|
Available options (and their defaults)
|
113
|
-
```
|
128
|
+
```js
|
114
129
|
{
|
115
130
|
"doc": {
|
116
131
|
"url_style": "default", // can also be "json"
|
@@ -131,7 +146,7 @@ require 'prmd/rake_tasks/doc'
|
|
131
146
|
|
132
147
|
namespace :schema do
|
133
148
|
Prmd::RakeTasks::Combine.new do |t|
|
134
|
-
t.options[:meta] = 'schema/meta.json'
|
149
|
+
t.options[:meta] = 'schema/meta.json' # use meta.yml if you prefer YAML format
|
135
150
|
t.paths << 'schema/schemata/api'
|
136
151
|
t.output_file = 'schema/api.json'
|
137
152
|
end
|
@@ -156,13 +171,15 @@ We suggest the following file layout for JSON schema related files:
|
|
156
171
|
/docs (top-level directory for project documentation)
|
157
172
|
/schema (API schema documentation)
|
158
173
|
/schemata
|
159
|
-
/{resource.json} (individual resource schema)
|
160
|
-
/meta.json (overall API metadata)
|
174
|
+
/{resource.[json,yml]} (individual resource schema)
|
175
|
+
/meta.[json,yml] (overall API metadata)
|
161
176
|
/overview.md (preamble for generated API docs)
|
162
177
|
/schema.json (complete generated JSON schema file)
|
163
178
|
/schema.md (complete generated API documentation file)
|
164
179
|
```
|
165
180
|
|
181
|
+
where `[json,yml]` means that it could be either `json` or `yml`.
|
182
|
+
|
166
183
|
## Contributing
|
167
184
|
|
168
185
|
1. Fork it
|
data/docs/schemata.md
CHANGED
@@ -84,6 +84,9 @@ Links that expect a json-encoded body as input MUST also include the following a
|
|
84
84
|
The `schema` object MAY also include a `required` array to define all attributes for this link, which can not be omitted.
|
85
85
|
If this field is not present, all attributes in this link are considered as optional.
|
86
86
|
|
87
|
+
Links that expect a custom http header MUST include the following attributes:
|
88
|
+
* `http_header` - an object which has the key as the header name, and value as an example header value.
|
89
|
+
|
87
90
|
```javascript
|
88
91
|
{
|
89
92
|
"links": [
|
@@ -92,6 +95,7 @@ If this field is not present, all attributes in this link are considered as opti
|
|
92
95
|
"href": "/resources",
|
93
96
|
"method": "POST",
|
94
97
|
"rel": "create",
|
98
|
+
"http_header": { "Custom-Header": "examplevalue" },
|
95
99
|
"schema": {
|
96
100
|
"properties": {
|
97
101
|
"owner": { "$ref": "/schemata/user#/definitions/identity" },
|
data/lib/prmd/core/combiner.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'prmd/schema'
|
2
2
|
require 'prmd/core/schema_hash'
|
3
|
+
require 'prmd/core/reference_localizer'
|
3
4
|
|
4
5
|
# :nodoc:
|
5
6
|
module Prmd
|
@@ -14,39 +15,10 @@ module Prmd
|
|
14
15
|
@meta = properties.fetch(:meta, {})
|
15
16
|
end
|
16
17
|
|
17
|
-
# @param [Array] array
|
18
|
-
# @return [Array]
|
19
|
-
def reference_localizer_array(array)
|
20
|
-
array.map { |element| reference_localizer(element) }
|
21
|
-
end
|
22
|
-
|
23
|
-
# @param [Hash] hash
|
24
|
-
# @return [Hash]
|
25
|
-
def reference_localizer_hash(hash)
|
26
|
-
if hash.key?('$ref')
|
27
|
-
hash['$ref'] = '#/definitions' + hash['$ref'].gsub('#', '')
|
28
|
-
.gsub('/schemata', '')
|
29
|
-
end
|
30
|
-
if hash.key?('href') && hash['href'].is_a?(String)
|
31
|
-
hash['href'] = hash['href'].gsub('%23', '')
|
32
|
-
.gsub(/%2Fschemata(%2F[^%]*%2F)/,
|
33
|
-
'%23%2Fdefinitions\1')
|
34
|
-
end
|
35
|
-
hash.each_with_object({}) { |(k, v), r| r[k] = reference_localizer(v) }
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
18
|
# @param [Object] datum
|
40
19
|
# @return [Object]
|
41
20
|
def reference_localizer(datum)
|
42
|
-
|
43
|
-
when Array
|
44
|
-
reference_localizer_array(datum)
|
45
|
-
when Hash
|
46
|
-
reference_localizer_hash(datum)
|
47
|
-
else
|
48
|
-
datum
|
49
|
-
end
|
21
|
+
ReferenceLocalizer.localize(datum)
|
50
22
|
end
|
51
23
|
|
52
24
|
#
|
@@ -65,8 +37,8 @@ module Prmd
|
|
65
37
|
id_ary = id.split('/').last
|
66
38
|
|
67
39
|
if s = schemata_map[id]
|
68
|
-
$stderr.puts "`#{id}` (from #{schema.filename}) was already defined" \
|
69
|
-
"in `#{s.filename}` and will overwrite the first" \
|
40
|
+
$stderr.puts "`#{id}` (from #{schema.filename}) was already defined " \
|
41
|
+
"in `#{s.filename}` and will overwrite the first " \
|
70
42
|
"definition"
|
71
43
|
end
|
72
44
|
# avoinding damaging the original schema
|
@@ -84,8 +56,6 @@ module Prmd
|
|
84
56
|
Prmd::Schema.new(data)
|
85
57
|
end
|
86
58
|
|
87
|
-
private :reference_localizer_array
|
88
|
-
private :reference_localizer_hash
|
89
59
|
private :reference_localizer
|
90
60
|
end
|
91
61
|
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# :nodoc:
|
2
|
+
module Prmd
|
3
|
+
# @api private
|
4
|
+
# Schema references localizer
|
5
|
+
class ReferenceLocalizer
|
6
|
+
attr_reader :object
|
7
|
+
|
8
|
+
# @param [Object] object
|
9
|
+
def initialize(object)
|
10
|
+
@object = object
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param [Object] object
|
14
|
+
# @return [ReferenceLocalizer]
|
15
|
+
def self.build(object)
|
16
|
+
case object
|
17
|
+
when Array
|
18
|
+
ForArray
|
19
|
+
when Hash
|
20
|
+
ForHash
|
21
|
+
else
|
22
|
+
self
|
23
|
+
end.new(object)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @param [Object] object
|
27
|
+
# @return [Object]
|
28
|
+
def self.localize(object)
|
29
|
+
build(object).localize
|
30
|
+
end
|
31
|
+
|
32
|
+
# @return [Object]
|
33
|
+
def localize
|
34
|
+
object
|
35
|
+
end
|
36
|
+
|
37
|
+
private :object
|
38
|
+
|
39
|
+
# @api private
|
40
|
+
# Schema references localizer for arrays
|
41
|
+
class ForArray < self
|
42
|
+
alias_method :array, :object
|
43
|
+
|
44
|
+
# @return [Array]
|
45
|
+
def localize
|
46
|
+
array.map { |element| ReferenceLocalizer.localize(element) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @api private
|
51
|
+
# Schema references localizer for hashes
|
52
|
+
class ForHash < self
|
53
|
+
alias_method :hash, :object
|
54
|
+
|
55
|
+
# @return [Hash]
|
56
|
+
def localize
|
57
|
+
localize_ref
|
58
|
+
localize_href
|
59
|
+
localize_values
|
60
|
+
end
|
61
|
+
|
62
|
+
def localize_ref
|
63
|
+
return unless hash.key?('$ref')
|
64
|
+
hash['$ref'] = '#/definitions' + local_reference
|
65
|
+
end
|
66
|
+
|
67
|
+
def localize_href
|
68
|
+
return unless hash.key?('href') && hash['href'].is_a?(String)
|
69
|
+
hash['href'] = hash['href'].gsub('%23', '')
|
70
|
+
.gsub(/%2Fschemata(%2F[^%]*%2F)/,
|
71
|
+
'%23%2Fdefinitions\1')
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [Hash]
|
75
|
+
def localize_values
|
76
|
+
hash.each_with_object({}) { |(k, v), r| r[k] = ReferenceLocalizer.localize(v) }
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [String]
|
80
|
+
def local_reference
|
81
|
+
ref = hash['$ref']
|
82
|
+
# clean out leading #/definitions to not create a duplicate one
|
83
|
+
ref = ref.gsub(/^#\/definitions\//, '#/') while ref.match(/^#\/definitions\//)
|
84
|
+
ref.gsub('#', '').gsub('/schemata', '')
|
85
|
+
end
|
86
|
+
|
87
|
+
private :localize_ref
|
88
|
+
private :localize_href
|
89
|
+
private :localize_values
|
90
|
+
private :local_reference
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -1,25 +1,14 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'json'
|
3
|
+
require 'prmd/multi_loader'
|
3
4
|
|
4
|
-
|
5
|
-
module Prmd
|
5
|
+
module Prmd #:nodoc:
|
6
6
|
# Attempts to load either a json or yaml file, the type is determined by
|
7
7
|
# filename extension.
|
8
8
|
#
|
9
9
|
# @param [String] filename
|
10
10
|
# @return [Object] data
|
11
11
|
def self.load_schema_file(filename)
|
12
|
-
|
13
|
-
File.open(filename) do |file|
|
14
|
-
case extname.downcase
|
15
|
-
when '.yaml', '.yml'
|
16
|
-
YAML.load(file.read)
|
17
|
-
when '.json'
|
18
|
-
JSON.load(file.read)
|
19
|
-
else
|
20
|
-
abort "Cannot load schema file #{filename}" \
|
21
|
-
"(unsupported file extension #{extname})"
|
22
|
-
end
|
23
|
-
end
|
12
|
+
Prmd::MultiLoader.load_file(filename)
|
24
13
|
end
|
25
14
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'prmd/multi_loader/loader'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Prmd #:nodoc:
|
5
|
+
module MultiLoader #:nodoc:
|
6
|
+
# JSON MultiLoader
|
7
|
+
module Json
|
8
|
+
extend Prmd::MultiLoader::Loader
|
9
|
+
|
10
|
+
# @see (Prmd::MultiLoader::Loader#load_data)
|
11
|
+
def self.load_data(data)
|
12
|
+
::JSON.load(data)
|
13
|
+
end
|
14
|
+
|
15
|
+
# register this loader for all .json files
|
16
|
+
extensions '.json'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Prmd #:nodoc:
|
2
|
+
module MultiLoader #:nodoc:
|
3
|
+
# Exception raised when a extension loader cannot be found.
|
4
|
+
class LoaderNotFound < StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Hash<String, Prmd::MultiLoader::Loader>]
|
8
|
+
@file_extensions = {}
|
9
|
+
|
10
|
+
class << self
|
11
|
+
attr_accessor :file_extensions
|
12
|
+
end
|
13
|
+
|
14
|
+
# Attempts to autoload a Loader named +name+
|
15
|
+
#
|
16
|
+
# @param [String]
|
17
|
+
# @return [Boolean] load success
|
18
|
+
def self.autoload_loader(name)
|
19
|
+
# extension names are preceeded with a .
|
20
|
+
# TODO. probably just remove the first .
|
21
|
+
loader_name = name.gsub('.', '')
|
22
|
+
require "prmd/multi_loader/#{loader_name}"
|
23
|
+
true
|
24
|
+
rescue
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
# Locates and returns a loader for the given +ext+
|
29
|
+
# If no extension is found the first time, MultiLoader will attempt
|
30
|
+
# to load one of the same name.
|
31
|
+
#
|
32
|
+
# @param [String] ext
|
33
|
+
# @return [Prmd::MultiLoader::Loader]
|
34
|
+
# @eg
|
35
|
+
# # by default, Prmd does not load the TOML Loader
|
36
|
+
# MultiLoader.loader('.toml')
|
37
|
+
# # this will check the loaders the first time and find that
|
38
|
+
# # there is no Loader for toml, it will then use the ::autoload_loader
|
39
|
+
# # to locate a Loader named "prmd/multi_loader/toml"
|
40
|
+
def self.loader(name)
|
41
|
+
tried_autoload = false
|
42
|
+
begin
|
43
|
+
@file_extensions.fetch(name)
|
44
|
+
rescue KeyError
|
45
|
+
if tried_autoload
|
46
|
+
raise LoaderNotFound, "Loader for extension (#{name}) was not found."
|
47
|
+
else
|
48
|
+
autoload_loader(name)
|
49
|
+
tried_autoload = true
|
50
|
+
retry
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# @param [String] ext
|
56
|
+
# @param [String] data
|
57
|
+
# @eg
|
58
|
+
# Prmd::MultiLoader.load_data('.json', json_string)
|
59
|
+
def self.load_data(ext, data)
|
60
|
+
loader(ext).load_data(data)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @param [String] ext name of the loader also the extension of the stream
|
64
|
+
# @param [IO] stream
|
65
|
+
# @eg
|
66
|
+
# Prmd::MultiLoader.load_stream('.json', io)
|
67
|
+
def self.load_stream(ext, stream)
|
68
|
+
loader(ext).load_stream(stream)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Shortcut for loading any supported file
|
72
|
+
#
|
73
|
+
# @param [String] ext
|
74
|
+
# @param [String] filename
|
75
|
+
# @eg
|
76
|
+
# Prmd::MultiLoader.load_file('my_file.json')
|
77
|
+
def self.load_file(filename)
|
78
|
+
ext = File.extname(filename)
|
79
|
+
loader(ext).load_file(filename)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Base Loader module used to extend all other loaders
|
83
|
+
module Loader
|
84
|
+
# Using the loader, parse or do whatever magic the loader does to the
|
85
|
+
# string to get back data.
|
86
|
+
#
|
87
|
+
# @param [String] data
|
88
|
+
# @return [Object]
|
89
|
+
# @abstract
|
90
|
+
def load_data(data)
|
91
|
+
# overwrite in children
|
92
|
+
end
|
93
|
+
|
94
|
+
# Load a stream
|
95
|
+
#
|
96
|
+
# @param [IO] stream
|
97
|
+
# @return [Object]
|
98
|
+
# @eg
|
99
|
+
# my_io = File.open('my_file.ext', 'r')
|
100
|
+
# my_loader.load_stream(my_io)
|
101
|
+
def load_stream(stream)
|
102
|
+
load_data(stream.read)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Load a file given a +filename+
|
106
|
+
#
|
107
|
+
# @param [String] filename
|
108
|
+
# @return [Object]
|
109
|
+
# @eg
|
110
|
+
# my_loader.load_file('my_file.ext')
|
111
|
+
def load_file(filename)
|
112
|
+
File.open(filename, 'r') { |f| return load_stream(f) }
|
113
|
+
end
|
114
|
+
|
115
|
+
# Register the loader to the +args+ extensions
|
116
|
+
#
|
117
|
+
# @param [Array<String>] args
|
118
|
+
# @eg extensions '.json'
|
119
|
+
def extensions(*args)
|
120
|
+
args.each do |file|
|
121
|
+
Prmd::MultiLoader.file_extensions[file] = self
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
private :extensions
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'prmd/multi_loader/loader'
|
2
|
+
require 'toml'
|
3
|
+
|
4
|
+
module Prmd #:nodoc:
|
5
|
+
module MultiLoader #:nodoc:
|
6
|
+
# TOML MultiLoader
|
7
|
+
module Toml
|
8
|
+
extend Prmd::MultiLoader::Loader
|
9
|
+
|
10
|
+
# @see (Prmd::MultiLoader::Loader#load_data)
|
11
|
+
def self.load_data(data)
|
12
|
+
::TOML.load(data)
|
13
|
+
end
|
14
|
+
|
15
|
+
# register this loader for all .toml files
|
16
|
+
extensions '.toml'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|