media_types 2.2.0 → 2.3.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/debian.yml +43 -43
- data/.github/workflows/publish-bookworm.yml +33 -0
- data/.github/workflows/publish-sid.yml +33 -0
- data/.github/workflows/ruby.yml +22 -22
- data/.gitignore +20 -10
- data/.rubocop.yml +29 -29
- data/CHANGELOG.md +175 -164
- data/Gemfile +6 -6
- data/LICENSE +21 -21
- data/README.md +666 -664
- data/Rakefile +12 -12
- data/bin/console +15 -15
- data/bin/setup +8 -8
- data/lib/media_types/constructable.rb +161 -160
- data/lib/media_types/dsl/errors.rb +18 -18
- data/lib/media_types/dsl.rb +172 -172
- data/lib/media_types/errors.rb +25 -19
- data/lib/media_types/formatter.rb +56 -56
- data/lib/media_types/hash.rb +21 -21
- data/lib/media_types/object.rb +35 -35
- data/lib/media_types/scheme/allow_nil.rb +30 -30
- data/lib/media_types/scheme/any_of.rb +41 -41
- data/lib/media_types/scheme/attribute.rb +46 -46
- data/lib/media_types/scheme/enumeration_context.rb +18 -18
- data/lib/media_types/scheme/enumeration_of_type.rb +80 -80
- data/lib/media_types/scheme/errors.rb +87 -87
- data/lib/media_types/scheme/links.rb +54 -54
- data/lib/media_types/scheme/missing_validation.rb +41 -41
- data/lib/media_types/scheme/not_strict.rb +15 -15
- data/lib/media_types/scheme/output_empty_guard.rb +45 -45
- data/lib/media_types/scheme/output_iterator_with_predicate.rb +66 -66
- data/lib/media_types/scheme/output_type_guard.rb +39 -39
- data/lib/media_types/scheme/rules.rb +186 -173
- data/lib/media_types/scheme/rules_exhausted_guard.rb +73 -73
- data/lib/media_types/scheme/validation_options.rb +44 -43
- data/lib/media_types/scheme.rb +535 -513
- data/lib/media_types/testing/assertions.rb +20 -20
- data/lib/media_types/validations.rb +118 -105
- data/lib/media_types/version.rb +5 -5
- data/lib/media_types/views.rb +12 -12
- data/lib/media_types.rb +73 -73
- data/media_types.gemspec +33 -33
- metadata +8 -6
@@ -1,41 +1,41 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'delegate'
|
4
|
-
|
5
|
-
module MediaTypes
|
6
|
-
class Scheme
|
7
|
-
class CaseEqualityWithList < SimpleDelegator
|
8
|
-
|
9
|
-
# True for Enumerable#any? {Object#===}
|
10
|
-
def ===(other)
|
11
|
-
any? { |it| it === other } # rubocop:disable Style/CaseEquality
|
12
|
-
end
|
13
|
-
|
14
|
-
def inspect
|
15
|
-
"[Scheme::AnyOf(#{__getobj__})]"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
class << self
|
20
|
-
# noinspection RubyClassMethodNamingConvention
|
21
|
-
##
|
22
|
-
# Allows +it+ to be any of the wrapped +klazzes+
|
23
|
-
#
|
24
|
-
# @param [Array<Class>] klazzes the classes that are valid for +it+
|
25
|
-
# @return [CaseEqualityWithList]
|
26
|
-
def AnyOf(*klazzes) # rubocop:disable Naming/MethodName
|
27
|
-
CaseEqualityWithList.new(klazzes)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# noinspection RubyInstanceMethodNamingConvention
|
32
|
-
##
|
33
|
-
# Allows +it+ to be any of the wrapped +klazzes+
|
34
|
-
#
|
35
|
-
# @param [Array<Class>] klazzes the classes that are valid for +it+
|
36
|
-
# @return [CaseEqualityWithList]
|
37
|
-
def AnyOf(*klazzes) # rubocop:disable Naming/MethodName
|
38
|
-
self.class.AnyOf(*klazzes)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'delegate'
|
4
|
+
|
5
|
+
module MediaTypes
|
6
|
+
class Scheme
|
7
|
+
class CaseEqualityWithList < SimpleDelegator
|
8
|
+
|
9
|
+
# True for Enumerable#any? {Object#===}
|
10
|
+
def ===(other)
|
11
|
+
any? { |it| it === other } # rubocop:disable Style/CaseEquality
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspect
|
15
|
+
"[Scheme::AnyOf(#{__getobj__})]"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
# noinspection RubyClassMethodNamingConvention
|
21
|
+
##
|
22
|
+
# Allows +it+ to be any of the wrapped +klazzes+
|
23
|
+
#
|
24
|
+
# @param [Array<Class>] klazzes the classes that are valid for +it+
|
25
|
+
# @return [CaseEqualityWithList]
|
26
|
+
def AnyOf(*klazzes) # rubocop:disable Naming/MethodName
|
27
|
+
CaseEqualityWithList.new(klazzes)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# noinspection RubyInstanceMethodNamingConvention
|
32
|
+
##
|
33
|
+
# Allows +it+ to be any of the wrapped +klazzes+
|
34
|
+
#
|
35
|
+
# @param [Array<Class>] klazzes the classes that are valid for +it+
|
36
|
+
# @return [CaseEqualityWithList]
|
37
|
+
def AnyOf(*klazzes) # rubocop:disable Naming/MethodName
|
38
|
+
self.class.AnyOf(*klazzes)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -1,46 +1,46 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'media_types/scheme/errors'
|
4
|
-
require 'media_types/scheme/allow_nil'
|
5
|
-
|
6
|
-
module MediaTypes
|
7
|
-
class Scheme
|
8
|
-
class Attribute
|
9
|
-
|
10
|
-
##
|
11
|
-
# An attribute that expects a value of type +type+
|
12
|
-
#
|
13
|
-
# @see AllowNil
|
14
|
-
# @see AnyOf
|
15
|
-
#
|
16
|
-
# @param [Class] type the class +it+ must be
|
17
|
-
# @param [TrueClass, FalseClass] allow_nil if true, nil? is allowed
|
18
|
-
#
|
19
|
-
def initialize(type, allow_nil: false)
|
20
|
-
self.type = allow_nil ? Scheme.AllowNil(type) : type
|
21
|
-
|
22
|
-
freeze
|
23
|
-
end
|
24
|
-
|
25
|
-
def validate!(output, options, **_opts)
|
26
|
-
return true if type === output # rubocop:disable Style/CaseEquality
|
27
|
-
raise ValidationError,
|
28
|
-
format(
|
29
|
-
'Expected %<type>s, got %<actual>s at [%<backtrace>s]',
|
30
|
-
type: type,
|
31
|
-
actual: output.inspect,
|
32
|
-
backtrace: options.backtrace.join('->')
|
33
|
-
)
|
34
|
-
end
|
35
|
-
|
36
|
-
def inspect
|
37
|
-
"[Scheme::Attribute of #{type.inspect}]"
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
attr_accessor :allow_nil, :type
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'media_types/scheme/errors'
|
4
|
+
require 'media_types/scheme/allow_nil'
|
5
|
+
|
6
|
+
module MediaTypes
|
7
|
+
class Scheme
|
8
|
+
class Attribute
|
9
|
+
|
10
|
+
##
|
11
|
+
# An attribute that expects a value of type +type+
|
12
|
+
#
|
13
|
+
# @see AllowNil
|
14
|
+
# @see AnyOf
|
15
|
+
#
|
16
|
+
# @param [Class] type the class +it+ must be
|
17
|
+
# @param [TrueClass, FalseClass] allow_nil if true, nil? is allowed
|
18
|
+
#
|
19
|
+
def initialize(type, allow_nil: false)
|
20
|
+
self.type = allow_nil ? Scheme.AllowNil(type) : type
|
21
|
+
|
22
|
+
freeze
|
23
|
+
end
|
24
|
+
|
25
|
+
def validate!(output, options, **_opts)
|
26
|
+
return true if type === output # rubocop:disable Style/CaseEquality
|
27
|
+
raise ValidationError,
|
28
|
+
format(
|
29
|
+
'Expected %<type>s, got %<actual>s at [%<backtrace>s]',
|
30
|
+
type: type,
|
31
|
+
actual: output.inspect,
|
32
|
+
backtrace: options.backtrace.join('->')
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
"[Scheme::Attribute of #{type.inspect}]"
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
attr_accessor :allow_nil, :type
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MediaTypes
|
4
|
-
class Scheme
|
5
|
-
class EnumerationContext
|
6
|
-
def initialize(rules:)
|
7
|
-
self.rules = rules
|
8
|
-
end
|
9
|
-
|
10
|
-
def enumerate(val)
|
11
|
-
self.key = val
|
12
|
-
self
|
13
|
-
end
|
14
|
-
|
15
|
-
attr_accessor :rules, :key
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MediaTypes
|
4
|
+
class Scheme
|
5
|
+
class EnumerationContext
|
6
|
+
def initialize(rules:)
|
7
|
+
self.rules = rules
|
8
|
+
end
|
9
|
+
|
10
|
+
def enumerate(val)
|
11
|
+
self.key = val
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_accessor :rules, :key
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,80 +1,80 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'media_types/scheme/errors'
|
4
|
-
|
5
|
-
module MediaTypes
|
6
|
-
class Scheme
|
7
|
-
class EnumerationOfType
|
8
|
-
|
9
|
-
##
|
10
|
-
# An attribute that expects a value of type +enumeration_type+ and each item of type +item_type+
|
11
|
-
#
|
12
|
-
# @param [Class] item_type the type of each item
|
13
|
-
# @param [Class] enumeration_type the type of the enumeration as a whole
|
14
|
-
# @param [TrueClass, FalseClass] allow_empty if true, an empty instance of +enumeration_type+ is valid
|
15
|
-
#
|
16
|
-
def initialize(item_type, enumeration_type: Array, allow_empty: false)
|
17
|
-
self.item_type = item_type
|
18
|
-
self.enumeration_type = enumeration_type
|
19
|
-
self.allow_empty = allow_empty
|
20
|
-
|
21
|
-
freeze
|
22
|
-
end
|
23
|
-
|
24
|
-
def validate!(output, options, **_opts)
|
25
|
-
validate_enumeration!(output, options) &&
|
26
|
-
validate_not_empty!(output, options) &&
|
27
|
-
validate_items!(output, options)
|
28
|
-
end
|
29
|
-
|
30
|
-
def inspect
|
31
|
-
"[Scheme::EnumerationOfType #{item_type} collection=#{enumeration_type} empty=#{allow_empty}]"
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
attr_accessor :allow_empty, :enumeration_type, :item_type
|
37
|
-
|
38
|
-
def validate_enumeration!(output, options)
|
39
|
-
return true if enumeration_type === output # rubocop:disable Style/CaseEquality
|
40
|
-
raise ValidationError,
|
41
|
-
format(
|
42
|
-
'Expected collection as %<type>s, got %<actual>s at [%<backtrace>s]',
|
43
|
-
type: enumeration_type,
|
44
|
-
actual: output.inspect,
|
45
|
-
backtrace: options.backtrace.join('->')
|
46
|
-
)
|
47
|
-
end
|
48
|
-
|
49
|
-
def validate_not_empty!(output, options)
|
50
|
-
return true if allow_empty
|
51
|
-
return true if output.respond_to?(:length) && output.length.positive?
|
52
|
-
return true if output.respond_to?(:empty?) && !output.empty?
|
53
|
-
|
54
|
-
raise EmptyOutputError,
|
55
|
-
format(
|
56
|
-
'Expected collection to be not empty, got empty at [%<backtrace>s]',
|
57
|
-
backtrace: options.backtrace.join('->')
|
58
|
-
)
|
59
|
-
end
|
60
|
-
|
61
|
-
def validate_items!(output, options)
|
62
|
-
output.each_with_index.all? do |item, index|
|
63
|
-
next true if item_type === item # rubocop:disable Style/CaseEquality
|
64
|
-
if item_type.is_a?(Scheme)
|
65
|
-
item_type.validate(item, options.trace("[#{index}]"))
|
66
|
-
next true
|
67
|
-
end
|
68
|
-
raise ValidationError,
|
69
|
-
format(
|
70
|
-
'Expected collection item as %<type>s, got %<actual>s at [%<backtrace>s]',
|
71
|
-
type: item_type.inspect,
|
72
|
-
actual: item.inspect,
|
73
|
-
backtrace: options.backtrace.join('->')
|
74
|
-
)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'media_types/scheme/errors'
|
4
|
+
|
5
|
+
module MediaTypes
|
6
|
+
class Scheme
|
7
|
+
class EnumerationOfType
|
8
|
+
|
9
|
+
##
|
10
|
+
# An attribute that expects a value of type +enumeration_type+ and each item of type +item_type+
|
11
|
+
#
|
12
|
+
# @param [Class] item_type the type of each item
|
13
|
+
# @param [Class] enumeration_type the type of the enumeration as a whole
|
14
|
+
# @param [TrueClass, FalseClass] allow_empty if true, an empty instance of +enumeration_type+ is valid
|
15
|
+
#
|
16
|
+
def initialize(item_type, enumeration_type: Array, allow_empty: false)
|
17
|
+
self.item_type = item_type
|
18
|
+
self.enumeration_type = enumeration_type
|
19
|
+
self.allow_empty = allow_empty
|
20
|
+
|
21
|
+
freeze
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate!(output, options, **_opts)
|
25
|
+
validate_enumeration!(output, options) &&
|
26
|
+
validate_not_empty!(output, options) &&
|
27
|
+
validate_items!(output, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
"[Scheme::EnumerationOfType #{item_type} collection=#{enumeration_type} empty=#{allow_empty}]"
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
attr_accessor :allow_empty, :enumeration_type, :item_type
|
37
|
+
|
38
|
+
def validate_enumeration!(output, options)
|
39
|
+
return true if enumeration_type === output # rubocop:disable Style/CaseEquality
|
40
|
+
raise ValidationError,
|
41
|
+
format(
|
42
|
+
'Expected collection as %<type>s, got %<actual>s at [%<backtrace>s]',
|
43
|
+
type: enumeration_type,
|
44
|
+
actual: output.inspect,
|
45
|
+
backtrace: options.backtrace.join('->')
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def validate_not_empty!(output, options)
|
50
|
+
return true if allow_empty
|
51
|
+
return true if output.respond_to?(:length) && output.length.positive?
|
52
|
+
return true if output.respond_to?(:empty?) && !output.empty?
|
53
|
+
|
54
|
+
raise EmptyOutputError,
|
55
|
+
format(
|
56
|
+
'Expected collection to be not empty, got empty at [%<backtrace>s]',
|
57
|
+
backtrace: options.backtrace.join('->')
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def validate_items!(output, options)
|
62
|
+
output.each_with_index.all? do |item, index|
|
63
|
+
next true if item_type === item # rubocop:disable Style/CaseEquality
|
64
|
+
if item_type.is_a?(Scheme)
|
65
|
+
item_type.validate(item, options.trace("[#{index}]"))
|
66
|
+
next true
|
67
|
+
end
|
68
|
+
raise ValidationError,
|
69
|
+
format(
|
70
|
+
'Expected collection item as %<type>s, got %<actual>s at [%<backtrace>s]',
|
71
|
+
type: item_type.inspect,
|
72
|
+
actual: item.inspect,
|
73
|
+
backtrace: options.backtrace.join('->')
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -1,87 +1,87 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MediaTypes
|
4
|
-
class Scheme
|
5
|
-
class ConflictingTypeDefinitionError < ArgumentError; end
|
6
|
-
|
7
|
-
# Base class for all validations errors
|
8
|
-
class ValidationError < ArgumentError; end
|
9
|
-
|
10
|
-
# Raised when trying to register an attribute with a non-string key
|
11
|
-
class KeyTypeError < ArgumentError; end
|
12
|
-
|
13
|
-
# Raised when trying to register a key twice
|
14
|
-
class DuplicateKeyError < ArgumentError; end
|
15
|
-
|
16
|
-
class DuplicateSymbolKeyError < DuplicateKeyError
|
17
|
-
MESSAGE_TEMPLATE = '%<rule_type>s rule with key :%<key>s has already been defined. Please remove one of the two.'
|
18
|
-
|
19
|
-
def initialize(rule_type, key)
|
20
|
-
super(format(MESSAGE_TEMPLATE, rule_type: rule_type, key: key))
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class DuplicateStringKeyError < DuplicateKeyError
|
25
|
-
MESSAGE_TEMPLATE = '%<rule_type>s rule with key %<key>s has already been defined. Please remove one of the two.'
|
26
|
-
|
27
|
-
def initialize(rule_type, key)
|
28
|
-
super(format(MESSAGE_TEMPLATE, { rule_type: rule_type, key: key }))
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
class StringOverwritingSymbolError < DuplicateKeyError
|
33
|
-
MESSAGE_TEMPLATE = 'Trying to add %<rule_type>s rule String key %<key>s while a Symbol with the same name already exists. Please remove one of the two.'
|
34
|
-
|
35
|
-
def initialize(rule_type, key)
|
36
|
-
super(format(MESSAGE_TEMPLATE, { rule_type: rule_type, key: key }))
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class SymbolOverwritingStringError < DuplicateKeyError
|
41
|
-
MESSAGE_TEMPLATE = 'Trying to add %<rule_type>s rule with Symbol key :%<key>s while a String key with the same name already exists. Please remove one of the two.'
|
42
|
-
|
43
|
-
def initialize(rule_type, key)
|
44
|
-
super(format(MESSAGE_TEMPLATE, { rule_type: rule_type, key: key }))
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
# Raised when it did not expect more data, but there was more left
|
49
|
-
class StrictValidationError < ValidationError; end
|
50
|
-
|
51
|
-
# Raised when it expected not to be empty, but it was
|
52
|
-
class EmptyOutputError < ValidationError; end
|
53
|
-
|
54
|
-
# Raised when a value did not have the expected type
|
55
|
-
class OutputTypeMismatch < ValidationError; end
|
56
|
-
|
57
|
-
# Raised when it expected more data but there wasn't any left
|
58
|
-
class ExhaustedOutputError < ValidationError; end
|
59
|
-
|
60
|
-
# Raised when trying to override a non default rule scheme in the Rules Hash's default object method
|
61
|
-
class OverwritingRuleError < ArgumentError; end
|
62
|
-
|
63
|
-
class DuplicateAnyRuleError < OverwritingRuleError
|
64
|
-
def message
|
65
|
-
"An 'any' rule has already been defined. Please remove one of the two."
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
class DuplicateNotStrictRuleError < OverwritingRuleError
|
70
|
-
def message
|
71
|
-
"The 'not_strict' rule has already been defined. Please remove one of the two."
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
class NotStrictOverwritingAnyError < OverwritingRuleError
|
76
|
-
def message
|
77
|
-
"An 'any' rule has already been defined. Setting 'not_strict' will override that rule. Please remove one of the two."
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class AnyOverwritingNotStrictError < OverwritingRuleError
|
82
|
-
def message
|
83
|
-
"The 'not_strict' rule has already been defined. Setting 'any' will override that rule. Please remove one of the two."
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MediaTypes
|
4
|
+
class Scheme
|
5
|
+
class ConflictingTypeDefinitionError < ArgumentError; end
|
6
|
+
|
7
|
+
# Base class for all validations errors
|
8
|
+
class ValidationError < ArgumentError; end
|
9
|
+
|
10
|
+
# Raised when trying to register an attribute with a non-string key
|
11
|
+
class KeyTypeError < ArgumentError; end
|
12
|
+
|
13
|
+
# Raised when trying to register a key twice
|
14
|
+
class DuplicateKeyError < ArgumentError; end
|
15
|
+
|
16
|
+
class DuplicateSymbolKeyError < DuplicateKeyError
|
17
|
+
MESSAGE_TEMPLATE = '%<rule_type>s rule with key :%<key>s has already been defined. Please remove one of the two.'
|
18
|
+
|
19
|
+
def initialize(rule_type, key)
|
20
|
+
super(format(MESSAGE_TEMPLATE, rule_type: rule_type, key: key))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class DuplicateStringKeyError < DuplicateKeyError
|
25
|
+
MESSAGE_TEMPLATE = '%<rule_type>s rule with key %<key>s has already been defined. Please remove one of the two.'
|
26
|
+
|
27
|
+
def initialize(rule_type, key)
|
28
|
+
super(format(MESSAGE_TEMPLATE, { rule_type: rule_type, key: key }))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class StringOverwritingSymbolError < DuplicateKeyError
|
33
|
+
MESSAGE_TEMPLATE = 'Trying to add %<rule_type>s rule String key %<key>s while a Symbol with the same name already exists. Please remove one of the two.'
|
34
|
+
|
35
|
+
def initialize(rule_type, key)
|
36
|
+
super(format(MESSAGE_TEMPLATE, { rule_type: rule_type, key: key }))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class SymbolOverwritingStringError < DuplicateKeyError
|
41
|
+
MESSAGE_TEMPLATE = 'Trying to add %<rule_type>s rule with Symbol key :%<key>s while a String key with the same name already exists. Please remove one of the two.'
|
42
|
+
|
43
|
+
def initialize(rule_type, key)
|
44
|
+
super(format(MESSAGE_TEMPLATE, { rule_type: rule_type, key: key }))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Raised when it did not expect more data, but there was more left
|
49
|
+
class StrictValidationError < ValidationError; end
|
50
|
+
|
51
|
+
# Raised when it expected not to be empty, but it was
|
52
|
+
class EmptyOutputError < ValidationError; end
|
53
|
+
|
54
|
+
# Raised when a value did not have the expected type
|
55
|
+
class OutputTypeMismatch < ValidationError; end
|
56
|
+
|
57
|
+
# Raised when it expected more data but there wasn't any left
|
58
|
+
class ExhaustedOutputError < ValidationError; end
|
59
|
+
|
60
|
+
# Raised when trying to override a non default rule scheme in the Rules Hash's default object method
|
61
|
+
class OverwritingRuleError < ArgumentError; end
|
62
|
+
|
63
|
+
class DuplicateAnyRuleError < OverwritingRuleError
|
64
|
+
def message
|
65
|
+
"An 'any' rule has already been defined. Please remove one of the two."
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class DuplicateNotStrictRuleError < OverwritingRuleError
|
70
|
+
def message
|
71
|
+
"The 'not_strict' rule has already been defined. Please remove one of the two."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class NotStrictOverwritingAnyError < OverwritingRuleError
|
76
|
+
def message
|
77
|
+
"An 'any' rule has already been defined. Setting 'not_strict' will override that rule. Please remove one of the two."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class AnyOverwritingNotStrictError < OverwritingRuleError
|
82
|
+
def message
|
83
|
+
"The 'not_strict' rule has already been defined. Setting 'any' will override that rule. Please remove one of the two."
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -1,54 +1,54 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'media_types/scheme/rules'
|
4
|
-
require 'media_types/scheme/rules_exhausted_guard'
|
5
|
-
|
6
|
-
module MediaTypes
|
7
|
-
class Scheme
|
8
|
-
class Links
|
9
|
-
def initialize
|
10
|
-
self.links = Rules.new(allow_empty: false, expected_type: ::Hash)
|
11
|
-
end
|
12
|
-
|
13
|
-
def link(key, allow_nil: false, optional: false, &block)
|
14
|
-
links.add(
|
15
|
-
key,
|
16
|
-
Scheme.new do
|
17
|
-
attribute :href, String, allow_nil: allow_nil
|
18
|
-
instance_exec(&block) if block_given?
|
19
|
-
end,
|
20
|
-
optional: optional
|
21
|
-
)
|
22
|
-
|
23
|
-
self
|
24
|
-
end
|
25
|
-
|
26
|
-
def validate!(output, options, **_opts)
|
27
|
-
RulesExhaustedGuard.call(output, options, rules: links)
|
28
|
-
end
|
29
|
-
|
30
|
-
def inspect
|
31
|
-
"[Scheme::Links #{links.keys}]"
|
32
|
-
end
|
33
|
-
|
34
|
-
def run_fixture_validations(expect_symbol_keys, backtrace = [])
|
35
|
-
fixture_errors = @links.flat_map {|key, rule|
|
36
|
-
if rule.is_a?(Scheme)
|
37
|
-
begin
|
38
|
-
rule.run_fixture_validations(expect_symbol_keys, backtrace.dup.append(key))
|
39
|
-
nil
|
40
|
-
rescue AssertionError => e
|
41
|
-
e.fixture_errors
|
42
|
-
end
|
43
|
-
end
|
44
|
-
}.compact
|
45
|
-
|
46
|
-
raise AssertionError.new(fixture_errors) unless fixture_errors.empty?
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
attr_accessor :links
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'media_types/scheme/rules'
|
4
|
+
require 'media_types/scheme/rules_exhausted_guard'
|
5
|
+
|
6
|
+
module MediaTypes
|
7
|
+
class Scheme
|
8
|
+
class Links
|
9
|
+
def initialize
|
10
|
+
self.links = Rules.new(allow_empty: false, expected_type: ::Hash)
|
11
|
+
end
|
12
|
+
|
13
|
+
def link(key, allow_nil: false, optional: false, &block)
|
14
|
+
links.add(
|
15
|
+
key,
|
16
|
+
Scheme.new do
|
17
|
+
attribute :href, String, allow_nil: allow_nil
|
18
|
+
instance_exec(&block) if block_given?
|
19
|
+
end,
|
20
|
+
optional: optional
|
21
|
+
)
|
22
|
+
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def validate!(output, options, **_opts)
|
27
|
+
RulesExhaustedGuard.call(output, options, rules: links)
|
28
|
+
end
|
29
|
+
|
30
|
+
def inspect
|
31
|
+
"[Scheme::Links #{links.keys}]"
|
32
|
+
end
|
33
|
+
|
34
|
+
def run_fixture_validations(expect_symbol_keys, backtrace = [])
|
35
|
+
fixture_errors = @links.flat_map {|key, rule|
|
36
|
+
if rule.is_a?(Scheme)
|
37
|
+
begin
|
38
|
+
rule.run_fixture_validations(expect_symbol_keys, backtrace.dup.append(key))
|
39
|
+
nil
|
40
|
+
rescue AssertionError => e
|
41
|
+
e.fixture_errors
|
42
|
+
end
|
43
|
+
end
|
44
|
+
}.compact
|
45
|
+
|
46
|
+
raise AssertionError.new(fixture_errors) unless fixture_errors.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_accessor :links
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|