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