Module: JSONSchemer::Format

Extended by:
Duration, Email, Hostname, JSONPointer, URITemplate
Defined in:
lib/json_schemer/format.rb,
lib/json_schemer/format/email.rb,
lib/json_schemer/format/duration.rb,
lib/json_schemer/format/hostname.rb,
lib/json_schemer/format/json_pointer.rb,
lib/json_schemer/format/uri_template.rb

Defined Under Namespace

Modules: Duration, Email, Hostname, JSONPointer, URITemplate

Constant Summary collapse

DATE_TIME =
proc do |instance, _format|
  !instance.is_a?(String) || valid_date_time?(instance)
end
DATE =
proc do |instance, _format|
  !instance.is_a?(String) || valid_date_time?("#{instance}T04:05:06.123456789+07:00")
end
TIME =
proc do |instance, _format|
  !instance.is_a?(String) || valid_date_time?("2001-02-03T#{instance}")
end
DURATION =
proc do |instance, _format|
  !instance.is_a?(String) || valid_duration?(instance)
end
EMAIL =
proc do |instance, _format|
  !instance.is_a?(String) || instance.ascii_only? && valid_email?(instance)
end
IDN_EMAIL =
proc do |instance, _format|
  !instance.is_a?(String) || valid_email?(instance)
end
HOSTNAME =
proc do |instance, _format|
  !instance.is_a?(String) || instance.ascii_only? && valid_hostname?(instance)
end
IDN_HOSTNAME =
proc do |instance, _format|
  !instance.is_a?(String) || valid_hostname?(instance)
end
IPV4 =
proc do |instance, _format|
  !instance.is_a?(String) || valid_ip?(instance, Socket::AF_INET)
end
IPV6 =
proc do |instance, _format|
  !instance.is_a?(String) || valid_ip?(instance, Socket::AF_INET6)
end
URI =
proc do |instance, _format|
  !instance.is_a?(String) || valid_uri?(instance)
end
URI_REFERENCE =
proc do |instance, _format|
  !instance.is_a?(String) || valid_uri_reference?(instance)
end
IRI =
proc do |instance, _format|
  !instance.is_a?(String) || valid_uri?(iri_escape(instance))
end
IRI_REFERENCE =
proc do |instance, _format|
  !instance.is_a?(String) || valid_uri_reference?(iri_escape(instance))
end
UUID =
proc do |instance, _format|
  !instance.is_a?(String) || valid_uuid?(instance)
end
URI_TEMPLATE =
proc do |instance, _format|
  !instance.is_a?(String) || valid_uri_template?(instance)
end
JSON_POINTER =
proc do |instance, _format|
  !instance.is_a?(String) || valid_json_pointer?(instance)
end
RELATIVE_JSON_POINTER =
proc do |instance, _format|
  !instance.is_a?(String) || valid_relative_json_pointer?(instance)
end
REGEX =
proc do |instance, _format|
  !instance.is_a?(String) || valid_regex?(instance)
end
DATE_TIME_OFFSET_REGEX =
/(Z|[\+\-]([01][0-9]|2[0-3]):[0-5][0-9])\z/i.freeze
DATE_TIME_SEPARATOR_CHARACTER_CLASS =
'[Tt\s]'
HOUR_24_REGEX =
/#{DATE_TIME_SEPARATOR_CHARACTER_CLASS}24:/.freeze
LEAP_SECOND_REGEX =
/#{DATE_TIME_SEPARATOR_CHARACTER_CLASS}\d{2}:\d{2}:6/.freeze
IP_REGEX =
/\A[\h:.]+\z/.freeze
INVALID_QUERY_REGEX =
/\s/.freeze
IRI_ESCAPE_REGEX =
/[^[:ascii:]]/
UUID_REGEX =
/\A\h{8}-\h{4}-\h{4}-[89AB]\h{3}-\h{12}\z/i
NIL_UUID =
'00000000-0000-0000-0000-000000000000'
BINARY_TO_PERCENT_ENCODED =
256.times.each_with_object({}) do |byte, out|
  out[-byte.chr(Encoding::BINARY)] = -sprintf('%%%02X', byte)
end.freeze

Constants included from URITemplate

URITemplate::EXPLODE, URITemplate::EXPRESSION, URITemplate::LITERALS, URITemplate::MAX_LENGTH, URITemplate::MODIFIER_LEVEL4, URITemplate::OPERATOR, URITemplate::PCT_ENCODED, URITemplate::PREFIX, URITemplate::URI_TEMPLATE_REGEX, URITemplate::VARCHAR, URITemplate::VARIABLE_LIST, URITemplate::VARNAME, URITemplate::VARSPEC

Constants included from JSONPointer

JSONPointer::JSON_POINTER_REGEX, JSONPointer::JSON_POINTER_REGEX_STRING, JSONPointer::RELATIVE_JSON_POINTER_REGEX

Constants included from Hostname

