swagger-core 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +14 -0
- data/.gitmodules +3 -0
- data/.rubocop.yml +21 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +8 -0
- data/lib/swagger.rb +30 -0
- data/lib/swagger/api_declaration.rb +25 -0
- data/lib/swagger/attachable.rb +31 -0
- data/lib/swagger/builder.rb +87 -0
- data/lib/swagger/definition_section.rb +34 -0
- data/lib/swagger/loaders.rb +29 -0
- data/lib/swagger/mime_type.rb +25 -0
- data/lib/swagger/notes.md +35 -0
- data/lib/swagger/schema.rb +59 -0
- data/lib/swagger/uri.rb +10 -0
- data/lib/swagger/uri_template.rb +10 -0
- data/lib/swagger/v2/api_declaration.rb +81 -0
- data/lib/swagger/v2/api_operation.rb +56 -0
- data/lib/swagger/v2/example.rb +24 -0
- data/lib/swagger/v2/info.rb +23 -0
- data/lib/swagger/v2/parameter.rb +6 -0
- data/lib/swagger/v2/path.rb +38 -0
- data/lib/swagger/v2/response.rb +21 -0
- data/lib/swagger/version.rb +3 -0
- data/resources/schemas/json_schema/draft-04.json +150 -0
- data/resources/schemas/swagger/v2.0/schema.json +532 -0
- data/spec/fixtures/petstore-full.yaml +134 -0
- data/spec/fixtures/swagger.yaml +100 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/swagger/api_declaration_spec.rb +88 -0
- data/spec/swagger/api_operation_spec.rb +91 -0
- data/spec/swagger/info_spec.rb +76 -0
- data/spec/swagger/swagger_spec.rb +25 -0
- data/swagger-core.gemspec +31 -0
- metadata +225 -0
data/.gitignore
ADDED
data/.gitmodules
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
+
# on 2014-08-05 12:05:37 -0400 using RuboCop version 0.24.1.
|
3
|
+
# The point is for the user to remove these configuration records
|
4
|
+
# one by one as the offenses are removed from the code base.
|
5
|
+
# Note that changes in the inspected code, or installation of new
|
6
|
+
# versions of RuboCop, may require this file to be generated again.
|
7
|
+
|
8
|
+
# Not yet...
|
9
|
+
Style/Documentation:
|
10
|
+
Enabled: false
|
11
|
+
Style/Encoding:
|
12
|
+
EnforcedStyle: when_needed
|
13
|
+
|
14
|
+
Metrics/LineLength:
|
15
|
+
Max: 120
|
16
|
+
Metrics/MethodLength:
|
17
|
+
Max: 15
|
18
|
+
|
19
|
+
AllCops:
|
20
|
+
Exclude:
|
21
|
+
- 'swagger_spec/**/*'
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Max Lincoln
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Swagger
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'swagger'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install swagger
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/swagger/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/lib/swagger.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'swagger/version'
|
2
|
+
require 'addressable/uri'
|
3
|
+
require 'addressable/template'
|
4
|
+
require 'hashie'
|
5
|
+
|
6
|
+
module Swagger
|
7
|
+
RESOURCES_DIR = File.expand_path '../../resources/', __FILE__
|
8
|
+
class InvalidDefinition < StandardError
|
9
|
+
def initialize(errors)
|
10
|
+
@errors = errors
|
11
|
+
super("The Swagger definition is invalid. The following errors were detected: #{errors.inspect}")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.load(file, loader = nil)
|
16
|
+
ext = File.extname file
|
17
|
+
loader ||= Swagger::Loaders.loader_for ext
|
18
|
+
loader.load File.read(file)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'swagger/attachable'
|
23
|
+
require 'swagger/definition_section'
|
24
|
+
require 'swagger/schema'
|
25
|
+
require 'swagger/uri'
|
26
|
+
require 'swagger/uri_template'
|
27
|
+
require 'swagger/loaders'
|
28
|
+
require 'swagger/mime_type'
|
29
|
+
require 'swagger/api_declaration'
|
30
|
+
require 'swagger/builder'
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Swagger
|
2
|
+
class APIDeclaration < DefinitionSection
|
3
|
+
def self.build(hash)
|
4
|
+
version = hash['swaggerVersion'] || hash['swagger']
|
5
|
+
major, _minor = version.to_s.split('.')
|
6
|
+
case major
|
7
|
+
when '2'
|
8
|
+
Swagger::V2::APIDeclaration.new hash
|
9
|
+
else
|
10
|
+
fail ArgumentError, "Swagger version #{version} is not currently supported"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(hash)
|
15
|
+
@vendor_extensions = {}
|
16
|
+
hash.each do |k, v|
|
17
|
+
@vendor_extensions[k] = v if k.to_s.start_with? 'x-'
|
18
|
+
end
|
19
|
+
# HACK: There's got to be a better way, but Dash wasn't working well with strings
|
20
|
+
super(Hashie::Mash.new(hash).to_hash(symbolize_keys: true))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'swagger/v2/api_declaration'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Swagger
|
2
|
+
module Attachable
|
3
|
+
# @api private
|
4
|
+
def attach_parent(parent)
|
5
|
+
@parent = parent
|
6
|
+
attach_to_children
|
7
|
+
end
|
8
|
+
|
9
|
+
# @api private
|
10
|
+
def attach_to_children # rubocop:disable Metrics/MethodLength
|
11
|
+
each_value do |v|
|
12
|
+
if v.respond_to? :attach_parent
|
13
|
+
v.attach_parent self
|
14
|
+
elsif v.respond_to? :each_value
|
15
|
+
v.each_value do |sv|
|
16
|
+
sv.attach_parent self if sv.respond_to? :attach_parent
|
17
|
+
end
|
18
|
+
elsif v.respond_to? :each
|
19
|
+
v.each do |sv|
|
20
|
+
sv.attach_parent self if sv.respond_to? :attach_parent
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def root
|
27
|
+
return self if parent.nil?
|
28
|
+
parent.root
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Swagger
|
2
|
+
# A Bash is a 'builder' Hash that can be used to be a
|
3
|
+
# Dash ('defined' or 'discrete' Hash). It provides a
|
4
|
+
# build method that turns it into a Dash. It enforces
|
5
|
+
# the same rules as a Dash except for 'required' properties,
|
6
|
+
# which are not enforced until converting to a Dash via `build`.
|
7
|
+
module Bash
|
8
|
+
module ClassMethods
|
9
|
+
def self.extend_object(dash)
|
10
|
+
fail TypeError, 'Bash only works on Dash' unless dash <= Hashie::Dash
|
11
|
+
dash.instance_variable_get('@required_properties').clear
|
12
|
+
dash.coerce_value Hashie::Dash, Swagger::Bash, strict: false
|
13
|
+
end
|
14
|
+
|
15
|
+
def required?(_name)
|
16
|
+
false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.included(dash) # rubocop:disable Metrics/MethodLength
|
21
|
+
fail TypeError, 'Bash only works on Dash' unless dash <= Hashie::Dash
|
22
|
+
dash.extend ClassMethods
|
23
|
+
dash.instance_variable_get('@required_properties').clear
|
24
|
+
|
25
|
+
# Very hacky... copy instance_variables for coercions
|
26
|
+
base_dash = dash.superclass
|
27
|
+
[:@properties, :@defaults].each do | property |
|
28
|
+
dash.instance_variable_set(property, base_dash.instance_variable_get(property))
|
29
|
+
end
|
30
|
+
|
31
|
+
[:@key_coercions, :@value_coercions].each do | property |
|
32
|
+
coercions = base_dash.instance_variable_get(property)
|
33
|
+
coercions.each_pair do | key, into |
|
34
|
+
infect_class coercions, key, into
|
35
|
+
end if coercions
|
36
|
+
dash.instance_variable_set(property, coercions)
|
37
|
+
end
|
38
|
+
|
39
|
+
def [](key, &_block)
|
40
|
+
super(key) do |v|
|
41
|
+
if block_given?
|
42
|
+
v ||= send(:[]=, key, {})
|
43
|
+
yield v
|
44
|
+
v
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def build
|
51
|
+
self.class.superclass.new(to_hash)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def self.infect_class(coercions, key, into)
|
57
|
+
if into.is_a? Hash
|
58
|
+
into.each_pair do | sub_key, sub_into |
|
59
|
+
coercions[key][sub_key] = infect sub_into
|
60
|
+
end
|
61
|
+
elsif into.is_a? Array
|
62
|
+
coercions[key] = into.map do | sub_into |
|
63
|
+
infect sub_into
|
64
|
+
end
|
65
|
+
else
|
66
|
+
coercions[key] = infect into
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.infect(klass)
|
71
|
+
return klass unless klass <= Hashie::Dash
|
72
|
+
|
73
|
+
klass.const_set('Bash',
|
74
|
+
Class.new(klass).tap do | bash_klass |
|
75
|
+
# include is public in Ruby 2.1+, hack to support older
|
76
|
+
bash_klass.send(:include, Bash)
|
77
|
+
end
|
78
|
+
) unless klass.const_defined? 'Bash'
|
79
|
+
|
80
|
+
klass.const_get('Bash')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Builder < Swagger::V2::APIDeclaration
|
85
|
+
include Swagger::Bash
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Swagger
|
2
|
+
class DefinitionSection < Hashie::Dash
|
3
|
+
include Hashie::Extensions::Coercion
|
4
|
+
include Hashie::Extensions::IndifferentAccess
|
5
|
+
include Swagger::Attachable
|
6
|
+
|
7
|
+
attr_accessor :parent
|
8
|
+
|
9
|
+
def initialize(hash)
|
10
|
+
super
|
11
|
+
attach_to_children
|
12
|
+
end
|
13
|
+
|
14
|
+
# @api private
|
15
|
+
# @!macro [new] section
|
16
|
+
# @!attribute [rw] $1
|
17
|
+
# $3
|
18
|
+
# @return [$2]
|
19
|
+
def self.section(name, type)
|
20
|
+
property name
|
21
|
+
coerce_key name, type
|
22
|
+
end
|
23
|
+
|
24
|
+
# @api private
|
25
|
+
# @!macro [new] section
|
26
|
+
# @!attribute [rw] $1
|
27
|
+
# **Required**. $3
|
28
|
+
# @return [$2]
|
29
|
+
def self.required_section(name, type)
|
30
|
+
property name, required: true
|
31
|
+
coerce_key name, type
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
autoload :YAML, 'yaml'
|
2
|
+
autoload :JSON, 'json'
|
3
|
+
|
4
|
+
module Swagger
|
5
|
+
module Loaders
|
6
|
+
def self.loader_for(ext)
|
7
|
+
case ext
|
8
|
+
when '.yaml', '.yml'
|
9
|
+
YAMLLoader
|
10
|
+
when '.json', '.js'
|
11
|
+
JSONLoader
|
12
|
+
else
|
13
|
+
fail ArgumentError, "No registered Loader for #{ext}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class YAMLLoader
|
18
|
+
def self.load(content)
|
19
|
+
APIDeclaration.build(YAML.load(content))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class JSONLoader
|
24
|
+
def self.load(content)
|
25
|
+
APIDeclaration.build(JSON.parse(content))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'mime/types'
|
2
|
+
|
3
|
+
module Swagger
|
4
|
+
class MimeType < String
|
5
|
+
extend Forwardable
|
6
|
+
def_delegators :@mime_type, :media_type, :sub_type
|
7
|
+
|
8
|
+
MIME_TYPE_FORMAT = /(\w+)\/(\w+\.)?([\w\.]+)(\+\w+)?\s*(;.*)?/
|
9
|
+
|
10
|
+
def initialize(mime_type_name)
|
11
|
+
@mime_type_name = mime_type_name.to_s
|
12
|
+
@mime_type = MIME::Types[@mime_type_name].first || base_type(@mime_type_name)
|
13
|
+
fail ArgumentError, "Unknown mime type or suffix: #{mime_type_name}" if @mime_type.nil?
|
14
|
+
super @mime_type_name
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def base_type(mime_type_name)
|
20
|
+
media_type, _sub_type, _tree, suffix, _parameters = MIME_TYPE_FORMAT.match mime_type_name
|
21
|
+
return MIME::Types["#{media_type}/#{suffix}"].first if media_type && suffix
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
Classes added to Swagger-Core (Java) for 2.0:
|
2
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/converter/ModelConverters.java
|
3
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Contact.java
|
4
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Info.java
|
5
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/License.java
|
6
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Model.java
|
7
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/ModelFactory.java
|
8
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Operation.java
|
9
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Path.java
|
10
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/RefModel.java
|
11
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Response.java
|
12
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Scheme.java
|
13
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Security.java
|
14
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/Swagger.java
|
15
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/parameters/AbstractParameter.java
|
16
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/parameters/BodyParameter.java
|
17
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/parameters/CookieParameter.java
|
18
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/parameters/HeaderParameter.java
|
19
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/parameters/Parameter.java
|
20
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/parameters/PathParameter.java
|
21
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/parameters/QueryParameter.java
|
22
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/AbstractProperty.java
|
23
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/ArrayProperty.java
|
24
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/BooleanProperty.java
|
25
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/DateProperty.java
|
26
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/DateTimeProperty.java
|
27
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/DoubleProperty.java
|
28
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/IntegerProperty.java
|
29
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/LongProperty.java
|
30
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/MapProperty.java
|
31
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/Property.java
|
32
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/RefProperty.java
|
33
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/StringProperty.java
|
34
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/models/properties/Xml.java
|
35
|
+
- [] modules/swagger-core/src/main/java/com/wordnik/swagger/util/Json.java
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Swagger
|
2
|
+
class Schema < Hashie::Mash
|
3
|
+
include Attachable
|
4
|
+
include Hashie::Extensions::MergeInitializer
|
5
|
+
include Hashie::Extensions::DeepFind
|
6
|
+
attr_accessor :parent
|
7
|
+
|
8
|
+
def initialize(hash, default = nil)
|
9
|
+
super
|
10
|
+
attach_to_children
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse
|
14
|
+
schema = clone
|
15
|
+
if schema.key?('$ref')
|
16
|
+
key = schema.delete('$ref')
|
17
|
+
model = root.definitions[key]
|
18
|
+
schema.merge!(model)
|
19
|
+
end
|
20
|
+
|
21
|
+
count = 0
|
22
|
+
until schema.refs_resolved?
|
23
|
+
fail 'Could not resolve non-remote $refs 5 cycles - circular references?' if count >= 5
|
24
|
+
schema.resolve_refs
|
25
|
+
count += 1
|
26
|
+
end
|
27
|
+
|
28
|
+
schema.to_hash
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def refs
|
34
|
+
deep_find_all('$ref')
|
35
|
+
end
|
36
|
+
|
37
|
+
def resolve_refs
|
38
|
+
items_and_props = [deep_select('items'), deep_select('properties')].flatten.compact
|
39
|
+
items_and_props.each do | item |
|
40
|
+
key = item.delete('$ref')
|
41
|
+
next if remote_ref? key
|
42
|
+
model = root.definitions[key]
|
43
|
+
item.merge!(model)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def refs_resolved?
|
48
|
+
return true if refs.nil?
|
49
|
+
|
50
|
+
refs.all? do |ref|
|
51
|
+
remote_ref?(ref)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def remote_ref?(ref)
|
56
|
+
ref.match(%r{\A\w+\://})
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|