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