module YARD::CodeObjects # A ClassObject represents a Ruby class in source code. It is a {ModuleObject} # with extra inheritance semantics through the superclass. class ClassObject < NamespaceObject # The {ClassObject} that this class object inherits from in Ruby source. # @return [ClassObject] a class object that is the superclass of this one attr_reader :superclass # Creates a new class object in +namespace+ with +name+ # # @see Base.new def initialize(namespace, name, *args, &block) super if is_exception? self.superclass ||= "::Exception" unless P(namespace, name) == P(:Exception) else case P(namespace, name).path when "BasicObject" nil when "Object" self.superclass ||= "::BasicObject" else self.superclass ||= "::Object" end end end # Whether or not the class is a Ruby Exception # # @return [Boolean] whether the object represents a Ruby exception def is_exception? inheritance_tree.reverse.any? {|o| BUILTIN_EXCEPTIONS_HASH.has_key? o.path } end # Returns the inheritance tree of the object including self. # # @param [Boolean] include_mods whether or not to include mixins in the # inheritance tree. # @return [Array] the list of code objects that make up # the inheritance tree. def inheritance_tree(include_mods = false) list = (include_mods ? mixins(:instance, :class) : []) if superclass.is_a?(Proxy) || superclass.respond_to?(:inheritance_tree) list += [superclass] unless superclass == P(:Object) || superclass == P(:BasicObject) end [self] + list.map do |m| next m if m == self next m unless m.respond_to?(:inheritance_tree) m.inheritance_tree(include_mods) end.flatten.uniq end # Returns the list of methods matching the options hash. Returns # all methods if hash is empty. # # @param [Hash] opts the options hash to match # @option opts [Boolean] :inherited (true) whether inherited methods should be # included in the list # @option opts [Boolean] :included (true) whether mixed in methods should be # included in the list # @return [Array] the list of methods that matched def meths(opts = {}) opts = SymbolHash[:inherited => true].update(opts) list = super(opts) list += inherited_meths(opts).reject do |o| next(false) if opts[:all] list.find {|o2| o2.name == o.name && o2.scope == o.scope } end if opts[:inherited] list end # Returns only the methods that were inherited. # # @return [Array] the list of inherited method objects def inherited_meths(opts = {}) inheritance_tree[1..-1].inject([]) do |list, superclass| if superclass.is_a?(Proxy) list else list += superclass.meths(opts).reject do |o| next(false) if opts[:all] child(:name => o.name, :scope => o.scope) || list.find {|o2| o2.name == o.name && o2.scope == o.scope } end end end end # Returns the list of constants matching the options hash. # # @param [Hash] opts the options hash to match # @option opts [Boolean] :inherited (true) whether inherited constant should be # included in the list # @option opts [Boolean] :included (true) whether mixed in constant should be # included in the list # @return [Array] the list of constant that matched def constants(opts = {}) opts = SymbolHash[:inherited => true].update(opts) super(opts) + (opts[:inherited] ? inherited_constants : []) end # Returns only the constants that were inherited. # # @return [Array] the list of inherited constant objects def inherited_constants inheritance_tree[1..-1].inject([]) do |list, superclass| if superclass.is_a?(Proxy) list else list += superclass.constants.reject do |o| child(:name => o.name) || list.find {|o2| o2.name == o.name } end end end end # Sets the superclass of the object # # @param [Base, Proxy, String, Symbol, nil] object the superclass value # @return [void] def superclass=(object) case object when Base, Proxy, NilClass @superclass = object when String, Symbol @superclass = Proxy.new(namespace, object) else raise ArgumentError, "superclass must be CodeObject, Proxy, String or Symbol" end if name == @superclass.name && namespace != YARD::Registry.root && !object.is_a?(Base) @superclass = Proxy.new(namespace.namespace, object) end if @superclass == self msg = "superclass #{@superclass.inspect} cannot be the same as the declared class #{self.inspect}" @superclass = P("::Object") raise ArgumentError, msg end end end end