lib/bindata/base.rb in bindata-2.0.0 vs lib/bindata/base.rb in bindata-2.1.0
- old
+ new
@@ -6,57 +6,37 @@
require 'bindata/params'
require 'bindata/registry'
require 'bindata/sanitize'
module BinData
- # ArgExtractors take the arguments passed to BinData::Base.new and
- # separate them into [value, parameters, parent].
- class BaseArgExtractor
- @@empty_hash = Hash.new.freeze
-
- def self.extract(the_class, the_args)
- args = the_args.dup
- value = parameters = parent = nil
-
- if args.length > 1 and args.last.is_a? BinData::Base
- parent = args.pop
- end
-
- if args.length > 0 and args.last.is_a? Hash
- parameters = args.pop
- end
-
- if args.length > 0
- value = args.pop
- end
-
- parameters ||= @@empty_hash
-
- return [value, parameters, parent]
- end
- end
-
# 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.
- def read(io)
- obj = self.new
+ # created data object. +args+ will be used when instantiating.
+ def read(io, *args)
+ obj = self.new(*args)
obj.read(io)
obj
end
- # The arg extractor for this class.
- def arg_extractor
- BaseArgExtractor
+ # The arg processor for this class.
+ def arg_processor(name = 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?
+ @arg_processor = superclass.arg_processor
+ else
+ @arg_processor
+ end
end
# The name of this class as used by Records, Arrays etc.
def bindata_name
RegisteredClasses.underscore_name(self.name)
@@ -67,24 +47,25 @@
RegisteredClasses.unregister(name)
end
# Registers all subclasses of this class for use
def register_subclasses #:nodoc:
- class << self
- define_method(:inherited) do |subclass|
- RegisteredClasses.register(subclass.name, subclass)
- register_subclasses
- end
+ define_singleton_method(:inherited) do |subclass|
+ RegisteredClasses.register(subclass.name, subclass)
+ register_subclasses
end
end
private :unregister_self, :register_subclasses
end
# Register all subclasses of this class.
register_subclasses
+ # Set the initial arg processor.
+ arg_processor :base
+
# Creates a new data object.
#
# Args are optional, but if present, must be in the following order.
#
# +value+ is a value that is +assign+ed immediately after initialization.
@@ -94,15 +75,12 @@
#
# +parent+ is the parent data object (e.g. struct, array, choice) this
# object resides under.
#
def initialize(*args)
- value, parameters, parent = extract_args(args)
+ value, @params, @parent = extract_args(args)
- @params = SanitizedParameters.sanitize(parameters, self.class)
- @parent = parent
-
initialize_shared_instance
initialize_instance
assign(value) if value
end
@@ -231,20 +209,21 @@
else
"obj"
end
end
- # Returns the offset of this object wrt to its most distant ancestor.
- def offset
+ # Returns the offset (in bytes) of this object with respect to its most
+ # distant ancestor.
+ def abs_offset
if @parent
- @parent.offset + @parent.offset_of(self)
+ @parent.abs_offset + @parent.offset_of(self)
else
0
end
end
- # Returns the offset of this object wrt to its parent.
+ # Returns the offset (in bytes) of this object with respect to its parent.
def rel_offset
if @parent
@parent.offset_of(self)
else
0
@@ -264,12 +243,12 @@
alias_method :base_respond_to?, :respond_to? #:nodoc:
#---------------
private
- def extract_args(the_args)
- self.class.arg_extractor.extract(self.class, the_args)
+ def extract_args(args)
+ self.class.arg_processor.extract_args(self.class, args)
end
def furthest_ancestor
if parent.nil?
self
@@ -280,8 +259,55 @@
end
end
def binary_string(str)
str.to_s.dup.force_encoding(Encoding::BINARY)
+ end
+ end
+
+ # ArgProcessors process the arguments passed to BinData::Base.new into
+ # the form required to initialise the BinData object.
+ #
+ # Any passed parameters are sanitized so the BinData object doesn't
+ # need to perform error checking on the parameters.
+ class BaseArgProcessor
+ @@empty_hash = Hash.new.freeze
+
+ # Takes the arguments passed to BinData::Base.new and
+ # extracts [value, sanitized_parameters, parent].
+ def extract_args(obj_class, obj_args)
+ value, params, parent = separate_args(obj_class, obj_args)
+ sanitized_params = SanitizedParameters.sanitize(params, obj_class)
+
+ [value, sanitized_params, parent]
+ end
+
+ # Separates the arguments passed to BinData::Base.new into
+ # [value, parameters, parent]. Called by #extract_args.
+ def separate_args(obj_class, obj_args)
+ args = obj_args.dup
+ value = parameters = parent = nil
+
+ if args.length > 1 and args.last.is_a? BinData::Base
+ parent = args.pop
+ end
+
+ if args.length > 0 and args.last.is_a? Hash
+ parameters = args.pop
+ end
+
+ if args.length > 0
+ value = args.pop
+ end
+
+ parameters ||= @@empty_hash
+
+ return [value, parameters, parent]
+ end
+
+ # Performs sanity checks on the given parameters.
+ # This method converts the parameters to the form expected
+ # by the data object.
+ def sanitize_parameters!(obj_class, obj_params)
end
end
end