lib/bindata/base.rb in bindata-0.9.2 vs lib/bindata/base.rb in bindata-0.9.3
- old
+ new
@@ -1,7 +1,8 @@
require 'bindata/io'
require 'bindata/lazy'
+require 'bindata/params'
require 'bindata/registry'
require 'bindata/sanitize'
require 'stringio'
module BinData
@@ -30,130 +31,78 @@
# [<tt>:adjust_offset</tt>] Ensures that the current IO offset is at this
# position before reading. This is like
# <tt>:check_offset</tt>, except that it will
# adjust the IO offset instead of raising an error.
class Base
+
class << self
- # Returns the mandatory parameters used by this class. Any given args
- # are appended to the parameters list. The parameters for a class will
- # include the parameters of its ancestors.
- def mandatory_parameters(*args)
- unless defined? @mandatory_parameters
- @mandatory_parameters = []
- ancestors[1..-1].each do |parent|
- if parent.respond_to?(:mandatory_parameters)
- pmp = parent.mandatory_parameters
- @mandatory_parameters.concat(pmp)
- end
- end
- end
- if not args.empty?
- args.each { |arg| @mandatory_parameters << arg.to_sym }
- @mandatory_parameters.uniq!
- end
- @mandatory_parameters
+ extend Parameters
+
+ # Define methods for:
+ # bindata_mandatory_parameters
+ # bindata_optional_parameters
+ # bindata_default_parameters
+ # bindata_mutually_exclusive_parameters
+
+ define_x_parameters(:bindata_mandatory, []) do |array, args|
+ args.each { |arg| array << arg.to_sym }
+ array.uniq!
end
- alias_method :mandatory_parameter, :mandatory_parameters
- # Returns the optional parameters used by this class. Any given args
- # are appended to the parameters list. The parameters for a class will
- # include the parameters of its ancestors.
- def optional_parameters(*args)
- unless defined? @optional_parameters
- @optional_parameters = []
- ancestors[1..-1].each do |parent|
- if parent.respond_to?(:optional_parameters)
- pop = parent.optional_parameters
- @optional_parameters.concat(pop)
- end
- end
- end
- if not args.empty?
- args.each { |arg| @optional_parameters << arg.to_sym }
- @optional_parameters.uniq!
- end
- @optional_parameters
+ define_x_parameters(:bindata_optional, []) do |array, args|
+ args.each { |arg| array << arg.to_sym }
+ array.uniq!
end
- alias_method :optional_parameter, :optional_parameters
- # Returns the default parameters used by this class. Any given args
- # are appended to the parameters list. The parameters for a class will
- # include the parameters of its ancestors.
- def default_parameters(params = {})
- unless defined? @default_parameters
- @default_parameters = {}
- ancestors[1..-1].each do |parent|
- if parent.respond_to?(:default_parameters)
- pdp = parent.default_parameters
- @default_parameters = @default_parameters.merge(pdp)
- end
- end
- end
- if not params.empty?
- @default_parameters = @default_parameters.merge(params)
- end
- @default_parameters
+ define_x_parameters(:bindata_default, {}) do |hash, args|
+ params = args.length > 0 ? args[0] : {}
+ hash.merge!(params)
end
- alias_method :default_parameter, :default_parameters
- # Returns the pairs of mutually exclusive parameters used by this class.
- # Any given args are appended to the parameters list. The parameters for
- # a class will include the parameters of its ancestors.
- def mutually_exclusive_parameters(*args)
- unless defined? @mutually_exclusive_parameters
- @mutually_exclusive_parameters = []
- ancestors[1..-1].each do |parent|
- if parent.respond_to?(:mutually_exclusive_parameters)
- pmep = parent.mutually_exclusive_parameters
- @mutually_exclusive_parameters.concat(pmep)
- end
- end
- end
- if not args.empty?
- @mutually_exclusive_parameters << [args[0].to_sym, args[1].to_sym]
- end
- @mutually_exclusive_parameters
+ define_x_parameters(:bindata_mutually_exclusive, []) do |array, args|
+ array << [args[0].to_sym, args[1].to_sym]
end
- # Returns a list of parameters that are accepted by this object
- def accepted_parameters
- (mandatory_parameters + optional_parameters + default_parameters.keys).uniq
+ # Returns a list of internal parameters that are accepted by this object
+ def internal_parameters
+ (bindata_mandatory_parameters + bindata_optional_parameters +
+ bindata_default_parameters.keys).uniq
end
- # Returns a sanitized +params+ that is of the form expected
- # by #initialize.
- def sanitize_parameters(sanitizer, params, *args)
- params = params.dup
-
+ # Ensures that +params+ is of the form expected by #initialize.
+ def sanitize_parameters!(sanitizer, params)
# replace :readwrite with :onlyif
if params.has_key?(:readwrite)
warn ":readwrite is deprecated. Replacing with :onlyif"
params[:onlyif] = params.delete(:readwrite)
end
# add default parameters
- default_parameters.each do |k,v|
+ bindata_default_parameters.each do |k,v|
params[k] = v unless params.has_key?(k)
end
# ensure mandatory parameters exist
- mandatory_parameters.each do |prm|
+ bindata_mandatory_parameters.each do |prm|
if not params.has_key?(prm)
raise ArgumentError, "parameter ':#{prm}' must be specified " +
"in #{self}"
end
end
# ensure mutual exclusion
- mutually_exclusive_parameters.each do |param1, param2|
+ bindata_mutually_exclusive_parameters.each do |param1, param2|
if params.has_key?(param1) and params.has_key?(param2)
raise ArgumentError, "params #{param1} and #{param2} " +
"are mutually exclusive"
end
end
+ end
- params
+ # Can this data object self reference itself?
+ def recursive?
+ false
end
# Instantiates this class and reads from +io+. For single value objects
# just the value is returned, otherwise the newly created data object is
# returned.
@@ -169,30 +118,31 @@
end
private :register
end
# Define the parameters we use in this class.
- optional_parameters :check_offset, :adjust_offset
- default_parameters :onlyif => true
- mutually_exclusive_parameters :check_offset, :adjust_offset
+ bindata_optional_parameters :check_offset, :adjust_offset
+ bindata_default_parameters :onlyif => true
+ bindata_mutually_exclusive_parameters :check_offset, :adjust_offset
# Creates a new data object.
#
# +params+ is a hash containing symbol keys. Some params may
- # reference callable objects (methods or procs). +env+ is the
- # environment that these callable objects are evaluated in.
- def initialize(params = {}, env = nil)
- unless SanitizedParameters === params
- params = Sanitizer.sanitize(self, params)
- end
+ # reference callable objects (methods or procs). +parent+ is the
+ # parent data object (e.g. struct, array, choice) this object resides
+ # under.
+ def initialize(params = {}, parent = nil)
+ @params = Sanitizer.sanitize(self.class, params)
+ @parent = parent
+ end
- @params = params.accepted_parameters
+ # The parent data object.
+ attr_accessor :parent
- # set up the environment
- @env = env || LazyEvalEnv.new
- @env.params = params.extra_parameters
- @env.data_object = self
+ # Returns all the custom parameters supplied to this data object.
+ def parameters
+ @params.extra_parameters
end
# Reads data into this data object by calling #do_read then #done_read.
def read(io)
io = BinData::IO.new(io) unless BinData::IO === io
@@ -270,36 +220,36 @@
# Return a human readable representation of this object.
def inspect
snapshot.inspect
end
+ # Returns the object this object represents.
+ def obj
+ self
+ end
+
#---------------
private
- # Creates a new LazyEvalEnv for use by a child data object.
- def create_env
- LazyEvalEnv.new(@env)
- end
-
# Returns the value of the evaluated parameter. +key+ references a
# parameter from the +params+ hash used when creating the data object.
# +values+ contains data that may be accessed when evaluating +key+.
# Returns nil if +key+ does not refer to any parameter.
def eval_param(key, values = nil)
- @env.lazy_eval(@params[key], values)
+ LazyEvaluator.eval(no_eval_param(key), self, values)
end
# Returns the parameter from the +params+ hash referenced by +key+.
# Use this method if you are sure the parameter is not to be evaluated.
# You most likely want #eval_param.
- def param(key)
- @params[key]
+ def no_eval_param(key)
+ @params.internal_parameters[key]
end
# Returns whether +key+ exists in the +params+ hash used when creating
# this data object.
def has_param?(key)
- @params.has_key?(key.to_sym)
+ @params.internal_parameters.has_key?(key)
end
# Checks that the current offset of +io+ is as expected. This should
# be called from #do_read before performing the reading.
def check_offset(io)