sober_swag 0.21.0 → 0.24.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/CHANGELOG.md +5 -0
  4. data/bin/console +30 -10
  5. data/docs/reporting.md +190 -0
  6. data/example/Gemfile +2 -2
  7. data/example/Gemfile.lock +104 -113
  8. data/example/app/controllers/application_controller.rb +4 -0
  9. data/example/app/controllers/people_controller.rb +44 -28
  10. data/example/app/output_objects/identified_output.rb +7 -0
  11. data/example/app/output_objects/person_output_object.rb +37 -11
  12. data/example/app/output_objects/post_output_object.rb +0 -4
  13. data/example/app/output_objects/reporting_post_output.rb +18 -0
  14. data/example/bin/rspec +29 -0
  15. data/example/spec/requests/people/create_spec.rb +3 -2
  16. data/example/spec/requests/people/index_spec.rb +1 -1
  17. data/lib/sober_swag/compiler/path.rb +3 -1
  18. data/lib/sober_swag/compiler.rb +58 -12
  19. data/lib/sober_swag/controller/route.rb +44 -8
  20. data/lib/sober_swag/controller.rb +18 -5
  21. data/lib/sober_swag/input_object.rb +1 -0
  22. data/lib/sober_swag/output_object/field_syntax.rb +2 -0
  23. data/lib/sober_swag/reporting/compiler.rb +39 -0
  24. data/lib/sober_swag/reporting/input/base.rb +11 -0
  25. data/lib/sober_swag/reporting/input/bool.rb +19 -0
  26. data/lib/sober_swag/reporting/input/converting/bool.rb +24 -0
  27. data/lib/sober_swag/reporting/input/converting/date.rb +30 -0
  28. data/lib/sober_swag/reporting/input/converting/date_time.rb +28 -0
  29. data/lib/sober_swag/reporting/input/converting/decimal.rb +24 -0
  30. data/lib/sober_swag/reporting/input/converting/integer.rb +19 -0
  31. data/lib/sober_swag/reporting/input/converting.rb +16 -0
  32. data/lib/sober_swag/reporting/input/defer.rb +29 -0
  33. data/lib/sober_swag/reporting/input/described.rb +38 -0
  34. data/lib/sober_swag/reporting/input/dictionary.rb +37 -0
  35. data/lib/sober_swag/reporting/input/either.rb +51 -0
  36. data/lib/sober_swag/reporting/input/enum.rb +44 -0
  37. data/lib/sober_swag/reporting/input/format.rb +39 -0
  38. data/lib/sober_swag/reporting/input/in_range.rb +61 -0
  39. data/lib/sober_swag/reporting/input/interface.rb +113 -0
  40. data/lib/sober_swag/reporting/input/list.rb +44 -0
  41. data/lib/sober_swag/reporting/input/mapped.rb +36 -0
  42. data/lib/sober_swag/reporting/input/merge_objects.rb +72 -0
  43. data/lib/sober_swag/reporting/input/multiple_of.rb +36 -0
  44. data/lib/sober_swag/reporting/input/null.rb +34 -0
  45. data/lib/sober_swag/reporting/input/number.rb +19 -0
  46. data/lib/sober_swag/reporting/input/object/property.rb +53 -0
  47. data/lib/sober_swag/reporting/input/object.rb +100 -0
  48. data/lib/sober_swag/reporting/input/pattern.rb +46 -0
  49. data/lib/sober_swag/reporting/input/referenced.rb +38 -0
  50. data/lib/sober_swag/reporting/input/struct.rb +272 -0
  51. data/lib/sober_swag/reporting/input/text.rb +42 -0
  52. data/lib/sober_swag/reporting/input.rb +56 -0
  53. data/lib/sober_swag/reporting/invalid_schema_error.rb +21 -0
  54. data/lib/sober_swag/reporting/output/base.rb +25 -0
  55. data/lib/sober_swag/reporting/output/bool.rb +25 -0
  56. data/lib/sober_swag/reporting/output/defer.rb +69 -0
  57. data/lib/sober_swag/reporting/output/described.rb +42 -0
  58. data/lib/sober_swag/reporting/output/dictionary.rb +46 -0
  59. data/lib/sober_swag/reporting/output/enum.rb +47 -0
  60. data/lib/sober_swag/reporting/output/in_range.rb +64 -0
  61. data/lib/sober_swag/reporting/output/interface.rb +98 -0
  62. data/lib/sober_swag/reporting/output/list.rb +54 -0
  63. data/lib/sober_swag/reporting/output/merge_objects.rb +97 -0
  64. data/lib/sober_swag/reporting/output/null.rb +25 -0
  65. data/lib/sober_swag/reporting/output/number.rb +25 -0
  66. data/lib/sober_swag/reporting/output/object/property.rb +45 -0
  67. data/lib/sober_swag/reporting/output/object.rb +54 -0
  68. data/lib/sober_swag/reporting/output/partitioned.rb +77 -0
  69. data/lib/sober_swag/reporting/output/pattern.rb +50 -0
  70. data/lib/sober_swag/reporting/output/referenced.rb +42 -0
  71. data/lib/sober_swag/reporting/output/struct.rb +287 -0
  72. data/lib/sober_swag/reporting/output/text.rb +25 -0
  73. data/lib/sober_swag/reporting/output/via_map.rb +67 -0
  74. data/lib/sober_swag/reporting/output/viewed.rb +72 -0
  75. data/lib/sober_swag/reporting/output.rb +56 -0
  76. data/lib/sober_swag/reporting/report/base.rb +57 -0
  77. data/lib/sober_swag/reporting/report/either.rb +36 -0
  78. data/lib/sober_swag/reporting/report/error.rb +15 -0
  79. data/lib/sober_swag/reporting/report/list.rb +28 -0
  80. data/lib/sober_swag/reporting/report/merged_object.rb +25 -0
  81. data/lib/sober_swag/reporting/report/object.rb +29 -0
  82. data/lib/sober_swag/reporting/report/output.rb +14 -0
  83. data/lib/sober_swag/reporting/report/value.rb +28 -0
  84. data/lib/sober_swag/reporting/report.rb +16 -0
  85. data/lib/sober_swag/reporting.rb +11 -0
  86. data/lib/sober_swag/version.rb +1 -1
  87. data/lib/sober_swag.rb +1 -0
  88. metadata +69 -2
