class GObjectIntrospection::Loader
Attributes
version[RW]
Public Class Methods
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 30 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 35 def load(namespace) repository = Repository.default repository.require(namespace, @version) pre_load(repository, namespace) repository.each(namespace) do |info| load_info(info) end post_load(repository, namespace) end
Private Instance Methods
build_arguments(info, arguments, &block)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 330 def build_arguments(info, arguments, &block) last_in_arg = info.in_args.last if block and last_in_arg and last_in_arg.gclosure? [arguments + [block], nil] else [arguments, block] end end
define_boxed(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 154 def define_boxed(info) 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_enum(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 170 def define_enum(info) self.class.define_class(info.gtype, enum_class_name(info), @base_module) end
define_equal_style_setter(info, klass, method_name)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 561 def define_equal_style_setter(info, klass, method_name) if /\Aset_/ =~ method_name and info.n_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 180 def define_error(info) self.class.define_error(info.error_domain, error_class_name(info), @base_module, :parent => error_parent_class(info), :gtype => info.gtype) end
define_method(info, klass, method_name)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 529 def define_method(info, klass, method_name) unlock_gvl = should_unlock_gvl?(info, klass) remove_existing_method(klass, method_name) function_info_p = (info.class == FunctionInfo) no_return_value_p = (info.return_type.tag == TypeTag::VOID and info.n_out_args.zero?) prepare = lambda do |arguments, &block| arguments, block = build_arguments(info, arguments, &block) validate_arguments(info, "#{klass}\##{method_name}", arguments) [arguments, block] end klass.__send__(:define_method, method_name) do |*arguments, &block| arguments = [self] + arguments if function_info_p arguments, block = prepare.call(arguments, &block) if block.nil? and info.require_callback? to_enum(method_name, *arguments) else options = { :arguments => arguments, :unlock_gvl => unlock_gvl, } options[:receiver] = self unless function_info_p return_value = info.invoke(options, &block) if no_return_value_p self else return_value end end end end
define_module_function(target_module, name, function_info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 80 def define_module_function(target_module, name, function_info) unlock_gvl = should_unlock_gvl?(function_info, target_module) prepare = lambda do |arguments, &block| arguments, block = build_arguments(function_info, arguments, &block) method_name = "#{target_module}\#.#{name}" validate_arguments(function_info, method_name, arguments) [arguments, block] end target_module.module_eval do define_method(name) do |*arguments, &block| arguments, block = prepare.call(arguments, &block) function_info.invoke({ :arguments => arguments, :unlock_gvl => unlock_gvl, }, &block) end module_function(name) end end
define_singleton_method(klass, name, info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 101 def define_singleton_method(klass, name, info) unlock_gvl = should_unlock_gvl?(info, klass) prepare = lambda do |arguments| arguments, block = build_arguments(info, arguments, &block) validate_arguments(info, "#{klass}.#{name}", arguments) [arguments, block] end singleton_class = (class << klass; self; end) singleton_class.__send__(:define_method, name) do |*arguments, &block| arguments, block = prepare.call(arguments, &block) if block.nil? and info.require_callback? to_enum(name, *arguments) else info.invoke({ :arguments => arguments, :unlock_gvl => unlock_gvl, }, &block) end end end
define_struct(info, options={})
click to toggle source
# File lib/gobject-introspection/loader.rb, line 123 def define_struct(info, options={}) if info.gtype == GLib::Type::NONE klass = self.class.define_struct(info.size, info.name, @base_module, :parent => options[:parent]) else klass = self.class.define_class(info.gtype, info.name, @base_module, :parent => options[:parent], :size => info.size) end load_fields(info, klass) load_methods(info, klass) end
enum_class_name(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 176 def enum_class_name(info) info.name end
error_class_name(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 188 def error_class_name(info) info.name end
error_parent_class(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 192 def error_parent_class(info) nil end
field_name(field_info, klass)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 245 def field_name(field_info, klass) field_info.name end
find_suitable_callable_info(infos, arguments)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 354 def find_suitable_callable_info(infos, arguments) min_n_args = nil max_n_args = nil candidate_infos = [] infos.each do |info| n_in_args = info.n_in_args n_required_in_args = info.n_required_in_args if (n_required_in_args..n_in_args).cover?(arguments.size) candidate_infos << info end min_n_args = [min_n_args || n_required_in_args, n_required_in_args].min max_n_args = [max_n_args || n_in_args, n_in_args].max end if candidate_infos.size == 1 return candidate_infos.first elsif candidate_infos.size > 1 candidate_info = candidate_infos.find do |info| in_arg_infos = info.in_args arguments.each.with_index.all? do |argument, i| match_argument?(in_arg_infos[i], argument) end end return candidate_info || candidate_infos.first end detail = "#{arguments.size} for #{min_n_args}" if min_n_args < max_n_args detail << "..#{max_n_args}" end raise ArgumentError, "wrong number of arguments (#{detail})" end
flags_class_name(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 228 def flags_class_name(info) info.name end
initialize_post(object)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 327 def initialize_post(object) end
load_boxed_info(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 162 def load_boxed_info(info) define_boxed(info) end
load_constant_info(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 584 def load_constant_info(info) @base_module.const_set(info.name, info.value) end
load_constructor_infos(infos, klass)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 291 def load_constructor_infos(infos, klass) return if infos.empty? prepare = lambda do |info, method_name, arguments, &block| arguments, block = build_arguments(info, arguments, &block) validate_arguments(info, "#{klass}\##{method_name}", arguments) [arguments, block] end call_initialize_post = lambda do |object| initialize_post(object) end infos.each do |info| name = "initialize_#{info.name}" unlock_gvl = should_unlock_gvl?(info, klass) klass.__send__(:define_method, name) do |*arguments, &block| arguments, block = prepare.call(info, name, arguments, &block) info.invoke({ :receiver => self, :arguments => arguments, :unlock_gvl => unlock_gvl, }, &block) call_initialize_post.call(self) end klass.__send__(:private, name) end find_info = lambda do |arguments| find_suitable_callable_info(infos, arguments) end klass.__send__(:define_method, "initialize") do |*arguments, &block| info = find_info.call(arguments, &block) __send__("initialize_#{info.name}", *arguments, &block) end end
load_enum_info(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 196 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(info.name, 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 166 def load_enum_value(value_info, enum_module) enum_module.const_set(value_info.name.upcase, value_info.value) end
load_field(info, i, field_info, klass)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 249 def load_field(info, i, field_info, klass) name = field_name(field_info, klass) flags = field_info.flags if flags.readable? if field_info.type.tag == TypeTag::BOOLEAN reader_method_name = "#{name}?" else reader_method_name = name end remove_existing_method(klass, reader_method_name) klass.__send__(:define_method, reader_method_name) do || info.get_field_value(self, i) end end if flags.writable? klass.__send__(:define_method, "#{name}=") do |value| info.set_field_value(self, i, value) end end end
load_fields(info, klass)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 238 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 212 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 216 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(info.name, flags_module) else self.class.define_class(info.gtype, flags_class_name(info), @base_module) end end
load_function_info(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 75 def load_function_info(info) name = rubyish_method_name(info) define_singleton_method(@base_module, name, info) end
load_function_infos(infos, klass)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 569 def load_function_infos(infos, klass) infos.each do |info| name = rubyish_method_name(info) next if name == "new" next if name == "alloc" define_singleton_method(klass, name, info) end end
load_info(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 52 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 578 def load_interface_info(info) interface_module = self.class.define_interface(info.gtype, info.name, @base_module) load_methods(info, interface_module) end
load_method_info(info, klass, method_name)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 518 def load_method_info(info, klass, method_name) define_method(info, klass, method_name) define_equal_style_setter(info, klass, method_name) end
load_method_infos(infos, klass)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 511 def load_method_infos(infos, klass) infos.each do |info| method_name = rubyish_method_name(info) load_method_info(info, klass, method_name) end end
load_methods(info, klass)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 272 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_constructor_infos(method_infos, klass) when MethodInfo load_method_infos(method_infos, klass) when FunctionInfo load_function_infos(method_infos, klass) else raise "TODO: #{method_info_class}" end end end
load_object_info(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 232 def load_object_info(info) klass = self.class.define_class(info.gtype, info.name, @base_module) load_fields(info, klass) load_methods(info, klass) end
load_struct_info(info)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 136 def load_struct_info(info) case info.name when /Class\z/ base_class_name = $PREMATCH method_infos = info.methods.find_all do |method_info| method_info.is_a?(MethodInfo) end unless methods.empty? base_class = @base_module.const_get(base_class_name) load_method_infos(method_infos, base_class.singleton_class) 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 588 def load_union_info(info) klass = self.class.define_class(info.gtype, info.name, @base_module) load_fields(info, klass) load_methods(info, klass) end
match_argument?(arg_info, argument)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 387 def match_argument?(arg_info, argument) type = arg_info.type case type.tag when TypeTag::BOOLEAN argument == true or argument == false when TypeTag::INT8, TypeTag::UINT8, TypeTag::INT16, TypeTag::UINT16, TypeTag::INT32, TypeTag::UINT32, TypeTag::INT64, TypeTag::UINT64, TypeTag::FLOAT, TypeTag::DOUBLE argument.is_a?(Numeric) when TypeTag::GTYPE argument.is_a?(GLib::Type) when TypeTag::UTF8 argument.is_a?(String) when TypeTag::FILENAME argument.is_a?(String) when TypeTag::ARRAY argument.is_a?(Array) when TypeTag::INTERFACE interface = type.interface case interface.type when InfoType::STRUCT match_argument_interface_struct?(arg_info, interface, argument) when InfoType::OBJECT, InfoType::INTERFACE argument.is_a?(interface.gtype.to_class) else # TODO false end when TypeTag::GLIST, TypeTag::GSLIST argument.is_a?(Array) else # TODO false end end
match_argument_interface_struct?(arg_info, interface, argument)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 432 def match_argument_interface_struct?(arg_info, interface, argument) gtype = interface.gtype case gtype.name when "void" # TODO false when "CairoSurface" if Object.const_defined?(:Cairo) argument.is_a?(Cairo::Surface) else false end else argument.is_a?(gtype.to_class) end end
post_load(repository, namespace)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 49 def post_load(repository, namespace) end
pre_load(repository, namespace)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 46 def pre_load(repository, namespace) end
remove_existing_method(klass, method_name)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 523 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_method_name(function_info, options={})
click to toggle source
# File lib/gobject-introspection/loader.rb, line 449 def rubyish_method_name(function_info, options={}) name = function_info.name if options[:prefix] name = name.gsub(/\A#{Regexp.escape(options[:prefix])}/, "") end return_type = function_info.return_type return_type_tag = return_type.tag case return_type_tag when TypeTag::BOOLEAN case name when /\A(?:is|get_is)_/ "#{$POSTMATCH}?" when /\Aget_/ if function_info.n_in_args.zero? if function_info.n_out_args.zero? "#{$POSTMATCH}?" else $POSTMATCH end else name end when /\A(?:has|use|can|in|.*_is)_/ "#{name}?" when "exists" "exist?" else name end when TypeTag::GLIST, TypeTag::GSLIST case name when /\A(?:list|get)_/ if function_info.n_in_args.zero? $POSTMATCH else name end else name end else case name when /\Aget_/ if function_info.n_in_args.zero? $POSTMATCH else name end when "to_string" "to_s" when "foreach" "each" else name end end end
should_unlock_gvl?(function_info, klass)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 507 def should_unlock_gvl?(function_info, klass) false end
validate_arguments(info, method_name, arguments)
click to toggle source
# File lib/gobject-introspection/loader.rb, line 339 def validate_arguments(info, method_name, arguments) n_in_args = info.n_in_args n_required_in_args = info.n_required_in_args return if (n_required_in_args..n_in_args).cover?(arguments.size) detail = "#{arguments.size} for " if n_in_args == n_required_in_args detail << "#{n_in_args}" else detail << "#{n_required_in_args}..#{n_in_args}" end message = "#{method_name}: wrong number of arguments (#{detail})" raise ArgumentError, message end