prmd 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/README.md +21 -4
  4. data/docs/schemata.md +4 -0
  5. data/lib/prmd/core/combiner.rb +4 -34
  6. data/lib/prmd/core/reference_localizer.rb +93 -0
  7. data/lib/prmd/load_schema_file.rb +3 -14
  8. data/lib/prmd/multi_loader.rb +2 -0
  9. data/lib/prmd/multi_loader/json.rb +19 -0
  10. data/lib/prmd/multi_loader/loader.rb +128 -0
  11. data/lib/prmd/multi_loader/toml.rb +19 -0
  12. data/lib/prmd/multi_loader/yajl.rb +19 -0
  13. data/lib/prmd/multi_loader/yaml.rb +19 -0
  14. data/lib/prmd/multi_loader/yml.rb +2 -0
  15. data/lib/prmd/rake_tasks/base.rb +33 -5
  16. data/lib/prmd/rake_tasks/combine.rb +20 -4
  17. data/lib/prmd/rake_tasks/doc.rb +24 -8
  18. data/lib/prmd/rake_tasks/verify.rb +17 -5
  19. data/lib/prmd/schema.rb +5 -1
  20. data/lib/prmd/templates/combine_head.json +3 -3
  21. data/lib/prmd/templates/init_default.json +5 -3
  22. data/lib/prmd/templates/init_resource.json.erb +18 -1
  23. data/lib/prmd/templates/schemata.md.erb +3 -0
  24. data/lib/prmd/templates/schemata/helper.erb +20 -0
  25. data/lib/prmd/templates/schemata/link.md.erb +11 -1
  26. data/lib/prmd/templates/schemata/link_curl_example.md.erb +8 -5
  27. data/lib/prmd/version.rb +1 -1
  28. data/test/commands/render_test.rb +60 -0
  29. data/test/core/reference_localizer_test.rb +65 -0
  30. data/test/helpers.rb +25 -3
  31. data/test/multi_loader/common.rb +35 -0
  32. data/test/multi_loader/json_test.rb +14 -0
  33. data/test/multi_loader/toml_test.rb +18 -0
  34. data/test/multi_loader/yajl_test.rb +18 -0
  35. data/test/multi_loader/yaml_test.rb +14 -0
  36. data/test/rake_tasks/combine_test.rb +38 -0
  37. data/test/rake_tasks/doc_test.rb +31 -0
  38. data/test/rake_tasks/verify_test.rb +23 -0
  39. data/test/schemata/data/test.json +6 -0
  40. data/test/schemata/data/test.toml +4 -0
  41. data/test/schemata/data/test.yaml +3 -0
  42. data/test/schemata/input/rake-meta.json +9 -0
  43. data/test/schemata/input/rake_combine/post.json +100 -0
  44. data/test/schemata/input/rake_combine/user.json +100 -0
  45. data/test/schemata/input/rake_doc.json +223 -0
  46. data/test/schemata/input/rake_verify.json +223 -0
  47. metadata +44 -3
  48. data/Gemfile.lock +0 -23
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 92c67299c0bc9e4bec5141b516ec7fa78d841f6d
4
- data.tar.gz: dbcdf2ec6712b37f5980904e998d7085d3ca6dc9
3
+ metadata.gz: f2d8980d47308e01724a4038226dcb44581cd4ad
4
+ data.tar.gz: 528abc2bf4b32d96469d27453bf011944a43e0fe
5
5
  SHA512:
6
- metadata.gz: bc6d901ec87dc0df4882265c7d5f95210f5bcf2777dda10870366547aabe9b42a90adc8007fa872b925f35ac1b192237a1c2eaebe8464f3b4083cad8405e90a5
7
- data.tar.gz: 2b117de96b7c80c06db4e7173d3954265531ab3f70df26512118854ea6025068e3d0852cc615f1c79a5da84bd5609a4c9ba95824f5292fef9ca41cfd393db06d
6
+ metadata.gz: af62a75a4a3cba5bec58e76be3ce9243697abbfec32fded14745a1f89cc29b32a7344b4fbd1fd2a3559b97a9b2ebce2eeb097f448a836353a52b52388e556587
7
+ data.tar.gz: e67e0d992a1ac14686565ddb53c071b46055ee8e57bb61fc149afb5c32fd458969cd080f87c5db1b57eb90d7f84c1f466250214eba8a22f1a61cc64508d22732
data/.gitignore CHANGED
@@ -17,3 +17,4 @@ tmp
17
17
  .yardoc
18
18
  _yardoc
19
19
  doc/
20
+ Gemfile.lock
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
- ```json
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
@@ -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" },
@@ -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
- case datum
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
- # :nodoc:
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
- extname = File.extname(filename)
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,2 @@
1
+ require 'prmd/multi_loader/json'
2
+ require 'prmd/multi_loader/yaml'
@@ -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