class BinData::Single

the value just read in.
or failure. Any other return is compared to
parameter. A boolean return indicates success
available to any lambda assigned to this
this criteria. The variable value is made
[:check_value] Raise an error unless the value read in meets
IO, not the result of the :value param.
will return the value of the data read from the
calls to #do_read and #done_read, #value
using this param. In the interval between
Explicitly calling #value= is prohibited when
[:value] The object will always have this value.
either #read or explicitly set with #value=.
[:initial_value] This is the initial value to use before one is
an object. These params include those for BinData::Base as well as:
Parameters may be provided at initialisation to control the behaviour of
== Parameters
obj.read(“007”) #=> BinData::ValidityError: value not as expected
obj = BinData::Uint8.new(:check_value => lambda { value < 5 })
obj.read(“005”) #=> BinData::ValidityError: value is ‘5’ but expected ‘3’
obj = BinData::Uint8.new(:check_value => 3)
obj.value #=> 42
obj.value = 5
obj.value #=> 42
obj = BinData::Uint8.new(:value => 42)
obj.value #=> 42
obj.clear
obj.value #=> 5
obj.value = 5
obj.value #=> 42
obj = BinData::Uint8.new(:initial_value => 42)
require ‘bindata’
object. This value can be read from or written to an IO stream.
as integer, float or string. Only one value can be contained by this
binary representation. A value corresponds to a primitive type such as
A BinData::Single object is a container for a value that has a particular

def _do_num_bytes(ignored)

Returns the number of bytes it will take to write this data.
def _do_num_bytes(ignored)
  val_to_str(_value).length
end

def _do_read(io)

Reads the value for this data from +io+.
def _do_read(io)
  @in_read = true
  @value   = read_val(io)
  # does the value meet expectations?
  if has_param?(:check_value)
    current_value = self.value
    expected = eval_param(:check_value, :value => current_value)
    if not expected
      raise ValidityError, "value '#{current_value}' not as expected"
    elsif current_value != expected and expected != true
      raise ValidityError, "value is '#{current_value}' but " +
                           "expected '#{expected}'"
    end
  end
end

def _do_write(io)

Writes the value for this data to +io+.
def _do_write(io)
  raise "can't write whilst reading" if @in_read
  io.writebytes(val_to_str(_value))
end

def _snapshot

Returns a snapshot of this data object.
def _snapshot
  value
end

def _value

modify the value.
method. This is so that #value can be overridden in subclasses to
The unmodified value of this data object. Note that #value calls this
def _value
  # Table of possible preconditions and expected outcome
  #   1. :value and !in_read          ->   :value
  #   2. :value and in_read           ->   @value
  #   3. :initial_value and clear?    ->   :initial_value
  #   4. :initial_value and !clear?   ->   @value
  #   5. clear?                       ->   sensible_default
  #   6. !clear?                      ->   @value
  if not @in_read and (evaluated_value = eval_param(:value))
    # rule 1 above
    evaluated_value
  else
    # combining all other rules gives this simplified expression
    @value || eval_param(:value) ||
      eval_param(:initial_value) || sensible_default()
  end
end

def clear

Resets the internal state to that of a newly created object.
def clear
  @value = nil
  @in_read = false
end

def clear?

Returns if the value of this data has been read or explicitly set.
def clear?
  @value.nil?
end

def done_read

To be called after calling #do_read.
def done_read
  @in_read = false
end

def initialize(params = {}, parent = nil)

def initialize(params = {}, parent = nil)
  super(params, parent)
  clear
end

def read_val(io)

Read a number of bytes from +io+ and return the value they represent.
def read_val(io)
  raise NotImplementedError
end

def sensible_default

Return a sensible default for this data.
def sensible_default
  raise NotImplementedError
end

def single_value?

Single objects are single_values
def single_value?
  true
end

def val_to_str(val)

Return the string representation that +val+ will take when written.
def val_to_str(val)
  raise NotImplementedError
end

def value

Returns the current value of this data.
def value
  _value
end

def value=(v)

Sets the value of this data.
def value=(v)
  # only allow modification if the value isn't predefined
  unless has_param?(:value)
    raise ArgumentError, "can't set a nil value" if v.nil?
    @value = v
    # Note that this doesn't do anything in ruby 1.8.x so ignore for now
    # # explicitly return the output of #value as v may be different
    # self.value
  end
end