README in bindata-0.8.1 vs README in bindata-0.9.0

- old
+ new

@@ -13,11 +13,11 @@ puts "Rectangle #{name} is #{width} x #{height}" It's ugly, violates DRY and feels like you're writing Perl, not Ruby. There is a better way. - class Rectangle < BinData::Struct + class Rectangle < BinData::MultiValue uint16le :len string :name, :read_length => :len uint32le :width uint32le :height end @@ -34,11 +34,11 @@ == Syntax BinData declarations are easy to read. Here's an example. - class MyFancyFormat < BinData::Struct + class MyFancyFormat < BinData::MultiValue stringz :comment uint8 :count, :check_value => lambda { (value % 2) == 0 } array :some_ints, :type => :int32be, :initial_length => :count end @@ -60,11 +60,11 @@ The general format of a BinData declaration is a class containing one or more fields. - class MyName < BinData::Struct + class MyName < BinData::MultiValue type field_name, :param1 => "foo", :param2 => bar, ... ... end *type* is the name of a supplied type (e.g. <tt>uint32be</tt>, +string+) @@ -98,11 +98,11 @@ io.putc(str.length) io.write(str) Here's how we'd implement the same example with BinData. - class PascalString < BinData::Struct + class PascalString < BinData::MultiValue uint8 :len, :value => lambda { data.length } string :data, :read_length => :len end # reading @@ -118,11 +118,11 @@ ps.write(io) This syntax needs explaining. Let's simplify by examining reading and writing separately. - class PascalStringReader < BinData::Struct + class PascalStringReader < BinData::MultiValue uint8 :len string :data, :read_length => :len end This states that when reading the string, the initial length of the string @@ -130,11 +130,11 @@ +len+ field. Note that <tt>:read_length => :len</tt> is syntactic sugar for <tt>:read_length => lambda { len }</tt>, but more on that later. - class PascalStringWriter < BinData::Struct + class PascalStringWriter < BinData::MultiValue uint8 :len, :value => lambda { data.length } string :data end This states that the value of +len+ is always equal to the length of +data+. @@ -150,10 +150,17 @@ == Predefined Types These are the predefined types. Custom types can be created by composing these types. +BinData::String:: A sequence of bytes. +BinData::Stringz:: A zero terminated sequence of bytes. + +BinData::Array:: A list of objects of the same type. +BinData::Choice:: A choice between several objects. +BinData::Struct:: An ordered collection of named objects. + BinData::Int8:: Signed 8 bit integer. BinData::Int16le:: Signed 16 bit integer (little endian). BinData::Int16be:: Signed 16 bit integer (big endian). BinData::Int32le:: Signed 32 bit integer (little endian). BinData::Int32be:: Signed 32 bit integer (big endian). @@ -171,20 +178,15 @@ BinData::FloatLe:: Single precision floating point number (little endian). BinData::FloatBe:: Single precision floating point number (big endian). BinData::DoubleLe:: Double precision floating point number (little endian). BinData::DoubleBe:: Double precision floating point number (big endian). -BinData::String:: A sequence of bytes. -BinData::Stringz:: A zero terminated sequence of bytes. +BinData::Rest:: Consumes the rest of the input stream. -BinData::Array:: A list of objects of the same type. -BinData::Choice:: A choice between several objects. -BinData::Struct:: An ordered collection of named objects. - == Parameters - class PascalStringWriter < BinData::Struct + class PascalStringWriter < BinData::MultiValue uint8 :len, :value => lambda { data.length } string :data end Revisiting the Pascal string writer, we see that a field can take @@ -215,11 +217,11 @@ The endianess of numeric types must be explicitly defined so that the code produced is independent of architecture. Explicitly specifying the endianess of each numeric type can become tedious, so the following shortcut is provided. - class A < BinData::Struct + class A < BinData::MultiValue endian :little uint16 :a uint32 :b double :c @@ -227,11 +229,11 @@ array :e, :type => :int16 end is equivalent to: - class A < BinData::Struct + class A < BinData::MultiValue uint16le :a uint32le :b double_le :c uint32be :d array :e, :type => :int16le @@ -241,15 +243,49 @@ as reducing the amount of typing necessary. Note that the endian keyword will cascade to nested types, as illustrated with the array in the above example. == Creating custom types -Custom types should be created by subclassing BinData::Struct. -Ocassionally it may be useful to subclass BinData::Single. Subclassing -other classes may have unexpected results and is unsupported. +Custom types should be created by subclassing BinData::MultiValue or +BinData::SingleValue. Ocassionally it may be useful to subclass +BinData::Single. Subclassing other classes may have unexpected results +and is unsupported. +Let us revisit the Pascal String example. + class PascalString < BinData::MultiValue + uint8 :len, :value => lambda { data.length } + string :data, :read_length => :len + end + +We'd like to make PascalString a custom type that behaves like a +BinData::Single object so we can use :initial_value etc. Here's an +example usage of what we'd like: + + class Favourites < BinData::MultiValue + pascal_string :language, :initial_value => "ruby" + pascal_string :os, :initial_value => "unix" + end + + f = Favourites.new + f.os = "freebsd" + f.to_s #=> "\004ruby\007freebsd" + +We create this type of custom string by inheriting from BinData::SingleValue +and implementing the #get and #set methods. + + class PascalString < BinData::SingleValue + uint8 :len, :value => lambda { data.length } + string :data, :read_length => :len + + def get; self.data; end + def set(v) self.data = v; end + end + +If the type we are creating represents a single value then inherit from +BinData::SingleValue, otherwise inherit from BinData::MultiValue. + == License BinData is released under the same license as Ruby. -Copyright (c) 2007 Dion Mendel +Copyright (c) 2007, 2008 Dion Mendel