module GLib module Deprecatable unless respond_to?(:define_singleton_method) def define_singleton_method(name, &block) singleton_class = class << self; self; end singleton_class.__send__(:define_method, name, &block) end end @@deprecated_const = {} def define_deprecated_const(deprecated_const, new_const = {}) @@deprecated_const[self] ||= {} @@deprecated_const[self][deprecated_const.to_sym] = new_const end def define_deprecated_enums(enums, prefix = nil) enums = resolve_constant_name(enums.to_s) enums.constants.each do |const| deprecated_const = prefix ? "#{prefix}_#{const}" : const new_const = [enums, const].join('::') define_deprecated_const(deprecated_const, new_const) end end alias :define_deprecated_flags :define_deprecated_enums def define_deprecated_singleton_method(deprecated_method, new_method = {}, &block) __define_deprecated_method__(:singleton, deprecated_method, new_method, &block) end def define_deprecated_method(deprecated_method, new_method = {}, &block) __define_deprecated_method__(:instance, deprecated_method, new_method, &block) end def define_deprecated_method_by_hash_args(deprecated_method, old_args, new_args, req_argc = 0, &block) klass = self alias_name = "__deprecatable_#{object_id}_#{deprecated_method}__" alias_method alias_name, deprecated_method private alias_name define_method(deprecated_method) do |*margs, &mblock| if (margs.size == req_argc) || (margs.size == (req_argc + 1) && margs.last.is_a?(Hash)) else margs = block.call(self, *margs, &mblock) msg = "#{caller[0]}: '#{klass}##{deprecated_method}(#{old_args})' style has been deprecated." warn "#{msg} Use '#{klass}##{deprecated_method}(#{new_args})' style." end __send__(alias_name, *margs, &mblock) end end @@deprecated_signal = {} def define_deprecated_signal(deprecated_signal, new_signal = {}) @@deprecated_signal[self] ||= {} @@deprecated_signal[self][deprecated_signal.to_s.gsub('_', '-').to_sym] = new_signal end def self.extended(class_or_module) GLib::Instantiatable.class_eval do %w(signal_connect signal_connect_after).each do |connect_method| alias_name = "__deprecatable_#{connect_method}__" next if private_method_defined?(alias_name) alias_method alias_name, connect_method private alias_name define_method(connect_method) do |signal, *margs, &mblock| signal = signal.to_s.gsub('_', '-').to_sym signals = @@deprecated_signal[self] if new_signal = (signals || {})[signal] msg = "#{caller[0]}: '#{signal}' signal has been deprecated." case new_signal when String, Symbol warn "#{msg} Use '#{new_signal}' signal." signal = new_signal when Hash if new_signal[:raise] raise DeprecatedError.new("#{msg} #{new_signal[:raise]}") elsif new_signal[:warn] warn "#{msg} #{new_signal[:warn]}" else warn "#{msg} Don't use this signal anymore." end return end end __send__(alias_name, signal, *margs, &mblock) end end end end private def const_missing(deprecated_const) new_const = (@@deprecated_const[self] || {})[deprecated_const.to_sym] if new_const.nil? return super end msg = "#{caller[0]}: '#{[name, deprecated_const].join('::')}' has been deprecated." case new_const when String, Symbol new_const_val = resolve_constant_name(new_const) case new_const_val when GLib::Enum, GLib::Flags alt = " or ':#{new_const_val.nick.gsub('-', '_')}'" end warn "#{msg} Use '#{new_const}'#{alt}." return const_set(deprecated_const, new_const_val) when Hash if new_const[:raise] raise DeprecatedError.new("#{msg} #{new_const[:raise]}") elsif new_const[:warn] warn "#{msg} #{new_const[:warn]}" else warn "#{msg} Don't use this constant anymore." end return else super end end def resolve_constant_name(name) name.to_s.split("::").inject(nil) do |context, local_name| if context.nil? candidates = [] candidate_context = ::Object self.to_s.split("::").each do |candidate_name| candidate = candidate_context.const_get(candidate_name) candidates.unshift(candidate) candidate_context = candidate end context = candidates.find do |candidate| candidate.const_defined?(local_name) end context ||= ::Object end context.const_get(local_name) end end def __define_deprecated_method__(type, deprecated_method, new_method = {}, &block) def_method = type == :singleton ? :define_singleton_method : :define_method sep = type == :singleton ? '.' : '#' klass = self __send__(def_method, deprecated_method) do |*margs, &mblock| msg = "#{caller[0]}: '#{klass}#{sep}#{deprecated_method}' has been deprecated." case new_method when String, Symbol warn "#{msg} Use '#{klass}#{sep}#{new_method}'." __send__(new_method, *margs, &mblock) when Hash if new_method[:raise] raise DeprecatedError.new("#{msg} #{new_method[:raise]}") elsif new_method[:warn] warn "#{msg} #{new_method[:warn]}" block.call(self, *margs, &mblock) if block end end end end end class DeprecatedError < RuntimeError end end