-
Notifications
You must be signed in to change notification settings - Fork 82
/
Copy patherror_formatter.rb
123 lines (105 loc) · 3.05 KB
/
error_formatter.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
module Contracts
class ErrorFormatters
def self.failure_msg(data)
class_for(data).new(data).message
end
def self.class_for(data)
return Contracts::KeywordArgsErrorFormatter if is_keysword_args?(data)
return DefaultErrorFormatter
end
def self.is_keysword_args?(data)
data[:contract].is_a?(Contracts::Builtin::KeywordArgs) && data[:arg].is_a?(Hash)
end
end
class DefaultErrorFormatter
attr_accessor :data
def initialize(data)
@data = data
end
def message
%{#{header}
Expected: #{expected},
Actual: #{data[:arg].inspect}
Value guarded in: #{data[:class]}::#{method_name}
With Contract: #{data[:contracts]}
At: #{position} }
end
private
def header
if data[:return_value]
"Contract violation for return value:"
else
"Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:"
end
end
def expected
Contracts::Formatters::Expected.new(data[:contract]).contract
end
def position
Contracts::Support.method_position(data[:method])
end
def method_name
Contracts::Support.method_name(data[:method])
end
end
class KeywordArgsErrorFormatter < DefaultErrorFormatter
def message
s = []
s << "#{header}"
s << " Expected: #{expected}"
s << " Actual: #{data[:arg].inspect}"
s << " Missing Contract: #{missing_contract_info}" if !missing_contract_info.empty?
s << " Invalid Args: #{invalid_args_info}" if !invalid_args_info.empty?
s << " Missing Args: #{missing_args_info}" if !missing_args_info.empty?
s << " Value guarded in: #{data[:class]}::#{method_name}"
s << " With Contract: #{data[:contracts]}"
s << " At: #{position} "
s.join("\n")
end
private
def missing_args_info
@missing_args_info ||= begin
missing_keys = contract_options.keys - arg.keys
contract_options.select do |key, value|
missing_keys.include?(key)
end
end
end
def missing_contract_info
@missing_contract_info ||= begin
contract_keys = contract_options.keys
arg.select{|key, value| !contract_keys.include?(key)}
end
end
def invalid_args_info
@invalid_args_info ||= begin
invalid_keys = []
arg.each do |key, value|
if contract = contract_options[key]
if !(check_contract(contract, value))
invalid_keys.push(key)
end
end
end
invalid_keys.map do |key|
{key => arg[key], :contract => contract_options[key] }
end
end
end
def check_contract(contract, value)
if contract.respond_to?(:valid?)
contract.valid?(value)
else
value.is_a?(contract)
end
rescue
false
end
def contract_options
@contract_options ||= data[:contract].send(:options)
end
def arg
data[:arg]
end
end
end