For one project i am currently working on i had to load and parse some binary files with ruby. The parser code was not very nice, so i came up with an idea:
The cool thing about this is: The DataFormat is a description of the data format and the code to load and save a file in this data format is generated automatically. So you dont have to worry about the loading and saving code, you just have to specify the format.
Some more examples:
This one reads an array of values.
The data that is returned is an instance of the class AttributeHash. The AttributeHash just wraps an hash and overwrites method_missing to delegate all attribute accesses to the wrapped hash (so it behaves like a javascript object).
But you can specify that an instance of some custom class should be created instead of an AttributeHash. Example:
The requirement for the class that will be instantiated is just that is must have methods for "attrname=" calls with "attrname" specified in the data format.
The different types that are currently available to describe a data format:
Supported types
NumberSerializer: short, int, long (+unsigned: ushort etc.), float, double
uint :attribute_name, :min => 1145, :max => 67546
StringSerializer: nullterminated(default) or fixed-length
string :attr_name, :length => 32
MagicSerializer: throws exception when the magic value (in this case 1337) is not found at the pecific position
magic :magic_number, :value => 1337
ArraySerializer: reads an array from the file. The data format of each entry can be specified.
array(:things,:length => :arr_length) do
int :thing_id
float :value
end
Status
Experimental version.
Todo:
- Option to specify if format is big- or little-endian
- Store errors (eg: integer out of range) in an error hash like in active record
- Optional elements (if :someattr == 0, then :otherattr is not present)
- Skip sections (if :someattr == 0, then skip x bytes)