Class: BinData::Base

Inherits:
Object
  • Object
show all
Extended by:
AcceptedParametersPlugin
Includes:
Framework, RegisterNamePlugin
Defined in:
lib/bindata/base.rb,
lib/bindata/struct.rb,
lib/bindata/warnings.rb,
lib/bindata/delayed_io.rb

Overview

This is the abstract base class for all data objects.

Defined Under Namespace

Modules: AutoCallDelayedIO

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from AcceptedParametersPlugin

accepted_parameters, default_parameters, mandatory_parameters, mutually_exclusive_parameters, optional_parameters

Methods included from RegisterNamePlugin

included, #initialize_shared_instance

Methods included from Framework

#assign, #bit_aligned?, #clear?, #debug_name_of, #offset_of, #snapshot

Instance Attribute Details

#parentObject

Returns the value of attribute parent.



88
89
90
# File 'lib/bindata/base.rb', line 88

def parent
  @parent
end

Class Method Details

.arg_processor(name = nil) ⇒ Object

The arg processor for this class.



26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/bindata/base.rb', line 26

def arg_processor(name = nil)
  @arg_processor ||= nil

  if name
    @arg_processor = "#{name}_arg_processor".gsub(/(?:^|_)(.)/) { $1.upcase }.to_sym
  elsif @arg_processor.is_a? Symbol
    @arg_processor = BinData.const_get(@arg_processor).new
  elsif @arg_processor.nil?
    @arg_processor = superclass.arg_processor
  else
    @arg_processor
  end
end

.auto_call_delayed_ioObject

The auto_call_delayed_io keyword sets a data object tree to perform multi pass I/O automatically.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/bindata/delayed_io.rb', line 161

def auto_call_delayed_io
  include AutoCallDelayedIO

  return if DelayedIO.method_defined? :initialize_instance_without_record_io

  DelayedIO.send(:alias_method, :initialize_instance_without_record_io, :initialize_instance)
  DelayedIO.send(:define_method, :initialize_instance) do
    if @parent && !defined? @delayed_io_recorded
      @delayed_io_recorded = true
      list = top_level_get(:delayed_ios)
      list << self if list
    end

    initialize_instance_without_record_io
  end
end

.bindata_nameObject

The name of this class as used by Records, Arrays etc.



41
42
43
# File 'lib/bindata/base.rb', line 41

def bindata_name
  RegisteredClasses.underscore_name(name)
end

.read(io, *args, &block) ⇒ Object

Instantiates this class and reads from io, returning the newly created data object. args will be used when instantiating.



19
20
21
22
23
# File 'lib/bindata/base.rb', line 19

def read(io, *args, &block)
  obj = new(*args)
  obj.read(io, &block)
  obj
end

.register_subclassesObject

Registers all subclasses of this class for use



51
52
53
54
55
56
57
# File 'lib/bindata/base.rb', line 51

def register_subclasses # :nodoc:
  singleton_class.send(:undef_method, :inherited)
  define_singleton_method(:inherited) do |subclass|
    RegisteredClasses.register(subclass.name, subclass)
    register_subclasses
  end
end

.unregister_selfObject

Call this method if this class is abstract and not to be used.



46
47
48
# File 'lib/bindata/base.rb', line 46

def unregister_self
  RegisteredClasses.unregister(name)
end

Instance Method Details

#==(other) ⇒ Object

:nodoc:



221
222
223
224
# File 'lib/bindata/base.rb', line 221

def ==(other) # :nodoc:
  # double dispatch
  other == snapshot
end

#=~(other) ⇒ Object

Override and delegate =~ as it is defined in Object.



201
202
203
# File 'lib/bindata/base.rb', line 201

def =~(other)
  snapshot =~ other
end

#abs_offsetObject

Returns the offset (in bytes) of this object with respect to its most distant ancestor.



212
213
214
# File 'lib/bindata/base.rb', line 212

def abs_offset
  @parent ? @parent.abs_offset + @parent.offset_of(self) : 0
end

#clearObject

Resets the internal state to that of a newly created object.



139
140
141
# File 'lib/bindata/base.rb', line 139

def clear
  initialize_instance
end

#debug_nameObject

Returns a user friendly name of this object for debugging purposes.



206
207
208
# File 'lib/bindata/base.rb', line 206

def debug_name
  @parent ? @parent.debug_name_of(self) : 'obj'
end

#eval_parameter(key, overrides = nil) ⇒ Object

Returns the result of evaluating the parameter identified by key.

overrides is an optional parameters like hash that allow the parameters given at object construction to be overridden.

Returns nil if key does not refer to any parameter.



112
113
114
115
116
117
118
119
# File 'lib/bindata/base.rb', line 112

def eval_parameter(key, overrides = nil)
  value = get_parameter(key)
  if value.is_a?(Symbol) || value.respond_to?(:arity)
    lazy_evaluator.lazy_eval(value, overrides)
  else
    value
  end
