Skip to content

Commit 94b140b

Browse files
authored
Added cleaner error messages to help migration (#82)
* Added cleaner error messages to help migration
1 parent bbe4245 commit 94b140b

File tree

9 files changed

+46
-21
lines changed

9 files changed

+46
-21
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ class Venue
6464
'mydomain'
6565
end
6666

67-
media_type 'venue'
67+
use_name 'venue'
6868

6969
validations do
7070
version 2 do

lib/media_types/dsl.rb

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ def validate_unsafe!(output, media_type = to_constructable, **opts)
4747
def validatable?(media_type = to_constructable)
4848
return false unless validations
4949

50-
validations.find(media_type, -> { nil })
50+
resolved = validations.find(media_type, -> { nil })
51+
52+
!resolved.nil?
5153
end
5254

5355
def register
@@ -112,7 +114,10 @@ def use_name(name)
112114
end
113115

114116
def validations(&block)
115-
return media_type_validations unless block_given?
117+
unless block_given?
118+
raise 'No validations defined' if media_type_validations.nil?
119+
return media_type_validations
120+
end
116121
self.media_type_validations = Validations.new(to_constructable, &block)
117122

118123
self

lib/media_types/scheme.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def valid?(output, **opts)
101101
#
102102
def validate(output, options = nil, **opts)
103103
options ||= ValidationOptions.new(**opts)
104+
options.context = output
104105

105106
catch(:end) do
106107
validate!(output, options, context: nil)

lib/media_types/scheme/missing_validation.rb

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,21 @@ class MissingValidation
99
def validate!(_output, options, context:, **_opts)
1010
# Check that no unknown keys are present
1111
return true unless options.strict
12-
raise_strict!(key: context.key, strict_keys: context.rules, backtrace: options.backtrace)
12+
raise_strict!(key: context.key, strict_keys: context.rules, backtrace: options.backtrace, found: options.scoped_output)
1313
end
1414

15-
def raise_strict!(key:, backtrace:, strict_keys:)
15+
def raise_strict!(key:, backtrace:, strict_keys:, found:)
1616
raise StrictValidationError, format(
1717
"Unknown key %<key>s in data.\n" \
1818
"\tFound at: %<backtrace>s\n" \
1919
"\tExpected:\n\n" \
20-
'%<strict_keys>s',
20+
"%<strict_keys>s\n\n" \
21+
"\tBut I Found:\n\n" \
22+
'%<found>s',
2123
key: key.inspect,
2224
backtrace: backtrace.join('->'),
23-
strict_keys: strict_keys.inspect(1)
25+
strict_keys: strict_keys.keys,
26+
found: (found.is_a? Hash) ? found.keys : found.class.name
2427
)
2528
end
2629

lib/media_types/scheme/output_empty_guard.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def initialize(output, options, rules:)
2121
def call
2222
return unless MediaTypes::Object.new(output).empty?
2323
throw(:end, true) if allow_empty?
24-
raise_empty!(backtrace: options.backtrace)
24+
raise_empty!(backtrace: options.backtrace, found: options.scoped_output)
2525
end
2626

2727
private
@@ -32,11 +32,12 @@ def allow_empty?
3232
rules.allow_empty? || rules.required.empty?
3333
end
3434

35-
def raise_empty!(backtrace:)
35+
def raise_empty!(backtrace:, found:)
3636
raise EmptyOutputError, format(
37-
'Expected output, got empty at %<backtrace>s. Required are: %<required>s.',
37+
'Expected output, got empty at %<backtrace>s. Required are: %<required>s. Found: %<found>s',
3838
backtrace: backtrace.join('->'),
39-
required: rules.required.keys
39+
required: rules.required.keys,
40+
found: (found.is_a? Hash) ? found.keys : found.class.name,
4041
)
4142
end
4243
end

lib/media_types/scheme/rules_exhausted_guard.rb

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def call
3131
result = iterate(->(key) { required_rules.remove(key) })
3232
return result if required_rules.empty?
3333

34-
raise_exhausted!(missing_keys: required_rules.keys, backtrace: options.backtrace)
34+
raise_exhausted!(missing_keys: required_rules.keys, backtrace: options.backtrace, found: output)
3535
end
3636

3737
def iterate(mark)
@@ -50,11 +50,12 @@ def iterate(mark)
5050

5151
attr_accessor :rules, :options, :output
5252

53-
def raise_exhausted!(missing_keys:, backtrace:)
53+
def raise_exhausted!(missing_keys:, backtrace:, found:)
5454
raise ExhaustedOutputError, format(
55-
'Missing keys in output: %<missing_keys>s at [%<backtrace>s]',
55+
'Missing keys in output: %<missing_keys>s at [%<backtrace>s]. I did find: %<found>s',
5656
missing_keys: missing_keys,
57-
backtrace: backtrace.join('->')
57+
backtrace: backtrace.join('->'),
58+
found: (found.is_a? Hash) ? found.keys : found.class.name,
5859
)
5960
end
6061
end

lib/media_types/scheme/validation_options.rb

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,39 @@
33
module MediaTypes
44
class Scheme
55
class ValidationOptions
6-
attr_accessor :exhaustive, :strict, :backtrace
6+
attr_accessor :exhaustive, :strict, :backtrace, :context
77

8-
def initialize(exhaustive: true, strict: true, backtrace: [])
8+
def initialize(context = {}, exhaustive: true, strict: true, backtrace: [])
99
self.exhaustive = exhaustive
1010
self.strict = strict
1111
self.backtrace = backtrace
12+
self.context = context
1213
end
1314

1415
def inspect
15-
"backtrack: #{backtrace.inspect}, strict: #{strict.inspect}, exhaustive: #{exhaustive}"
16+
"backtrack: #{backtrace.inspect}, strict: #{strict.inspect}, exhaustive: #{exhaustive}, current_obj: #{scoped_output.to_json}"
17+
end
18+
19+
def scoped_output
20+
current = context
21+
22+
backtrace.drop(1).first([0, backtrace.size - 2].max).each do |e|
23+
current = current[e] unless current.nil?
24+
end
25+
26+
current
1627
end
1728

1829
def with_backtrace(backtrace)
19-
ValidationOptions.new(exhaustive: exhaustive, strict: strict, backtrace: backtrace)
30+
ValidationOptions.new(context, exhaustive: exhaustive, strict: strict, backtrace: backtrace)
2031
end
2132

2233
def trace(*traces)
2334
with_backtrace(backtrace.dup.concat(traces))
2435
end
2536

2637
def exhaustive!
27-
ValidationOptions.new(exhaustive: true, strict: strict, backtrace: backtrace)
38+
ValidationOptions.new(context, exhaustive: true, strict: strict, backtrace: backtrace)
2839
end
2940
end
3041
end

lib/media_types/validations.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ def find(media_type, default = -> { Scheme.new(allow_empty: true) { not_strict }
4646

4747
def method_missing(method_name, *arguments, &block)
4848
if scheme.respond_to?(method_name)
49+
media_type.__getobj__.media_type_combinations ||= Set.new
4950
media_type.__getobj__.media_type_combinations.add(media_type.as_key)
5051

5152
return scheme.send(method_name, *arguments, &block)

test/media_types/validations_test.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ def self.organisation
1818
end
1919

2020
def test_it_is_not_validatable
21-
refute TestSchemeType.validatable?
21+
assert_raises RuntimeError do
22+
TestSchemeType.validatable?
23+
end
2224
end
2325
end
2426
end

0 commit comments

Comments
 (0)