class RbPlusPlus::Builders::ClassNode

Handles the generation of Rice code to wrap classes

Public Instance Methods

build() click to toggle source
# File lib/rbplusplus/builders/class.rb, line 13
def build
  add_child IncludeNode.new(self, "rice/Class.hpp", :system)
  add_child IncludeNode.new(self, "rice/Data_Type.hpp", :system)
  add_child IncludeNode.new(self, code.file)

  typedef = find_typedef

  @short_name, @qualified_name = typedef ? [typedef.name, typedef.qualified_name] : [code.name, code.qualified_name]

  Logger.info "Wrapping class #{@qualified_name}"

  @class_base_type = @qualified_name

  supers = self.code.superclasses(:public)
  @superclass = supers[0]

  if supers.length > 1
    if (@superclass = self.code._get_superclass).nil?
      @superclass = supers[0]
      Logger.warn :mutiple_superclasses, "#{@qualified_name} has multiple public superclasses. " +
        "Will use first superclass, which is #{@superclass.qualified_name} "
        "Please use #use_superclass to specify another superclass as needed."
    end
  end

  @director = nil
  if self.code.needs_director?
    @director = DirectorNode.new(self.code, self, @qualified_name, @superclass)
    add_child @director
  end

  self.rice_variable = "rb_c#{@short_name.as_variable}"
  self.rice_variable_type = "Rice::Data_Type< #{@qualified_name} >"

  with_enumerations
  with_classes
  with_constructors
  with_constants
  with_variables
  with_methods

  unless @director
    check_allocation_strategies
  end
end
qualified_name() click to toggle source
# File lib/rbplusplus/builders/class.rb, line 9
def qualified_name
  @qualified_name || self.code.qualified_name
end
write() click to toggle source
# File lib/rbplusplus/builders/class.rb, line 59
def write
  prefix = "#{rice_variable_type} #{rice_variable} = "
  ruby_name = @short_name
  superclass = @superclass.qualified_name if @superclass && !do_not_wrap?(@superclass)

  class_names = [@qualified_name]
  class_names << superclass if superclass
  class_names = class_names.join(",")

  if parent.rice_variable
    registrations << "\t#{prefix} Rice::define_class_under< #{class_names} >" +
                       "(#{parent.rice_variable}, \"#{ruby_name}\");"
  else
    registrations << "\t#{prefix} Rice::define_class< #{class_names} >(\"#{ruby_name}\");"
  end

  handle_custom_code
end

Private Instance Methods

check_allocation_strategies() click to toggle source

We need to be sure to inform Rice of classes that may not have public constructors or destructors. This is because when a class is wrapped, code is generated to allocate the class directly. If this code tries to use a non-public constructor, we hit a compiler error.

# File lib/rbplusplus/builders/class.rb, line 97
def check_allocation_strategies
  # Due to the nature of CastXML's handling of templated classes, there are some
  # classes that might not have any gcc-generated constructors or destructors.
  # We check here if we're one of those classes and completely skip this step
  return if [self.code.constructors].flatten.empty?

  # See if the destructor is public
  has_public_destructor = self.code.destructor && self.code.destructor.public?

  if !has_public_destructor
    add_global_child AllocationStrategyNode.new(self,
                      self.code, true, has_public_destructor)
  end
end
handle_custom_code() click to toggle source

Here we take the code manually added to the extension via add_custom_code

# File lib/rbplusplus/builders/class.rb, line 81
def handle_custom_code
  # Any declaration code, usually wrapper function definitions
  self.code._get_custom_declarations.flatten.each do |decl|
    declarations << decl
  end

  # And the registration code to hook into Rice
  self.code._get_custom_wrappings.flatten.each do |wrap|
    registrations << "\t#{wrap.gsub(/<class>/, self.rice_variable)}"
  end
end
with_methods() click to toggle source

Wrap up all public methods

# File lib/rbplusplus/builders/class.rb, line 113
def with_methods
  method_names = @director ? @director.methods_wrapped.map {|m| m.name } : []
  [self.code.methods].flatten.each do |method|
    next if do_not_wrap?(method)
    next if method_names.include?(method.name)

    arguments = [method.arguments].flatten

    # Ignore methods that have non-public arguments anywhere
    if !arguments.empty? && !arguments.select {|a| !a.cpp_type.base_type.public?}.empty?
      Logger.info "Ignoring method #{method.qualified_name} due to non-public argument type(s)"
      next
    end

    if method.static?
      add_child StaticMethodNode.new(method, self)
    else
      add_child MethodNode.new(method, self)
    end
  end
end