@@ -0,0 +1,36 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ ##
5
+ # Adds the multipleOf constraint to input types.
6
+ # Will use the '%' operator to calculate this, which may behave oddly for floats.
7
+ class MultipleOf < Base
8
+ def initialize(input, mult)
9
+ @input = input
10
+ @mult = mult
11
+ end
12
+
13
+ ##
14
+ # @return [Interface]
15
+ attr_reader :input
16
+
17
+ ##
18
+ # @return [Numeric]
19
+ attr_reader :mult
20
+
21
+ def call(value)
22
+ parsed = input.call(value)
23
+
24
+ return parsed if parsed.is_a?(Report::Base)
25
+ return Report::Value.new(["was not a multiple of #{mult}"]) unless (parsed % mult).zero?
26
+
27
+ parsed
28
+ end
29
+
30
+ def swagger_schema
31
+ modify_schema(input, { multipleOf: mult })
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,34 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ ##
5
+ # Null input values.
6
+ # Validates that the input is null.
7
+ class Null < Base
8
+ def call(value)
9
+ return nil if value.nil?
10
+
11
+ Report::Value.new(['was not nil'])
12
+ end
13
+
14
+ def hash
15
+ [self.class.hash, 1].hash
16
+ end
17
+
18
+ def eql?(other)
19
+ other.class == self.class
20
+ end
21
+
22
+ def <=>(other)
23
+ eql?(other) ? 0 : nil
24
+ end
25
+
26
+ include Comparable
27
+
28
+ def swagger_schema
29
+ [{ type: 'null' }, {}]
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ ##
5
+ # Parse some kind of number.
6
+ class Number < Base
7
+ def call(input)
8
+ return Report::Value.new(['is not a number']) unless input.is_a?(Numeric)
9
+
10
+ input
11
+ end
12
+
13
+ def swagger_schema
14
+ [{ type: 'number' }, {}]
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,53 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ class Object
5
+ ##
6
+ # Describe a single property key in an object.
7
+ class Property
8
+ def initialize(value, required:, description: '')
9
+ @value = value
10
+ @required = required
11
+ @description = description
12
+ end
13
+
14
+ ##
15
+ # @return [SoberSwag::Reporting::Input::Interface] value type
16
+ attr_reader :value
17
+
18
+ def required?
19
+ @required
20
+ end
21
+
22
+ ##
23
+ # @return [String, nil] description
24
+ attr_reader :description
25
+
26
+ def property_schema
27
+ direct, refined = value.swagger_schema
28
+
29
+ if description
30
+ [add_description(direct), refined]
31
+ else
32
+ [direct, refined]
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def add_description(dir)
39
+ t =
40
+ if dir.key?(:$ref)
41
+ # workaround: we have to do this if we want to allow
42
+ # descriptions in reference types
43
+ { allOf: [dir] }
44
+ else
45
+ dir
46
+ end
47
+ t.merge(description: description)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,100 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ ##
5
+ # Input object values
6
+ class Object < Base
7
+ autoload :Property, 'sober_swag/reporting/input/object/property'
8
+ ##
9
+ # @param fields [Hash<Symbol, Property>]
10
+ def initialize(fields)
11
+ @fields = fields
12
+ end
13
+
14
+ ##
15
+ # @return [Hash<String,#call>]
16
+ attr_reader :fields
17
+
18
+ def call(value)
19
+ return Report::Value.new(['was a not a JSON object']) unless value.is_a?(Hash)
20
+
21
+ bad, good = fields.map { |k, prop|
22
+ extract_value(k, prop, value)
23
+ }.compact.partition { |(_, v)| v.is_a?(Report::Base) }
24
+
25
+ return Report::Object.new(bad.to_h) if bad.any?
26
+
27
+ good.to_h
28
+ end
29
+
30
+ def swagger_schema
31
+ fields, found = field_schemas
32
+
33
+ obj = {
34
+ type: 'object',
35
+ properties: fields
36
+ }.merge(required_portion)
37
+
38
+ [obj, found]
39
+ end
40
+
41
+ def swagger_query_schema
42
+ swagger_parameter_schema.map do |param|
43
+ param.merge({ in: :query, style: :deepObject, explode: true })
44
+ end
45
+ end
46
+
47
+ def swagger_path_schema
48
+ swagger_parameter_schema.map do |param|
49
+ param.merge({ in: :path })
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def swagger_parameter_schema
56
+ fields.map do |name, field|
57
+ key_schema, = field.property_schema
58
+ base = {
59
+ name: name,
60
+ schema: key_schema,
61
+ required: field.required?
62
+ }
63
+ field.description ? base.merge(description: field.description) : base
64
+ end
65
+ end
66
+
67
+ def field_schemas
68
+ fields.reduce([{}, {}]) do |(field_schemas, found), (k, v)|
69
+ key_schema, key_found = v.property_schema
70
+ [
71
+ field_schemas.merge(k => key_schema),
72
+ found.merge(key_found)
73
+ ]
74
+ end
75
+ end
76
+
77
+ ##
78
+ # Either the list of required keys, or something stating "provide at least one key."
79
+ # This is needed because you can't have an empty list of keys.
80
+ def required_portion
81
+ required_fields = fields.map { |k, v| k if v.required? }.compact
82
+
83
+ if required_fields.empty?
84
+ {}
85
+ else
86
+ { required: required_fields }
87
+ end
88
+ end
89
+
90
+ def extract_value(key, property, input)
91
+ if input.key?(key)
92
+ [key, property.value.call(input[key])]
93
+ elsif property.required?
94
+ [key, Report::Value.new(['is required'])]
95
+ end
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,46 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ ##
5
+ # Input values that validate against a pattern
6
+ class Pattern < Base
7
+ def initialize(input, pattern)
8
+ @input = input
9
+ @pattern = pattern
10
+ end
11
+
12
+ ##
13
+ # @return [#call] input type
14
+ attr_reader :input
15
+
16
+ ##
17
+ # @return [#matches] regexp matcher
18
+ attr_reader :pattern
19
+
20
+ def call(value)
21
+ val = input.call(value)
22
+
23
+ return val if val.is_a?(Report::Base)
24
+
25
+ if pattern.match?(value)
26
+ value
27
+ else
28
+ Report::Value.new(["did not match pattern #{pattern}"])
29
+ end
30
+ end
31
+
32
+ def swagger_schema
33
+ single, found = input.swagger_schema
34
+
35
+ [add_schema_key(single, { pattern: formatted_pattern }), found]
36
+ end
37
+
38
+ ##
39
+ # Try to format a pattern so it'll work nicely with JS.
40
+ def formatted_pattern
41
+ pattern.to_s.gsub('?-mix:', '')
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,38 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ ##
5
+ # An input that should be "referenced" in the final schema.
6
+ class Referenced < Base
7
+ def initialize(value, reference)
8
+ @value = value
9
+ @reference = reference
10
+ end
11
+
12
+ ##
13
+ # @return [Interface] the actual input
14
+ attr_reader :value
15
+ ##
16
+ # @return [String] key in the components hash
17
+ attr_reader :reference
18
+
19
+ def call(input)
20
+ @value.call(input)
21
+ end
22
+
23
+ def swagger_schema
24
+ [
25
+ { "$ref": ref_path },
26
+ { reference => proc { value.swagger_schema } }
27
+ ]
28
+ end
29
+
30
+ private
31
+
32
+ def ref_path
33
+ "#/components/schemas/#{reference}"
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,272 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ ##
5
+ # Base class of input structs.
6
+ #
7
+ # These allow you to define both an input type and a ruby type at once.
8
+ # They provide a fluid interface for doing so.
9
+ #
10
+ # Classes which inherit from {Struct} "quack like" an {Interface}, so you can use them as input type definitions.
11
+ #
12
+ # You should add attributes using the {.attribute} or {.attribute?} methods.
13
+ # These also let you nest definitions, so this is okay:
14
+ #
15
+ # ```ruby
16
+ # class Person < SoberSwag::Reporting::Input::Struct
17
+ # attribute :first_name, SoberSwag::Reporting::Input.text
18
+ # attribute :stats do
19
+ # attribute :average_score, SoberSwag::Reporting::Input.number
20
+ # end
21
+ # end
22
+ # ```
23
+ class Struct # rubocop:disable Metrics/ClassLength
24
+ class << self
25
+ ##
26
+ # @overload attribute(name, input, description: nil)
27
+ # Define a new attribute, which will be required.
28
+ # @param name [Symbol] the name of this attribute
29
+ # @param input [Interface] input reporting type
30
+ # @param description [String,nil] description for this attribute
31
+ # @overload attribute(name, description: nil, &block)
32
+ # Define a new nested attribute, which will be required, using a block to describe
33
+ # a sub-struct. This block will immediately be evaluated to create a child struct.
34
+ # @param name [Symbol] the name of the attribute.
35
+ # The sub-struct defined will be stored in a constant on this class,
36
+ # under this name, classified.
37
+ #
38
+ # So if the name is :first_name, then the constant will be FirstName
39
+ # @param description [String, nil] describe this attribute
40
+ # @yieldself [SoberSwag::Reporting::Input::Struct] yields
41
+ def attribute(name, input = nil, description: nil, &block)
42
+ input_type = make_input_type(name, input, block)
43
+ add_attribute!(name, input_type, required: true, description: description)
44
+ end
45
+
46
+ ##
47
+ # @overload attribute?(name, input, description: nil)
48
+ # Define a new attribute, which will be not required.
49
+ # @param name [Symbol] the name of this attribute
50
+ # @param input [Interface] input reporting type
51
+ # @param description [String,nil] description for this attribute
52
+ # @overload attribute?(name, description: nil, &block)
53
+ # Define a new nested attribute, which will not be required, using a block to describe
54
+ # a sub-struct. This block will immediately be evaluated to create a child struct.
55
+ # @param name [Symbol] the name of the attribute.
56
+ # The sub-struct defined will be stored in a constant on this class,
57
+ # under this name, classified.
58
+ #
59
+ # So if the name is :first_name, then the constant will be FirstName
60
+ # @param description [String, nil] describe this attribute
61
+ # @yieldself [SoberSwag::Reporting::Input::Struct] yields
62
+ def attribute?(name, input = nil, description: nil, &block)
63
+ input_type = make_input_type(name, input, block)
64
+
65
+ add_attribute!(name, input_type, required: false, description: description)
66
+ end
67
+
68
+ ##
69
+ # Add an attribute, specifying if it is required or not via an argument.
70
+ # You should use {#attribute} or {#attribute?} instead of this almost always.
71
+ #
72
+ # @param name [Symbol] name of this attribute
73
+ # @param input [Interface] type fot this attribue
74
+ # @param required [true,false] if this attribute is required
75
+ # @param description [String,nil] optional description for this attribute
76
+ #
77
+ def add_attribute!(name, input, required:, description: nil)
78
+ raise ArgumentError, 'name must be a symbol' unless name.is_a?(Symbol)
79
+ raise ArgumentError, 'input type must be a SoberSwag::Reporting::Input::Interface' unless input.is_a?(Interface)
80
+
81
+ define_attribute(name) # defines an instance method to access this attribute
82
+
83
+ object_properties[name] = Object::Property.new(
84
+ input,
85
+ required: required,
86
+ description: description
87
+ )
88
+ end
89
+
90
+ ##
91
+ # Get a list of properties defined by *this instance*.
92
+ #
93
+ # Please do not mutate this, it will break everything.
94
+ #
95
+ # @return [Hash<Symbol, Object::Property>]
96
+ def object_properties
97
+ @object_properties ||= {}
98
+ end
99
+
100
+ ##
101
+ # @return [SoberSwag::Reporting::Input::Struct,nil] the struct we inherit from.
102
+ # Used to implement `allOf` style inheritance.
103
+ attr_accessor :parent_struct
104
+
105
+ ##
106
+ # @param other [Class] the inheriting class
107
+ #
108
+ # Used to implement `allOf` style inheritance by setting {#parent_struct} on the object that is inheriting from us.
109
+ def inherited(other)
110
+ other.parent_struct = self unless self == SoberSwag::Reporting::Input::Struct
111
+ end
112
+
113
+ include Interface
114
+
115
+ ##
116
+ # @return [SoberSwag::Reporting::Input::Base] the type to use for input.
117
+ def input_type
118
+ object_type.mapped { |x| new(x) }.referenced(identifier)
119
+ end
120
+
121
+ ##
122
+ # @overload identifier()
123
+ # @return [String,nil] the identifier for this object, used for its reference path.
124
+ # @overload identifier(val)
125
+ # Sets an identifier for this struct.
126
+ # @param val [String] the identifier to set
127
+ # @return [String] the set identifier.
128
+ def identifier(val = nil)
129
+ if val
130
+ @identifier = val
131
+ else
132
+ @identifier || name&.gsub('::', '.')
133
+ end
134
+ end
135
+
136
+ ##
137
+ # @return [SoberSwag::Reporting::Input::Struct, SoberSwag::Reporting::Report::Base] the struct class,
138
+ # or a report of what went wrong.
139
+ def call(attrs)
140
+ input_type.call(attrs)
141
+ end
142
+
143
+ ##
144
+ # @see #call
145
+ def parse(json)
146
+ call(json)
147
+ end
148
+
149
+ ##
150
+ # @see call!
151
+ def parse!(json)
152
+ call!(json)
153
+ end
154
+
155
+ ##
156
+ # @return [Array[Hash, Hash]] swagger schema type.
157
+ def swagger_schema
158
+ input_type.swagger_schema
159
+ end
160
+
161
+ def swagger_query_schema
162
+ object_type.swagger_query_schema
163
+ end
164
+
165
+ def swagger_path_schema
166
+ object_type.swagger_path_schema
167
+ end
168
+
169
+ private
170
+
171
+ def make_input_type(name, input, block)
172
+ raise ArgumentError, 'cannot pass a block to make a sub-struct and a field type' if input && block
173
+
174
+ return input if input
175
+
176
+ raise ArgumentError, 'must pass an input type OR a block to make a sub-struct' unless block
177
+
178
+ const_name = name.to_s.camelize
179
+
180
+ raise ArgumentError, 'cannot define struct sub-type, constant already exists!' if const_defined?(const_name)
181
+
182
+ Class.new(SoberSwag::Reporting::Input::Struct, &block).tap { |c| const_set(const_name, c) }
183
+ end
184
+
185
+ ##
186
+ # Quick method which defines an accessor method for this struct.
187
+ def define_attribute(name)
188
+ define_method(name) do
189
+ struct_properties[name]
190
+ end
191
+ define_method("#{name}_present?") do
192
+ struct_properties.key?(name)
193
+ end
194
+ end
195
+
196
+ def object_type
197
+ if parent_struct.nil?
198
+ Object.new(object_properties)
199
+ else
200
+ MergeObjects.new(parent_struct, Object.new(object_properties))
201
+ end
202
+ end
203
+ end
204
+
205
+ def initialize(props)
206
+ @struct_properties = props
207
+ end
208
+
209
+ attr_reader :struct_properties
210
+
211
+ def [](name)
212
+ @struct_properties[name]
213
+ end
214
+
215
+ ##
216
+ # Hash code for this struct.
217
+ def hash
218
+ [self.class.hash, *ordered_values.hash].hash
219
+ end
220
+
221
+ ##
222
+ # Return an array of the values of this, in order.
223
+ def ordered_values
224
+ self.class.object_properties.keys.map { |k| @struct_properties[k] }
225
+ end
226
+
227
+ ##
228
+ # Allow structs to be compared like values.
229
+ def eql?(other)
230
+ return false unless other.is_a?(self.class)
231
+
232
+ ordered_values.eql?(other.ordered_values)
233
+ end
234
+
235
+ ##
236
+ # Allow structs to be ordered like values.
237
+ def <=>(other)
238
+ return nil unless other.is_a?(self.class)
239
+
240
+ ordered_values <=> other.ordered_values
241
+ end
242
+
243
+ include Comparable
244
+
245
+ ##
246
+ # Extracts the transformed struct properties.
247
+ #
248
+ # Keys not present in the input will also not be present in this hash.
249
+ def to_h
250
+ @struct_properties.transform_values do |value|
251
+ if value.is_a?(SoberSwag::Reporting::Input::Struct)
252
+ value.to_h
253
+ else
254
+ value
255
+ end
256
+ end
257
+ end
258
+
259
+ def to_s
260
+ inspect
261
+ end
262
+
263
+ def inspect
264
+ keys = self.class.object_properties.keys.each.with_object([]) do |k, obj|
265
+ obj << "#{k}=#{public_send(k).inspect}" if public_send(:"#{k}_present?")
266
+ end
267
+ "#<#{self.class.name || self.class.inspect[2..-2]} #{keys.join(' ')}>"
268
+ end
269
+ end
270
+ end
271
+ end
272
+ end
@@ -0,0 +1,42 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ module Input
4
+ ##
5
+ # Input for a single text value.
6
+ class Text < Base
7
+ def call(value)
8
+ return value if value.is_a?(String)
9
+
10
+ Report::Value.new(['was not a string'])
11
+ end
12
+
13
+ ##
14
+ # Get a new input value which requires a regexp.
15
+ #
16
+ # @paran regexp [Regexp] regular expression to match on
17
+ # @return [Pattern] pattern-based input.
18
+ def with_pattern(regexp)
19
+ Pattern.new(self, regexp)
20
+ end
21
+
22
+ include Comparable
23
+
24
+ def eql?(other)
25
+ other.class == self.class
26
+ end
27
+
28
+ def <=>(other)
29
+ eql?(other) ? 0 : 1
30
+ end
31
+
32
+ def hash
33
+ [self.class.hash, 1].hash
34
+ end
35
+
36
+ def swagger_schema
37
+ [{ type: 'string' }, {}]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,56 @@
1
+ module SoberSwag
2
+ module Reporting
3
+ ##
4
+ # Module for SoberSwag reporting inputs.
5
+ module Input
6
+ autoload :Base, 'sober_swag/reporting/input/base'
7
+ autoload :Bool, 'sober_swag/reporting/input/bool'
8
+ autoload :Converting, 'sober_swag/reporting/input/converting'
9
+ autoload :Described, 'sober_swag/reporting/input/described'
10
+ autoload :Dictionary, 'sober_swag/reporting/input/dictionary'
11
+ autoload :Defer, 'sober_swag/reporting/input/defer'
12
+ autoload :Enum, 'sober_swag/reporting/input/enum'
13
+ autoload :Either, 'sober_swag/reporting/input/either'
14
+ autoload :Format, 'sober_swag/reporting/input/format'
15
+ autoload :Number, 'sober_swag/reporting/input/number'
16
+ autoload :Interface, 'sober_swag/reporting/input/interface'
17
+ autoload :InRange, 'sober_swag/reporting/input/in_range'
18
+ autoload :List, 'sober_swag/reporting/input/list'
19
+ autoload :MultipleOf, 'sober_swag/reporting/input/multiple_of'
20
+ autoload :Mapped, 'sober_swag/reporting/input/mapped'
21
+ autoload :MergeObjects, 'sober_swag/reporting/input/merge_objects'
22
+ autoload :Null, 'sober_swag/reporting/input/null'
23
+ autoload :Object, 'sober_swag/reporting/input/object'
24
+ autoload :Pattern, 'sober_swag/reporting/input/pattern'
25
+ autoload :Referenced, 'sober_swag/reporting/input/referenced'
26
+ autoload :Struct, 'sober_swag/reporting/input/struct'
27
+ autoload :Text, 'sober_swag/reporting/input/text'
28
+
29
+ class << self
30
+ ##
31
+ # @return [SoberSwag::Reporting::Input::Bool]
32
+ def bool
33
+ Bool.new
34
+ end
35
+
36
+ ##
37
+ # @return [SoberSwag::Reporting::Input::Text]
38
+ def text
39
+ Text.new
40
+ end
41
+
42
+ ##
43
+ # @return [SoberSwag::Reporting::Input::Number]
44
+ def number
45
+ Number.new
46
+ end
47
+
48
+ ##
49
+ # @return [SoberSwag::Reporting::Input::Null]
50
+ def null
51
+ Null.new
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end