respect 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.md +289 -0
- data/RELATED_WORK.md +40 -0
- data/RELEASE_NOTES.md +23 -0
- data/Rakefile +31 -0
- data/STATUS_MATRIX.html +137 -0
- data/lib/respect.rb +231 -0
- data/lib/respect/any_schema.rb +22 -0
- data/lib/respect/array_def.rb +28 -0
- data/lib/respect/array_schema.rb +203 -0
- data/lib/respect/boolean_schema.rb +32 -0
- data/lib/respect/composite_schema.rb +86 -0
- data/lib/respect/core_statements.rb +206 -0
- data/lib/respect/datetime_schema.rb +27 -0
- data/lib/respect/def_without_name.rb +6 -0
- data/lib/respect/divisible_by_validator.rb +20 -0
- data/lib/respect/doc_helper.rb +24 -0
- data/lib/respect/doc_parser.rb +37 -0
- data/lib/respect/dsl_dumper.rb +181 -0
- data/lib/respect/equal_to_validator.rb +20 -0
- data/lib/respect/fake_name_proxy.rb +116 -0
- data/lib/respect/float_schema.rb +27 -0
- data/lib/respect/format_validator.rb +136 -0
- data/lib/respect/global_def.rb +79 -0
- data/lib/respect/greater_than_or_equal_to_validator.rb +19 -0
- data/lib/respect/greater_than_validator.rb +19 -0
- data/lib/respect/has_constraints.rb +34 -0
- data/lib/respect/hash_def.rb +40 -0
- data/lib/respect/hash_schema.rb +218 -0
- data/lib/respect/in_validator.rb +19 -0
- data/lib/respect/integer_schema.rb +27 -0
- data/lib/respect/ip_addr_schema.rb +23 -0
- data/lib/respect/ipv4_addr_schema.rb +27 -0
- data/lib/respect/ipv6_addr_schema.rb +27 -0
- data/lib/respect/items_def.rb +21 -0
- data/lib/respect/json_schema_html_formatter.rb +143 -0
- data/lib/respect/less_than_or_equal_to_validator.rb +19 -0
- data/lib/respect/less_than_validator.rb +19 -0
- data/lib/respect/match_validator.rb +19 -0
- data/lib/respect/max_length_validator.rb +20 -0
- data/lib/respect/min_length_validator.rb +20 -0
- data/lib/respect/multiple_of_validator.rb +10 -0
- data/lib/respect/null_schema.rb +26 -0
- data/lib/respect/numeric_schema.rb +33 -0
- data/lib/respect/org3_dumper.rb +213 -0
- data/lib/respect/regexp_schema.rb +19 -0
- data/lib/respect/schema.rb +285 -0
- data/lib/respect/schema_def.rb +16 -0
- data/lib/respect/string_schema.rb +21 -0
- data/lib/respect/unit_test_helper.rb +37 -0
- data/lib/respect/uri_schema.rb +23 -0
- data/lib/respect/utc_time_schema.rb +17 -0
- data/lib/respect/validator.rb +51 -0
- data/lib/respect/version.rb +3 -0
- data/test/any_schema_test.rb +79 -0
- data/test/array_def_test.rb +113 -0
- data/test/array_schema_test.rb +487 -0
- data/test/boolean_schema_test.rb +89 -0
- data/test/composite_schema_test.rb +30 -0
- data/test/datetime_schema_test.rb +83 -0
- data/test/doc_helper_test.rb +34 -0
- data/test/doc_parser_test.rb +109 -0
- data/test/dsl_dumper_test.rb +395 -0
- data/test/fake_name_proxy_test.rb +138 -0
- data/test/float_schema_test.rb +146 -0
- data/test/format_validator_test.rb +224 -0
- data/test/hash_def_test.rb +126 -0
- data/test/hash_schema_test.rb +613 -0
- data/test/integer_schema_test.rb +142 -0
- data/test/ip_addr_schema_test.rb +78 -0
- data/test/ipv4_addr_schema_test.rb +71 -0
- data/test/ipv6_addr_schema_test.rb +71 -0
- data/test/json_schema_html_formatter_test.rb +214 -0
- data/test/null_schema_test.rb +46 -0
- data/test/numeric_schema_test.rb +294 -0
- data/test/org3_dumper_test.rb +784 -0
- data/test/regexp_schema_test.rb +54 -0
- data/test/respect_test.rb +108 -0
- data/test/schema_def_test.rb +405 -0
- data/test/schema_test.rb +290 -0
- data/test/string_schema_test.rb +209 -0
- data/test/support/circle.rb +11 -0
- data/test/support/color.rb +24 -0
- data/test/support/point.rb +11 -0
- data/test/support/respect/circle_schema.rb +16 -0
- data/test/support/respect/color_def.rb +19 -0
- data/test/support/respect/color_schema.rb +33 -0
- data/test/support/respect/point_schema.rb +19 -0
- data/test/support/respect/rgba_schema.rb +20 -0
- data/test/support/respect/universal_validator.rb +25 -0
- data/test/support/respect/user_macros.rb +12 -0
- data/test/support/rgba.rb +11 -0
- data/test/test_helper.rb +90 -0
- data/test/uri_schema_test.rb +54 -0
- data/test/utc_time_schema_test.rb +63 -0
- data/test/validator_test.rb +22 -0
- metadata +288 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
module Respect
|
2
|
+
# Dump a schema to a string representation using the DSL syntax so you
|
3
|
+
# can evaluate it and get the same schema back.
|
4
|
+
#
|
5
|
+
# Theoretically, this must always be true:
|
6
|
+
# eval(DslDumper.new(schema).dump) == schema
|
7
|
+
#
|
8
|
+
# The current implementation covers all the _Schema_ and _Validator_
|
9
|
+
# classes defined in this package. User-defined sub-class of {Schema}
|
10
|
+
# are not guarantee to work. Specially those using a custom "Def" class
|
11
|
+
# or with special attributes. The API of this dumper is *experimental*,
|
12
|
+
# so relying on it to teach the dumper how to dump a user-defined schema
|
13
|
+
# class may break in future releases.
|
14
|
+
#
|
15
|
+
# However, sub-classes of {CompositeSchema} are handled
|
16
|
+
# properly as well as all {Validator} sub-classes.
|
17
|
+
class DslDumper
|
18
|
+
|
19
|
+
def initialize(schema)
|
20
|
+
@schema = schema
|
21
|
+
@indent_level = 0
|
22
|
+
@indent_size = 2
|
23
|
+
@context_data = {}
|
24
|
+
end
|
25
|
+
|
26
|
+
attr_reader :schema, :output
|
27
|
+
|
28
|
+
def dump(output = nil)
|
29
|
+
@output = output
|
30
|
+
@output ||= String.new
|
31
|
+
self << "Respect::Schema.define do |s|"
|
32
|
+
self.indent do
|
33
|
+
self.dump_schema(@schema)
|
34
|
+
end
|
35
|
+
self << "\nend\n"
|
36
|
+
@output
|
37
|
+
end
|
38
|
+
|
39
|
+
def <<(str)
|
40
|
+
@output << str.gsub(/(\n+)/, "\\1#{indentation}")
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def indent(count = 1, &block)
|
45
|
+
@indent_level += count
|
46
|
+
if block
|
47
|
+
block.call
|
48
|
+
unindent(count)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def unindent(count = 1)
|
53
|
+
@indent_level -= count
|
54
|
+
end
|
55
|
+
|
56
|
+
def indentation
|
57
|
+
" " * @indent_size * @indent_level
|
58
|
+
end
|
59
|
+
|
60
|
+
attr_accessor :context_data
|
61
|
+
|
62
|
+
def dump_block(args = [ "s" ], &block)
|
63
|
+
self << " do |#{args.join(', ')}|"
|
64
|
+
self.indent(&block)
|
65
|
+
self << "\nend"
|
66
|
+
end
|
67
|
+
|
68
|
+
def dump_schema(schema)
|
69
|
+
self.dump_doc(schema)
|
70
|
+
self << "\ns."
|
71
|
+
self.dump_name(schema)
|
72
|
+
self.dump_arguments(schema)
|
73
|
+
self.dump_body(schema)
|
74
|
+
self
|
75
|
+
end
|
76
|
+
|
77
|
+
def dump_doc(schema, prefix = false)
|
78
|
+
if schema.doc
|
79
|
+
if schema.description
|
80
|
+
self << "\n"
|
81
|
+
self << %q{s.doc <<-EOS.strip_heredoc}
|
82
|
+
self.indent do
|
83
|
+
self << "\n"
|
84
|
+
self << schema.doc
|
85
|
+
self << "EOS"
|
86
|
+
end
|
87
|
+
else
|
88
|
+
self << "\ns.doc \"#{schema.title}\""
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def dump_name(schema)
|
94
|
+
self << schema.class.statement_name
|
95
|
+
end
|
96
|
+
|
97
|
+
def dump_arguments(schema)
|
98
|
+
# Fetch name if there is one?
|
99
|
+
if self.context_data.has_key?(:name)
|
100
|
+
name = self.context_data[:name]
|
101
|
+
else
|
102
|
+
name = nil
|
103
|
+
end
|
104
|
+
# Compute options to dump.
|
105
|
+
options = schema.non_default_options.reject do |opt|
|
106
|
+
opt == :doc
|
107
|
+
end
|
108
|
+
# Dump name and options
|
109
|
+
if name || !options.empty?
|
110
|
+
if name
|
111
|
+
self << " "
|
112
|
+
self << name.inspect
|
113
|
+
end
|
114
|
+
if !options.empty?
|
115
|
+
if name
|
116
|
+
self << ","
|
117
|
+
end
|
118
|
+
self << " "
|
119
|
+
self.dump_options(schema)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
self
|
123
|
+
end
|
124
|
+
|
125
|
+
def dump_options(schema)
|
126
|
+
options = schema.non_default_options
|
127
|
+
option_keys = options.keys
|
128
|
+
option_keys.each do |opt|
|
129
|
+
self << opt.inspect
|
130
|
+
self << " => "
|
131
|
+
self << options[opt].inspect
|
132
|
+
self << ", " unless opt == option_keys.last
|
133
|
+
end
|
134
|
+
self
|
135
|
+
end
|
136
|
+
|
137
|
+
def dump_body(schema)
|
138
|
+
symbol = "dump_body_for_#{schema.class.statement_name}"
|
139
|
+
if respond_to? symbol
|
140
|
+
send(symbol, schema)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def dump_body_for_hash(schema)
|
145
|
+
dump_block do
|
146
|
+
schema.properties.each do |name, schema|
|
147
|
+
context_data[:name] = name
|
148
|
+
dump_schema(schema)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def dump_body_for_array(schema)
|
154
|
+
dump_block do
|
155
|
+
context_data.delete(:name)
|
156
|
+
if schema.item
|
157
|
+
dump_schema(schema.item)
|
158
|
+
end
|
159
|
+
if schema.items && !schema.items.empty?
|
160
|
+
self << "\ns.items do |s|"
|
161
|
+
indent do
|
162
|
+
schema.items.each do |schema|
|
163
|
+
dump_schema(schema)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
self << "\nend"
|
167
|
+
end
|
168
|
+
if schema.extra_items && !schema.extra_items.empty?
|
169
|
+
self << "\ns.extra_items do |s|"
|
170
|
+
indent do
|
171
|
+
schema.extra_items.each do |schema|
|
172
|
+
dump_schema(schema)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
self << "\nend"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
end # module Respect
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Respect
|
2
|
+
class EqualToValidator < Validator
|
3
|
+
def initialize(expected)
|
4
|
+
@expected = expected
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate(value)
|
8
|
+
unless value == @expected
|
9
|
+
raise ValidationError,
|
10
|
+
"wrong value: `#{value}':#{value.class} instead of `#@expected':#{@expected.class}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def to_h_org3
|
17
|
+
{ 'enum' => [ @expected ] }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module Respect
|
2
|
+
# The evaluation proxy used for the DSL.
|
3
|
+
#
|
4
|
+
# This class sends all methods it receives to the target object it has
|
5
|
+
# received when initialized.
|
6
|
+
#
|
7
|
+
# If the target's response to +accept_name?+ is +false+, this proxy
|
8
|
+
# passes a +nil+ value as first argument to target's dynamic methods
|
9
|
+
# and target's methods expecting a name as first argument.
|
10
|
+
#
|
11
|
+
# This is useful to factor method code that should work in two different
|
12
|
+
# contexts. For instance, in the context of a hash schema definition,
|
13
|
+
# core statements expect a name as first argument whereas in the context
|
14
|
+
# of an array schema definition they do not.
|
15
|
+
#
|
16
|
+
# HashSchema.define do |s|
|
17
|
+
# s.integer "age", greater_than: 0
|
18
|
+
# end
|
19
|
+
# ArraySchema.define do |s|
|
20
|
+
# # FakeNameProxy passes +nil+ here as value for the +name+ argument.
|
21
|
+
# s.integer greater_than: 0
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# To factor this code, we define the +integer+ method in a module included
|
25
|
+
# in both context classes.
|
26
|
+
#
|
27
|
+
# module CoreStatements
|
28
|
+
# def integer(name, options = {})
|
29
|
+
# update_context name, IntegerSchema.define(options)
|
30
|
+
# end
|
31
|
+
# end
|
32
|
+
# class HashDef
|
33
|
+
# include CoreStatements
|
34
|
+
# def accept_name?; true; end
|
35
|
+
# def update_context(name, schema)
|
36
|
+
# @hash_schema[name] = schema
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
# class ArrayDef
|
40
|
+
# include CoreStatements
|
41
|
+
# def accept_name?; false; end
|
42
|
+
# def update_context(name, schema)
|
43
|
+
# @array_schema.item = schema
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# The +update_context+ method simply ignored the name argument in ArrayDef
|
48
|
+
# because it does not make any sens in this context.
|
49
|
+
class FakeNameProxy < BasicObject
|
50
|
+
|
51
|
+
def initialize(target)
|
52
|
+
@target = target
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return the DSL context object where the evaluation takes place.
|
56
|
+
attr_reader :target
|
57
|
+
|
58
|
+
def method_missing(symbol, *args, &block)
|
59
|
+
if respond_to_missing?(symbol, false)
|
60
|
+
# If the target's default behavior for its methods is to not accept a name as
|
61
|
+
# first argument (this is the case for ArrayDef), we introspect the method
|
62
|
+
# to decide whether we have to send a nil name as first argument.
|
63
|
+
if should_fake_name?
|
64
|
+
method = @target.method(symbol)
|
65
|
+
else
|
66
|
+
method = nil
|
67
|
+
end
|
68
|
+
# If we have a method and this method is either dynamic or expects a name as its first parameter.
|
69
|
+
if method && (dynamic_method?(symbol) || has_name_param?(method))
|
70
|
+
args.insert(0, nil)
|
71
|
+
begin
|
72
|
+
method.call(*args, &block)
|
73
|
+
rescue ::ArgumentError => e
|
74
|
+
# Decrements argument number mentioned in the message by one.
|
75
|
+
message = e.message.sub(/ \((\d+) for (\d+)\)$/) do |match|
|
76
|
+
# FIXME(Nicolas Despres): Not sure if this class is still
|
77
|
+
# re-entrant since we use $1 and $2. I could not find a way to access
|
78
|
+
# to the data matched by sub.
|
79
|
+
" (#{$1.to_i - 1} for #{$2.to_i - 1})"
|
80
|
+
end
|
81
|
+
::Kernel.raise(::ArgumentError, message)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
@target.public_send(symbol, *args, &block)
|
85
|
+
end
|
86
|
+
else
|
87
|
+
super
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def respond_to_missing?(symbol, include_all)
|
92
|
+
# We ignore include_all since we are only interested in non-private methods.
|
93
|
+
@target.respond_to?(symbol)
|
94
|
+
end
|
95
|
+
|
96
|
+
# Evaluate the given +block+ in the context of this class and pass it this
|
97
|
+
# instance as argument and returns the value returned by the block.
|
98
|
+
def eval(&block)
|
99
|
+
block.call(self)
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def dynamic_method?(symbol)
|
105
|
+
!@target.methods.include?(symbol)
|
106
|
+
end
|
107
|
+
|
108
|
+
def has_name_param?(method)
|
109
|
+
!method.parameters.empty? && method.parameters.first.last == :name
|
110
|
+
end
|
111
|
+
|
112
|
+
def should_fake_name?
|
113
|
+
@target.respond_to?(:accept_name?) && !@target.accept_name?
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Respect
|
2
|
+
class FloatSchema < NumericSchema
|
3
|
+
|
4
|
+
def validate_type(object)
|
5
|
+
case object
|
6
|
+
when String
|
7
|
+
if object =~ /^[-+]?\d+(\.\d+)?$/
|
8
|
+
object.to_f
|
9
|
+
else
|
10
|
+
raise ValidationError,
|
11
|
+
"malformed float value: `#{object}'"
|
12
|
+
end
|
13
|
+
when Float
|
14
|
+
object
|
15
|
+
when NilClass
|
16
|
+
if allow_nil?
|
17
|
+
nil
|
18
|
+
else
|
19
|
+
raise ValidationError, "object is nil but this #{self.class} does not allow nil"
|
20
|
+
end
|
21
|
+
else
|
22
|
+
raise ValidationError, "object is not a float but a '#{object.class}'"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end # class FloatSchema
|
27
|
+
end # module Respect
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'ipaddr'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Respect
|
5
|
+
class FormatValidator < Validator
|
6
|
+
|
7
|
+
PHONE_NUMBER_REGEXP = /^((\+|00)\d{1,2})?\d+$/
|
8
|
+
|
9
|
+
# FIXME(Nicolas Despres): RFC 1034 mentions that a valid domain can be " "
|
10
|
+
# in section 3.5. (see http://www.rfc-editor.org/rfc/rfc1034.txt) but we don't
|
11
|
+
# since I don't understand when it is useful.
|
12
|
+
HOSTNAME_REGEXP = /^[a-z][a-z0-9-]*(\.[a-z][a-z0-9-]*)*$/i
|
13
|
+
|
14
|
+
def initialize(format)
|
15
|
+
@format = format
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate(value)
|
19
|
+
send("validate_#@format", value)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Validate the given string _value_ describes a well-formed email
|
23
|
+
# address following this specification
|
24
|
+
# http://www.w3.org/TR/2012/CR-html5-20121217/forms.html#valid-e-mail-address
|
25
|
+
def validate_email(value)
|
26
|
+
unless value =~ /^[a-zA-Z0-9.!#$\%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
|
27
|
+
raise ValidationError, "invalid email address format '#{value}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Validate URI string format following RFC 2396
|
32
|
+
# (see http://tools.ietf.org/html/rfc2396)
|
33
|
+
def validate_uri(value)
|
34
|
+
URI.parse(value)
|
35
|
+
rescue URI::InvalidURIError => e
|
36
|
+
raise ValidationError, "invalid URI: #{e.message}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# Validate the given string _value_ describes a regular expression
|
40
|
+
# following the Ruby regular expression syntax.
|
41
|
+
def validate_regexp(value)
|
42
|
+
Regexp.new(value)
|
43
|
+
rescue RegexpError => e
|
44
|
+
raise ValidationError, "invalid regexp: #{e.message}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Validate date and time string format following RFC 3399
|
48
|
+
# (see https://tools.ietf.org/html/rfc3339)
|
49
|
+
def validate_datetime(value)
|
50
|
+
DateTime.rfc3339(value)
|
51
|
+
rescue ArgumentError => e
|
52
|
+
raise ValidationError, e.message
|
53
|
+
end
|
54
|
+
|
55
|
+
# Validate IPV4 using the standard "ipaddr" ruby module.
|
56
|
+
def validate_ipv4_addr(value)
|
57
|
+
ipaddr = IPAddr.new(value)
|
58
|
+
unless ipaddr.ipv4?
|
59
|
+
raise ValidationError, "IP address '#{value}' is not IPv4"
|
60
|
+
end
|
61
|
+
ipaddr
|
62
|
+
rescue ArgumentError => e
|
63
|
+
raise ValidationError, "invalid IPv4 address '#{value}' - #{e.message}"
|
64
|
+
end
|
65
|
+
|
66
|
+
# Validate phone number following E.123
|
67
|
+
# (see http://en.wikipedia.org/wiki/E.123)
|
68
|
+
def validate_phone_number(value)
|
69
|
+
unless value =~ PHONE_NUMBER_REGEXP
|
70
|
+
raise ValidationError, "invalid phone number '#{value}'"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Validate that the given string _value_ describes a well-formed
|
75
|
+
# IPV6 network address using the standard "ipaddr" ruby module.
|
76
|
+
def validate_ipv6_addr(value)
|
77
|
+
ipaddr = IPAddr.new(value)
|
78
|
+
unless ipaddr.ipv6?
|
79
|
+
raise ValidationError, "IP address '#{value}' is not IPv6"
|
80
|
+
end
|
81
|
+
ipaddr
|
82
|
+
rescue ArgumentError => e
|
83
|
+
raise ValidationError, "invalid IPv6 address '#{value}' - #{e.message}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# Validate that the given string _value_ describes a well-formed
|
87
|
+
# IP (IPv6 or IPv4) network address using the standard "ipaddr" ruby module.
|
88
|
+
def validate_ip_addr(value)
|
89
|
+
IPAddr.new(value)
|
90
|
+
rescue ArgumentError => e
|
91
|
+
raise ValidationError, "invalid IP address '#{value}' - #{e.message}"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Validate that the given string _value_ describes a well-formed
|
95
|
+
# host name as specified by RFC 1034.
|
96
|
+
# (see http://www.rfc-editor.org/rfc/rfc1034.txt)
|
97
|
+
def validate_hostname(value)
|
98
|
+
match_data = HOSTNAME_REGEXP.match(value)
|
99
|
+
if match_data
|
100
|
+
value.split('.').each_with_index do |label, i|
|
101
|
+
unless label.length <= 63
|
102
|
+
raise ValidationError,
|
103
|
+
"hostname's #{i.ordinalize} label '#{label}' is not less than 63 characters in '#{value}'"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
else
|
107
|
+
raise ValidationError, "invalid hostname '#{value}'"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def to_h_org3
|
114
|
+
{ 'format' => convert_to_org3_format(@format) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def convert_to_org3_format(format)
|
118
|
+
format_type_map = {
|
119
|
+
regexp: 'regex',
|
120
|
+
datetime: 'date-time',
|
121
|
+
ipv4_addr: 'ip-address',
|
122
|
+
phone_number: 'phone',
|
123
|
+
ipv6_addr: 'ipv6',
|
124
|
+
ip_addr: nil,
|
125
|
+
hostname: 'host-name',
|
126
|
+
}.freeze
|
127
|
+
if format_type_map.has_key?(format)
|
128
|
+
translation_value = format_type_map[format]
|
129
|
+
translation_value unless translation_value.nil?
|
130
|
+
else
|
131
|
+
format.to_s
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end # class FormatValidator
|
136
|
+
end # module Respect
|