lib/bindata/base.rb in bindata-2.2.0 vs lib/bindata/base.rb in bindata-2.3.0

- old
+ new

@@ -1,33 +1,33 @@ require 'bindata/framework' require 'bindata/io' require 'bindata/lazy' require 'bindata/name' -require 'bindata/offset' require 'bindata/params' require 'bindata/registry' require 'bindata/sanitize' module BinData # This is the abstract base class for all data objects. class Base extend AcceptedParametersPlugin include Framework - include CheckOrAdjustOffsetPlugin include RegisterNamePlugin class << self # Instantiates this class and reads from +io+, returning the newly # created data object. +args+ will be used when instantiating. - def read(io, *args) + def read(io, *args, &block) obj = self.new(*args) - obj.read(io) + obj.read(io, &block) obj end # The arg processor for this class. def arg_processor(name = nil) + @arg_processor ||= nil + if name @arg_processor = "#{name}_arg_processor".gsub(/(?:^|_)(.)/) { $1.upcase }.to_sym elsif @arg_processor.is_a? Symbol @arg_processor = BinData::const_get(@arg_processor).new elsif @arg_processor.nil? @@ -47,10 +47,11 @@ RegisteredClasses.unregister(name) end # Registers all subclasses of this class for use def register_subclasses #:nodoc: + singleton_class.send(:undef_method, :inherited) define_singleton_method(:inherited) do |subclass| RegisteredClasses.register(subclass.name, subclass) register_subclasses end end @@ -136,57 +137,50 @@ def clear initialize_instance end # Reads data into this data object. - def read(io) + def read(io, &block) io = BinData::IO::Read.new(io) unless BinData::IO::Read === io - @in_read = true - clear - do_read(io) - @in_read = false + start_read do + clear + do_read(io) + end + block.call(self) if block_given? self end - #:nodoc: - attr_reader :in_read - protected :in_read - - # Returns if this object is currently being read. This is used - # internally by BasePrimitive. - def reading? #:nodoc: - furthest_ancestor.in_read - end - protected :reading? - # Writes the value for this data object to +io+. - def write(io) + def write(io, &block) io = BinData::IO::Write.new(io) unless BinData::IO::Write === io do_write(io) io.flush + + block.call(self) if block_given? + self end # Returns the number of bytes it will take to write this data object. def num_bytes do_num_bytes.ceil end # Returns the string representation of this data object. - def to_binary_s + def to_binary_s(&block) io = BinData::IO.create_string_io - write(io) + write(io, &block) io.rewind io.read end # Returns the hexadecimal string representation of this data object. - def to_hex - to_binary_s.unpack('H*')[0] + def to_hex(&block) + to_binary_s(&block).unpack('H*')[0] end # Return a human readable representation of this data object. def inspect snapshot.inspect @@ -241,28 +235,50 @@ end # A version of +respond_to?+ used by the lazy evaluator. It doesn't # reinvoke the evaluator so as to avoid infinite evaluation loops. def safe_respond_to?(symbol, include_private = false) #:nodoc: - respond_to?(symbol, include_private) + base_respond_to?(symbol, include_private) end alias_method :base_respond_to?, :respond_to? #:nodoc: #--------------- private def extract_args(args) self.class.arg_processor.extract_args(self.class, args) end - def furthest_ancestor + def start_read(&block) + top_level_set(:in_read, true) + block.call + ensure + top_level_set(:in_read, false) + end + + # Is this object tree currently being read? Used by BasePrimitive. + def reading? + top_level_get(:in_read) + end + + def top_level_set(sym, value) + top_level.instance_variable_set("@tl_#{sym}", value) + end + + def top_level_get(sym) + top_level.instance_variable_defined?("@tl_#{sym}") and + top_level.instance_variable_get("@tl_#{sym}") + end + + def top_level if parent.nil? - self + tl = self else - an = parent - an = an.parent while an.parent - an + tl = parent + tl = tl.parent while tl.parent end + + tl end def binary_string(str) str.to_s.dup.force_encoding(Encoding::BINARY) end