skeleton 0.3.3 → 0.4.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 +140 -65
- data/Rakefile +10 -3
- data/lib/skeleton.rb +6 -10
- data/lib/skeleton/contact.rb +1 -13
- data/lib/skeleton/error.rb +4 -0
- data/lib/skeleton/graph.rb +56 -0
- data/lib/skeleton/header.rb +2 -63
- data/lib/skeleton/items.rb +34 -0
- data/lib/skeleton/license.rb +1 -12
- data/lib/skeleton/model.rb +13 -17
- data/lib/skeleton/operation.rb +50 -121
- data/lib/skeleton/parameter.rb +31 -88
- data/lib/skeleton/parameters.rb +40 -0
- data/lib/skeleton/path.rb +42 -80
- data/lib/skeleton/presenter.rb +19 -0
- data/lib/skeleton/property.rb +6 -0
- data/lib/skeleton/response.rb +24 -45
- data/lib/skeleton/schema.rb +80 -63
- data/lib/skeleton/scope.rb +18 -0
- data/lib/skeleton/security_scheme.rb +19 -37
- data/lib/skeleton/serializers/options.rb +215 -0
- data/lib/skeleton/serializers/swagger.rb +197 -0
- data/lib/skeleton/structure.rb +92 -138
- data/lib/skeleton/swagger.rb +9 -0
- data/lib/skeleton/tag.rb +11 -16
- data/lib/skeleton/version.rb +1 -1
- data/skeleton.gemspec +2 -0
- data/test/fixtures/json-schema-draft-04.json +150 -0
- data/test/fixtures/schema.json +1482 -0
- data/test/integrations/validate_complex_schema_spec.rb +42 -0
- data/test/skeleton/graph_test.rb +22 -0
- data/test/skeleton/mapper_test.rb +84 -0
- data/test/skeleton/operation_test.rb +11 -0
- data/test/skeleton/parameter_test.rb +34 -0
- data/test/skeleton/parameters_test.rb +9 -0
- data/test/skeleton/path_test.rb +46 -0
- data/test/skeleton/property_test.rb +8 -0
- data/test/skeleton/serializers/options_test.rb +68 -0
- data/test/skeleton/serializers/swagger_test.rb +30 -0
- data/test/support/factories/structure_factory.rb +86 -0
- data/test/support/fixtures.rb +6 -0
- data/test/support/kissmetrics/core_api.rb +542 -0
- data/{spec/spec_helper.rb → test/test_helper.rb} +7 -1
- metadata +73 -25
- data/lib/skeleton/config.rb +0 -37
- data/lib/skeleton/documentation.rb +0 -17
- data/lib/skeleton/example.rb +0 -31
- data/lib/skeleton/headers.rb +0 -50
- data/lib/skeleton/helpers/controller_helpers.rb +0 -25
- data/lib/skeleton/info.rb +0 -40
- data/lib/skeleton/item.rb +0 -99
- data/lib/skeleton/responses.rb +0 -59
- data/lib/skeleton/scopes.rb +0 -24
- data/lib/skeleton/security_definitions.rb +0 -46
- data/lib/skeleton/security_requirement.rb +0 -29
- data/spec/integrations/use_case_spec.rb +0 -131
- data/spec/skeleton/operation_spec.rb +0 -113
- data/spec/skeleton/serializers/contact_spec.rb +0 -30
- data/spec/skeleton/serializers/documentation_spec.rb +0 -23
- data/spec/skeleton/serializers/header_spec.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9294bad43773b066e5ce9b168b882617f614d8a2
|
4
|
+
data.tar.gz: ff3a33117c6924c76cec5478162571f44f761c07
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b22eccf0dbd13780cb453fe23a6c24391dd47de28786b113be1944acc7d5c0e79bc2b2889ec3e5c7d0947b1dc50472fbe28d944bdc5c2a8401e64dfe65136ad4
|
7
|
+
data.tar.gz: e8de75ff865e644fcd3e6966b8f541a5710fef50e3f6e95ff3f2d1d80590e36973d465717b904e55ed4c44632bda3d0e933e1b07a03cfc7c44ea79dc3be8ca3a
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -7,88 +7,162 @@ running code.
|
|
7
7
|
|
8
8
|
```ruby
|
9
9
|
# You would put this somewhere such as config/initializers/skeleton.rb
|
10
|
-
Skeleton.
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
structure.schemes = %w(https)
|
16
|
-
structure.consumes = %(application/json)
|
17
|
-
structure.produces = %(application/json)
|
18
|
-
end
|
10
|
+
structure = Skeleton.build do |s|
|
11
|
+
s.title = 'KISSmetrics API'
|
12
|
+
s.version = '1.0.0'
|
13
|
+
s.description = 'A simply complex skeleton'
|
19
14
|
|
20
|
-
|
21
|
-
info.version = '1.0.6'
|
22
|
-
info.title = 'An Example API'
|
23
|
-
info.description = 'An api to interact with data'
|
24
|
-
info.terms_of_service = 'https://api.example.com/terms/'
|
25
|
-
end
|
15
|
+
s.terms = 'https://www.kissmetrics.com/terms'
|
26
16
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
contact.url = 'https://github.com/warmwaffles/skeleton'
|
31
|
-
end
|
17
|
+
s.contact.name = 'KISSmetrics'
|
18
|
+
s.contact.email = 'support@kissmetrics.com'
|
19
|
+
s.contact.url = 'https://support.kissmetrics.com'
|
32
20
|
|
33
|
-
|
34
|
-
|
35
|
-
|
21
|
+
s.license.name = 'KISSmetrics'
|
22
|
+
s.license.url = 'https://www.kissmetrics.com'
|
23
|
+
|
24
|
+
s.host = 'api.kissmetrics.com'
|
25
|
+
s.base_path = '/core'
|
26
|
+
s.scheme(:https)
|
27
|
+
s.consume('application/json')
|
28
|
+
s.produce('application/json')
|
36
29
|
end
|
37
30
|
```
|
38
31
|
|
39
|
-
|
32
|
+
## Defining models
|
40
33
|
|
41
34
|
```ruby
|
42
|
-
|
43
|
-
|
35
|
+
structure.define_model('Link') do
|
36
|
+
describe('The link object used for api discovery')
|
37
|
+
required(:href, type: 'string')
|
38
|
+
required(:rel, type: 'string')
|
39
|
+
optional(:templated, type: 'boolean')
|
40
|
+
optional(:name, type: 'string')
|
41
|
+
end
|
42
|
+
|
43
|
+
structure.define_model('Error') do
|
44
|
+
describe('Represents an error')
|
45
|
+
required(:message, type: 'string')
|
46
|
+
optional(:field, type: 'string')
|
47
|
+
optional(:errors, type: 'array', items: { ref: 'Error' })
|
48
|
+
end
|
49
|
+
|
50
|
+
structure.define_model('Meta') do
|
51
|
+
describe('The meta information regarding the request')
|
52
|
+
required(:status, type: 'integer')
|
53
|
+
optional(:message, type: 'string')
|
54
|
+
optional(:errors, type: 'array', items: { ref: 'Error' })
|
44
55
|
end
|
45
56
|
```
|
46
57
|
|
47
|
-
|
58
|
+
If you wish to reference a definition from within another model, all you need to
|
59
|
+
do is to pass a `:ref`. If you want to know more about this structure, please
|
60
|
+
see the swagger documentation.
|
61
|
+
|
62
|
+
## Defining paths
|
48
63
|
|
49
64
|
```ruby
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
skeleton.define_path('/products') do
|
66
|
+
get do
|
67
|
+
identify('list-products')
|
68
|
+
tag('product')
|
69
|
+
summarize('List products')
|
70
|
+
describe('List all of the products')
|
71
|
+
|
72
|
+
parameters(:query) do
|
73
|
+
optional(:limit, type: 'integer', format: 'int32', default: 20, maximum: 50, minimum: 0)
|
74
|
+
optional(:offset, type: 'integer', format: 'int32', default: 0)
|
75
|
+
end
|
76
|
+
|
77
|
+
response(200, default: true) do
|
78
|
+
describe('Product list')
|
79
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
80
|
+
schema(ref: 'Product')
|
81
|
+
end
|
82
|
+
|
83
|
+
response(403) do
|
84
|
+
describe('Unauthorized')
|
85
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
86
|
+
schema(ref: 'ErrorResponse')
|
68
87
|
end
|
69
88
|
end
|
70
89
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
p.required = true
|
80
|
-
end
|
90
|
+
head do
|
91
|
+
tag('product')
|
92
|
+
summarize('List products headers')
|
93
|
+
describe('List the headers for the products action')
|
94
|
+
|
95
|
+
parameters(:query) do
|
96
|
+
optional(:limit, type: 'integer', format: 'int32', default: 20, maximum: 50, minimum: 0)
|
97
|
+
optional(:offset, type: 'integer', format: 'int32', default: 0)
|
81
98
|
end
|
82
99
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
100
|
+
response(200, default: true) do
|
101
|
+
describe('Product list')
|
102
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
103
|
+
end
|
104
|
+
|
105
|
+
response(403) do
|
106
|
+
describe('Unauthorized')
|
107
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
post do
|
112
|
+
tag('product')
|
113
|
+
summarize('Create product')
|
114
|
+
describe('Create a product')
|
115
|
+
|
116
|
+
parameters(:body) do
|
117
|
+
required(:body, schema: { ref: 'NewProduct' })
|
118
|
+
end
|
119
|
+
|
120
|
+
response(201) do
|
121
|
+
describe('Product created')
|
122
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
123
|
+
schema(ref: 'Product')
|
124
|
+
end
|
125
|
+
|
126
|
+
response(400) do
|
127
|
+
describe('Client error')
|
128
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
129
|
+
schema(ref: 'ErrorResponse')
|
130
|
+
end
|
131
|
+
|
132
|
+
response(403) do
|
133
|
+
describe('Unauthorized')
|
134
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
135
|
+
schema(ref: 'ErrorResponse')
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
options do
|
140
|
+
tag('product')
|
141
|
+
summarize('List actions for a product')
|
142
|
+
describe('List actions for a product')
|
143
|
+
|
144
|
+
parameters(:query) do
|
145
|
+
optional(:limit, type: 'integer', format: 'int32', default: 20, maximum: 50, minimum: 0)
|
146
|
+
optional(:offset, type: 'integer', format: 'int32', default: 0)
|
147
|
+
end
|
148
|
+
|
149
|
+
response(200, default: true) do
|
150
|
+
describe('Product action list')
|
151
|
+
header('Allow', type: 'array', items: { type: 'string' }, collection_format: 'csv')
|
152
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
153
|
+
schema(ref: 'OptionsResponse')
|
154
|
+
end
|
155
|
+
|
156
|
+
response(400) do
|
157
|
+
describe('Client error')
|
158
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
159
|
+
schema(ref: 'ErrorResponse')
|
160
|
+
end
|
161
|
+
|
162
|
+
response(403) do
|
163
|
+
describe('Unauthorized')
|
164
|
+
header('Link', type: 'string', description: 'The list of links for the resource')
|
165
|
+
schema(ref: 'ErrorResponse')
|
92
166
|
end
|
93
167
|
end
|
94
168
|
end
|
@@ -102,7 +176,8 @@ class DocumentationController < ApplicationController
|
|
102
176
|
def swagger
|
103
177
|
respond_to do |format|
|
104
178
|
format.json do
|
105
|
-
|
179
|
+
serializer = Skeleton::Serializers::Swagger.new(my_structure)
|
180
|
+
render(json: MultiJson.dump(serializer.to_h), status: 200)
|
106
181
|
end
|
107
182
|
end
|
108
183
|
end
|
data/Rakefile
CHANGED
@@ -2,16 +2,23 @@ require 'bundler/gem_tasks'
|
|
2
2
|
|
3
3
|
namespace :test do
|
4
4
|
task :env do
|
5
|
-
$LOAD_PATH.unshift('lib', '
|
5
|
+
$LOAD_PATH.unshift('lib', 'test')
|
6
6
|
end
|
7
7
|
|
8
8
|
desc 'Runs only the specs in this project'
|
9
9
|
task :specs => [:env] do
|
10
|
-
Dir.glob('./
|
10
|
+
Dir.glob('./test/**/*_spec.rb') { |f| require f }
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Runs only the test units in this project'
|
14
|
+
task :units => [:env] do
|
15
|
+
Dir.glob('./test/**/*_test.rb') { |f| require f }
|
11
16
|
end
|
12
17
|
|
13
18
|
desc 'Runs all of the tests within this project'
|
14
|
-
task :all => [:
|
19
|
+
task :all => [:env] do
|
20
|
+
Dir.glob('./test/**/*_{spec,test}.rb') { |f| require f }
|
21
|
+
end
|
15
22
|
end
|
16
23
|
|
17
24
|
desc 'Runs all of the tests within this project'
|
data/lib/skeleton.rb
CHANGED
@@ -1,20 +1,16 @@
|
|
1
1
|
require 'skeleton/version'
|
2
2
|
require 'skeleton/structure'
|
3
|
-
require 'skeleton/
|
4
|
-
require 'skeleton/
|
3
|
+
require 'skeleton/serializers/swagger'
|
4
|
+
require 'skeleton/serializers/options'
|
5
5
|
|
6
6
|
module Skeleton
|
7
|
+
# Allows you to build a skeleton structure from within a block
|
8
|
+
#
|
9
|
+
# @return [Skeleton::Structure]
|
7
10
|
def self.build(&block)
|
8
11
|
structure = Skeleton::Structure.new
|
9
12
|
yield(structure) if block
|
10
13
|
structure
|
11
14
|
end
|
12
|
-
|
13
|
-
def self.config
|
14
|
-
@config ||= Skeleton::Config.new
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.configure(&block)
|
18
|
-
yield(config) if block
|
19
|
-
end
|
20
15
|
end
|
16
|
+
|
data/lib/skeleton/contact.rb
CHANGED
@@ -1,17 +1,5 @@
|
|
1
|
-
require 'skeleton/model'
|
2
|
-
|
3
1
|
module Skeleton
|
4
|
-
class Contact
|
2
|
+
class Contact
|
5
3
|
attr_accessor :name, :email, :url
|
6
|
-
attr_presence :name, :email, :url
|
7
|
-
|
8
|
-
def to_h
|
9
|
-
hash = {}
|
10
|
-
hash[:name] = name if name?
|
11
|
-
hash[:email] = email if email?
|
12
|
-
hash[:url] = url if url?
|
13
|
-
hash
|
14
|
-
end
|
15
|
-
alias_method :to_swagger_hash, :to_h
|
16
4
|
end
|
17
5
|
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'tsort'
|
3
|
+
|
4
|
+
module Skeleton
|
5
|
+
class Graph
|
6
|
+
include Enumerable
|
7
|
+
include TSort
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@dep = Hash.new { |h,k| h[k] = Set.new }
|
11
|
+
end
|
12
|
+
|
13
|
+
# Register a dependency
|
14
|
+
#
|
15
|
+
# @param base [Object] the base object
|
16
|
+
# @param list [Object,Array] list of dependents
|
17
|
+
def register(base, *list)
|
18
|
+
dependents = Array(list).flatten
|
19
|
+
@dep[base] ||= Set.new
|
20
|
+
@dep[base].merge(dependents)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Iterate over each of the nodes in this graph with their edge
|
24
|
+
#
|
25
|
+
# @return [void]
|
26
|
+
def each(&block)
|
27
|
+
@dep.each do |base, set|
|
28
|
+
set.each do |name|
|
29
|
+
yield(base, name) if block
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Takes all of the nodes in this graph and creates a set with them
|
35
|
+
#
|
36
|
+
# @return [Set]
|
37
|
+
def to_set
|
38
|
+
set = Set.new
|
39
|
+
@dep.each do |base, deps|
|
40
|
+
set.add(base)
|
41
|
+
set.merge(deps)
|
42
|
+
end
|
43
|
+
set
|
44
|
+
end
|
45
|
+
|
46
|
+
def each_dependent_for(base, &block)
|
47
|
+
each_strongly_connected_component_from(base) do |dependent, _|
|
48
|
+
yield(dependent)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def tsort_each_child(node, &block)
|
53
|
+
@dep[node].each(&block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/skeleton/header.rb
CHANGED
@@ -1,67 +1,6 @@
|
|
1
|
-
require 'skeleton/
|
1
|
+
require 'skeleton/schema'
|
2
2
|
|
3
3
|
module Skeleton
|
4
|
-
class Header <
|
5
|
-
attr_accessor :type, :format, :title, :description, :default, :multiple_of,
|
6
|
-
:maximum, :exclusive_maximum, :minimum, :exclusive_minimum,
|
7
|
-
:max_length, :min_length, :pattern, :max_items, :min_items,
|
8
|
-
:unique_items, :max_properties, :min_properties
|
9
|
-
|
10
|
-
attr_writer :enum
|
11
|
-
attr_presence :exclusive_maximum, :exclusive_minimum, :unique_items
|
12
|
-
|
13
|
-
def enum
|
14
|
-
@enum ||= []
|
15
|
-
end
|
16
|
-
|
17
|
-
def enum?
|
18
|
-
!enum.empty?
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_h
|
22
|
-
hash = {}
|
23
|
-
hash[:description] = header.description if header.description?
|
24
|
-
hash[:type] = header.type if header.type?
|
25
|
-
hash[:format] = header.format if header.format?
|
26
|
-
hash[:items] = header.items if header.items?
|
27
|
-
hash[:collection_format] = header.collection_format if header.collection_format?
|
28
|
-
hash[:default] = header.default if header.default?
|
29
|
-
hash[:maximum] = header.maximum if header.maximum?
|
30
|
-
hash[:exclusive_maximum] = header.exclusive_maximum if header.exclusive_maximum?
|
31
|
-
hash[:minimum] = header.minimum if header.minimum?
|
32
|
-
hash[:exclusive_minimum] = header.exclusive_minimum if header.exclusive_minimum?
|
33
|
-
hash[:max_length] = header.max_length if header.max_length?
|
34
|
-
hash[:min_length] = header.min_length if header.min_length?
|
35
|
-
hash[:pattern] = header.pattern if header.pattern?
|
36
|
-
hash[:max_items] = header.max_items if header.max_items?
|
37
|
-
hash[:min_items] = header.min_items if header.min_items?
|
38
|
-
hash[:unique_items] = header.unique_items if header.unique_items?
|
39
|
-
hash[:enum] = header.enum if header.enum?
|
40
|
-
hash[:multiple_of] = header.multiple_of if header.multiple_of?
|
41
|
-
hash
|
42
|
-
end
|
43
|
-
|
44
|
-
def to_swagger_hash
|
45
|
-
hash = {}
|
46
|
-
hash[:description] = header.description if header.description?
|
47
|
-
hash[:type] = header.type if header.type?
|
48
|
-
hash[:format] = header.format if header.format?
|
49
|
-
hash[:items] = header.items if header.items?
|
50
|
-
hash[:collectionFormat] = header.collection_format if header.collection_format?
|
51
|
-
hash[:default] = header.default if header.default?
|
52
|
-
hash[:maximum] = header.maximum if header.maximum?
|
53
|
-
hash[:exclusiveMaximum] = header.exclusive_maximum if header.exclusive_maximum?
|
54
|
-
hash[:minimum] = header.minimum if header.minimum?
|
55
|
-
hash[:exclusiveMinimum] = header.exclusive_minimum if header.exclusive_minimum?
|
56
|
-
hash[:maxLength] = header.max_length if header.max_length?
|
57
|
-
hash[:minLength] = header.min_length if header.min_length?
|
58
|
-
hash[:pattern] = header.pattern if header.pattern?
|
59
|
-
hash[:maxItems] = header.max_items if header.max_items?
|
60
|
-
hash[:minItems] = header.min_items if header.min_items?
|
61
|
-
hash[:uniqueItems] = header.unique_items if header.unique_items?
|
62
|
-
hash[:enum] = header.enum if header.enum?
|
63
|
-
hash[:multipleOf] = header.multiple_of if header.multiple_of?
|
64
|
-
hash
|
65
|
-
end
|
4
|
+
class Header < Schema
|
66
5
|
end
|
67
6
|
end
|