sober_swag 0.1.0 → 0.2.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/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
|