Hostname::ARABIC_EXTENDED_DIGITS_REGEX, Hostname::ARABIC_INDIC_DIGITS_REGEX, Hostname::CONTEXT_REGEX, Hostname::EXCEPTIONS_DISALLOWED, Hostname::EXCEPTIONS_PVALID, Hostname::GREEK_LOWER_NUMERAL_SIGN, Hostname::HEBREW_PUNCTUATION, Hostname::HOSTNAME_REGEX, Hostname::JOINING_TYPE_D_CHARACTER_CLASS, Hostname::JOINING_TYPE_L_CHARACTER_CLASS, Hostname::JOINING_TYPE_R_CHARACTER_CLASS, Hostname::JOINING_TYPE_T_CHARACTER_CLASS, Hostname::KATAKANA_MIDDLE_DOT_CONTEXT_REGEX, Hostname::KATAKANA_MIDDLE_DOT_REGEX, Hostname::LABEL_CHARACTER_CLASS, Hostname::LABEL_REGEX_STRING, Hostname::LEADING_CHARACTER_CLASS, Hostname::LETTER_DIGITS, Hostname::MARKS, Hostname::MIDDLE_DOT, Hostname::VIRAMA_CHARACTER_CLASS, Hostname::ZERO_WIDTH_NON_JOINER_JOINING_TYPE, Hostname::ZERO_WIDTH_VIRAMA

Constants included from Email

Email::ADDRESS_LITERAL, Email::ATOM, Email::A_TEXT, Email::DOT_STRING, Email::EMAIL_REGEX, Email::LOCAL_PART, Email::MAILBOX, Email::QUOTED_PAIR_SMTP, Email::QUOTED_STRING, Email::Q_CONTENT_SMTP, Email::Q_TEXT_SMTP, Email::UTF8_NON_ASCII

Constants included from Duration

Duration::DURATION_REGEX, Duration::DUR_DATE, Duration::DUR_DAY, Duration::DUR_HOUR, Duration::DUR_MINUTE, Duration::DUR_MONTH, Duration::DUR_SECOND, Duration::DUR_TIME, Duration::DUR_WEEK, Duration::DUR_YEAR

Class Method Summary collapse

Methods included from URITemplate

valid_uri_template?

Methods included from JSONPointer

valid_json_pointer?, valid_relative_json_pointer?

Methods included from Hostname

valid_hostname?

Methods included from Email

valid_email?

Methods included from Duration

valid_duration?

Class Method Details

.iri_escape(data) ⇒ Object



132
133
134
# File 'lib/json_schemer/format.rb', line 132

def iri_escape(data)
  Format.percent_encode(data, IRI_ESCAPE_REGEX)
end

.parse_uri_scheme(data) ⇒ Object

Raises:

  • (::URI::InvalidURIError)


112
113
114
115
116
117
# File 'lib/json_schemer/format.rb', line 112

def parse_uri_scheme(data)
  scheme, _userinfo, _host, _port, _registry, _path, opaque, query, _fragment = ::URI::RFC3986_PARSER.split(data)
  # ::URI::RFC3986_PARSER.parse allows spaces in these and I don't think it should
  raise ::URI::InvalidURIError if INVALID_QUERY_REGEX.match?(query) || INVALID_QUERY_REGEX.match?(opaque)
  scheme
end

.percent_encode(data, regexp) ⇒ Object



90
91
92
93
94
# File 'lib/json_schemer/format.rb', line 90

def percent_encode(data, regexp)
  binary = data.b
  binary.gsub!(regexp, BINARY_TO_PERCENT_ENCODED)
  binary.force_encoding(data.encoding)
end

.valid_date_time?(data) ⇒ Boolean

Returns:

  • (Boolean)


96
97
98
99
100
101
102
103
# File 'lib/json_schemer/format.rb', line 96

def valid_date_time?(data)
  return false if HOUR_24_REGEX.match?(data)
  datetime = DateTime.rfc3339(data)
  return false if LEAP_SECOND_REGEX.match?(data) && datetime.new_offset.strftime('%H:%M') != '23:59'
  DATE_TIME_OFFSET_REGEX.match?(data)
rescue ArgumentError
  false
end

.valid_ip?(data, family) ⇒ Boolean

Returns:

  • (Boolean)


105
106
107
108
109
110
# File 'lib/json_schemer/format.rb', line 105

def valid_ip?(data, family)
  IPAddr.new(data, family)
  IP_REGEX.match?(data)
rescue IPAddr::Error
  false
end

.valid_regex?(data) ⇒ Boolean

Returns:

  • (Boolean)


136
137
138
139
140
# File 'lib/json_schemer/format.rb', line 136

def valid_regex?(data)
  !!EcmaRegexp.ruby_equivalent(data)
rescue InvalidEcmaRegexp
  false
end

.valid_uri?(data) ⇒ Boolean

Returns:

  • (Boolean)


119
120
121
122
123
# File 'lib/json_schemer/format.rb', line 119

def valid_uri?(data)
  !!parse_uri_scheme(data)
rescue ::URI::InvalidURIError
  false
end

.valid_uri_reference?(data) ⇒ Boolean

Returns:

  • (Boolean)


125
126
127
128
129
130
# File 'lib/json_schemer/format.rb', line 125

def valid_uri_reference?(data)
  parse_uri_scheme(data)
  true
rescue ::URI::InvalidURIError
  false
end

.valid_uuid?(data) ⇒ Boolean

Returns:

  • (Boolean)


142
143
144
# File 'lib/json_schemer/format.rb', line 142

def valid_uuid?(data)
  UUID_REGEX.match?(data) || NIL_UUID == data
end