lib/bindata/sanitize.rb in bindata-0.9.2 vs lib/bindata/sanitize.rb in bindata-0.9.3
- old
+ new
@@ -1,16 +1,58 @@
require 'forwardable'
module BinData
+
+ # A BinData object accepts arbitrary parameters. This class only contains
+ # parameters that have been sanitized, and categorizes them according to
+ # whether they are BinData::Base.internal_parameters or are extra.
+ class SanitizedParameters
+ extend Forwardable
+
+ # Sanitize the given parameters.
+ def initialize(klass, params)
+ @hash = params
+ @internal_parameters = {}
+ @extra_parameters = {}
+
+ # partition parameters into known and extra parameters
+ @hash.each do |k,v|
+ k = k.to_sym
+ if v.nil?
+ raise ArgumentError, "parameter :#{k} has nil value in #{klass}"
+ end
+
+ if klass.internal_parameters.include?(k)
+ @internal_parameters[k] = v
+ else
+ @extra_parameters[k] = v
+ end
+ end
+ end
+
+ attr_reader :internal_parameters, :extra_parameters
+
+ def_delegators :@hash, :[], :has_key?, :include?, :keys
+ end
+
+ # The Sanitizer sanitizes the parameters that are passed when creating a
+ # BinData object. Sanitizing consists of checking for mandatory, optional
+ # and default parameters and ensuring the values of known parameters are
+ # valid.
class Sanitizer
+
class << self
+
# Sanitize +params+ for +obj+.
# Returns sanitized parameters.
- def sanitize(obj, params)
- sanitizer = self.new
- klass, new_params = sanitizer.sanitize(obj.class, params)
- new_params
+ def sanitize(klass, params)
+ if SanitizedParameters === params
+ params
+ else
+ sanitizer = self.new
+ sanitizer.sanitize_params(klass, params)
+ end
end
# Returns true if +type+ is registered.
def type_exists?(type, endian = nil)
lookup(type, endian) != nil
@@ -50,72 +92,46 @@
else
yield
end
end
- # Sanitizes +params+ for +type+.
- # Returns [klass, sanitized_params]
- def sanitize(type, params)
- if Class === type
- klass = type
- else
- klass = self.class.lookup(type, @endian)
- raise TypeError, "unknown type '#{type}'" if klass.nil?
- end
+ # Converts +type+ into the appropriate class.
+ def lookup_klass(type)
+ klass = self.class.lookup(type, @endian)
+ raise TypeError, "unknown type '#{type}'" if klass.nil?
+ klass
+ end
- params ||= {}
- if @seen.include?(klass)
+ # Sanitizes +params+ for +klass+.
+ # Returns +sanitized_params+.
+ def sanitize_params(klass, params)
+ new_params = params.nil? ? {} : params.dup
+
+ if klass.recursive? and @seen.include?(klass)
# This klass is defined recursively. Remember the current endian
# and delay sanitizing the parameters until later.
- if @endian != nil and klass.accepted_parameters.include?(:endian) and
- not params.has_key?(:endian)
- params = params.dup
- params[:endian] = @endian
- end
+ new_params[:endian] = @endian if can_store_endian?(klass, new_params)
+ ret_val = new_params
else
- # subclasses of MultiValue may be defined recursively
- # TODO: define a class field instead
- possibly_recursive = (BinData.const_defined?(:MultiValue) and
- klass.ancestors.include?(BinData.const_get(:MultiValue)))
- @seen.push klass if possibly_recursive
+ @seen.push(klass)
- new_params = klass.sanitize_parameters(self, params)
- params = SanitizedParameters.new(klass, new_params)
+ # Sanitize new_params. This may recursively call this method again.
+ klass.sanitize_parameters!(self, new_params)
+ ret_val = SanitizedParameters.new(klass, new_params)
+
+ @seen.pop
end
- [klass, params]
+ ret_val
end
- end
- # A BinData object accepts arbitrary parameters. This class ensures that
- # the parameters have been sanitized, and categorizes them according to
- # whether they are BinData::Base.accepted_parameters or are extra.
- class SanitizedParameters
- extend Forwardable
+ #---------------
+ private
- # Sanitize the given parameters.
- def initialize(klass, params)
- @hash = params
- @accepted_parameters = {}
- @extra_parameters = {}
-
- # partition parameters into known and extra parameters
- @hash.each do |k,v|
- k = k.to_sym
- if v.nil?
- raise ArgumentError, "parameter :#{k} has nil value in #{klass}"
- end
-
- if klass.accepted_parameters.include?(k)
- @accepted_parameters[k] = v
- else
- @extra_parameters[k] = v
- end
- end
+ # Can we store the current endian for later?
+ def can_store_endian?(klass, params)
+ (@endian != nil and klass.internal_parameters.include?(:endian) and
+ not params.has_key?(:endian))
end
-
- attr_reader :accepted_parameters, :extra_parameters
-
- def_delegators :@hash, :[], :has_key?, :include?, :keys
end
end