swagalicious 0.1.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +74 -0
- data/.travis.yml +6 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +50 -0
- data/LICENSE.txt +21 -0
- data/README.md +65 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/core/ext/hash.rb +19 -0
- data/lib/swagalicious.rb +30 -0
- data/lib/swagalicious/configuration.rb +53 -0
- data/lib/swagalicious/example_group_helpers.rb +79 -0
- data/lib/swagalicious/example_helpers.rb +65 -0
- data/lib/swagalicious/extended_schema.rb +21 -0
- data/lib/swagalicious/request_factory.rb +187 -0
- data/lib/swagalicious/response_validator.rb +64 -0
- data/lib/swagalicious/swagger_formatter.rb +193 -0
- data/lib/swagalicious/version.rb +3 -0
- data/swagalicious.gemspec +32 -0
- metadata +140 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 941a558739b2079027c117ccea67ffc90c7a21f682811ab817a739ef0ea93d82
|
4
|
+
data.tar.gz: 275cce80dedbfcaa5b5e76d01499fe18babcc7e30a948806ad95df1cea46d475
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2e8f90a288217b8e27e85411194a73a7f5d1bbe7bd8881a1f086c11319b8ee9a832143bc9c610a8398fb11051484be70f828f3a1625d5c2180d5e1d1194e5121
|
7
|
+
data.tar.gz: 181ff6d1a9dcab5b13499f648b75299f4ab6321c2ea4d65956a94d4bd8b62f90d8e049c771629ed457ca828635f7f90ab35f9bba630b437d0ebb11136d0cdb19
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require: rubocop-rspec
|
2
|
+
|
3
|
+
AllCops:
|
4
|
+
DisplayCopNames: true
|
5
|
+
DisabledByDefault: true
|
6
|
+
Exclude:
|
7
|
+
- "cypress/**/*"
|
8
|
+
- "db/migrations/**/*.rb"
|
9
|
+
- "docs/**/*"
|
10
|
+
- "node_modules/**/*"
|
11
|
+
- "private/**/*"
|
12
|
+
- "public/**/*"
|
13
|
+
- "static/**/*"
|
14
|
+
- "tmp/**/*"
|
15
|
+
- "vendor/**/*"
|
16
|
+
|
17
|
+
Layout/EmptyLines:
|
18
|
+
Enabled: true
|
19
|
+
|
20
|
+
Layout/ExtraSpacing:
|
21
|
+
Enabled: true
|
22
|
+
ForceEqualSignAlignment: true
|
23
|
+
|
24
|
+
Layout/HashAlignment:
|
25
|
+
Enabled: true
|
26
|
+
EnforcedColonStyle: table
|
27
|
+
EnforcedHashRocketStyle: table
|
28
|
+
EnforcedLastArgumentHashStyle: ignore_implicit
|
29
|
+
|
30
|
+
Layout/TrailingEmptyLines:
|
31
|
+
Enabled: true
|
32
|
+
|
33
|
+
Layout/TrailingWhitespace:
|
34
|
+
Enabled: true
|
35
|
+
|
36
|
+
RSpec/AlignLeftLetBrace:
|
37
|
+
Enabled: true
|
38
|
+
|
39
|
+
RSpec/DescribedClass:
|
40
|
+
EnforcedStyle: described_class
|
41
|
+
|
42
|
+
RSpec/EmptyLineAfterFinalLet:
|
43
|
+
Enabled: true
|
44
|
+
|
45
|
+
Style/Alias:
|
46
|
+
EnforcedStyle: prefer_alias_method
|
47
|
+
|
48
|
+
Style/Documentation:
|
49
|
+
Enabled: false
|
50
|
+
|
51
|
+
Style/HashEachMethods:
|
52
|
+
Enabled: false
|
53
|
+
|
54
|
+
Style/HashSyntax:
|
55
|
+
Enabled: true
|
56
|
+
EnforcedStyle: ruby19
|
57
|
+
|
58
|
+
Style/HashTransformKeys:
|
59
|
+
Enabled: true
|
60
|
+
|
61
|
+
Style/HashTransformValues:
|
62
|
+
Enabled: false
|
63
|
+
|
64
|
+
Style/Lambda:
|
65
|
+
EnforcedStyle: literal
|
66
|
+
|
67
|
+
Style/SignalException:
|
68
|
+
Enabled: false
|
69
|
+
|
70
|
+
Style/StringLiterals:
|
71
|
+
EnforcedStyle: double_quotes
|
72
|
+
|
73
|
+
Style/StringLiteralsInInterpolation:
|
74
|
+
EnforcedStyle: double_quotes
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
swagalicious (0.1.0)
|
5
|
+
faraday (~> 1.0.1)
|
6
|
+
json-schema (~> 2.8.1)
|
7
|
+
oj (~> 3.10.14)
|
8
|
+
rack-test (~> 1.1.0)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
addressable (2.7.0)
|
14
|
+
public_suffix (>= 2.0.2, < 5.0)
|
15
|
+
diff-lcs (1.4.4)
|
16
|
+
faraday (1.0.1)
|
17
|
+
multipart-post (>= 1.2, < 3)
|
18
|
+
json-schema (2.8.1)
|
19
|
+
addressable (>= 2.4)
|
20
|
+
multipart-post (2.1.1)
|
21
|
+
oj (3.10.14)
|
22
|
+
public_suffix (4.0.6)
|
23
|
+
rack (2.2.3)
|
24
|
+
rack-test (1.1.0)
|
25
|
+
rack (>= 1.0, < 3)
|
26
|
+
rake (12.3.3)
|
27
|
+
rspec (3.9.0)
|
28
|
+
rspec-core (~> 3.9.0)
|
29
|
+
rspec-expectations (~> 3.9.0)
|
30
|
+
rspec-mocks (~> 3.9.0)
|
31
|
+
rspec-core (3.9.2)
|
32
|
+
rspec-support (~> 3.9.3)
|
33
|
+
rspec-expectations (3.9.2)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.9.0)
|
36
|
+
rspec-mocks (3.9.1)
|
37
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
38
|
+
rspec-support (~> 3.9.0)
|
39
|
+
rspec-support (3.9.3)
|
40
|
+
|
41
|
+
PLATFORMS
|
42
|
+
ruby
|
43
|
+
|
44
|
+
DEPENDENCIES
|
45
|
+
rake (~> 12.0)
|
46
|
+
rspec (~> 3.0)
|
47
|
+
swagalicious!
|
48
|
+
|
49
|
+
BUNDLED WITH
|
50
|
+
2.1.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Eugene Howe
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
# Swagalicious
|
2
|
+
|
3
|
+
This gem is an implementation of https://github.com/rswag/rswag/blob/master/rswag-specs that does not rely on Rails. Most of the code is a blatant copy/paste from that repo, most of the credit goes to them.
|
4
|
+
|
5
|
+
Currenty it does not implement any API or UI. In the application that is using this gem, we are using https://github.com/Redocly/redoc that is accessed through a rack middleware.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'swagalicious'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install swagalicious
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
Add the following to your `spec_helper.rb` or add a new `swagger_helper.rb`
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
require 'swagalicious`
|
29
|
+
|
30
|
+
DEFINITIONS = Oj.load(File.read(File.expand_path("docs/definitions.json", __dir__))).freeze
|
31
|
+
|
32
|
+
RSpec.configure do |c|
|
33
|
+
c.swagger_root = "public/swagger_docs" # This is the relative path where the swagger docs will be output
|
34
|
+
c.swagger_docs = {
|
35
|
+
"path/to/swagger_doc.json" => {
|
36
|
+
swagger: "3.0",
|
37
|
+
basePath: "/api/",
|
38
|
+
version: "v1",
|
39
|
+
info: {
|
40
|
+
title: "Namespace for my API"
|
41
|
+
},
|
42
|
+
components: {
|
43
|
+
securitySchemes: {
|
44
|
+
apiKey: {
|
45
|
+
type: :apiKey,
|
46
|
+
name: "authorization",
|
47
|
+
in: :header,
|
48
|
+
}
|
49
|
+
}
|
50
|
+
},
|
51
|
+
}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
## Contributing
|
59
|
+
|
60
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/eugene@xtreme-computers.net/swagalicious.
|
61
|
+
|
62
|
+
|
63
|
+
## License
|
64
|
+
|
65
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "swagalicious"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class Hash
|
2
|
+
def deep_merge!(other_hash)
|
3
|
+
self.merge(other_hash) do |key, oldval, newval|
|
4
|
+
oldval = oldval.to_hash if oldval.respond_to?(:to_hash)
|
5
|
+
newval = newval.to_hash if newval.respond_to?(:to_hash)
|
6
|
+
oldval.class.to_s == "Hash" && newval.class.to_s == "Hash" ? oldval.deep_merge(newval) : newval
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def slice(*keep_keys)
|
11
|
+
h = {}
|
12
|
+
keep_keys.each { |key| has_key?(key) && h[key] = fetch(key, nil) }
|
13
|
+
h
|
14
|
+
end
|
15
|
+
|
16
|
+
def except(*less_keys)
|
17
|
+
slice(*keys - less_keys)
|
18
|
+
end
|
19
|
+
end
|
data/lib/swagalicious.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require "rspec/core"
|
2
|
+
|
3
|
+
require_relative "swagalicious/version"
|
4
|
+
|
5
|
+
module Swagalicious
|
6
|
+
class Error < StandardError; end
|
7
|
+
|
8
|
+
require_relative "swagalicious/configuration"
|
9
|
+
require_relative "swagalicious/example_group_helpers"
|
10
|
+
require_relative "swagalicious/example_helpers"
|
11
|
+
require_relative "swagalicious/extended_schema"
|
12
|
+
require_relative "swagalicious/request_factory"
|
13
|
+
require_relative "swagalicious/response_validator"
|
14
|
+
require_relative "swagalicious/swagger_formatter"
|
15
|
+
|
16
|
+
::RSpec::Core::ExampleGroup.define_example_group_method :path
|
17
|
+
|
18
|
+
::RSpec.configure do |c|
|
19
|
+
c.add_setting :swagger_format
|
20
|
+
c.add_setting :swagger_root
|
21
|
+
c.add_setting :swagger_docs
|
22
|
+
c.add_setting :swagger_dry_run
|
23
|
+
c.extend Swagalicious::ExampleGroupHelpers, type: :doc
|
24
|
+
c.include Swagalicious::ExampleHelpers, type: :doc
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.config
|
28
|
+
@config ||= Swagalicious::Configuration.new(RSpec.configuration)
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Swagalicious
|
2
|
+
class ConfigurationError < StandardError; end
|
3
|
+
|
4
|
+
class Configuration
|
5
|
+
def initialize(rspec_config)
|
6
|
+
@rspec_config = rspec_config
|
7
|
+
end
|
8
|
+
|
9
|
+
def swagger_root
|
10
|
+
@swagger_root ||= begin
|
11
|
+
if @rspec_config.swagger_root.nil?
|
12
|
+
raise ConfigurationError, "No swagger_root provided. See swagger_helper.rb"
|
13
|
+
end
|
14
|
+
@rspec_config.swagger_root
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def swagger_docs
|
19
|
+
@swagger_docs ||= begin
|
20
|
+
if @rspec_config.swagger_docs.nil? || @rspec_config.swagger_docs.empty?
|
21
|
+
raise ConfigurationError, "No swagger_docs defined. See swagger_helper.rb"
|
22
|
+
end
|
23
|
+
@rspec_config.swagger_docs
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def swagger_dry_run
|
28
|
+
@swagger_dry_run ||= begin
|
29
|
+
@rspec_config.swagger_dry_run.nil? || @rspec_config.swagger_dry_run
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def swagger_format
|
34
|
+
@swagger_format ||= begin
|
35
|
+
@rspec_config.swagger_format = :json if @rspec_config.swagger_format.nil? || @rspec_config.swagger_format.empty?
|
36
|
+
raise ConfigurationError, "Unknown swagger_format '#{@rspec_config.swagger_format}'" unless [:json, :yaml].include?(@rspec_config.swagger_format)
|
37
|
+
@rspec_config.swagger_format
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_swagger_doc(name)
|
42
|
+
return swagger_docs.values.first if name.nil?
|
43
|
+
raise ConfigurationError, "Unknown swagger_doc '#{name}'" unless swagger_docs[name]
|
44
|
+
|
45
|
+
swagger_docs[name]
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_swagger_doc_version(name)
|
49
|
+
doc = get_swagger_doc(name)
|
50
|
+
doc[:openapi] || doc[:swagger]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Swagalicious
|
2
|
+
module ExampleGroupHelpers
|
3
|
+
def path(template, metadata={}, &block)
|
4
|
+
metadata[:path_item] = { template: template }
|
5
|
+
describe(template, metadata, &block)
|
6
|
+
end
|
7
|
+
|
8
|
+
[ :get, :post, :patch, :put, :delete, :head ].each do |verb|
|
9
|
+
define_method(verb) do |summary, &block|
|
10
|
+
api_metadata = { operation: { verb: verb, summary: summary } }
|
11
|
+
describe(verb, api_metadata, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
[ :operationId, :deprecated, :security ].each do |attr_name|
|
16
|
+
define_method(attr_name) do |value|
|
17
|
+
metadata[:operation][attr_name] = value
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# NOTE: 'description' requires special treatment because ExampleGroup already
|
22
|
+
# defines a method with that name. Provide an override that supports the existing
|
23
|
+
# functionality while also setting the appropriate metadata if applicable
|
24
|
+
def description(value=nil)
|
25
|
+
return super() if value.nil?
|
26
|
+
metadata[:operation][:description] = value
|
27
|
+
end
|
28
|
+
|
29
|
+
# These are array properties - note the splat operator
|
30
|
+
[ :tags, :consumes, :produces, :schemes ].each do |attr_name|
|
31
|
+
define_method(attr_name) do |*value|
|
32
|
+
metadata[:operation][attr_name] = value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def parameter(attributes)
|
37
|
+
if attributes[:in] && attributes[:in].to_sym == :path
|
38
|
+
attributes[:required] = true
|
39
|
+
end
|
40
|
+
|
41
|
+
if metadata.has_key?(:operation)
|
42
|
+
metadata[:operation][:parameters] ||= []
|
43
|
+
metadata[:operation][:parameters] << attributes
|
44
|
+
else
|
45
|
+
metadata[:path_item][:parameters] ||= []
|
46
|
+
metadata[:path_item][:parameters] << attributes
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def response(code, description, metadata={}, &block)
|
51
|
+
metadata[:response] = { code: code, description: description }
|
52
|
+
context(description, metadata, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def schema(value)
|
56
|
+
metadata[:response][:schema] = value
|
57
|
+
end
|
58
|
+
|
59
|
+
def header(name, attributes)
|
60
|
+
metadata[:response][:headers] ||= {}
|
61
|
+
metadata[:response][:headers][name] = attributes
|
62
|
+
end
|
63
|
+
|
64
|
+
# NOTE: Similar to 'description', 'examples' need to handle the case when
|
65
|
+
# being invoked with no params to avoid overriding 'examples' method of
|
66
|
+
# rspec-core ExampleGroup
|
67
|
+
def examples(example = nil)
|
68
|
+
return super() if example.nil?
|
69
|
+
metadata[:response][:examples] = example
|
70
|
+
end
|
71
|
+
|
72
|
+
def validate_schema!(mocked: false, mock_name: nil)
|
73
|
+
it "returns a #{metadata[:response][:code]} response" do |example|
|
74
|
+
yield if block_given?
|
75
|
+
submit_request(example.metadata, mocked: mocked, mock_name: mock_name)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "faraday/adapter/rack"
|
3
|
+
require "rack"
|
4
|
+
require "oj"
|
5
|
+
|
6
|
+
require_relative "response_validator"
|
7
|
+
|
8
|
+
module Swagalicious
|
9
|
+
module ExampleHelpers
|
10
|
+
include Rack::Test::Methods
|
11
|
+
|
12
|
+
class MockResponse
|
13
|
+
attr_reader :body, :status, :headers
|
14
|
+
|
15
|
+
def initialize(file_name)
|
16
|
+
@body = File.read(File.expand_path("#{File.join(ENV["MOCK_PATH"], file_name)}.json", __FILE__))
|
17
|
+
@status = 200
|
18
|
+
@headers = {}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def app
|
23
|
+
@app ||= Rack::Builder.parse_file("config.ru").first
|
24
|
+
end
|
25
|
+
|
26
|
+
def client
|
27
|
+
@client ||= Faraday.new do |b|
|
28
|
+
b.adapter Faraday::Adapter::Rack, app
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def submit_request(metadata, mocked: false, mock_name: nil)
|
33
|
+
request = RequestFactory.new.build_request(metadata, self)
|
34
|
+
|
35
|
+
response = if mocked
|
36
|
+
file_name = File.basename(mock_name || URI.parse(request[:path]).path)
|
37
|
+
|
38
|
+
MockResponse.new(file_name)
|
39
|
+
else
|
40
|
+
client.public_send(request[:verb]) do |req|
|
41
|
+
req.url request[:path].gsub("//", "/")
|
42
|
+
req.headers = request[:headers]
|
43
|
+
req.body = request[:payload]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
body = response.body
|
48
|
+
body = "{}" if body.empty?
|
49
|
+
|
50
|
+
@body = Oj.load(body, symbol_keys: true)
|
51
|
+
|
52
|
+
if request[:payload]
|
53
|
+
metadata[:response][:request] = Oj.load(request[:payload])
|
54
|
+
end
|
55
|
+
|
56
|
+
metadata[:response][:examples] ||= {}
|
57
|
+
metadata[:response][:examples]["application/json"] = @body
|
58
|
+
|
59
|
+
# Validates response matches the proper schema
|
60
|
+
Swagalicious::ResponseValidator.new.validate!(metadata, response)
|
61
|
+
|
62
|
+
response
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "json-schema"
|
2
|
+
|
3
|
+
module Swagalicious
|
4
|
+
class ExtendedSchema < JSON::Schema::Draft4
|
5
|
+
def initialize
|
6
|
+
super
|
7
|
+
@attributes["type"] = ExtendedTypeAttribute
|
8
|
+
@uri = URI.parse("http://tempuri.org/swagalicious/extended_schema")
|
9
|
+
@names = ["http://tempuri.org/swagalicious/extended_schema"]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute
|
14
|
+
def self.validate(current_schema, data, fragments, processor, validator, options={})
|
15
|
+
return if data.nil? && current_schema.schema["null"] == true
|
16
|
+
super
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
JSON::Validator.register_validator(ExtendedSchema.new)
|
21
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "faraday/adapter/rack"
|
3
|
+
|
4
|
+
module Swagalicious
|
5
|
+
class RequestFactory
|
6
|
+
def initialize(config = ::Swagalicious.config)
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def build_request(metadata, example)
|
11
|
+
swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc])
|
12
|
+
parameters = expand_parameters(metadata, swagger_doc, example)
|
13
|
+
|
14
|
+
{}.tap do |request|
|
15
|
+
add_verb(request, metadata)
|
16
|
+
add_path(request, metadata, swagger_doc, parameters, example)
|
17
|
+
add_headers(request, metadata, swagger_doc, parameters, example)
|
18
|
+
add_payload(request, parameters, example)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def expand_parameters(metadata, swagger_doc, example)
|
25
|
+
operation_params = metadata[:operation][:parameters] || []
|
26
|
+
path_item_params = metadata[:path_item][:parameters] || []
|
27
|
+
security_params = derive_security_params(metadata, swagger_doc)
|
28
|
+
|
29
|
+
# NOTE: Use of + instead of concat to avoid mutation of the metadata object
|
30
|
+
(operation_params + path_item_params + security_params)
|
31
|
+
.map { |p| p["$ref"] ? resolve_parameter(p["$ref"], swagger_doc) : p }
|
32
|
+
.uniq { |p| p[:name] }
|
33
|
+
.reject { |p| p[:required] == false && !example.respond_to?(p[:name]) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def derive_security_params(metadata, swagger_doc)
|
37
|
+
requirements = metadata[:operation][:security] || swagger_doc[:security] || []
|
38
|
+
scheme_names = requirements.flat_map(&:keys)
|
39
|
+
schemes = security_version(scheme_names, swagger_doc)
|
40
|
+
|
41
|
+
schemes.map do |scheme|
|
42
|
+
param = (scheme[:type] == :apiKey) ? scheme.slice(:name, :in) : { name: "Authorization", in: :header }
|
43
|
+
param.merge(type: :string, required: requirements.one?)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def security_version(scheme_names, swagger_doc)
|
48
|
+
if swagger_doc.key?(:securityDefinitions)
|
49
|
+
puts "Swagalicious: WARNING: securityDefinitions is replaced in OpenAPI3! Rename to components/securitySchemes (in swagger_helper.rb)"
|
50
|
+
swagger_doc[:components] ||= { securitySchemes: swagger_doc[:securityDefinitions] }
|
51
|
+
swagger_doc.delete(:securityDefinitions)
|
52
|
+
end
|
53
|
+
components = swagger_doc[:components] || {}
|
54
|
+
(components[:securitySchemes] || {}).slice(*scheme_names).values
|
55
|
+
end
|
56
|
+
|
57
|
+
def resolve_parameter(ref, swagger_doc)
|
58
|
+
key = key_version(ref, swagger_doc)
|
59
|
+
definitions = definition_version(swagger_doc)
|
60
|
+
raise "Referenced parameter '#{ref}' must be defined" unless definitions && definitions[key]
|
61
|
+
|
62
|
+
definitions[key]
|
63
|
+
end
|
64
|
+
|
65
|
+
def key_version(ref, swagger_doc)
|
66
|
+
if ref.start_with?("#/parameters/")
|
67
|
+
puts "Swagalicious: WARNING: #/parameters/ refs are replaced in OpenAPI3! Rename to #/components/parameters/"
|
68
|
+
ref.sub("#/parameters/", "").to_sym
|
69
|
+
else
|
70
|
+
ref.sub("#/components/parameters/", "").to_sym
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def definition_version(swagger_doc)
|
75
|
+
if swagger_doc.key?(:parameters)
|
76
|
+
puts "Swagalicious: WARNING: parameters is replaced in OpenAPI3! Rename to components/parameters (in swagger_helper.rb)"
|
77
|
+
swagger_doc[:parameters]
|
78
|
+
else
|
79
|
+
components = swagger_doc[:components] || {}
|
80
|
+
components[:parameters]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_verb(request, metadata)
|
85
|
+
request[:verb] = metadata[:operation][:verb]
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_path(request, metadata, swagger_doc, parameters, example)
|
89
|
+
template = (swagger_doc[:basePath] || "") + metadata[:path_item][:template]
|
90
|
+
|
91
|
+
request[:path] = template.tap do |path_template|
|
92
|
+
parameters.select { |p| p[:in] == :path }.each do |p|
|
93
|
+
path_template.gsub!("{#{p[:name]}}", example.send(p[:name]).to_s)
|
94
|
+
end
|
95
|
+
|
96
|
+
parameters.select { |p| p[:in] == :query }.each_with_index do |p, i|
|
97
|
+
path_template.concat(i.zero? ? "?" : "&")
|
98
|
+
path_template.concat(build_query_string_part(p, example.send(p[:name])))
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def build_query_string_part(param, value)
|
104
|
+
name = param[:name]
|
105
|
+
return "#{name}=#{value}" unless param[:type].to_sym == :array
|
106
|
+
|
107
|
+
case param[:collectionFormat]
|
108
|
+
when :ssv
|
109
|
+
"#{name}=#{value.join(" ")}"
|
110
|
+
when :tsv
|
111
|
+
"#{name}=#{value.join("\t")}"
|
112
|
+
when :pipes
|
113
|
+
"#{name}=#{value.join("|")}"
|
114
|
+
when :multi
|
115
|
+
value.map { |v| "#{name}=#{v}" }.join("&")
|
116
|
+
else
|
117
|
+
"#{name}=#{value.join(",")}" # csv is default
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_headers(request, metadata, swagger_doc, parameters, example)
|
122
|
+
tuples = parameters
|
123
|
+
.select { |p| p[:in] == :header }
|
124
|
+
.map { |p| [p[:name], example.send(p[:name]).to_s] }
|
125
|
+
|
126
|
+
# Accept header
|
127
|
+
produces = metadata[:operation][:produces] || swagger_doc[:produces]
|
128
|
+
if produces
|
129
|
+
accept = example.respond_to?(:Accept) ? example.send(:Accept) : produces.first
|
130
|
+
tuples << ["Accept", accept]
|
131
|
+
end
|
132
|
+
|
133
|
+
# Content-Type header
|
134
|
+
consumes = metadata[:operation][:consumes] || swagger_doc[:consumes]
|
135
|
+
if consumes
|
136
|
+
content_type = example.respond_to?(:"Content-Type") ? example.send(:"Content-Type") : consumes.first
|
137
|
+
tuples << ["Content-Type", content_type]
|
138
|
+
end
|
139
|
+
|
140
|
+
# Rails test infrastructure requires rackified headers
|
141
|
+
rackified_tuples = tuples.map do |pair|
|
142
|
+
[
|
143
|
+
case pair[0]
|
144
|
+
when "Accept" then "HTTP_ACCEPT"
|
145
|
+
when "Content-Type" then "CONTENT_TYPE"
|
146
|
+
when "Authorization" then "HTTP_AUTHORIZATION"
|
147
|
+
else pair[0]
|
148
|
+
end,
|
149
|
+
pair[1]
|
150
|
+
]
|
151
|
+
end
|
152
|
+
|
153
|
+
request[:headers] = Hash[rackified_tuples]
|
154
|
+
end
|
155
|
+
|
156
|
+
def add_payload(request, parameters, example)
|
157
|
+
content_type = request[:headers]["CONTENT_TYPE"]
|
158
|
+
return if content_type.nil?
|
159
|
+
|
160
|
+
if ["application/x-www-form-urlencoded", "multipart/form-data"].include?(content_type)
|
161
|
+
request[:payload] = build_form_payload(parameters, example)
|
162
|
+
else
|
163
|
+
request[:payload] = build_json_payload(parameters, example)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def build_form_payload(parameters, example)
|
168
|
+
# See http://seejohncode.com/2012/04/29/quick-tip-testing-multipart-uploads-with-rspec/
|
169
|
+
# Rather that serializing with the appropriate encoding (e.g. multipart/form-data),
|
170
|
+
# Rails test infrastructure allows us to send the values directly as a hash
|
171
|
+
# PROS: simple to implement, CONS: serialization/deserialization is bypassed in test
|
172
|
+
tuples = parameters
|
173
|
+
.select { |p| p[:in] == :formData }
|
174
|
+
.map { |p| [p[:name], example.send(p[:name])] }
|
175
|
+
Hash[tuples]
|
176
|
+
end
|
177
|
+
|
178
|
+
def build_json_payload(parameters, example)
|
179
|
+
body_param = parameters.select { |p| p[:in] == :body }.first
|
180
|
+
body_param ? example.send(body_param[:name]).to_json : nil
|
181
|
+
end
|
182
|
+
|
183
|
+
def doc_version(doc)
|
184
|
+
doc[:openapi] || doc[:swagger] || "3"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Swagalicious
|
4
|
+
class UnexpectedResponse < StandardError; end
|
5
|
+
|
6
|
+
class ResponseValidator
|
7
|
+
def initialize(config = ::Swagalicious::config)
|
8
|
+
@config = config
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate!(metadata, response)
|
12
|
+
swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc])
|
13
|
+
|
14
|
+
validate_code!(metadata, response.status)
|
15
|
+
validate_headers!(metadata, response.headers)
|
16
|
+
validate_body!(metadata, swagger_doc, response.body)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def validate_code!(metadata, response)
|
22
|
+
expected = metadata[:response][:code].to_s
|
23
|
+
if response.to_s != expected.to_s
|
24
|
+
raise UnexpectedResponse, "Expected response code '#{response}' to match '#{expected}'"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_headers!(metadata, headers)
|
29
|
+
expected = (metadata[:response][:headers] || {}).keys
|
30
|
+
expected.each do |name|
|
31
|
+
raise UnexpectedResponse, "Expected response header #{name} to be present" if headers[name.to_s].nil?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_body!(metadata, swagger_doc, body)
|
36
|
+
response_schema = metadata[:response][:schema]
|
37
|
+
return if response_schema.nil?
|
38
|
+
|
39
|
+
version = @config.get_swagger_doc_version(metadata[:swagger_doc])
|
40
|
+
schemas = definitions_or_component_schemas(swagger_doc, version)
|
41
|
+
|
42
|
+
validation_schema = response_schema
|
43
|
+
.merge("$schema" => "http://tempuri.org/swagalicious/extended_schema")
|
44
|
+
.merge(schemas)
|
45
|
+
|
46
|
+
errors = JSON::Validator.fully_validate(validation_schema, body)
|
47
|
+
raise UnexpectedResponse, "Expected response body to match schema: #{errors[0]}" if errors.any?
|
48
|
+
end
|
49
|
+
|
50
|
+
def definitions_or_component_schemas(swagger_doc, version)
|
51
|
+
if version.start_with?("2")
|
52
|
+
swagger_doc.slice(:definitions)
|
53
|
+
else # Openapi3
|
54
|
+
if swagger_doc.key?(:definitions)
|
55
|
+
puts "Swagger::Specs: WARNING: definitions is replaced in OpenAPI3! Rename to components/schemas (in swagger_helper.rb)"
|
56
|
+
swagger_doc.slice(:definitions)
|
57
|
+
else
|
58
|
+
components = swagger_doc[:components] || {}
|
59
|
+
{ components: { schemas: components[:schemas] } }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../core/ext/hash"
|
4
|
+
|
5
|
+
module Swagalicious
|
6
|
+
class SwaggerFormatter
|
7
|
+
RSpec::Core::Formatters.register self, :example_group_finished, :stop
|
8
|
+
|
9
|
+
def initialize(output, config = Swagalicious.config)
|
10
|
+
@output = output
|
11
|
+
@config = config
|
12
|
+
|
13
|
+
@output.puts "Generating Swagger docs ..."
|
14
|
+
end
|
15
|
+
|
16
|
+
def example_group_finished(notification)
|
17
|
+
metadata = notification.group.metadata
|
18
|
+
|
19
|
+
# !metadata[:document] won"t work, since nil means we should generate
|
20
|
+
# docs.
|
21
|
+
return if metadata[:document] == false
|
22
|
+
return unless metadata.key?(:response)
|
23
|
+
|
24
|
+
swagger_doc = @config.get_swagger_doc(metadata[:swagger_doc])
|
25
|
+
|
26
|
+
# This is called multiple times per file!
|
27
|
+
# metadata[:operation] is also re-used between examples within file
|
28
|
+
# therefore be careful NOT to modify its content here.
|
29
|
+
upgrade_request_type!(metadata)
|
30
|
+
upgrade_servers!(swagger_doc)
|
31
|
+
upgrade_oauth!(swagger_doc)
|
32
|
+
upgrade_response_produces!(swagger_doc, metadata)
|
33
|
+
|
34
|
+
swagger_doc.deep_merge!(metadata_to_swagger(metadata))
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop(_notification = nil)
|
38
|
+
@config.swagger_docs.each do |url_path, doc|
|
39
|
+
unless doc_version(doc).start_with?("2")
|
40
|
+
doc[:paths]&.each_pair do |_k, v|
|
41
|
+
v.each_pair do |_verb, value|
|
42
|
+
is_hash = value.is_a?(Hash)
|
43
|
+
if is_hash && value.dig(:parameters)
|
44
|
+
schema_param = value.dig(:parameters)&.find { |p| (p[:in] == :body || p[:in] == :formData) && p[:schema] }
|
45
|
+
mime_list = value.dig(:consumes)
|
46
|
+
if value && schema_param && mime_list
|
47
|
+
value[:requestBody] = { content: {} } unless value.dig(:requestBody, :content)
|
48
|
+
mime_list.each do |mime|
|
49
|
+
value[:requestBody][:content][mime] = { schema: schema_param[:schema] }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
value[:parameters].reject! { |p| p[:in] == :body || p[:in] == :formData }
|
54
|
+
end
|
55
|
+
remove_invalid_operation_keys!(value)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
file_path = File.join(@config.swagger_root, url_path)
|
61
|
+
dirname = File.dirname(file_path)
|
62
|
+
FileUtils.mkdir_p dirname unless File.exist?(dirname)
|
63
|
+
|
64
|
+
File.open(file_path, "w") do |file|
|
65
|
+
file.write(pretty_generate(doc))
|
66
|
+
end
|
67
|
+
|
68
|
+
@output.puts "Swagger doc generated at #{file_path}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def pretty_generate(doc)
|
75
|
+
if @config.swagger_format == :yaml
|
76
|
+
clean_doc = yaml_prepare(doc)
|
77
|
+
YAML.dump(clean_doc)
|
78
|
+
else # config errors are thrown in "def swagger_format", no throw needed here
|
79
|
+
JSON.pretty_generate(doc)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def yaml_prepare(doc)
|
84
|
+
json_doc = JSON.pretty_generate(doc)
|
85
|
+
JSON.parse(json_doc)
|
86
|
+
end
|
87
|
+
|
88
|
+
def metadata_to_swagger(metadata)
|
89
|
+
response_code = metadata[:response][:code]
|
90
|
+
response = metadata[:response].reject { |k, _v| k == :code }
|
91
|
+
|
92
|
+
verb = metadata[:operation][:verb]
|
93
|
+
operation = metadata[:operation]
|
94
|
+
.reject { |k, _v| k == :verb }
|
95
|
+
.merge(responses: { response_code => response })
|
96
|
+
|
97
|
+
path_template = metadata[:path_item][:template]
|
98
|
+
path_item = metadata[:path_item]
|
99
|
+
.reject { |k, _v| k == :template }
|
100
|
+
.merge(verb => operation)
|
101
|
+
|
102
|
+
{ paths: { path_template => path_item } }
|
103
|
+
end
|
104
|
+
|
105
|
+
def doc_version(doc)
|
106
|
+
doc[:openapi] || doc[:swagger] || "3"
|
107
|
+
end
|
108
|
+
|
109
|
+
def upgrade_response_produces!(swagger_doc, metadata)
|
110
|
+
# Accept header
|
111
|
+
mime_list = Array(metadata[:operation][:produces] || swagger_doc[:produces])
|
112
|
+
target_node = metadata[:response]
|
113
|
+
upgrade_content!(mime_list, target_node)
|
114
|
+
metadata[:response].delete(:schema)
|
115
|
+
end
|
116
|
+
|
117
|
+
def upgrade_content!(mime_list, target_node)
|
118
|
+
target_node.merge!(content: {})
|
119
|
+
schema = target_node[:schema]
|
120
|
+
return if mime_list.empty? || schema.nil?
|
121
|
+
|
122
|
+
mime_list.each do |mime_type|
|
123
|
+
# TODO upgrade to have content-type specific schema
|
124
|
+
target_node[:content][mime_type] = { schema: schema }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def upgrade_request_type!(metadata)
|
129
|
+
# No deprecation here as it seems valid to allow type as a shorthand
|
130
|
+
operation_nodes = metadata[:operation][:parameters] || []
|
131
|
+
path_nodes = metadata[:path_item][:parameters] || []
|
132
|
+
header_node = metadata[:response][:headers] || {}
|
133
|
+
|
134
|
+
(operation_nodes + path_nodes + [header_node]).each do |node|
|
135
|
+
if node && node[:type] && node[:schema].nil?
|
136
|
+
node[:schema] = { type: node[:type] }
|
137
|
+
node.delete(:type)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def upgrade_servers!(swagger_doc)
|
143
|
+
return unless swagger_doc[:servers].nil? && swagger_doc.key?(:schemes)
|
144
|
+
|
145
|
+
puts "Swagalicious: WARNING: schemes, host, and basePath are replaced in OpenAPI3! Rename to array of servers[{url}] (in swagger_helper.rb)"
|
146
|
+
|
147
|
+
swagger_doc[:servers] = { urls: [] }
|
148
|
+
swagger_doc[:schemes].each do |scheme|
|
149
|
+
swagger_doc[:servers][:urls] << scheme + "://" + swagger_doc[:host] + swagger_doc[:basePath]
|
150
|
+
end
|
151
|
+
|
152
|
+
swagger_doc.delete(:schemes)
|
153
|
+
swagger_doc.delete(:host)
|
154
|
+
swagger_doc.delete(:basePath)
|
155
|
+
end
|
156
|
+
|
157
|
+
def upgrade_oauth!(swagger_doc)
|
158
|
+
# find flow in securitySchemes (securityDefinitions will have been re-written)
|
159
|
+
schemes = swagger_doc.dig(:components, :securitySchemes)
|
160
|
+
return unless schemes&.any? { |_k, v| v.key?(:flow) }
|
161
|
+
|
162
|
+
schemes.each do |name, v|
|
163
|
+
next unless v.key?(:flow)
|
164
|
+
|
165
|
+
puts "Swagalicious: WARNING: securityDefinitions flow is replaced in OpenAPI3! Rename to components/securitySchemes/#{name}/flows[] (in swagger_helper.rb)"
|
166
|
+
|
167
|
+
flow = swagger_doc[:components][:securitySchemes][name].delete(:flow).to_s
|
168
|
+
|
169
|
+
if flow == "accessCode"
|
170
|
+
puts "Swagalicious: WARNING: securityDefinitions accessCode is replaced in OpenAPI3! Rename to clientCredentials (in swagger_helper.rb)"
|
171
|
+
flow = "authorizationCode"
|
172
|
+
end
|
173
|
+
|
174
|
+
if flow == "application"
|
175
|
+
puts "Swagalicious: WARNING: securityDefinitions application is replaced in OpenAPI3! Rename to authorizationCode (in swagger_helper.rb)"
|
176
|
+
flow = "clientCredentials"
|
177
|
+
end
|
178
|
+
|
179
|
+
flow_elements = swagger_doc[:components][:securitySchemes][name].except(:type).each_with_object({}) do |(k, _v), a|
|
180
|
+
a[k] = swagger_doc[:components][:securitySchemes][name].delete(k)
|
181
|
+
end
|
182
|
+
|
183
|
+
swagger_doc[:components][:securitySchemes][name].merge!(flows: { flow => flow_elements })
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def remove_invalid_operation_keys!(value)
|
188
|
+
is_hash = value.is_a?(Hash)
|
189
|
+
value.delete(:consumes) if is_hash && value.dig(:consumes)
|
190
|
+
value.delete(:produces) if is_hash && value.dig(:produces)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative "lib/swagalicious/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "swagalicious"
|
5
|
+
spec.version = Swagalicious::VERSION
|
6
|
+
spec.authors = ["Eugene Howe"]
|
7
|
+
spec.email = ["eugene@xtreme-computers.net"]
|
8
|
+
|
9
|
+
spec.summary = %q{RSwag without Rails}
|
10
|
+
spec.description = %q{This gem is almost a straight copy and paste of https://github.com/rswag/rswag/tree/master/rswag-specs with the Rails specific code stripped out so it can be used in Rack applications that don't use Rails.}
|
11
|
+
spec.homepage = "https://github.com/ehowe/swagalicious"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
14
|
+
|
15
|
+
spec.metadata["allowed_push_host"] = "https://rubygems.org"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
|
+
end
|
25
|
+
spec.require_paths = ["lib"]
|
26
|
+
|
27
|
+
spec.add_dependency "faraday", "~> 1.0.1"
|
28
|
+
spec.add_dependency "json-schema", "~> 2.8.1"
|
29
|
+
spec.add_dependency "oj", "~> 3.10.14"
|
30
|
+
spec.add_dependency "rack-test", "~> 1.1.0"
|
31
|
+
spec.add_dependency "rspec", "~> 3.9.0"
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: swagalicious
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eugene Howe
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-09-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.1
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json-schema
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.8.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.8.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: oj
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 3.10.14
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 3.10.14
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rack-test
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.1.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.1.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 3.9.0
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 3.9.0
|
83
|
+
description: This gem is almost a straight copy and paste of https://github.com/rswag/rswag/tree/master/rswag-specs
|
84
|
+
with the Rails specific code stripped out so it can be used in Rack applications
|
85
|
+
that don't use Rails.
|
86
|
+
email:
|
87
|
+
- eugene@xtreme-computers.net
|
88
|
+
executables: []
|
89
|
+
extensions: []
|
90
|
+
extra_rdoc_files: []
|
91
|
+
files:
|
92
|
+
- ".gitignore"
|
93
|
+
- ".rspec"
|
94
|
+
- ".rubocop.yml"
|
95
|
+
- ".travis.yml"
|
96
|
+
- Gemfile
|
97
|
+
- Gemfile.lock
|
98
|
+
- LICENSE.txt
|
99
|
+
- README.md
|
100
|
+
- Rakefile
|
101
|
+
- bin/console
|
102
|
+
- bin/setup
|
103
|
+
- lib/core/ext/hash.rb
|
104
|
+
- lib/swagalicious.rb
|
105
|
+
- lib/swagalicious/configuration.rb
|
106
|
+
- lib/swagalicious/example_group_helpers.rb
|
107
|
+
- lib/swagalicious/example_helpers.rb
|
108
|
+
- lib/swagalicious/extended_schema.rb
|
109
|
+
- lib/swagalicious/request_factory.rb
|
110
|
+
- lib/swagalicious/response_validator.rb
|
111
|
+
- lib/swagalicious/swagger_formatter.rb
|
112
|
+
- lib/swagalicious/version.rb
|
113
|
+
- swagalicious.gemspec
|
114
|
+
homepage: https://github.com/ehowe/swagalicious
|
115
|
+
licenses:
|
116
|
+
- MIT
|
117
|
+
metadata:
|
118
|
+
allowed_push_host: https://rubygems.org
|
119
|
+
homepage_uri: https://github.com/ehowe/swagalicious
|
120
|
+
source_code_uri: https://github.com/ehowe/swagalicious
|
121
|
+
post_install_message:
|
122
|
+
rdoc_options: []
|
123
|
+
require_paths:
|
124
|
+
- lib
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
126
|
+
requirements:
|
127
|
+
- - ">="
|
128
|
+
- !ruby/object:Gem::Version
|
129
|
+
version: 2.3.0
|
130
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
131
|
+
requirements:
|
132
|
+
- - ">="
|
133
|
+
- !ruby/object:Gem::Version
|
134
|
+
version: '0'
|
135
|
+
requirements: []
|
136
|
+
rubygems_version: 3.0.6
|
137
|
+
signing_key:
|
138
|
+
specification_version: 4
|
139
|
+
summary: RSwag without Rails
|
140
|
+
test_files: []
|