class GObjectIntrospection::Loader

Attributes

version[RW]

Public Class Methods

initialize_instance_post(object) click to toggle source
# File lib/gobject-introspection/loader.rb, line 28
def initialize_instance_post(object)
end
load(namespace, base_module, options={}) click to toggle source
# File lib/gobject-introspection/loader.rb, line 22
def load(namespace, base_module, options={})
  loader = new(base_module)
  loader.version = options[:version]
  loader.load(namespace)
end
new(base_module) click to toggle source
# File lib/gobject-introspection/loader.rb, line 33
def initialize(base_module)
  @base_module = base_module
  @version = nil
end

Public Instance Methods

load(namespace) click to toggle source
# File lib/gobject-introspection/loader.rb, line 38
def load(namespace)
  repository = Repository.default
  repository.require(namespace, @version)
  prepare_class(@base_module) do
    pre_load(repository, namespace)
    repository.each(namespace) do |info|
      load_info(info) if info.is_a?(InterfaceInfo)
    end
    repository.each(namespace) do |info|
      load_info(info) unless info.is_a?(InterfaceInfo)
    end
    post_load(repository, namespace)
  end
end

Private Instance Methods

apply_methods_module(mod, target) click to toggle source
# File lib/gobject-introspection/loader.rb, line 668
def apply_methods_module(mod, target)
  target.include(mod)
  post_methods_module(mod)
