sober_swag 0.19.0 → 0.20.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/.github/workflows/lint.yml +1 -1
- data/.github/workflows/ruby.yml +1 -1
- data/.gitignore +2 -0
- data/.rubocop.yml +5 -1
- data/.yardopts +7 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +8 -0
- data/README.md +1 -1
- data/docs/serializers.md +3 -0
- data/example/Gemfile +1 -1
- data/example/config/environments/production.rb +1 -1
- data/lib/sober_swag.rb +6 -1
- data/lib/sober_swag/compiler.rb +29 -3
- data/lib/sober_swag/compiler/path.rb +42 -3
- data/lib/sober_swag/compiler/paths.rb +20 -0
- data/lib/sober_swag/compiler/primitive.rb +17 -0
- data/lib/sober_swag/compiler/type.rb +105 -22
- data/lib/sober_swag/controller.rb +39 -12
- data/lib/sober_swag/controller/route.rb +103 -20
- data/lib/sober_swag/input_object.rb +90 -7
- data/lib/sober_swag/nodes/array.rb +19 -0
- data/lib/sober_swag/nodes/attribute.rb +45 -4
- data/lib/sober_swag/nodes/base.rb +27 -7
- data/lib/sober_swag/nodes/binary.rb +30 -13
- data/lib/sober_swag/nodes/enum.rb +16 -1
- data/lib/sober_swag/nodes/list.rb +20 -0
- data/lib/sober_swag/nodes/nullable_primitive.rb +3 -0
- data/lib/sober_swag/nodes/object.rb +4 -1
- data/lib/sober_swag/nodes/one_of.rb +11 -3
- data/lib/sober_swag/nodes/primitive.rb +34 -2
- data/lib/sober_swag/nodes/sum.rb +8 -0
- data/lib/sober_swag/output_object.rb +35 -4
- data/lib/sober_swag/output_object/definition.rb +31 -1
- data/lib/sober_swag/output_object/field.rb +31 -11
- data/lib/sober_swag/output_object/field_syntax.rb +19 -3
- data/lib/sober_swag/output_object/view.rb +46 -1
- data/lib/sober_swag/parser.rb +7 -1
- data/lib/sober_swag/serializer/array.rb +27 -3
- data/lib/sober_swag/serializer/base.rb +75 -25
- data/lib/sober_swag/serializer/conditional.rb +33 -1
- data/lib/sober_swag/serializer/field_list.rb +18 -2
- data/lib/sober_swag/serializer/mapped.rb +10 -1
- data/lib/sober_swag/serializer/optional.rb +18 -1
- data/lib/sober_swag/serializer/primitive.rb +3 -0
- data/lib/sober_swag/server.rb +5 -1
- data/lib/sober_swag/type/named.rb +14 -0
- data/lib/sober_swag/types/comma_array.rb +4 -0
- data/lib/sober_swag/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97cb4bbfd84f28f6f79368c3f78182835217868a1d3142c38107ab3b03552952
|
4
|
+
data.tar.gz: 1cd8446250a8ddadc16eb114a773b9d317c2182e2bcb8c692c59681331ef972b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f6b055ea451db16f12a02ebe2bc6da459aefcf13605a54f4f0b0cff8aa694b73e2c4cb2c2f759a89c859a820a74a37391728998e0939a770cda2783c2190586e
|
7
|
+
data.tar.gz: 3a49c153297750447c2776b086da135b81c80a1b628780d9a7ab6f68f204ddeaa3b21e08ffd02f8a49e92f1a7ac5942b0e42d295307299e8623ebb6a765731dd
|
data/.github/workflows/lint.yml
CHANGED
data/.github/workflows/ruby.yml
CHANGED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -2,6 +2,7 @@ require: rubocop-rspec
|
|
2
2
|
|
3
3
|
AllCops:
|
4
4
|
TargetRubyVersion: 2.6.0
|
5
|
+
NewCops: enable
|
5
6
|
Exclude:
|
6
7
|
- 'bin/bundle'
|
7
8
|
- 'example/bin/bundle'
|
@@ -22,6 +23,9 @@ Metrics/BlockLength:
|
|
22
23
|
- 'sober_swag.gemspec'
|
23
24
|
- 'example/spec/**/*.rb'
|
24
25
|
|
26
|
+
Lint/MissingSuper:
|
27
|
+
Enabled: false
|
28
|
+
|
25
29
|
RSpec/ImplicitBlockExpectation:
|
26
30
|
Enabled: false
|
27
31
|
|
@@ -123,4 +127,4 @@ Style/FrozenStringLiteralComment:
|
|
123
127
|
Enabled: false
|
124
128
|
|
125
129
|
Style/BlockDelimiters:
|
126
|
-
EnforcedStyle: braces_for_chaining
|
130
|
+
EnforcedStyle: braces_for_chaining
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v0.20.0] 2021-05-17
|
4
|
+
|
5
|
+
- Added YARD documentation to almost every method
|
6
|
+
- Added `except` parameter to the `merge` method, which allows a specified field to be excluded from the merge.
|
7
|
+
|
3
8
|
## [v0.19.0] 2021-03-10
|
4
9
|
|
5
10
|
- Use [redoc](https://github.com/Redocly/redoc) for generated documentation UI
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -11,7 +11,7 @@ An introductory presentation is available [here](https://www.icloud.com/keynote/
|
|
11
11
|
|
12
12
|
Further documentation on using the gem is available in the `docs/` directory:
|
13
13
|
|
14
|
-
-
|
14
|
+
- {file:docs/serializers.md Serializers}
|
15
15
|
|
16
16
|
## Types for a fully-automated API
|
17
17
|
|
data/docs/serializers.md
CHANGED
@@ -241,6 +241,9 @@ end
|
|
241
241
|
Using `#merge` lets you add in all the fields from one output object into another.
|
242
242
|
You can even use `merge` from within a view.
|
243
243
|
|
244
|
+
Exclude any unneeded fields from the merge by passing a hash:
|
245
|
+
`merge GenericBioOutput, { except: [:position] }`
|
246
|
+
|
244
247
|
Note that `merge` does *not* copy anything but fields.
|
245
248
|
Identifiers and views will not be copied over.
|
246
249
|
|
data/example/Gemfile
CHANGED
@@ -34,7 +34,7 @@ group :development, :test do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
group :development do
|
37
|
-
gem 'listen', '>= 3.0.5', '< 3.
|
37
|
+
gem 'listen', '>= 3.0.5', '< 3.6'
|
38
38
|
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
|
39
39
|
gem 'spring'
|
40
40
|
gem 'spring-watcher-listen', '~> 2.0.0'
|
@@ -60,7 +60,7 @@ Rails.application.configure do
|
|
60
60
|
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
|
61
61
|
|
62
62
|
if ENV['RAILS_LOG_TO_STDOUT'].present?
|
63
|
-
logger = ActiveSupport::Logger.new(
|
63
|
+
logger = ActiveSupport::Logger.new($stdout)
|
64
64
|
logger.formatter = config.log_formatter
|
65
65
|
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
66
66
|
end
|
data/lib/sober_swag.rb
CHANGED
@@ -9,8 +9,10 @@ require 'sober_swag/version'
|
|
9
9
|
require 'active_support/inflector'
|
10
10
|
|
11
11
|
##
|
12
|
-
# Root namespace
|
12
|
+
# Root namespace for the SoberSwag Module.
|
13
13
|
module SoberSwag
|
14
|
+
##
|
15
|
+
# Root Error Class for SoberSwag errors.
|
14
16
|
class Error < StandardError; end
|
15
17
|
|
16
18
|
autoload :Parser, 'sober_swag/parser'
|
@@ -26,7 +28,10 @@ module SoberSwag
|
|
26
28
|
##
|
27
29
|
# Define a struct of something.
|
28
30
|
# Useful to prevent weirdness from autoloading.
|
31
|
+
#
|
29
32
|
# @param parent [Class] the base class for the struct (default of {SoberSwag::Struct})
|
33
|
+
# @yieldself [SoberSwag::InputObject]
|
34
|
+
# @return [Class] the input object class generated
|
30
35
|
def self.input_object(parent = nil, &block)
|
31
36
|
Class.new(parent || SoberSwag::InputObject, &block)
|
32
37
|
end
|
data/lib/sober_swag/compiler.rb
CHANGED
@@ -17,6 +17,8 @@ module SoberSwag
|
|
17
17
|
|
18
18
|
##
|
19
19
|
# Convert a compiler to the overall type definition.
|
20
|
+
#
|
21
|
+
# @return Hash the swagger definition.
|
20
22
|
def to_swagger
|
21
23
|
{
|
22
24
|
paths: path_schemas,
|
@@ -29,16 +31,23 @@ module SoberSwag
|
|
29
31
|
##
|
30
32
|
# Add a path to be compiled.
|
31
33
|
# @param route [SoberSwag::Controller::Route] the route to add.
|
34
|
+
# @return [Compiler] self
|
32
35
|
def add_route(route)
|
33
36
|
tap { @paths.add_route(route) }
|
34
37
|
end
|
35
38
|
|
39
|
+
##
|
40
|
+
# Get the schema of each object type defined in this Compiler.
|
41
|
+
#
|
42
|
+
# @return [Hash]
|
36
43
|
def object_schemas
|
37
44
|
@types.map { |v| [v.ref_name, v.object_schema] }.to_h
|
38
45
|
end
|
39
46
|
|
40
47
|
##
|
41
48
|
# The path section of the swagger schema.
|
49
|
+
#
|
50
|
+
# @return [Hash]
|
42
51
|
def path_schemas
|
43
52
|
@paths.paths_list(self)
|
44
53
|
end
|
@@ -46,6 +55,9 @@ module SoberSwag
|
|
46
55
|
##
|
47
56
|
# Compile a type to a new, path-params list.
|
48
57
|
# This will add all subtypes to the found types list.
|
58
|
+
#
|
59
|
+
# @param type [Class] the type to get a path_params definition for
|
60
|
+
# @return [Hash]
|
49
61
|
def path_params_for(type)
|
50
62
|
with_types_discovered(type).path_schema
|
51
63
|
end
|
@@ -53,6 +65,9 @@ module SoberSwag
|
|
53
65
|
##
|
54
66
|
# Get the query params list for a type.
|
55
67
|
# All found types will be added to the reference dictionary.
|
68
|
+
#
|
69
|
+
# @param type [Class] the type to get the query_params definitions for
|
70
|
+
# @return [Hash]
|
56
71
|
def query_params_for(type)
|
57
72
|
with_types_discovered(type).query_schema
|
58
73
|
end
|
@@ -60,25 +75,36 @@ module SoberSwag
|
|
60
75
|
##
|
61
76
|
# Get the request body definition for a type.
|
62
77
|
# This will always be a ref.
|
78
|
+
#
|
79
|
+
# @param type [Class] the type to get the body definition for
|
80
|
+
# @return [Hash]
|
63
81
|
def body_for(type)
|
64
82
|
add_type(type)
|
65
83
|
Type.new(type).schema_stub
|
66
84
|
end
|
67
85
|
|
68
86
|
##
|
69
|
-
# Get the definition of a response type
|
87
|
+
# Get the definition of a response type.
|
88
|
+
#
|
89
|
+
# This is an alias of {#body_for}
|
90
|
+
# @see body_for
|
70
91
|
def response_for(type)
|
71
92
|
body_for(type)
|
72
93
|
end
|
73
94
|
|
74
95
|
##
|
75
|
-
# Get the existing schema for a given type
|
96
|
+
# Get the existing schema for a given type.
|
97
|
+
#
|
98
|
+
# @param type [Class] the type to get the schema for
|
99
|
+
# @return [Hash,nil] the swagger schema for this object, or nil if it was not found.
|
76
100
|
def schema_for(type)
|
77
101
|
@types.find { |type_comp| type_comp.type == type }&.object_schema
|
78
102
|
end
|
79
103
|
|
80
104
|
##
|
81
|
-
# Add a type in the types reference dictionary, essentially
|
105
|
+
# Add a type in the types reference dictionary, essentially.
|
106
|
+
# @param type [Class] the type to compiler
|
107
|
+
# @return [SoberSwag::Compiler] self
|
82
108
|
def add_type(type)
|
83
109
|
# use tap here to avoid an explicit self at the end of this
|
84
110
|
# which makes this method chainable
|
@@ -1,8 +1,11 @@
|
|
1
1
|
module SoberSwag
|
2
2
|
class Compiler
|
3
3
|
##
|
4
|
-
#
|
5
|
-
#
|
4
|
+
# This compiler transforms a {SoberSwag::Controller::Route} object into its associated OpenAPI V3 definition.
|
5
|
+
# These definitions are [called "paths" in the OpenAPI V3 spec](https://swagger.io/docs/specification/paths-and-operations/),
|
6
|
+
# thus the name of this compiler.
|
7
|
+
#
|
8
|
+
# It only compiles a *single* "path" at a time.
|
6
9
|
class Path
|
7
10
|
##
|
8
11
|
# @param route [SoberSwag::Controller::Route] a route to use
|
@@ -12,8 +15,18 @@ module SoberSwag
|
|
12
15
|
@compiler = compiler
|
13
16
|
end
|
14
17
|
|
15
|
-
|
18
|
+
##
|
19
|
+
# @return [SoberSwag::Controller::Route]
|
20
|
+
attr_reader :route
|
21
|
+
|
22
|
+
##
|
23
|
+
# @return [SoberSwag::Compiler] the compiler used for type compilation
|
24
|
+
attr_reader :compiler
|
16
25
|
|
26
|
+
##
|
27
|
+
# The OpenAPI V3 "path" object for the associated {SoberSwag::Controller::Route}
|
28
|
+
#
|
29
|
+
# @return [Hash] the OpenAPI V3 description
|
17
30
|
def schema
|
18
31
|
base = {}
|
19
32
|
base[:summary] = route.summary if route.summary
|
@@ -25,6 +38,11 @@ module SoberSwag
|
|
25
38
|
base
|
26
39
|
end
|
27
40
|
|
41
|
+
##
|
42
|
+
# An array of "response" objects from swagger.
|
43
|
+
#
|
44
|
+
# @return [Hash{String => Hash}]
|
45
|
+
# response code to response object.
|
28
46
|
def responses # rubocop:disable Metrics/MethodLength
|
29
47
|
route.response_serializers.map { |status, serializer|
|
30
48
|
[
|
@@ -41,10 +59,19 @@ module SoberSwag
|
|
41
59
|
}.to_h
|
42
60
|
end
|
43
61
|
|
62
|
+
##
|
63
|
+
# An array of all parameters, be they in the query or in the path.
|
64
|
+
# See [this page](https://swagger.io/docs/specification/serialization/) for what that looks like.
|
65
|
+
#
|
66
|
+
# @return [Array<Hash>]
|
44
67
|
def params
|
45
68
|
query_params + path_params
|
46
69
|
end
|
47
70
|
|
71
|
+
##
|
72
|
+
# An array of schemas for all query parameters.
|
73
|
+
#
|
74
|
+
# @return [Array<Hash>] the schemas
|
48
75
|
def query_params
|
49
76
|
if route.query_params_class
|
50
77
|
compiler.query_params_for(route.query_params_class)
|
@@ -53,6 +80,10 @@ module SoberSwag
|
|
53
80
|
end
|
54
81
|
end
|
55
82
|
|
83
|
+
##
|
84
|
+
# An array of schemas for all path parameters.
|
85
|
+
#
|
86
|
+
# @return [Array<Hash>] the schemas
|
56
87
|
def path_params
|
57
88
|
if route.path_params_class
|
58
89
|
compiler.path_params_for(route.path_params_class)
|
@@ -61,6 +92,11 @@ module SoberSwag
|
|
61
92
|
end
|
62
93
|
end
|
63
94
|
|
95
|
+
##
|
96
|
+
# The schema for a request body.
|
97
|
+
# Matches [this spec.](https://swagger.io/docs/specification/paths-and-operations/)
|
98
|
+
#
|
99
|
+
# @return [Hash] the schema
|
64
100
|
def request_body
|
65
101
|
return nil unless route.request_body_class
|
66
102
|
|
@@ -74,6 +110,9 @@ module SoberSwag
|
|
74
110
|
}
|
75
111
|
end
|
76
112
|
|
113
|
+
##
|
114
|
+
# The tags for this path.
|
115
|
+
# @return [Array<String>] the tags
|
77
116
|
def tags
|
78
117
|
return nil unless route.tags.any?
|
79
118
|
|
@@ -2,15 +2,28 @@ module SoberSwag
|
|
2
2
|
class Compiler
|
3
3
|
##
|
4
4
|
# Compile multiple routes into a paths set.
|
5
|
+
# This basically just aggregates {SoberSwag::Controller::Route} objects.
|
5
6
|
class Paths
|
7
|
+
##
|
8
|
+
# Set up a new paths compiler with no routes in it.
|
6
9
|
def initialize
|
7
10
|
@routes = []
|
8
11
|
end
|
9
12
|
|
13
|
+
##
|
14
|
+
# Add on a new {SoberSwag::Controller::Route}
|
15
|
+
#
|
16
|
+
# @param route [SoberSwag::Controller::Route] the route description to add to compilation
|
17
|
+
# @return [SoberSwag::Compiler::Paths] self
|
10
18
|
def add_route(route)
|
11
19
|
@routes << route
|
20
|
+
|
21
|
+
self
|
12
22
|
end
|
13
23
|
|
24
|
+
##
|
25
|
+
# In the OpenAPI V3 spec, we group action definitions by their path.
|
26
|
+
# This helps us do that.
|
14
27
|
def grouped_paths
|
15
28
|
routes.group_by(&:path)
|
16
29
|
end
|
@@ -20,6 +33,9 @@ module SoberSwag
|
|
20
33
|
# paths list. Since this is only a compiler for paths,
|
21
34
|
# it has *no idea* how to handle types. So, it takes a compiler
|
22
35
|
# which it will use to do that for it.
|
36
|
+
#
|
37
|
+
# @param compiler [SoberSwag::Compiler::Type] the type compiler to use
|
38
|
+
# @return [Hash] a schema for all contained routes.
|
23
39
|
def paths_list(compiler)
|
24
40
|
grouped_paths.transform_values do |values|
|
25
41
|
values.map { |route|
|
@@ -31,6 +47,8 @@ module SoberSwag
|
|
31
47
|
##
|
32
48
|
# Get a list of all types we discovered when compiling
|
33
49
|
# the paths.
|
50
|
+
#
|
51
|
+
# @yield [Class] all the types found in all the routes described in here.
|
34
52
|
def found_types
|
35
53
|
return enum_for(:found_types) unless block_given?
|
36
54
|
|
@@ -41,6 +59,8 @@ module SoberSwag
|
|
41
59
|
end
|
42
60
|
end
|
43
61
|
|
62
|
+
##
|
63
|
+
# @return [Array<SoberSwag::Controller::Route>] the routes to document
|
44
64
|
attr_reader :routes
|
45
65
|
|
46
66
|
private
|
@@ -4,7 +4,11 @@ module SoberSwag
|
|
4
4
|
# Compiles a primitive type.
|
5
5
|
# Almost always constructed with the values from
|
6
6
|
# {SoberSwag::Nodes::Primitive}.
|
7
|
+
#
|
8
|
+
# This works by either generating a swagger primitive definition, *or* a `$ref` to one with a given identifier.
|
7
9
|
class Primitive
|
10
|
+
##
|
11
|
+
# @param type [Class] the swagger-able class to document.
|
8
12
|
def initialize(type)
|
9
13
|
@type = type
|
10
14
|
|
@@ -13,6 +17,8 @@ module SoberSwag
|
|
13
17
|
|
14
18
|
attr_reader :type
|
15
19
|
|
20
|
+
##
|
21
|
+
# Is this documenting one of the build-in swagger types?
|
16
22
|
def swagger_primitive?
|
17
23
|
SWAGGER_PRIMITIVE_DEFS.include?(type)
|
18
24
|
end
|
@@ -25,6 +31,9 @@ module SoberSwag
|
|
25
31
|
|
26
32
|
##
|
27
33
|
# Turn this type into a swagger hash with a proper type key.
|
34
|
+
# This is suitable for use as the value of a `schema` key in a definition.
|
35
|
+
#
|
36
|
+
# @return [Hash] the schema.
|
28
37
|
def type_hash
|
29
38
|
if swagger_primitive?
|
30
39
|
SWAGGER_PRIMITIVE_DEFS.fetch(type)
|
@@ -37,10 +46,16 @@ module SoberSwag
|
|
37
46
|
end
|
38
47
|
end
|
39
48
|
|
49
|
+
##
|
50
|
+
# Primitive schema used for ruby `Date` values.
|
40
51
|
DATE_PRIMITIVE = { type: :string, format: :date }.freeze
|
52
|
+
##
|
53
|
+
# Primitive schema used for ruby `DateTime` values.
|
41
54
|
DATE_TIME_PRIMITIVE = { type: :string, format: :'date-time' }.freeze
|
42
55
|
HASH_PRIMITIVE = { type: :object, additionalProperties: true }.freeze
|
43
56
|
|
57
|
+
##
|
58
|
+
# Map of types that are considered "primitive types" in the OpenAPI V3 spec.
|
44
59
|
SWAGGER_PRIMITIVE_DEFS =
|
45
60
|
{
|
46
61
|
NilClass => :null,
|
@@ -57,6 +72,8 @@ module SoberSwag
|
|
57
72
|
Hash => HASH_PRIMITIVE
|
58
73
|
).transform_values(&:freeze).freeze
|
59
74
|
|
75
|
+
##
|
76
|
+
# @return [String] the schema reference
|
60
77
|
def ref_name
|
61
78
|
raise Error, 'is not a type that is named!' if swagger_primitive?
|
62
79
|
|