swagger-core 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.gitmodules ADDED
@@ -0,0 +1,3 @@
1
+ [submodule "swagger_spec"]
2
+ path = swagger_spec
3
+ url = https://github.com/wordnik/swagger-spec
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
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.0.0
5
+ - 1.9.3
6
+ - jruby
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in swagger.gemspec
4
+ gemspec
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
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new
7
+
8
+ task default: [:spec, :rubocop]
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