end
define_boxed(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 165
def define_boxed(info)
  return if info.gtype == GLib::Type::NONE
  klass = self.class.define_class(info.gtype, info.name, @base_module)
  _ = klass # TODO: Remove me. It is just for suppressing a warning.
  # TODO
  # load_fields(info, klass)
  # load_methods(info, klass)
end
define_constant(name, info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 629
def define_constant(name, info)
  @base_module.const_set(name, info.value)
end
define_enum(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 184
def define_enum(info)
  # TODO: Can we do the same things for flags on NONE GType?
  return if info.gtype == GLib::Type::NONE
  klass = self.class.define_class(info.gtype,
                                 rubyish_class_name(info),
                                 @base_module)
  prepare_class(klass) do
    load_methods(info, klass)
  end
end
define_equal_style_setter(info, klass, method_name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 586
def define_equal_style_setter(info, klass, method_name)
  if /\Aset_/ =~ method_name and info.n_in_args == 1
    setter_method_name = "#{$POSTMATCH}="
    remove_existing_method(klass, setter_method_name)
    klass.__send__(:alias_method, setter_method_name, method_name)
  end
end
define_error(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 195
def define_error(info)
  self.class.define_error(info.error_domain,
                          rubyish_class_name(info),
                          @base_module,
                          :parent => error_parent_class(info),
                          :gtype => info.gtype)
end
define_inspect(info, klass, method_name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 594
    def define_inspect(info, klass, method_name)
      if method_name == "to_s" and info.n_args.zero?
        klass.class_eval(<<-DEFINE_METHOD, __FILE__, __LINE__ + 1)
          def inspect
            super.gsub(/>\\z/) {" \#{to_s}>"}
          end
        DEFINE_METHOD
      end
    end
define_method(info, klass, method_name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 571
    def define_method(info, klass, method_name)
      return if method_name.empty?
      prepare_function_info_lock_gvl(info, klass)
      remove_existing_method(klass, method_name)
      invoker = Invoker.new(info, method_name, "#{klass}\##{method_name}")
      invokers = klass::INVOKERS
      invokers[method_name] = invoker
      klass.class_eval(<<-DEFINE_METHOD, __FILE__, __LINE__ + 1)
        def #{method_name}(*arguments, &block)
          invoker = INVOKERS["#{method_name}"]
          invoker.invoke(self, arguments, block)
        end
      DEFINE_METHOD
    end
define_methods_module(name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 661
def define_methods_module(name)
  mod = Module.new
  @base_module.const_set(name, mod)
  mod.const_set(:INVOKERS, {})
  mod
end
define_module_function(function_info, target_module, name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 92
    def define_module_function(function_info, target_module, name)
      prepare_function_info_lock_gvl(function_info, target_module)
      full_method_name = "#{target_module}\#.#{name}"
      invoker = Invoker.new(function_info, name, full_method_name)
      target_module::INVOKERS[name] = invoker
      target_module.module_eval(<<-DEFINE_METHOD, __FILE__, __LINE__ + 1)
        def #{name}(*arguments, &block)
          INVOKERS["#{name}"].invoke(nil, arguments, block)
        end
        module_function(:#{name})
      DEFINE_METHOD
    end
define_singleton_method(info, klass, name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 105
    def define_singleton_method(info, klass, name)
      case name
      when "hash"
        # Ignore methods that require 1+ arguments and use well-known
        # name. It may break something.
        return unless info.n_required_in_args.zero?
      end
      prepare_function_info_lock_gvl(info, klass)
      invoker = Invoker.new(info, name, "#{klass}.#{name}")
      singleton_class = klass.singleton_class
      singleton_class::INVOKERS[name] = invoker
      singleton_class.class_eval(<<-DEFINE_METHOD, __FILE__, __LINE__ + 1)
        def #{name}(*arguments, &block)
          INVOKERS["#{name}"].invoke(nil, arguments, block)
        end
      DEFINE_METHOD
    end
define_struct(info, options={}) click to toggle source
# File lib/gobject-introspection/loader.rb, line 123
def define_struct(info, options={})
  name = rubyish_class_name(info)
  if info.gtype == GLib::Type::NONE
    klass = self.class.define_struct(info.size, name, @base_module,
                                     :parent => options[:parent])
  else
    size = info.size
    size = nil if size.zero?
    klass = self.class.define_class(info.gtype, name, @base_module,
                                    :parent => options[:parent],
                                    :size   => size)
  end
  prepare_class(klass) do
    load_fields(info, klass)
    load_methods(info, klass)
  end
end
error_parent_class(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 203
def error_parent_class(info)
  nil
end
field_name(field_info, klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 269
def field_name(field_info, klass)
  field_info.name
end
flags_class_name(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 244
def flags_class_name(info)
  info.name
end
load_boxed_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 174
def load_boxed_info(info)
  define_boxed(info)
end
load_constant_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 625
def load_constant_info(info)
  define_constant(info.name, info)
end
load_enum_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 207
def load_enum_info(info)
  if info.gtype == GLib::Type::NONE
    enum_module = Module.new
    info.values.each do |value_info|
      load_enum_value(value_info, enum_module)
    end
    @base_module.const_set(rubyish_class_name(info), enum_module)
  else
    if info.error_domain
      define_error(info)
    else
      define_enum(info)
    end
  end
end
load_enum_value(value_info, enum_module) click to toggle source
# File lib/gobject-introspection/loader.rb, line 178
def load_enum_value(value_info, enum_module)
  value = value_info.value
  Ractor.make_shareable(value) if defined?(Ractor)
  enum_module.const_set(value_info.name.upcase, value)
end
load_field(info, i, field_info, klass, options={}) click to toggle source
# File lib/gobject-introspection/loader.rb, line 273
def load_field(info, i, field_info, klass, options={})
  name = field_name(field_info, klass)
  flags = field_info.flags

  readable = options[:readable]
  readable = flags.readable? if readable.nil?
  if readable
    reader_method_name = rubyish_field_reader_name(field_info, name)
    load_field_reader(info, i, field_info, klass, name, reader_method_name)
  end

  writable = options[:writable]
  writable = flags.writable? if writable.nil?
  if writable
    load_field_writer(info, i, field_info, klass, name, "#{name}=")
  end
end
load_field_reader(info, i, field_info, klass, name, method_name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 291
def load_field_reader(info, i, field_info, klass, name, method_name)
  remove_existing_method(klass, method_name)

  need_number_to_bool_convert = false
  if name.start_with?("is_") and
      field_info.type.tag == TypeTag::UINT32
    need_number_to_bool_convert = true
  end
  klass.__send__(:define_method, method_name) do ||
    value = info.get_field_value(self, i)
    if need_number_to_bool_convert
      value != 0
    else
      value
    end
  end
end
load_field_writer(info, i, field_info, klass, name, method_name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 309
def load_field_writer(info, i, field_info, klass, name, method_name)
  klass.__send__(:define_method, method_name) do |value|
    info.set_field_value(self, i, value)
  end
end
load_fields(info, klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 262
def load_fields(info, klass)
  info.n_fields.times do |i|
    field_info = info.get_field(i)
    load_field(info, i, field_info, klass)
  end
end
load_flag_value(value_info, flags_module) click to toggle source
# File lib/gobject-introspection/loader.rb, line 223
def load_flag_value(value_info, flags_module)
  flags_module.const_set(value_info.name.upcase, value_info.value)
end
load_flags_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 227
def load_flags_info(info)
  if info.gtype == GLib::Type::NONE
    flags_module = Module.new
    info.values.each do |value_info|
      load_flag_value(value_info, flags_module)
    end
    @base_module.const_set(rubyish_class_name(info), flags_module)
  else
    klass = self.class.define_class(info.gtype,
                                    flags_class_name(info),
                                    @base_module)
    prepare_class(klass) do
      load_methods(info, klass)
    end
  end
end
load_function_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 83
def load_function_info(info)
  name = rubyish_method_name(info)
  define_singleton_method(info, @base_module, name)
end
load_function_info_singleton_method(info, klass, method_name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 88
def load_function_info_singleton_method(info, klass, method_name)
  define_singleton_method(info, klass, method_name)
end
load_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 60
def load_info(info)
  case info
  when FunctionInfo
    load_function_info(info)
  when StructInfo
    load_struct_info(info)
  when BoxedInfo
    load_boxed_info(info)
  when FlagsInfo
    load_flags_info(info)
  when EnumInfo
    load_enum_info(info)
  when ObjectInfo
    load_object_info(info)
  when InterfaceInfo
    load_interface_info(info)
  when ConstantInfo
    load_constant_info(info)
  when UnionInfo
    load_union_info(info)
  end
end
load_interface_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 613
def load_interface_info(info)
  return if info.gtype == GLib::Type::NONE
  interface_module =
    self.class.define_interface(info.gtype,
                                rubyish_class_name(info),
                                @base_module)
  prepare_class(interface_module) do
    load_virtual_functions(info, interface_module)
    load_methods(info, interface_module)
  end
end
load_method_info(info, klass, method_name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 559
def load_method_info(info, klass, method_name)
  define_method(info, klass, method_name)
  define_equal_style_setter(info, klass, method_name)
  define_inspect(info, klass, method_name)
end
load_methods(info, klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 315
def load_methods(info, klass)
  grouped_methods = info.methods.group_by do |method_info|
    method_info.class
  end
  grouped_methods.each do |method_info_class, method_infos|
    next if method_infos.empty?
    case method_infos.first
    when ConstructorInfo
      load_methods_constructor(method_infos, klass)
    when MethodInfo
      load_methods_method(method_infos, klass)
    when FunctionInfo
      load_methods_function(method_infos, klass)
    else
      raise "TODO: #{method_info_class}"
    end
  end
  if klass.method_defined?(:each) and
      klass.instance_method(:each).owner == klass
    klass.include(Enumerable)
  end
end
load_methods_constructor(infos, klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 338
    def load_methods_constructor(infos, klass)
      return if infos.empty?

      klass.const_set(:LOADER_CLASS, self.class)
      invokers = {}
      klass.const_set(:INITIALIZE_INVOKERS, invokers)
      infos.each do |info|
        name = "initialize_#{info.name}"
        prepare_function_info_lock_gvl(info, klass)
        invoker = Invoker.new(info, name, "#{klass}\##{name}")
        invokers[name] = invoker
        klass.class_eval(<<-DEFINE_METHOD, __FILE__, __LINE__ + 1)
          def #{name}(*arguments, &block)
            invoker = INITIALIZE_INVOKERS["#{name}"]
            invoker.invoke(self, arguments, block)
            LOADER_CLASS.initialize_instance_post(self)
          end
          private :#{name}
        DEFINE_METHOD
      end

      klass.class_eval(<<-DEFINE_METHOD, __FILE__, __LINE__ + 1)
        def initialize(*arguments, &block)
          invokers = INITIALIZE_INVOKERS
          invokers.values.each do |invoker|
            catch do |tag|
              invoker.invoke(self, arguments.dup, block, tag)
              LOADER_CLASS.initialize_instance_post(self)
              return
            end
          end
          full_method_name = "\#{self.class.name}\#\#{__method__}"
          message = "wrong arguments: "
          message << "\#{full_method_name}("
          message << arguments.collect(&:inspect).join(", ")
          message << "):\\n"
          message << "available signatures:"
          invokers.each_value do |invoker|
            message << "\\n\#{full_method_name}\#{invoker.signature}"
          end
          raise ArgumentError, message
        end
      DEFINE_METHOD
      Ractor.make_shareable(klass::INITIALIZE_INVOKERS) if defined?(Ractor)
    end
load_methods_function(infos, klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 604
def load_methods_function(infos, klass)
  infos.each do |info|
    name = rubyish_method_name(info)
    next if name == "new"
    next if name == "alloc"
    load_function_info_singleton_method(info, klass, name)
  end
end
load_methods_method(infos, klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 552
def load_methods_method(infos, klass)
  infos.each do |info|
    method_name = rubyish_method_name(info)
    load_method_info(info, klass, method_name)
  end
end
load_object_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 248
def load_object_info(info)
  return if info.gtype == GLib::Type::NONE
  # e.g.: GstBitmask
  return if info.fundamental? and !info.gtype.instantiatable?
  klass = self.class.define_class(info.gtype,
                                  rubyish_class_name(info),
                                  @base_module)
  prepare_class(klass) do
    load_virtual_functions(info, klass)
    load_fields(info, klass)
    load_methods(info, klass)
  end
end
load_struct_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 141
def load_struct_info(info)
  case info.name
  when /Class\z/
    base_class_name = rubyish_class_name(info)
    method_infos = info.methods.find_all do |method_info|
      method_info.is_a?(MethodInfo)
    end
    unless method_infos.empty?
      base_class = @base_module.const_get(base_class_name)
      singleton_class = base_class.singleton_class
      invokers = singleton_class.const_get(:INVOKERS).dup
      singleton_class.__send__(:remove_const, :INVOKERS)
      singleton_class.const_set(:INVOKERS, invokers)
      load_methods_method(method_infos, singleton_class)
      Ractor.make_shareable(singleton_class::INVOKERS) if defined?(Ractor)
      singleton_class.private_constant(:INVOKERS)
    end
  else
    return if info.gtype_struct?

    define_struct(info)
  end
end
load_union_info(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 633
def load_union_info(info)
  return if info.gtype == GLib::Type::NONE
  klass = self.class.define_class(info.gtype, info.name, @base_module)
  prepare_class(klass) do
    load_fields(info, klass)
    load_methods(info, klass)
  end
end
load_virtual_functions(info, klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 384
def load_virtual_functions(info, klass)
  klass.extend(VirtualFunctionImplementable)
  gtype_prefix = rubyish_gtype_name(klass.gtype.name)
  implementor = VirtualFunctionImplementor.new(self.class,
                                               gtype_prefix,
                                               info.vfuncs)
  klass.__send__(:initialize_virtual_function_implementable,
                 implementor)
end
post_load(repository, namespace) click to toggle source
# File lib/gobject-introspection/loader.rb, line 57
def post_load(repository, namespace)
end
post_methods_module(mod) click to toggle source
# File lib/gobject-introspection/loader.rb, line 673
def post_methods_module(mod)
  return unless defined?(Ractor)
  Ractor.make_shareable(mod::INVOKERS)
  mod.private_constant(:INVOKERS)
end
post_prepare_class(klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 653
def post_prepare_class(klass)
  return unless defined?(Ractor)
  Ractor.make_shareable(klass::INVOKERS)
  Ractor.make_shareable(klass.singleton_class::INVOKERS)
  klass.private_constant(:INVOKERS)
  klass.singleton_class.private_constant(:INVOKERS)
end
pre_load(repository, namespace) click to toggle source
# File lib/gobject-introspection/loader.rb, line 54
def pre_load(repository, namespace)
end
pre_prepare_class(klass) click to toggle source
# File lib/gobject-introspection/loader.rb, line 648
def pre_prepare_class(klass)
  klass.const_set(:INVOKERS, {})
  klass.singleton_class.const_set(:INVOKERS, {})
end
prepare_class(klass) { || ... } click to toggle source
# File lib/gobject-introspection/loader.rb, line 642
def prepare_class(klass)
  pre_prepare_class(klass)
  yield
  post_prepare_class(klass)
end
prepare_function_info_lock_gvl(function_info, target_module) click to toggle source
# File lib/gobject-introspection/loader.rb, line 544
def prepare_function_info_lock_gvl(function_info, target_module)
  # For backward compatibility
  if respond_to?(:should_unlock_gvl?)
    function_info.lock_gvl_default =
      !should_unlock_gvl?(function_info, target_module)
  end
end
remove_existing_method(klass, method_name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 565
def remove_existing_method(klass, method_name)
  return unless klass.method_defined?(method_name)
  return unless klass.instance_method(method_name).owner == klass
  klass.__send__(:remove_method, method_name)
end
rubyish_class_name(info) click to toggle source
# File lib/gobject-introspection/loader.rb, line 529
def rubyish_class_name(info)
  name = info.name
  case info
  when StructInfo
    case name
    when /Class\z/
      $PREMATCH
    else
      name
    end
  else
    name
  end
end
rubyish_field_reader_name(field_info, name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 514
def rubyish_field_reader_name(field_info, name)
  case field_info.type.tag
  when TypeTag::BOOLEAN
    name.gsub(/\Ais_/, "") + "?"
  when TypeTag::UINT32
    if /\Ais_/ =~ name
      "#{$POSTMATCH}?"
    else
      name
    end
  else
    name
  end
end
rubyish_gtype_name(name) click to toggle source
# File lib/gobject-introspection/loader.rb, line 394
def rubyish_gtype_name(name)
  name.scan(/[A-Z]+[a-z\d]+/).collect(&:downcase).join("_")
end
rubyish_method_name(function_info, options={}) click to toggle source
# File lib/gobject-introspection/loader.rb, line 398
def rubyish_method_name(function_info, options={})
  name = function_info.name
  if options[:prefix]
    name = name.gsub(/\A#{Regexp.escape(options[:prefix])}/, "")
  end
  if name == "initialize"
    name += "_raw"
  end

  n_in_args = function_info.n_in_args
  if options[:n_in_args_offset]
    n_in_args += options[:n_in_args_offset]
  end

  return_type = function_info.return_type
  return_type_tag = return_type.tag
  if return_type_tag == TypeTag::VOID
    out_arg_tags = function_info.out_args.collect {|arg| arg.type.tag}
    if out_arg_tags == [TypeTag::ARRAY, TypeTag::INT32]
      return_type_tag = TypeTag::ARRAY
    end
  end

  case return_type_tag
  when TypeTag::BOOLEAN
    case name
    when "equal"
      if n_in_args == 1
        "=="
      else
        name
      end
    when "not_equal"
      if n_in_args == 1
        "!="
      else
        name
      end
    when "less_than"
      if n_in_args == 1
        "<"
      else
        name
      end
    when "less_than_or_equal"
      if n_in_args == 1
        "<="
      else
        name
      end
    when "greater_than"
      if n_in_args == 1
        ">"
      else
        name
      end
    when "greater_than_or_equal"
      if n_in_args == 1
        ">="
      else
        name
      end
    when /\A(?:is|get_is|can_be)_/
      "#{$POSTMATCH}?"
    when /\Aget_/
      if n_in_args.zero?
        if function_info.n_out_args.zero?
          "#{$POSTMATCH}?"
        else
          $POSTMATCH
        end
      else
        name
      end
    when /\A(?:has|use|can|in|on|.*_is)_/
      "#{name}?"
    when "exists"
      "exist?"
    else
      name
    end
  when TypeTag::GLIST, TypeTag::GSLIST, TypeTag::ARRAY
    case name
    when /\A(?:list|get)_/
      if n_in_args.zero?
        $POSTMATCH
      else
        name
      end
    else
      name
    end
  else
    case name
    when /\Aget_/
      if n_in_args.zero?
        $POSTMATCH
      else
        name
      end
    when "to_string"
      if n_in_args.zero?
        "to_s"
      else
        name
      end
    when "to_integer"
      "to_i"
    when "foreach"
      "each"
    else
      name
    end
  end
end