class BinData::DSLMixin::DSLParser

A DSLParser parses and accumulates field definitions of the form

type name, params

where:

* +type+ is the under_scored name of a registered type
* +name+ is the (possible optional) name of the field
* +params+ is a hash containing any parameters

Attributes

parser_type[R]

Public Class Methods

new(the_class, parser_type) click to toggle source
# File lib/bindata/dsl.rb, line 64
def initialize(the_class, parser_type)
  raise "unknown parser type #{parser_type}" unless parser_abilities[parser_type]

  @the_class      = the_class
  @parser_type    = parser_type
  @validator      = DSLFieldValidator.new(the_class, self)
  @endian         = nil
end

Public Instance Methods

dsl_params() click to toggle source
# File lib/bindata/dsl.rb, line 124
def dsl_params
  send(parser_abilities[@parser_type].at(0))
end
endian(endian = nil) click to toggle source
# File lib/bindata/dsl.rb, line 75
def endian(endian = nil)
  if endian
    set_endian(endian)
  elsif @endian.nil?
    set_endian(parent_attribute(:endian))
  end
  @endian
end
fields() click to toggle source
# File lib/bindata/dsl.rb, line 114
def fields
  unless defined? @fields
    fields = parent_fields
    @fields = SanitizedFields.new(hints)
    @fields.copy_fields(fields) if fields
  end

  @fields
end
hide(*args) click to toggle source
# File lib/bindata/dsl.rb, line 101
def hide(*args)
  if option?(:hidden_fields)
    hidden = args.collect { |name| name.to_sym }

    unless defined? @hide
      @hide = parent_attribute(:hide, []).dup
    end

    @hide.concat(hidden.compact)
    @hide
  end
end
method_missing(*args, &block) click to toggle source
# File lib/bindata/dsl.rb, line 128
def method_missing(*args, &block)
  ensure_hints
  parse_and_append_field(*args, &block)
end
search_prefix(*args) click to toggle source
# File lib/bindata/dsl.rb, line 84
def search_prefix(*args)
  unless defined? @search_prefix
    @search_prefix = parent_attribute(:search_prefix, []).dup
  end

  prefix = args.collect { |name| name.to_sym }.compact
  if prefix.size > 0
    if has_fields?
      dsl_raise SyntaxError, "search_prefix must be called before defining fields"
    end

    @search_prefix = prefix.concat(@search_prefix)
  end

  @search_prefix
end

Private Instance Methods

append_field(type, name, params) click to toggle source
# File lib/bindata/dsl.rb, line 199
def append_field(type, name, params)
  fields.add_field(type, name, params)
rescue BinData::UnRegisteredTypeError => err
  raise TypeError, "unknown type '#{err.message}'"
end
dsl_raise(exception, message) click to toggle source
# File lib/bindata/dsl.rb, line 215
def dsl_raise(exception, message)
  backtrace = caller
  backtrace.shift while %r{bindata/dsl.rb} =~ backtrace.first

  raise exception, message + " in #{@the_class}", backtrace
end
ensure_hints() click to toggle source
# File lib/bindata/dsl.rb, line 151
def ensure_hints
  endian
  search_prefix
end
has_fields?() click to toggle source
# File lib/bindata/dsl.rb, line 185
def has_fields?
  defined? @fields and @fields.length > 0
end
hints() click to toggle source
# File lib/bindata/dsl.rb, line 156
def hints
  { :endian => endian, :search_prefix => search_prefix }
end
option?(opt) click to toggle source
# File lib/bindata/dsl.rb, line 147
def option?(opt)
  parser_abilities[@parser_type].at(1).include?(opt)
end
parent_attribute(attr, default = nil) click to toggle source
# File lib/bindata/dsl.rb, line 205
def parent_attribute(attr, default = nil)
  parent = @the_class.superclass
  parser = parent.respond_to?(:dsl_parser) ? parent.dsl_parser : nil
  if parser and parser.respond_to?(attr)
    parser.send(attr)
  else
    default
  end
end
parent_fields() click to toggle source
# File lib/bindata/dsl.rb, line 181
def parent_fields
  parent_attribute(:fields)
end
parse_and_append_field(*args, &block) click to toggle source
# File lib/bindata/dsl.rb, line 189
def parse_and_append_field(*args, &block)
  parser = DSLFieldParser.new(hints, *args, &block)
  begin
    @validator.validate_field(parser.name)
    append_field(parser.type, parser.name, parser.params)
  rescue Exception => err
    dsl_raise err.class, err.message
  end
end
parser_abilities() click to toggle source
# File lib/bindata/dsl.rb, line 136
def parser_abilities
  @abilities ||= {
    :struct     => [:to_struct_params, [:multiple_fields, :optional_fieldnames, :hidden_fields]],
    :array      => [:to_array_params,  [:multiple_fields, :optional_fieldnames]],
    :buffer     => [:to_array_params,  [:multiple_fields, :optional_fieldnames, :hidden_fields]],
    :choice     => [:to_choice_params, [:multiple_fields, :all_or_none_fieldnames, :fieldnames_are_values]],
    :delayed_io => [:to_array_params,  [:multiple_fields, :optional_fieldnames, :hidden_fields]],
    :primitive  => [:to_struct_params, [:multiple_fields, :optional_fieldnames]]
  }
end
set_endian(endian) click to toggle source
# File lib/bindata/dsl.rb, line 160
def set_endian(endian)
  if endian
    if has_fields?
      dsl_raise SyntaxError, "endian must be called before defining fields"
    end
    if not valid_endian?(endian)
      dsl_raise ArgumentError, "unknown value for endian '#{endian}'"
    end

    if endian == :big_and_little
      DSLBigAndLittleEndianHandler.handle(@the_class)
    end

    @endian = endian
  end
end
to_array_params() click to toggle source
# File lib/bindata/dsl.rb, line 222
def to_array_params
  case fields.length
  when 0
    {}
  when 1
    {:type => fields[0].prototype}
  else
    {:type => [:struct, to_struct_params]}
  end
end
to_choice_params() click to toggle source
# File lib/bindata/dsl.rb, line 233
def to_choice_params
  if fields.length == 0
    {}
  elsif fields.all_field_names_blank?
    {:choices => fields.collect { |f| f.prototype }}
  else
    choices = {}
    fields.each { |f| choices[f.name] = f.prototype }
    {:choices => choices}
  end
end
to_struct_params() click to toggle source
# File lib/bindata/dsl.rb, line 245
def to_struct_params
  result = {:fields => fields}
  if not endian.nil?
    result[:endian] = endian
  end
  if not search_prefix.empty?
    result[:search_prefix] = search_prefix
  end
  if option?(:hidden_fields) and not hide.empty?
    result[:hide] = hide
  end

  result
end
valid_endian?(endian) click to toggle source
# File lib/bindata/dsl.rb, line 177
def valid_endian?(endian)
  [:big, :little, :big_and_little].include?(endian)
end