Module: Selenium::WebDriver::BiDi::Serialization::Record::Deserializer Private
| Relationships & Source Files | |
| Defined in: | rb/lib/selenium/webdriver/bidi/serialization/record.rb |
Overview
Inbound construction: the keyword #new (validated) and the wire #from_json.
Constant Summary
-
PRIMITIVE_TYPES =
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 279
Ruby classes a checkable primitive admits.
numberis any Numeric (JSON has one number type);integerrequires an Integer — a browser emits5, not5.0, for an integer (JS has no int/float split), so this rarely false-positives yet still rejects a genuine non-integer like 1.5. A field with no primitive descriptor is left unchecked.{ 'string' => [::String], 'boolean' => [::TrueClass, ::FalseClass], 'number' => [::Numeric], 'integer' => [::Integer] }.freeze
Instance Method Summary
-
#from_json(json_payload)
Internal use only
Inbound: builds from the wire.
- #new(**kwargs) Internal use only
-
#check_outbound_primitive(field, value)
private
Internal use only
Outbound mirror of check_primitive: a primitive-typed arg (
string/integer/…) must be the matching Ruby type, so a caller mistake (a string width, a float count) is a local ArgumentError here rather than a rejection the browser reports a round-trip later. -
#check_outbound_scalar(field, value)
private
Internal use only
Outbound mirror of scalar_value: a bare map key must match one of the arm's primitives.
-
#check_outbound_shape(field, value)
private
Internal use only
Outbound mirror of check_shape: a list-typed arg must be an array, a scalar-shaped one (enum or ref, not a list) must not — a local ArgumentError, not a wire round-trip.
- #check_primitive(field, raw) private Internal use only
-
#check_shape(field, raw)
private
Internal use only
A declared list must arrive as an array; a scalar-shaped field (enum or ref, not a list) must not.
- #enum_hash(field) private Internal use only
- #extra(json_payload) private Internal use only
- #fixed?(field) ⇒ Boolean private Internal use only
-
#missing_required(field)
private
Internal use only
A required field absent from the response is tolerated as omitted (UNSET) and warned, so a schema ahead of the browser does not block the caller; strict mode (SE_BIDI_STRICT) escalates to an error for callers who want it.
- #read(field, raw) private Internal use only
-
#read_list(field, raw, klass)
private
Internal use only
Parses each element.
-
#read_map_entry(field, element, klass)
private
Internal use only
A map entry is a
[key, value]pair. -
#read_ref(field, raw)
private
Internal use only
Reads a ref-typed value into its class.
-
#scalar_value(field, value)
private
Internal use only
A bare scalar at a scalar-tolerant union position must match one of the union's scalar-arm primitives (
scalaris a primitive name or an array of them); a wrong-typed scalar (a number where a string is expected) is a wire error, not something to pass through. -
#validate_const(field, value)
private
Internal use only
A nullable constant (
literal / null) is caller-settable but its only non-null value is the literal, so a value that is neither the literal nor nil (nil is handled above) is a local error rather than a wire round-trip. -
#validate_present(field, value)
private
Internal use only
Checks a field that carries an actual value (neither omitted nor nil): a nullable-const field against its literal, list/scalar shape, primitive type (lists excepted, as inbound does), ref type, and enum membership (resolved lazily so a cross-domain enum need not load first).
-
#validate_ref(field, value)
private
Internal use only
Outbound mirror of read_ref: a ref-typed value must be the type it declares, so a wrong record or a value no union variant accepts is a caller error caught here, not a browser round-trip.
-
#validate_ref_entry(field, klass, element)
private
Internal use only
A [key, value] map entry: the key may be a variant or a bare scalar, the value is a variant.
-
#validate_ref_list(field, klass, list)
private
Internal use only
Mirrors read_list: a scalar field is a [key, value] map, a nested list recurses, otherwise each element is checked against the ref.
-
#validate_ref_value(field, klass, value)
private
Internal use only
A record ref must be an instance of that record; a union ref must be one the union accepts.
-
#validate_values(attributes)
private
Internal use only
Checks each field's value: a required field cannot be omitted (UNSET), a non-nullable field cannot be nil (nil is neither a value nor the UNSET omit-sentinel, so it would be silently dropped on the wire), a nullable-const field must carry its literal (not some other value), a primitive field must be the matching Ruby type, and an enum field must be in its allowed set.
-
#warn_undeclared(undeclared)
private
Internal use only
Forward-compat signal: a property a closed type does not model is dropped and warned so schema drift is visible (an extensible type keeps its extras silently — the spec sanctions them).
- #wire_value(field, json_payload) private Internal use only
Instance Method Details
#check_outbound_primitive(field, value) (private)
Outbound mirror of check_primitive: a primitive-typed arg (string/integer/…) must be
the matching Ruby type, so a caller mistake (a string width, a float count) is a local
ArgumentError here rather than a rejection the browser reports a round-trip later. A field
with no primitive descriptor (enum, ref, opaque) passes; lists are skipped, as inbound does.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 206
def check_outbound_primitive(field, value) expected = PRIMITIVE_TYPES[field.primitive] return if expected.nil? || expected.any? { |type| value.is_a?(type) } raise ::ArgumentError, "#{name}##{field.name} expected #{field.primitive}, got #{value.inspect}" end
#check_outbound_scalar(field, value) (private)
Outbound mirror of scalar_value: a bare map key must match one of the arm's primitives.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 175
def check_outbound_scalar(field, value) expected = Array(field.scalar).flat_map { |primitive| PRIMITIVE_TYPES[primitive] || [] } return if expected.empty? || expected.any? { |type| value.is_a?(type) } raise ::ArgumentError, "#{name}##{field.name} expected #{Array(field.scalar).join(' or ')}, got #{value.inspect}" end
#check_outbound_shape(field, value) (private)
Outbound mirror of check_shape: a list-typed arg must be an array, a scalar-shaped one (enum or ref, not a list) must not — a local ArgumentError, not a wire round-trip.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 194
def check_outbound_shape(field, value) return if field.list == value.is_a?(::Array) return unless field.list || field.enum || field.ref kind = field.list ? 'a list' : 'a single value' raise ::ArgumentError, "#{name}##{field.name} expected #{kind}, got #{value.inspect}" end
#check_primitive(field, raw) (private)
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 284
def check_primitive(field, raw) expected = PRIMITIVE_TYPES[field.primitive] return if expected.nil? || expected.any? { |type| raw.is_a?(type) } raise Error::SerializationError, "#{name}##{field.name} expected #{field.primitive}, got #{raw.inspect}" end
#check_shape(field, raw) (private)
A declared list must arrive as an array; a scalar-shaped field (enum or ref, not a list) must not. An opaque field carries no shape descriptor, so it passes through.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 267
def check_shape(field, raw) return if field.list == raw.is_a?(::Array) return unless field.list || field.enum || field.ref raise Error::SerializationError, "#{name}##{field.name} expected #{field.list ? 'a list' : 'a single value'}, got #{raw.inspect}" end
#enum_hash(field) (private)
[ GitHub ]#extra(json_payload) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 339
def extra(json_payload) known = (@wire_keys ||= fields.map(&:wire_key)) json_payload.except(*known) end
#fixed?(field) ⇒ Boolean (private)
#from_json(json_payload)
Inbound: builds from the wire. A missing required field is omitted and warned (or raised in strict mode, in #wire_value); enum tokens are mapped back to symbols and an unrecognized one raises (in #read); an undeclared property is captured silently (extensible) or warned and dropped (closed) — strict on shape, lenient on extras.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 86
def from_json(json_payload) unless json_payload.is_a?(::Hash) raise Error::SerializationError, "#{name} expected an object on the wire, got #{json_payload.inspect}" end attributes = fields.to_h do |f| [f.name, wire_value(f, json_payload)] end undeclared = extra(json_payload) if extensible? attributes[:extensions] = undeclared # the spec sanctions these extras; preserve them silently else warn_undeclared(undeclared) unless undeclared.empty? end construct(**attributes) end
#missing_required(field) (private)
A required field absent from the response is tolerated as omitted (UNSET) and warned, so a schema ahead of the browser does not block the caller; strict mode (SE_BIDI_STRICT) escalates to an error for callers who want it. Omitted (UNSET) stays distinct from an explicit null (nil), which matters for the required-and-nullable fields the schema flags.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 229
def missing_required(field) = "#{name}##{field.name} is required but was missing from the response" raise Error::SerializationError, if Serialization.strict? WebDriver.logger.warn(, id: :bidi_missing_required) UNSET end
#new(**kwargs)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 72
def new(**kwargs) # Start from what was passed so ::Data's constructor rejects an unknown key, then fill # each field with its value or UNSET (omitted), forcing fixed discriminators. attributes = kwargs.dup fields.each { |f| attributes[f.name] = fixed?(f) ? f.fixed : attributes.fetch(f.name, UNSET) } attributes[:extensions] = kwargs.fetch(:extensions, {}) if extensible? validate_values(attributes) construct(**attributes) end
#read(field, raw) (private)
[ GitHub ]# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 237
def read(field, raw) if raw.nil? return raw if field.nullable raise Error::SerializationError, "#{name}##{field.name} received null but is not nullable" end check_shape(field, raw) return Serialization.to_symbol("#{name}##{field.name}", raw, enum_hash(field)) if field.enum if field.ref.nil? check_primitive(field, raw) unless field.list return raw end read_ref(field, raw) end
#read_list(field, raw, klass) (private)
Parses each element. A scalar field is a map encoded as [key, value] pairs, so
every element must be a 2-item pair — each is read as one, and a malformed entry is
rejected. Non-scalar lists recurse into nested lists; other elements deserialize.
#read_map_entry(field, element, klass) (private)
A map entry is a [key, value] pair. The key is Ref / text — an object key
deserializes, a bare-string key passes through once validated against the arm's
primitive. The value is the object-only Ref and always deserializes, so a bare scalar
there is rejected (object_only holds at the value position). A non-pair element is a
malformed entry and is rejected outright.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 315
def read_map_entry(field, element, klass) unless element.is_a?(::Array) && element.size == 2 raise Error::SerializationError, "#{name}##{field.name} expected a [key, value] pair, got #{element.inspect}" end key, value = element key = key.is_a?(::Hash) ? klass.from_json(key) : scalar_value(field, key) [key, klass.from_json(value)] end
#read_ref(field, raw) (private)
Reads a ref-typed value into its class. A scalar position is an inline union with
a scalar arm collapsed onto its union ref (a map's string keys): a non-object leaf
passes through instead of being handed to the object_only union, but only when it
matches the arm's primitive (scalar carries it). A list recurses per element.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 258
def read_ref(field, raw) klass = (@refs ||= {})[field.name] ||= Protocol.const_get(field.ref) return read_list(field, raw, klass) if field.list field.scalar && !raw.is_a?(::Hash) ? scalar_value(field, raw) : klass.from_json(raw) end
#scalar_value(field, value) (private)
A bare scalar at a scalar-tolerant union position must match one of the union's
scalar-arm primitives (scalar is a primitive name or an array of them); a
wrong-typed scalar (a number where a string is expected) is a wire error, not
something to pass through. An unrecognized primitive (none in PRIMITIVE_TYPES) is
left unchecked, matching the lenient default elsewhere.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 331
def scalar_value(field, value) expected = Array(field.scalar).flat_map { |primitive| PRIMITIVE_TYPES[primitive] || [] } return value if expected.empty? || expected.any? { |type| value.is_a?(type) } raise Error::SerializationError, "#{name}##{field.name} expected #{Array(field.scalar).join(' or ')}, got #{value.inspect}" end
#validate_const(field, value) (private)
A nullable constant (literal / null) is caller-settable but its only non-null value is
the literal, so a value that is neither the literal nor nil (nil is handled above) is a
local error rather than a wire round-trip. A non-const field carries UNSET here and passes.
#validate_present(field, value) (private)
Checks a field that carries an actual value (neither omitted nor nil): a nullable-const field against its literal, list/scalar shape, primitive type (lists excepted, as inbound does), ref type, and enum membership (resolved lazily so a cross-domain enum need not load first).
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 126
def validate_present(field, value) validate_const(field, value) check_outbound_shape(field, value) check_outbound_primitive(field, value) unless field.list validate_ref(field, value) if field.ref Serialization.validate!("#{name}##{field.name}", value, Protocol.const_get(field.enum)) if field.enum end
#validate_ref(field, value) (private)
Outbound mirror of read_ref: a ref-typed value must be the type it declares, so a wrong record or a value no union variant accepts is a caller error caught here, not a browser round-trip. Shape is already checked, so a list is an Array.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 137
def validate_ref(field, value) klass = (@refs ||= {})[field.name] ||= Protocol.const_get(field.ref) field.list ? validate_ref_list(field, klass, value) : validate_ref_value(field, klass, value) end
#validate_ref_entry(field, klass, element) (private)
A [key, value] map entry: the key may be a variant or a bare scalar, the value is a variant.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 157
def validate_ref_entry(field, klass, element) unless element.is_a?(::Array) && element.size == 2 raise ::ArgumentError, "#{name}##{field.name} expected a [key, value] pair, got #{element.inspect}" end key, value = element key.is_a?(Serializable) ? validate_ref_value(field, klass, key) : check_outbound_scalar(field, key) validate_ref_value(field, klass, value) end
#validate_ref_list(field, klass, list) (private)
Mirrors read_list: a scalar field is a [key, value] map, a nested list recurses, otherwise each element is checked against the ref.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 144
def validate_ref_list(field, klass, list) list.each do |element| if field.scalar validate_ref_entry(field, klass, element) elsif element.is_a?(::Array) validate_ref_list(field, klass, element) else validate_ref_value(field, klass, element) end end end
#validate_ref_value(field, klass, value) (private)
A record ref must be an instance of that record; a union ref must be one the union accepts.
#validate_values(attributes) (private)
Checks each field's value: a required field cannot be omitted (UNSET), a non-nullable
field cannot be nil (nil is neither a value nor the UNSET omit-sentinel, so it would be
silently dropped on the wire), a nullable-const field must carry its literal (not some
other value), a primitive field must be the matching Ruby type, and an enum field must be
in its allowed set. The enum constant is resolved lazily so a cross-domain enum need not be
loaded first. Outbound only (from #new); inbound presence/primitive/enum are checked
separately in wire_value+/+read.
# File 'rb/lib/selenium/webdriver/bidi/serialization/record.rb', line 112
def validate_values(attributes) fields.each do |f| value = attributes[f.name] raise ::ArgumentError, "#{name}##{f.name} is required" if UNSET.equal?(value) && f.required raise ::ArgumentError, "#{name}##{f.name} cannot be nil" if value.nil? && !f.nullable next if value.nil? || UNSET.equal?(value) validate_present(f, value) end end
#warn_undeclared(undeclared) (private)
Forward-compat signal: a property a closed type does not model is dropped and warned so
schema drift is visible (an extensible type keeps its extras silently — the spec sanctions
them). Tagged :bidi_undeclared_property so a caller can silence it via logger.ignore.