lib/bindata/sanitize.rb in bindata-0.9.1 vs lib/bindata/sanitize.rb in bindata-0.9.2

- old
+ new

@@ -1,18 +1,102 @@ require 'forwardable' module BinData + 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 + end + + # Returns true if +type+ is registered. + def type_exists?(type, endian = nil) + lookup(type, endian) != nil + end + + # Returns the class matching a previously registered +name+. + def lookup(name, endian) + name = name.to_s + klass = Registry.instance.lookup(name) + if klass.nil? and endian != nil + # lookup failed so attempt endian lookup + if /^u?int\d{1,3}$/ =~ name + new_name = name + ((endian == :little) ? "le" : "be") + klass = Registry.instance.lookup(new_name) + elsif ["float", "double"].include?(name) + new_name = name + ((endian == :little) ? "_le" : "_be") + klass = Registry.instance.lookup(new_name) + end + end + klass + end + end + + # Create a new Sanitizer. + def initialize + @seen = [] + @endian = nil + end + + # Executes the given block with +endian+ set as the current endian. + def with_endian(endian, &block) + if endian != nil + saved_endian = @endian + @endian = endian + yield + @endian = saved_endian + 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 + + params ||= {} + if @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 + 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 + + new_params = klass.sanitize_parameters(self, params) + params = SanitizedParameters.new(klass, new_params) + end + + [klass, params] + 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 # Sanitize the given parameters. - def initialize(klass, params, *args) - params ||= {} - @hash = klass.sanitize_parameters(params, *args) + def initialize(klass, params) + @hash = params @accepted_parameters = {} @extra_parameters = {} # partition parameters into known and extra parameters @hash.each do |k,v| @@ -32,5 +116,6 @@ attr_reader :accepted_parameters, :extra_parameters def_delegators :@hash, :[], :has_key?, :include?, :keys end end +