class BinData::SanitizedParameters

at a single time.
is to recursively sanitize the parameters of an entire BinData object chain
SanitizedParameters is a hash-like collection of parameters. Its purpose
validation.
The purpose of the sanitizing code is to eliminate the duplicated
such as an array of records, there is much duplicated sanitizing.
are valid. When instantiating many objects with identical parameters,
behaviour. These parameters must be sanitized to ensure their values
BinData objects are instantiated with parameters to determine their

def create_sanitized_choices(choices)

def create_sanitized_choices(choices)
  SanitizedChoices.new(choices, hints)
end

def create_sanitized_endian(endian)

def create_sanitized_endian(endian)
  if endian == :big
    BIG_ENDIAN
  elsif endian == :little
    LITTLE_ENDIAN
  elsif endian == :big_and_little
    raise ArgumentError, "endian: :big or endian: :little is required"
  else
    raise ArgumentError, "unknown value for endian '#{endian}'"
  end
end

def create_sanitized_fields

def create_sanitized_fields
  SanitizedFields.new(hints)
end

def create_sanitized_object_prototype(obj_type, obj_params)

def create_sanitized_object_prototype(obj_type, obj_params)
  SanitizedPrototype.new(obj_type, obj_params, hints)
end

def create_sanitized_params(params, the_class)

def create_sanitized_params(params, the_class)
  SanitizedParameters.new(params, the_class, hints)
end

def ensure_mandatory_parameters_exist

def ensure_mandatory_parameters_exist
  @the_class.mandatory_parameters.each do |key|
    unless has_parameter?(key)
      raise ArgumentError,
              "parameter '#{key}' must be specified in #{@the_class}"
    end
  end
end

def ensure_mutual_exclusion_of_parameters

def ensure_mutual_exclusion_of_parameters
  return if length < 2
  @the_class.mutually_exclusive_parameters.each do |key1, key2|
    if has_parameter?(key1) && has_parameter?(key2)
      raise ArgumentError, "params '#{key1}' and '#{key2}' " \
                           "are mutually exclusive in #{@the_class}"
    end
  end
end

def ensure_no_nil_values

def ensure_no_nil_values
  each do |key, value|
    if value.nil?
      raise ArgumentError,
            "parameter '#{key}' has nil value in #{@the_class}"
    end
  end
end

def has_at_least_one_of?(*keys)

def has_at_least_one_of?(*keys)
  keys.each do |key|
    return true if has_parameter?(key)
  end
  false
end

def hints

def hints
  { endian: self[:endian], search_prefix: self[:search_prefix] }
end

def initialize(parameters, the_class, hints)

def initialize(parameters, the_class, hints)
  parameters.each_pair { |key, value| self[key.to_sym] = value }
  @the_class = the_class
  if hints[:endian]
    self[:endian] ||= hints[:endian]
  end
  if hints[:search_prefix] && !hints[:search_prefix].empty?
    self[:search_prefix] = Array(self[:search_prefix]).concat(Array(hints[:search_prefix]))
  end
  sanitize!
end

def merge_default_parameters!

def merge_default_parameters!
  @the_class.default_parameters.each do |key, value|
    self[key] = value unless has_parameter?(key)
  end
end

def must_be_integer(*keys)

def must_be_integer(*keys)
  keys.each do |key|
    if has_parameter?(key)
      parameter = self[key]
      unless Symbol === parameter ||
             parameter.respond_to?(:arity) ||
             parameter.respond_to?(:to_int)
        raise ArgumentError, "parameter '#{key}' in #{@the_class} must " \
                             "evaluate to an integer, got #{parameter.class}"
      end
    end
  end
end

def needs_sanitizing?(key)

def needs_sanitizing?(key)
  has_parameter?(key) && !self[key].is_a?(SanitizedParameter)
end

def rename_parameter(old_key, new_key)

def rename_parameter(old_key, new_key)
  if has_parameter?(old_key)
    self[new_key] = delete(old_key)
  end
end

def sanitize(parameters, the_class)

def sanitize(parameters, the_class)
  if SanitizedParameters === parameters
    parameters
  else
    SanitizedParameters.new(parameters, the_class, {})
  end
end

def sanitize(key, &block)

def sanitize(key, &block)
  if needs_sanitizing?(key)
    self[key] = yield(self[key])
  end
end

def sanitize!

def sanitize!
  ensure_no_nil_values
  merge_default_parameters!
  @the_class.arg_processor.sanitize_parameters!(@the_class, self)
  ensure_mandatory_parameters_exist
  ensure_mutual_exclusion_of_parameters
end

def sanitize_choices(key, &block)

def sanitize_choices(key, &block)
  sanitize(key) do |obj|
    create_sanitized_choices(yield(obj))
  end
end

def sanitize_endian(key)

def sanitize_endian(key)
  sanitize(key) { |endian| create_sanitized_endian(endian) }
end

def sanitize_fields(key, &block)

def sanitize_fields(key, &block)
  sanitize(key) do |fields|
    sanitized_fields = create_sanitized_fields
    yield(fields, sanitized_fields)
    sanitized_fields
  end
end

def sanitize_object_prototype(key)

def sanitize_object_prototype(key)
  sanitize(key) do |obj_type, obj_params|
    create_sanitized_object_prototype(obj_type, obj_params)
  end
end

def warn_replacement_parameter(bad_key, suggested_key)

def warn_replacement_parameter(bad_key, suggested_key)
  if has_parameter?(bad_key)
    Kernel.warn ":#{bad_key} is not used with #{@the_class}.  " \
                "You probably want to change this to :#{suggested_key}"
  end
end