end

#get_parameter(key) ⇒ Object

Returns the parameter referenced by key. Use this method if you are sure the parameter is not to be evaluated. You most likely want #eval_parameter.



129
130
131
# File 'lib/bindata/base.rb', line 129

def get_parameter(key)
  @params[key]
end

#has_parameter?(key) ⇒ Boolean

Returns whether key exists in the parameters hash.

Returns:

  • (Boolean)


134
135
136
# File 'lib/bindata/base.rb', line 134

def has_parameter?(key)
  @params.has_parameter?(key)
end

#initialize_instance(*args) ⇒ Object



25
26
27
28
29
# File 'lib/bindata/warnings.rb', line 25

def initialize_instance(*args)
  unless args.empty?
    fail "#{caller[0]} remove the call to super in #initialize_instance"
  end
end

#initialize_with_warning(*args) ⇒ Object Also known as: initialize



12
13
14
15
16
17
18
19
20
21
22
# File 'lib/bindata/warnings.rb', line 12

def initialize_with_warning(*args)
  owner = method(:initialize).owner
  if owner != BinData::Base
    msg = "Don't override #initialize on #{owner}."
    if %w[BinData::Base BinData::BasePrimitive].include? self.class.superclass.name
      msg += "\nrename #initialize to #initialize_instance."
    end
    fail msg
  end
  initialize_without_warning(*args)
end

#inspectObject

Return a human readable representation of this data object.



186
187
188
# File 'lib/bindata/base.rb', line 186

def inspect
  snapshot.inspect
end

#lazy_evaluatorObject

Returns a lazy evaluator for this object.



122
123
124
# File 'lib/bindata/base.rb', line 122

def lazy_evaluator # :nodoc:
  @lazy_evaluator ||= LazyEvaluator.new(self)
end

#new(value = nil, parent = nil) ⇒ Object

Creates a new data object based on this instance.

This implements the prototype design pattern.

All parameters will be be duplicated. Use this method when creating multiple objects with the same parameters.



97
98
99
100
101
102
103
104
# File 'lib/bindata/base.rb', line 97

def new(value = nil, parent = nil)
  obj = clone
  obj.parent = parent if parent
  obj.initialize_instance
  obj.assign(value) if value

  obj
end

#num_bytesObject

Returns the number of bytes it will take to write this data object.



169
170
171
# File 'lib/bindata/base.rb', line 169

def num_bytes
  do_num_bytes.ceil
end

#pretty_print(pp) ⇒ Object

Work with Ruby’s pretty-printer library.



196
197
198
# File 'lib/bindata/base.rb', line 196

def pretty_print(pp) # :nodoc:
  pp.pp(snapshot)
end

#read(io, &block) ⇒ Object

Reads data into this data object.



144
145
146
147
148
149
150
151
152
153
154
# File 'lib/bindata/base.rb', line 144

def read(io, &block)
  io = BinData::IO::Read.new(io) unless BinData::IO::Read === io

  start_read do
    clear
    do_read(io)
  end
  block.call(self) if block_given?

  self
end

#rel_offsetObject

Returns the offset (in bytes) of this object with respect to its parent.



217
218
219
# File 'lib/bindata/base.rb', line 217

def rel_offset
  @parent ? @parent.offset_of(self) : 0
end

#safe_respond_to?(symbol, include_private = false) ⇒ Boolean

A version of respond_to? used by the lazy evaluator. It doesn’t reinvoke the evaluator so as to avoid infinite evaluation loops.

Returns:

  • (Boolean)


228
229
230
# File 'lib/bindata/base.rb', line 228

def safe_respond_to?(symbol, include_private = false) # :nodoc:
  base_respond_to?(symbol, include_private)
end

#to_binary_s(&block) ⇒ Object

Returns the string representation of this data object.



174
175
176
177
178
# File 'lib/bindata/base.rb', line 174

def to_binary_s(&block)
  io = BinData::IO.create_string_io
  write(io, &block)
  io.string
end

#to_hex(&block) ⇒ Object

Returns the hexadecimal string representation of this data object.



181
182
183
# File 'lib/bindata/base.rb', line 181

def to_hex(&block)
  to_binary_s(&block).unpack1('H*')
end

#to_sObject

Return a string representing this data object.



191
192
193
# File 'lib/bindata/base.rb', line 191

def to_s
  snapshot.to_s
end

#write(io, &block) ⇒ Object

Writes the value for this data object to io.



157
158
159
160
161
162
163
164
165
166
# File 'lib/bindata/base.rb', line 157

def write(io, &block)
  io = BinData::IO::Write.new(io) unless BinData::IO::Write === io

  do_write(io)
  io.flush

  block.call(self) if block_given?

  self
end