-
-
Notifications
You must be signed in to change notification settings - Fork 392
/
class_object.rb
145 lines (133 loc) · 4.99 KB
/
class_object.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
module YARD::CodeObjects
register_separator NSEP, :class
# 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.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<NamespaceObject>] 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<MethodObject>] 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<MethodObject>] 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<ConstantObject>] 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<ConstantObject>] 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 #{inspect}"
@superclass = P("::Object")
raise ArgumentError, msg
end
end
end
end