class Wrapture::ClassSpec

A description of a class, including its constants, functions, and other details.

Attributes

struct[R]

The underlying struct of this class.

Public Class Methods

effective_type(spec) click to toggle source

Gives the effective type of the given class spec hash.

# File lib/wrapture/class_spec.rb, line 54
def self.effective_type(spec)
  inferred_pointer_wrapper = spec['constructors'].any? do |func|
    func['wrapped-function']['return']['type'] == EQUIVALENT_POINTER_KEYWORD
  end

  if spec.key?('type')
    valid_types = %w[pointer struct]
    unless valid_types.include?(spec['type'])
      type_message = "#{spec['type']} is not a valid class type"
      raise InvalidSpecKey.new(type_message, valid_keys: valid_types)
    end

    spec['type']
  elsif inferred_pointer_wrapper
    'pointer'
  else
    'struct'
  end
end
new(spec, scope: Scope.new) click to toggle source

Creates a class spec based on the provided hash spec.

The scope can be provided if available.

The hash must have the following keys:

name

the name of the class

namespace

the namespace to put the class into

equivalent-struct

a hash describing the struct this class wraps

The following keys are optional:

doc

a string containing the documentation for this class

constructors

a list of function specs that can create this class

destructor

a function spec for the destructor of the class

functions

a list of function specs

constants

a list of constant specs

# File lib/wrapture/class_spec.rb, line 92
def initialize(spec, scope: Scope.new)
  @spec = Marshal.load(Marshal.dump(spec))
  TemplateSpec.replace_all_uses(@spec, *scope.templates)

  @spec = ClassSpec.normalize_spec_hash(@spec)

  @struct = if @spec.key?(EQUIVALENT_STRUCT_KEYWORD)
              StructSpec.new(@spec[EQUIVALENT_STRUCT_KEYWORD])
            end

  @functions = @spec['constructors'].map do |constructor_spec|
    full_spec = constructor_spec.dup
    full_spec['name'] = @spec['name']
    full_spec['params'] = constructor_spec['wrapped-function']['params']

    FunctionSpec.new(full_spec, self, constructor: true)
  end

  if @spec.key?('destructor')
    destructor_spec = @spec['destructor'].dup
    destructor_spec['name'] = "~#{@spec['name']}"

    @functions << FunctionSpec.new(destructor_spec, self, destructor: true)
  end

  @spec['functions'].each do |function_spec|
    @functions << FunctionSpec.new(function_spec, self)
  end

  @constants = @spec['constants'].map do |constant_spec|
    ConstantSpec.new(constant_spec)
  end

  @doc = @spec.key?('doc') ? Comment.new(@spec['doc']) : nil

  scope << self
  @scope = scope
end
normalize_spec_hash(spec) click to toggle source

Normalizes a hash specification of a class. Normalization will check for things like invalid keys, duplicate entries in include lists, and will set missing keys to their default values (for example, an empty list if no includes are given).

If this spec cannot be normalized, for example because it is invalid or it uses an unsupported version type, then an exception is raised.

# File lib/wrapture/class_spec.rb, line 32
def self.normalize_spec_hash(spec)
  raise NoNamespace unless spec.key?('namespace')
  raise MissingSpecKey, 'name key is required' unless spec.key?('name')

  Comment.validate_doc(spec['doc']) if spec.key?('doc')

  normalized = spec.dup
  normalized.default = []

  normalized['version'] = Wrapture.spec_version(spec)
  normalized['includes'] = Wrapture.normalize_includes(spec['includes'])
  normalized['type'] = ClassSpec.effective_type(normalized)

  if spec.key?('parent')
    includes = Wrapture.normalize_includes(spec['parent']['includes'])
    normalized['parent']['includes'] = includes
  end

  normalized
end

Public Instance Methods

cast(instance, to, from = name) click to toggle source

Returns a cast of an instance of this class with the provided name to the specified type. Optionally the from parameter may hold the type of the instance, either a reference or a pointer.

# File lib/wrapture/class_spec.rb, line 134
def cast(instance, to, from = name)
  member_access = from.pointer? ? '->' : '.'

  struct = "struct #{@struct.name}"

  if [EQUIVALENT_STRUCT_KEYWORD, struct].include?(to)
    "#{'*' if pointer_wrapper?}#{instance}#{member_access}equivalent"
  elsif [EQUIVALENT_POINTER_KEYWORD, "#{struct} *"].include?(to)
    "#{'&' unless pointer_wrapper?}#{instance}#{member_access}equivalent"
  end
end
generate_wrappers() click to toggle source

Generates the wrapper class declaration and definition files.

# File lib/wrapture/class_spec.rb, line 147
def generate_wrappers
  [generate_declaration_file, generate_definition_file]
end
name() click to toggle source

The name of the class

# File lib/wrapture/class_spec.rb, line 152
def name
  @spec['name']
end
overloads?(parent_spec) click to toggle source

True if this class overloads the given one. A class is considered an overload if its parent is the given class, it has the same equivalent struct name, and the equivalent struct has a set of rules. The overloaded class cannot have any rules in its equivalent struct, or it will not be overloaded.

# File lib/wrapture/class_spec.rb, line 161
def overloads?(parent_spec)
  return false unless parent_spec.struct&.rules&.empty?

  parent_spec.struct.name == struct_name &&
    parent_spec.name == parent_name &&
    !@struct.rules.empty?
end
parent_name() click to toggle source

The name of the parent of this class, or nil if there is no parent.

# File lib/wrapture/class_spec.rb, line 170
def parent_name
  @spec['parent']['name'] if child?
end
pointer_wrapper?() click to toggle source

Determines if this class is a wrapper for a struct pointer or not.

# File lib/wrapture/class_spec.rb, line 175
def pointer_wrapper?
  @spec['type'] == 'pointer'
end
struct_name() click to toggle source

The name of the equivalent struct of this class.

# File lib/wrapture/class_spec.rb, line 180
def struct_name
  @struct.name
end
this_struct() click to toggle source

Gives a code snippet that accesses the equivalent struct from within the class using the 'this' keyword.

# File lib/wrapture/class_spec.rb, line 186
def this_struct
  if pointer_wrapper?
    '*(this->equivalent)'
  else
    'this->equivalent'
  end
end
this_struct_pointer() click to toggle source

Gives a code snippet that accesses the equivalent struct pointer from within the class using the 'this' keyword.

# File lib/wrapture/class_spec.rb, line 196
def this_struct_pointer
  "#{'&' unless pointer_wrapper?}this->equivalent"
end
type(type) click to toggle source

Returns the ClassSpec for the given type in this class's scope.

# File lib/wrapture/class_spec.rb, line 201
def type(type)
  @scope.type(type)
end
type?(type) click to toggle source

Returns true if the given type exists in this class's scope.

# File lib/wrapture/class_spec.rb, line 206
def type?(type)
  @scope.type?(type)
end