sober_swag 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/config/rubocop_linter_action.yml +5 -0
- data/.github/workflows/lint.yml +15 -0
- data/.github/workflows/ruby.yml +23 -1
- data/.gitignore +3 -0
- data/.rubocop.yml +73 -1
- data/.ruby-version +1 -1
- data/Gemfile.lock +29 -5
- data/README.md +109 -0
- data/bin/console +15 -14
- data/docs/serializers.md +203 -0
- data/example/.rspec +1 -0
- data/example/.ruby-version +1 -1
- data/example/Gemfile +10 -6
- data/example/Gemfile.lock +96 -76
- data/example/app/controllers/people_controller.rb +37 -21
- data/example/app/controllers/posts_controller.rb +102 -0
- data/example/app/models/application_record.rb +3 -0
- data/example/app/models/person.rb +6 -0
- data/example/app/models/post.rb +9 -0
- data/example/app/output_objects/person_errors_output_object.rb +5 -0
- data/example/app/output_objects/person_output_object.rb +15 -0
- data/example/app/output_objects/post_output_object.rb +10 -0
- data/example/bin/bundle +24 -20
- data/example/bin/rails +1 -1
- data/example/bin/rake +1 -1
- data/example/config/application.rb +11 -7
- data/example/config/environments/development.rb +0 -1
- data/example/config/environments/production.rb +3 -3
- data/example/config/puma.rb +5 -5
- data/example/config/routes.rb +3 -0
- data/example/config/spring.rb +4 -4
- data/example/db/migrate/20200311152021_create_people.rb +0 -1
- data/example/db/migrate/20200603172347_create_posts.rb +11 -0
- data/example/db/schema.rb +16 -7
- data/example/spec/rails_helper.rb +64 -0
- data/example/spec/requests/people/create_spec.rb +52 -0
- data/example/spec/requests/people/get_spec.rb +35 -0
- data/example/spec/requests/people/index_spec.rb +69 -0
- data/example/spec/spec_helper.rb +94 -0
- data/lib/sober_swag.rb +6 -3
- data/lib/sober_swag/compiler/error.rb +2 -0
- data/lib/sober_swag/compiler/path.rb +2 -5
- data/lib/sober_swag/compiler/paths.rb +0 -1
- data/lib/sober_swag/compiler/type.rb +28 -15
- data/lib/sober_swag/controller.rb +16 -11
- data/lib/sober_swag/controller/route.rb +18 -21
- data/lib/sober_swag/controller/undefined_body_error.rb +3 -0
- data/lib/sober_swag/controller/undefined_path_error.rb +3 -0
- data/lib/sober_swag/controller/undefined_query_error.rb +3 -0
- data/lib/sober_swag/input_object.rb +28 -0
- data/lib/sober_swag/nodes/array.rb +1 -1
- data/lib/sober_swag/nodes/base.rb +2 -4
- data/lib/sober_swag/nodes/binary.rb +2 -1
- data/lib/sober_swag/nodes/enum.rb +4 -2
- data/lib/sober_swag/nodes/list.rb +0 -1
- data/lib/sober_swag/nodes/primitive.rb +6 -5
- data/lib/sober_swag/output_object.rb +102 -0
- data/lib/sober_swag/output_object/definition.rb +30 -0
- data/lib/sober_swag/{blueprint → output_object}/field.rb +14 -4
- data/lib/sober_swag/{blueprint → output_object}/field_syntax.rb +1 -1
- data/lib/sober_swag/{blueprint → output_object}/view.rb +15 -6
- data/lib/sober_swag/parser.rb +5 -3
- data/lib/sober_swag/serializer.rb +5 -2
- data/lib/sober_swag/serializer/array.rb +12 -0
- data/lib/sober_swag/serializer/base.rb +50 -1
- data/lib/sober_swag/serializer/conditional.rb +15 -2
- data/lib/sober_swag/serializer/field_list.rb +29 -6
- data/lib/sober_swag/serializer/mapped.rb +12 -2
- data/lib/sober_swag/serializer/meta.rb +35 -0
- data/lib/sober_swag/serializer/optional.rb +17 -2
- data/lib/sober_swag/serializer/primitive.rb +4 -1
- data/lib/sober_swag/server.rb +83 -0
- data/lib/sober_swag/types.rb +3 -0
- data/lib/sober_swag/version.rb +1 -1
- data/sober_swag.gemspec +6 -4
- metadata +77 -44
- data/example/person.json +0 -4
- data/example/test/controllers/.keep +0 -0
- data/example/test/fixtures/.keep +0 -0
- data/example/test/fixtures/files/.keep +0 -0
- data/example/test/fixtures/people.yml +0 -11
- data/example/test/integration/.keep +0 -0
- data/example/test/models/.keep +0 -0
- data/example/test/models/person_test.rb +0 -7
- data/example/test/test_helper.rb +0 -13
- data/lib/sober_swag/blueprint.rb +0 -113
- data/lib/sober_swag/path.rb +0 -8
- data/lib/sober_swag/path/integer.rb +0 -21
- data/lib/sober_swag/path/lit.rb +0 -41
- data/lib/sober_swag/path/literal.rb +0 -29
- data/lib/sober_swag/path/param.rb +0 -33
@@ -1,14 +1,16 @@
|
|
1
1
|
module SoberSwag
|
2
|
-
class
|
2
|
+
class OutputObject
|
3
|
+
##
|
4
|
+
# DSL for defining a view.
|
5
|
+
# Used in `view` blocks within {SoberSwag::OutputObject.define}.
|
3
6
|
class View
|
4
|
-
|
5
7
|
def self.define(name, base_fields, &block)
|
6
|
-
|
8
|
+
new(name, base_fields).tap do |view|
|
7
9
|
view.instance_eval(&block)
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
11
|
-
class NestingError < Error; end
|
13
|
+
class NestingError < Error; end
|
12
14
|
|
13
15
|
include FieldSyntax
|
14
16
|
|
@@ -19,8 +21,16 @@ module SoberSwag
|
|
19
21
|
|
20
22
|
attr_reader :name, :fields
|
21
23
|
|
24
|
+
def serialize(obj, opts = {})
|
25
|
+
serializer.serialize(obj, opts)
|
26
|
+
end
|
27
|
+
|
28
|
+
def type
|
29
|
+
serializer.type
|
30
|
+
end
|
31
|
+
|
22
32
|
def except!(name)
|
23
|
-
@fields.
|
33
|
+
@fields.reject! { |f| f.name == name }
|
24
34
|
end
|
25
35
|
|
26
36
|
def view(*)
|
@@ -38,7 +48,6 @@ module SoberSwag
|
|
38
48
|
@serializer ||=
|
39
49
|
SoberSwag::Serializer::FieldList.new(fields)
|
40
50
|
end
|
41
|
-
|
42
51
|
end
|
43
52
|
end
|
44
53
|
end
|
data/lib/sober_swag/parser.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
module SoberSwag
|
2
|
+
##
|
3
|
+
# Parses a *Dry-Types Schema* into a set of nodes we can use to compile.
|
4
|
+
# This is mostly because the vistior pattern sucks and catamorphisms are nice.
|
2
5
|
class Parser
|
3
6
|
def initialize(node)
|
4
7
|
@node = node
|
5
8
|
@found = Set.new
|
6
9
|
end
|
7
10
|
|
8
|
-
def to_syntax
|
11
|
+
def to_syntax # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
9
12
|
case @node
|
10
13
|
when Dry::Types::Array::Member
|
11
14
|
Nodes::List.new(bind(Parser.new(@node.member)))
|
@@ -41,7 +44,7 @@ module SoberSwag
|
|
41
44
|
bind(Parser.new(@node.type))
|
42
45
|
when Dry::Types::Nominal
|
43
46
|
# start off with the moral equivalent of NodeTree[String]
|
44
|
-
Nodes::Primitive.new(@node.primitive)
|
47
|
+
Nodes::Primitive.new(@node.primitive, @node.meta)
|
45
48
|
else
|
46
49
|
# Inside of this case we have a class that is some user-defined type
|
47
50
|
# We put it in our array of found types, and consider it a primitive
|
@@ -68,6 +71,5 @@ module SoberSwag
|
|
68
71
|
@found += other.found
|
69
72
|
result
|
70
73
|
end
|
71
|
-
|
72
74
|
end
|
73
75
|
end
|
@@ -1,4 +1,7 @@
|
|
1
1
|
module SoberSwag
|
2
|
+
##
|
3
|
+
# Container module for serializers.
|
4
|
+
# The interface for these is described in {SoberSwag::Serializer::Base}.
|
2
5
|
module Serializer
|
3
6
|
autoload(:Base, 'sober_swag/serializer/base')
|
4
7
|
autoload(:Primitive, 'sober_swag/serializer/primitive')
|
@@ -7,6 +10,7 @@ module SoberSwag
|
|
7
10
|
autoload(:Mapped, 'sober_swag/serializer/mapped')
|
8
11
|
autoload(:Optional, 'sober_swag/serializer/optional')
|
9
12
|
autoload(:FieldList, 'sober_swag/serializer/field_list')
|
13
|
+
autoload(:Meta, 'sober_swag/serializer/meta')
|
10
14
|
|
11
15
|
class << self
|
12
16
|
##
|
@@ -14,10 +18,9 @@ module SoberSwag
|
|
14
18
|
# in values raw.
|
15
19
|
#
|
16
20
|
# @param contained {Class} Dry::Type to use
|
17
|
-
def Primitive(contained)
|
21
|
+
def Primitive(contained) # rubocop:disable Naming/MethodName
|
18
22
|
SoberSwag::Serializer::Primitive.new(contained)
|
19
23
|
end
|
20
24
|
end
|
21
|
-
|
22
25
|
end
|
23
26
|
end
|
@@ -7,6 +7,18 @@ module SoberSwag
|
|
7
7
|
@element_serializer = element_serializer
|
8
8
|
end
|
9
9
|
|
10
|
+
def lazy_type?
|
11
|
+
@element_serializer.lazy_type?
|
12
|
+
end
|
13
|
+
|
14
|
+
def lazy_type
|
15
|
+
SoberSwag::Types::Array.of(@element_serializer.lazy_type)
|
16
|
+
end
|
17
|
+
|
18
|
+
def finalize_lazy_type!
|
19
|
+
@element_serializer.finalize_lazy_type!
|
20
|
+
end
|
21
|
+
|
10
22
|
attr_reader :element_serializer
|
11
23
|
|
12
24
|
def serialize(object, options = {})
|
@@ -1,7 +1,10 @@
|
|
1
1
|
module SoberSwag
|
2
2
|
module Serializer
|
3
|
+
##
|
4
|
+
# Base interface class that all other serializers are subclasses of.
|
5
|
+
# This also defines methods as stubs, which is sort of bad ruby style, but makes documentation
|
6
|
+
# easier to generate.
|
3
7
|
class Base
|
4
|
-
|
5
8
|
##
|
6
9
|
# Return a new serializer that is an *array* of elements of this serializer.
|
7
10
|
def array
|
@@ -14,6 +17,46 @@ module SoberSwag
|
|
14
17
|
SoberSwag::Serializer::Optional.new(self)
|
15
18
|
end
|
16
19
|
|
20
|
+
##
|
21
|
+
# Is this type lazily defined?
|
22
|
+
#
|
23
|
+
# Used for mutual recursion.
|
24
|
+
def lazy_type?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
##
|
29
|
+
# The lazy version of this type, for mutual recursion.
|
30
|
+
def lazy_type
|
31
|
+
type
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Finalize a lazy type.
|
36
|
+
#
|
37
|
+
# Should be idempotent: call it once, and it does nothing on subsequent calls (but returns the type).
|
38
|
+
def finalize_lazy_type!
|
39
|
+
type
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Serialize an object.
|
44
|
+
def serialize(_object, _options = {})
|
45
|
+
raise ArgumentError, 'not implemented!'
|
46
|
+
end
|
47
|
+
|
48
|
+
##
|
49
|
+
# Get the type that we serialize to.
|
50
|
+
def type
|
51
|
+
raise ArgumentError, 'not implemented!'
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# Add metadata onto the *type* of a serializer.
|
56
|
+
def meta(hash)
|
57
|
+
SoberSwag::Serializer::Meta.new(self, hash)
|
58
|
+
end
|
59
|
+
|
17
60
|
##
|
18
61
|
# If I am a serializer for type 'a', and you give me a way to turn 'a's into 'b's,
|
19
62
|
# I can give you a serializer for type 'b' by running the funciton you gave.
|
@@ -33,6 +76,12 @@ module SoberSwag
|
|
33
76
|
self
|
34
77
|
end
|
35
78
|
|
79
|
+
##
|
80
|
+
# Get the type name of this to be used externally, or set it if an argument is provided
|
81
|
+
def identifier(arg = nil)
|
82
|
+
@identifier = arg if arg
|
83
|
+
@identifier
|
84
|
+
end
|
36
85
|
end
|
37
86
|
end
|
38
87
|
end
|
@@ -25,9 +25,10 @@ module SoberSwag
|
|
25
25
|
|
26
26
|
def serialize(object, options = {})
|
27
27
|
tag, val = chooser.call(object, options)
|
28
|
-
|
28
|
+
case tag
|
29
|
+
when :left
|
29
30
|
left.serialize(val, options)
|
30
|
-
|
31
|
+
when :right
|
31
32
|
right.serialize(val, options)
|
32
33
|
else
|
33
34
|
raise BadChoiceError, "result of chooser proc was not a left or right, but a #{val.class}"
|
@@ -44,6 +45,18 @@ module SoberSwag
|
|
44
45
|
left.type | right.type
|
45
46
|
end
|
46
47
|
end
|
48
|
+
|
49
|
+
def lazy_type
|
50
|
+
left.lazy_type | right.lazy_type
|
51
|
+
end
|
52
|
+
|
53
|
+
def lazy_type?
|
54
|
+
left.lazy_type? || right.lazy_type?
|
55
|
+
end
|
56
|
+
|
57
|
+
def finalize_lazy_type!
|
58
|
+
[left, right].each(&:finalize_lazy_type!)
|
59
|
+
end
|
47
60
|
end
|
48
61
|
end
|
49
62
|
end
|
@@ -4,7 +4,6 @@ module SoberSwag
|
|
4
4
|
# Extract out a hash from a list of
|
5
5
|
# name/serializer pairs.
|
6
6
|
class FieldList < Base
|
7
|
-
|
8
7
|
def initialize(field_list)
|
9
8
|
@field_list = field_list
|
10
9
|
end
|
@@ -17,8 +16,7 @@ module SoberSwag
|
|
17
16
|
SoberSwag::Serializer.Primitive(SoberSwag::Types.const_get(symbol))
|
18
17
|
end
|
19
18
|
|
20
|
-
|
21
|
-
def serialize(object, options)
|
19
|
+
def serialize(object, options = {})
|
22
20
|
field_list.map { |field|
|
23
21
|
[field.name, field.serializer.serialize(object, options)]
|
24
22
|
}.to_h
|
@@ -28,17 +26,42 @@ module SoberSwag
|
|
28
26
|
@type ||= make_struct_type!
|
29
27
|
end
|
30
28
|
|
29
|
+
def lazy_type?
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
def lazy_type
|
34
|
+
struct_class
|
35
|
+
end
|
36
|
+
|
37
|
+
def finalize_lazy_type!
|
38
|
+
make_struct_type!
|
39
|
+
end
|
40
|
+
|
31
41
|
private
|
32
42
|
|
33
|
-
def make_struct_type!
|
43
|
+
def make_struct_type! # rubocop:disable Metrics/MethodLength
|
44
|
+
# mutual recursion makes this really, really annoying.
|
45
|
+
return struct_class if @made_struct_type
|
46
|
+
|
34
47
|
f = field_list
|
35
|
-
|
48
|
+
s = identifier
|
49
|
+
struct_class.instance_eval do
|
50
|
+
identifier(s)
|
36
51
|
f.each do |field|
|
37
|
-
attribute field.name, field.serializer.
|
52
|
+
attribute field.name, field.serializer.lazy_type
|
38
53
|
end
|
39
54
|
end
|
55
|
+
@made_struct_type = true
|
56
|
+
|
57
|
+
field_list.map(&:serializer).each(&:finalize_lazy_type!)
|
58
|
+
|
59
|
+
struct_class
|
40
60
|
end
|
41
61
|
|
62
|
+
def struct_class
|
63
|
+
@struct_class ||= Class.new(SoberSwag::InputObject)
|
64
|
+
end
|
42
65
|
end
|
43
66
|
end
|
44
67
|
end
|
@@ -3,7 +3,6 @@ module SoberSwag
|
|
3
3
|
##
|
4
4
|
# A new serializer by mapping over the serialization function
|
5
5
|
class Mapped < Base
|
6
|
-
|
7
6
|
def initialize(base, map_f)
|
8
7
|
@base = base
|
9
8
|
@map_f = map_f
|
@@ -13,6 +12,18 @@ module SoberSwag
|
|
13
12
|
@base.serialize(@map_f.call(object), options)
|
14
13
|
end
|
15
14
|
|
15
|
+
def lazy_type?
|
16
|
+
@base.lazy_type?
|
17
|
+
end
|
18
|
+
|
19
|
+
def lazy_type
|
20
|
+
@base.lazy_type
|
21
|
+
end
|
22
|
+
|
23
|
+
def finalize_lazy_type!
|
24
|
+
@base.finalize_lazy_type!
|
25
|
+
end
|
26
|
+
|
16
27
|
def type
|
17
28
|
@base.type
|
18
29
|
end
|
@@ -23,7 +34,6 @@ module SoberSwag
|
|
23
34
|
def via_map(&block)
|
24
35
|
SoberSwag::Serializer::Mapped.new(@base, @map_f >> block)
|
25
36
|
end
|
26
|
-
|
27
37
|
end
|
28
38
|
end
|
29
39
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module SoberSwag
|
2
|
+
module Serializer
|
3
|
+
##
|
4
|
+
# Provides metadata on a serializer.
|
5
|
+
# All actions delegate to the base.
|
6
|
+
class Meta < Base
|
7
|
+
def initialize(base, meta)
|
8
|
+
@base = base
|
9
|
+
@meta = meta
|
10
|
+
end
|
11
|
+
|
12
|
+
attr_reader :base, :meta
|
13
|
+
|
14
|
+
def serialize(args, opts = {})
|
15
|
+
base.serialize(args, opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def lazy_type
|
19
|
+
@base.lazy_type.meta(**meta)
|
20
|
+
end
|
21
|
+
|
22
|
+
def type
|
23
|
+
@base.type.meta(**meta)
|
24
|
+
end
|
25
|
+
|
26
|
+
def finalize_lazy_type!
|
27
|
+
@base.finalize_lazy_type!
|
28
|
+
end
|
29
|
+
|
30
|
+
def lazy_type?
|
31
|
+
@base.lazy_type?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -1,13 +1,29 @@
|
|
1
1
|
module SoberSwag
|
2
2
|
module Serializer
|
3
|
+
##
|
4
|
+
# Given something that serializes a type 'A',
|
5
|
+
# this can be used to make a serializer of type 'A | nil'.
|
6
|
+
#
|
7
|
+
# Or, put another way, makes serializers not crash on nil values.
|
3
8
|
class Optional < Base
|
4
|
-
|
5
9
|
def initialize(inner)
|
6
10
|
@inner = inner
|
7
11
|
end
|
8
12
|
|
9
13
|
attr_reader :inner
|
10
14
|
|
15
|
+
def lazy_type?
|
16
|
+
@inner.lazy_type?
|
17
|
+
end
|
18
|
+
|
19
|
+
def lazy_type
|
20
|
+
@inner.lazy_type.optional
|
21
|
+
end
|
22
|
+
|
23
|
+
def finalize_lazy_type!
|
24
|
+
@inner.finalize_lazy_type!
|
25
|
+
end
|
26
|
+
|
11
27
|
def serialize(object, options = {})
|
12
28
|
if object.nil?
|
13
29
|
object
|
@@ -23,7 +39,6 @@ module SoberSwag
|
|
23
39
|
def optional(*)
|
24
40
|
raise ArgumentError, 'no nesting optionals please'
|
25
41
|
end
|
26
|
-
|
27
42
|
end
|
28
43
|
end
|
29
44
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
module SoberSwag
|
2
2
|
module Serializer
|
3
|
+
##
|
4
|
+
# A class that does *no* serialization: you give it a type,
|
5
|
+
# and it will pass any serialized input on verbatim.
|
3
6
|
class Primitive < Base
|
4
7
|
def initialize(type)
|
5
8
|
@type = type
|
@@ -7,7 +10,7 @@ module SoberSwag
|
|
7
10
|
|
8
11
|
attr_reader :type
|
9
12
|
|
10
|
-
def serialize(object,
|
13
|
+
def serialize(object, _options = {})
|
11
14
|
object
|
12
15
|
end
|
13
16
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module SoberSwag
|
4
|
+
##
|
5
|
+
# A basic, rack-only server to serve up swagger definitions.
|
6
|
+
# By default it is configured to work with rails, but you can pass stuff to initialize.
|
7
|
+
class Server
|
8
|
+
RAILS_CONTROLLER_PROC = proc do
|
9
|
+
Rails.application.routes.routes.map { |route|
|
10
|
+
route.defaults[:controller]
|
11
|
+
}.to_set.reject(&:nil?).map { |controller|
|
12
|
+
"#{controller}_controller".classify.constantize
|
13
|
+
}.filter { |controller| controller.ancestors.include?(SoberSwag::Controller) }
|
14
|
+
end
|
15
|
+
|
16
|
+
##
|
17
|
+
# Start up.
|
18
|
+
#
|
19
|
+
# @param controller_proc [Proc] a proc that, when called, gives a list of {SoberSwag::Controller}s to document
|
20
|
+
# @param cache [Bool | Proc] if we should cache our defintions (default false)
|
21
|
+
def initialize(
|
22
|
+
controller_proc: RAILS_CONTROLLER_PROC,
|
23
|
+
cache: false
|
24
|
+
)
|
25
|
+
@controller_proc = controller_proc
|
26
|
+
@cache = cache
|
27
|
+
end
|
28
|
+
|
29
|
+
EFFECT_HTML = <<~HTML.freeze
|
30
|
+
<!DOCTYPE html>
|
31
|
+
<html>
|
32
|
+
<head>
|
33
|
+
<title>Swagger-UI</title>
|
34
|
+
<script src="https://unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
|
35
|
+
<link rel="stylesheet" href="https://unpkg.com/swagger-ui-dist@3.23.4/swagger-ui.css"></link>
|
36
|
+
</head>
|
37
|
+
<body>
|
38
|
+
<div id="swagger">
|
39
|
+
</div>
|
40
|
+
<script>
|
41
|
+
SwaggerUIBundle({url: 'SCRIPT_NAME', dom_id: '#swagger'})
|
42
|
+
</script>
|
43
|
+
</body>
|
44
|
+
</html>
|
45
|
+
HTML
|
46
|
+
|
47
|
+
def call(env)
|
48
|
+
req = Rack::Request.new(env)
|
49
|
+
if req.path_info&.match?(/json/si) || req.get_header('Accept')&.match?(/json/si)
|
50
|
+
[200, { 'Content-Type' => 'application/json' }, [generate_json_string]]
|
51
|
+
else
|
52
|
+
[200, { 'Content-Type' => 'text/html' }, [EFFECT_HTML.gsub(/SCRIPT_NAME/, env['SCRIPT_NAME'] + '.json')]]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def generate_json_string
|
57
|
+
if cache?
|
58
|
+
@json_string ||= JSON.dump(generate_swagger)
|
59
|
+
else
|
60
|
+
JSON.dump(generate_swagger)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def cache?
|
65
|
+
@cache.respond_to?(:call) ? @cache.call : @cache
|
66
|
+
end
|
67
|
+
|
68
|
+
def generate_swagger
|
69
|
+
routes = sober_controllers.flat_map(&:defined_routes).reduce(SoberSwag::Compiler.new) { |c, r| c.add_route(r) }
|
70
|
+
{
|
71
|
+
openapi: '3.0.0',
|
72
|
+
info: {
|
73
|
+
version: '1',
|
74
|
+
title: 'SoberSwag Swagger'
|
75
|
+
}
|
76
|
+
}.merge(routes.to_swagger)
|
77
|
+
end
|
78
|
+
|
79
|
+
def sober_controllers
|
80
|
+
@controller_proc.call
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|