skeleton 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +92 -69
- data/Rakefile +2 -7
- data/lib/skeleton.rb +14 -4
- data/lib/skeleton/attributes.rb +19 -0
- data/lib/skeleton/config.rb +38 -0
- data/lib/skeleton/contact.rb +17 -0
- data/lib/skeleton/documentation.rb +17 -0
- data/lib/skeleton/example.rb +20 -6
- data/lib/skeleton/header.rb +67 -0
- data/lib/skeleton/headers.rb +50 -0
- data/lib/skeleton/helpers/controller_helpers.rb +25 -0
- data/lib/skeleton/info.rb +40 -0
- data/lib/skeleton/item.rb +99 -0
- data/lib/skeleton/license.rb +16 -0
- data/lib/skeleton/model.rb +31 -0
- data/lib/skeleton/operation.rb +157 -0
- data/lib/skeleton/parameter.rb +100 -20
- data/lib/skeleton/path.rb +111 -0
- data/lib/skeleton/response.rb +59 -0
- data/lib/skeleton/responses.rb +59 -0
- data/lib/skeleton/schema.rb +70 -0
- data/lib/skeleton/scopes.rb +24 -0
- data/lib/skeleton/security_definitions.rb +46 -0
- data/lib/skeleton/security_requirement.rb +29 -0
- data/lib/skeleton/security_scheme.rb +47 -0
- data/lib/skeleton/serializers/swagger.rb +212 -0
- data/lib/skeleton/structure.rb +191 -0
- data/lib/skeleton/tag.rb +24 -0
- data/lib/skeleton/version.rb +1 -1
- data/spec/integrations/use_case_spec.rb +130 -0
- data/spec/skeleton/operation_spec.rb +113 -0
- data/spec/skeleton/serializers/contact_spec.rb +30 -0
- data/spec/skeleton/serializers/documentation_spec.rb +23 -0
- data/spec/skeleton/serializers/header_spec.rb +57 -0
- data/spec/spec_helper.rb +8 -0
- metadata +36 -15
- data/lib/skeleton/action.rb +0 -46
- data/lib/skeleton/builder.rb +0 -47
- data/lib/skeleton/link.rb +0 -57
- data/spec/skeleton/integrated_spec.rb +0 -38
- data/test/skeleton/action_test.rb +0 -78
- data/test/skeleton/builder_test.rb +0 -51
- data/test/skeleton/link_test.rb +0 -68
- data/test/test_helper.rb +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61b5c57ad3f55a99c4f8f7b0c671d7e3bad289e2
|
4
|
+
data.tar.gz: 4532bd18c8c705881bce6e06660e402448dc37ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bcfa898ec87b7a53c0c7409629222b8aa200544f72e1f10b78ad01c13e58af7ccf8d265defbecaedb1191c50156168357b34a7fec3284f9cf78e5e73e7e91ba5
|
7
|
+
data.tar.gz: 61969916dcf9824aa13baa48a6bcd9931ef35097afb3e40ee3a944182bad472332cf2106eea437bb6a285c9cfe84880fa705ed35d6666163e774e7560a4a0e8b
|
data/README.md
CHANGED
@@ -1,89 +1,112 @@
|
|
1
1
|
# Skeleton
|
2
2
|
|
3
|
-
|
4
|
-
|
3
|
+
Was born from the desire for api documentation that can live along side actively
|
4
|
+
running code.
|
5
5
|
|
6
6
|
## Example
|
7
7
|
|
8
8
|
```ruby
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
p.restriction('Minimum value is 0')
|
20
|
-
p.restriction('Maximum value is 9000')
|
21
|
-
end
|
9
|
+
# You would put this somewhere such as config/initializers/skeleton.rb
|
10
|
+
Skeleton.configure do |config|
|
11
|
+
config.define do |structure|
|
12
|
+
structure.host = 'api.example.com'
|
13
|
+
structure.base_path = '/foo'
|
14
|
+
|
15
|
+
structure.schemes = %w(https)
|
16
|
+
structure.consumes = %(application/json)
|
17
|
+
structure.produces = %(application/json)
|
18
|
+
end
|
22
19
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
20
|
+
config.info do |info|
|
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
|
29
26
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
27
|
+
config.contact do |contact|
|
28
|
+
contact.name = 'WarmWaffles'
|
29
|
+
contact.email = 'warmwaffles@gmail.com'
|
30
|
+
contact.url = 'https://github.com/warmwaffles/skeleton'
|
31
|
+
end
|
34
32
|
|
35
|
-
|
33
|
+
config.license do |license|
|
34
|
+
license.name = 'MIT'
|
36
35
|
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
Inside of your rails controller you would do the following
|
37
40
|
|
38
|
-
|
41
|
+
```ruby
|
42
|
+
class ApplicationController < ActionController::Base
|
43
|
+
include Skeleton::Helpers::ControllerHelpers
|
39
44
|
end
|
45
|
+
```
|
46
|
+
|
47
|
+
Inside a controller that you wish to document do the following
|
40
48
|
|
41
|
-
|
49
|
+
```ruby
|
50
|
+
class AccountsController < ApplicationController
|
51
|
+
define_api_path('/accounts') do |path|
|
52
|
+
path.get do |operation|
|
53
|
+
operation.tag('account')
|
54
|
+
operation.description = 'List all of the accounts available to you'
|
55
|
+
|
56
|
+
operation.parameter(:query, 'limit') do |p|
|
57
|
+
p.description = 'maximum number of results to return'
|
58
|
+
p.type = 'integer'
|
59
|
+
p.format = 'int32'
|
60
|
+
p.required = false
|
61
|
+
end
|
62
|
+
operation.parameter(:query, 'offset') do |p|
|
63
|
+
p.description = 'offset within the results returned'
|
64
|
+
p.type = 'integer'
|
65
|
+
p.format = 'int32'
|
66
|
+
p.required = false
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
define_api_path('/accounts/{account_id}') do |path|
|
72
|
+
path.get do |operation|
|
73
|
+
operation.tag('account')
|
74
|
+
operation.description = 'Get an account'
|
75
|
+
operation.parameter(:query, 'account_id') do |p|
|
76
|
+
p.description = 'The account id'
|
77
|
+
p.type = 'string'
|
78
|
+
p.format = 'uuid'
|
79
|
+
p.required = true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
path.options do |operation|
|
84
|
+
operation.tag('account')
|
85
|
+
operation.description = 'Show available options for the account'
|
86
|
+
operation.parameter(:query, 'account_id') do |p|
|
87
|
+
p.description = 'The account id'
|
88
|
+
p.type = 'string'
|
89
|
+
p.format = 'uuid'
|
90
|
+
p.required = true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
42
95
|
```
|
43
96
|
|
44
|
-
|
97
|
+
If you want to dump the documentation to swagger you can simply do the
|
98
|
+
following:
|
45
99
|
|
46
100
|
```ruby
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
"allowed"=>[],
|
57
|
-
"restrictions"=>[
|
58
|
-
"Minimum value is 0",
|
59
|
-
"Maximum value is 9000"
|
60
|
-
]
|
61
|
-
},
|
62
|
-
"offset"=>{
|
63
|
-
"type"=>"integer",
|
64
|
-
"description"=>"The offset within the collection",
|
65
|
-
"required"=>false,
|
66
|
-
"allowed"=>[],
|
67
|
-
"restrictions"=>[
|
68
|
-
"Minimum value is 0"
|
69
|
-
]
|
70
|
-
}
|
71
|
-
},
|
72
|
-
"links"=>[
|
73
|
-
{
|
74
|
-
"name"=>"Self",
|
75
|
-
"rel"=>"self",
|
76
|
-
"href"=>"https://api.example.org/resources"
|
77
|
-
}
|
78
|
-
],
|
79
|
-
"examples"=>[
|
80
|
-
{
|
81
|
-
"limit"=>10,
|
82
|
-
"offset"=>0
|
83
|
-
}
|
84
|
-
]
|
85
|
-
}
|
86
|
-
}
|
101
|
+
class DocumentationController < ApplicationController
|
102
|
+
def swagger
|
103
|
+
respond_to do |format|
|
104
|
+
format.json do
|
105
|
+
render(json: Skeleton.config.to_swagger_json, status: 200)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
87
110
|
```
|
88
111
|
|
89
112
|
## Testing
|
data/Rakefile
CHANGED
@@ -2,12 +2,7 @@ require 'bundler/gem_tasks'
|
|
2
2
|
|
3
3
|
namespace :test do
|
4
4
|
task :env do
|
5
|
-
$LOAD_PATH.unshift('lib', 'spec'
|
6
|
-
end
|
7
|
-
|
8
|
-
desc 'Runs only the units in this project'
|
9
|
-
task :units => [:env] do
|
10
|
-
Dir.glob('./test/**/*_test.rb') { |f| require f }
|
5
|
+
$LOAD_PATH.unshift('lib', 'spec')
|
11
6
|
end
|
12
7
|
|
13
8
|
desc 'Runs only the specs in this project'
|
@@ -16,7 +11,7 @@ namespace :test do
|
|
16
11
|
end
|
17
12
|
|
18
13
|
desc 'Runs all of the tests within this project'
|
19
|
-
task :all => [:
|
14
|
+
task :all => [:specs]
|
20
15
|
end
|
21
16
|
|
22
17
|
desc 'Runs all of the tests within this project'
|
data/lib/skeleton.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
require 'skeleton/version'
|
2
|
-
require 'skeleton/
|
2
|
+
require 'skeleton/structure'
|
3
|
+
require 'skeleton/config'
|
4
|
+
require 'skeleton/helpers/controller_helpers'
|
3
5
|
|
4
6
|
module Skeleton
|
5
7
|
def self.build(&block)
|
6
|
-
|
7
|
-
yield(
|
8
|
-
|
8
|
+
structure = Skeleton::Structure.new
|
9
|
+
yield(structure) if block
|
10
|
+
structure
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.config
|
14
|
+
@config ||= Skeleton::Config.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.configure(&block)
|
18
|
+
yield(config) if block
|
9
19
|
end
|
10
20
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Skeleton
|
2
|
+
module Attributes
|
3
|
+
def attr_presence(*methods)
|
4
|
+
Array(methods).each do |method|
|
5
|
+
define_method("#{method}?") do
|
6
|
+
!!self.public_send(method.to_s)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def attr_not_empty(*methods)
|
12
|
+
Array(methods).each do |method|
|
13
|
+
define_method("#{method}?") do
|
14
|
+
!self.public_send(method.to_s).empty?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'skeleton/structure'
|
2
|
+
require 'skeleton/serializers/swagger'
|
3
|
+
|
4
|
+
module Skeleton
|
5
|
+
class Config
|
6
|
+
def structure
|
7
|
+
@structure ||= Skeleton::Structure.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def info(&block)
|
11
|
+
yield(structure.info) if block
|
12
|
+
end
|
13
|
+
|
14
|
+
def define(&block)
|
15
|
+
yield(structure) if block
|
16
|
+
end
|
17
|
+
|
18
|
+
def contact(&block)
|
19
|
+
yield(structure.info.contact) if block
|
20
|
+
end
|
21
|
+
|
22
|
+
def license(&block)
|
23
|
+
yield(structure.info.license) if block
|
24
|
+
end
|
25
|
+
|
26
|
+
def path(resource, &block)
|
27
|
+
structure.path(resource, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def parameter(location, name, &block)
|
31
|
+
structure.parameter(location, name, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_swagger_json
|
35
|
+
structure.to_swagger_json
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'skeleton/model'
|
2
|
+
|
3
|
+
module Skeleton
|
4
|
+
class Contact < Model
|
5
|
+
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
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'skeleton/model'
|
2
|
+
|
3
|
+
module Skeleton
|
4
|
+
class Documentation < Model
|
5
|
+
|
6
|
+
attr_accessor :description, :url
|
7
|
+
attr_presence :description, :url
|
8
|
+
|
9
|
+
def to_h
|
10
|
+
hash = {}
|
11
|
+
hash[:description] = description if description?
|
12
|
+
hash[:url] = url if url?
|
13
|
+
hash
|
14
|
+
end
|
15
|
+
alias_method :to_swagger_hash, :to_h
|
16
|
+
end
|
17
|
+
end
|
data/lib/skeleton/example.rb
CHANGED
@@ -1,17 +1,31 @@
|
|
1
1
|
module Skeleton
|
2
2
|
class Example
|
3
3
|
def initialize
|
4
|
-
@
|
4
|
+
@mimes = {}
|
5
5
|
end
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
|
7
|
+
def []=(mime_type, value)
|
8
|
+
@mimes[mime_type] = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def [](mime_type)
|
12
|
+
@mimes[mime_type]
|
10
13
|
end
|
11
14
|
|
12
15
|
def to_h
|
13
|
-
|
16
|
+
hash = {}
|
17
|
+
@mimes.each do |type, value|
|
18
|
+
hash[type] = value.respond_to?(:to_h) ? value.to_h : value
|
19
|
+
end
|
20
|
+
hash
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_swagger_hash
|
24
|
+
hash = {}
|
25
|
+
@mimes.each do |type, value|
|
26
|
+
hash[type] = value.respond_to?(:to_h) ? value.to_swagger_hash : value
|
27
|
+
end
|
28
|
+
hash
|
14
29
|
end
|
15
|
-
alias_method :to_hash, :to_h
|
16
30
|
end
|
17
31
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'skeleton/model'
|
2
|
+
|
3
|
+
module Skeleton
|
4
|
+
class Header < Model
|
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
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'skeleton/model'
|
2
|
+
require 'skeleton/header'
|
3
|
+
|
4
|
+
module Skeleton
|
5
|
+
class Headers < Model
|
6
|
+
def initialize(args={})
|
7
|
+
@fields = {}
|
8
|
+
args.each { |k, v| set(k, v)}
|
9
|
+
end
|
10
|
+
|
11
|
+
def get(name)
|
12
|
+
@fields[name]
|
13
|
+
end
|
14
|
+
alias_method :[], :get
|
15
|
+
|
16
|
+
def set(name, value)
|
17
|
+
case value
|
18
|
+
when Hash
|
19
|
+
@fields[name] = Skeleton::Header.new(value)
|
20
|
+
else
|
21
|
+
@fields[name] = value
|
22
|
+
end
|
23
|
+
end
|
24
|
+
alias_method :[]=, :set
|
25
|
+
|
26
|
+
def to_h
|
27
|
+
hash ={}
|
28
|
+
@fields.each do |name, value|
|
29
|
+
if value.respond_to?(:to_h)
|
30
|
+
hash[name] = value.to_h
|
31
|
+
else
|
32
|
+
hash[name] = value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
hash
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_swagger_hash
|
39
|
+
hash ={}
|
40
|
+
@fields.each do |name, value|
|
41
|
+
if value.respond_to?(:to_swagger_hash)
|
42
|
+
hash[name] = value.to_swagger_hash
|
43
|
+
else
|
44
|
+
hash[name] = value
|
45
|
+
end
|
46
|
+
end
|
47
|
+
hash
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|