Skip to content

Ignore constants discovered in passing #599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 30 additions & 13 deletions lib/rdoc/context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -407,13 +407,18 @@ def add_class_or_module mod, self_hash, all_hash
mod.section = current_section # TODO declaring context? something is
# wrong here...
mod.parent = self
mod.full_name = nil
mod.store = @store

unless @done_documenting then
self_hash[mod.name] = mod
# this must be done AFTER adding mod to its parent, so that the full
# name is correct:
all_hash[mod.full_name] = mod
if @store.unmatched_constant_alias[mod.full_name] then
to, file = @store.unmatched_constant_alias[mod.full_name]
add_module_alias mod, mod.name, to, file
end
end

mod
Expand Down Expand Up @@ -510,41 +515,53 @@ def add_module(class_type, name)
add_class_or_module mod, @modules, @store.modules_hash
end

##
# Adds a module by +RDoc::NormalModule+ instance. See also #add_module.

def add_module_by_normal_module(mod)
add_class_or_module mod, @modules, @store.modules_hash
end

##
# Adds an alias from +from+ (a class or module) to +name+ which was defined
# in +file+.

def add_module_alias from, name, file
def add_module_alias from, from_name, to, file
return from if @done_documenting

to_name = child_name name
to_full_name = child_name to.name

# if we already know this name, don't register an alias:
# see the metaprogramming in lib/active_support/basic_object.rb,
# where we already know BasicObject is a class when we find
# BasicObject = BlankSlate
return from if @store.find_class_or_module to_name
return from if @store.find_class_or_module to_full_name

unless from
@store.unmatched_constant_alias[child_name(from_name)] = [to, file]
return to
end

to = from.dup
to.name = name
to.full_name = nil
new_to = from.dup
new_to.name = to.name
new_to.full_name = nil

if to.module? then
@store.modules_hash[to_name] = to
@modules[name] = to
if new_to.module? then
@store.modules_hash[to_full_name] = new_to
@modules[to.name] = new_to
else
@store.classes_hash[to_name] = to
@classes[name] = to
@store.classes_hash[to_full_name] = new_to
@classes[to.name] = new_to
end

# Registers a constant for this alias. The constant value and comment
# will be updated later, when the Ruby parser adds the constant
const = RDoc::Constant.new name, nil, to.comment
const = RDoc::Constant.new to.name, nil, new_to.comment
const.record_location file
const.is_alias_for = from
add_constant const

to
new_to
end

##
Expand Down
22 changes: 17 additions & 5 deletions lib/rdoc/parser/ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ def create_module_alias container, constant, rhs_name # :nodoc:
container.find_module_named rhs_name
end

container.add_module_alias mod, constant.name, @top_level if mod
container.add_module_alias mod, rhs_name, constant, @top_level
end

##
Expand Down Expand Up @@ -356,12 +356,15 @@ def get_class_or_module container, ignore_constants = false
given_name << name_t[:text]

is_self = name_t[:kind] == :on_op && name_t[:text] == '<<'
new_modules = []
while !is_self && (tk = peek_tk) and :on_op == tk[:kind] and '::' == tk[:text] do
prev_container = container
container = container.find_module_named name_t[:text]
container ||=
if ignore_constants then
RDoc::Context.new
c = RDoc::NormalModule.new name_t[:text]
new_modules << [prev_container, c]
c
else
c = prev_container.add_module RDoc::NormalModule, name_t[:text]
c.ignore unless prev_container.document_children
Expand All @@ -386,7 +389,7 @@ def get_class_or_module container, ignore_constants = false

skip_tkspace false

return [container, name_t, given_name]
return [container, name_t, given_name, new_modules]
end

##
Expand Down Expand Up @@ -761,7 +764,7 @@ def parse_class container, single, tk, comment
line_no = tk[:line_no]

declaration_context = container
container, name_t, given_name = get_class_or_module container
container, name_t, given_name, = get_class_or_module container

if name_t[:kind] == :on_const
cls = parse_class_regular container, declaration_context, single,
Expand Down Expand Up @@ -878,10 +881,11 @@ def parse_constant container, tk, comment, ignore_constants = false

return unless name =~ /^\w+$/

new_modules = []
if :on_op == peek_tk[:kind] && '::' == peek_tk[:text] then
unget_tk tk

container, name_t, = get_class_or_module container, ignore_constants
container, name_t, _, new_modules = get_class_or_module container, true

name = name_t[:text]
end
Expand All @@ -908,6 +912,14 @@ def parse_constant container, tk, comment, ignore_constants = false
end
get_tk

unless ignore_constants
new_modules.each do |prev_c, new_module|
prev_c.add_module_by_normal_module new_module
new_module.ignore unless prev_c.document_children
@top_level.add_to_classes_or_modules new_module
end
end

value = ''
con = RDoc::Constant.new name, value, comment

Expand Down
7 changes: 7 additions & 0 deletions lib/rdoc/store.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ def message # :nodoc:

attr_accessor :encoding

##
# The lazy constants alias will be discovered in passing

attr_reader :unmatched_constant_alias

##
# Creates a new Store of +type+ that will load or save to +path+

Expand Down Expand Up @@ -152,6 +157,8 @@ def initialize path = nil, type = nil

@unique_classes = nil
@unique_modules = nil

@unmatched_constant_alias = {}
end

##
Expand Down
12 changes: 8 additions & 4 deletions test/test_rdoc_class_module.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1277,7 +1277,8 @@ def test_update_aliases_class
n1 = @xref_data.add_module RDoc::NormalClass, 'N1'
n1_k2 = n1.add_module RDoc::NormalClass, 'N2'

n1.add_module_alias n1_k2, 'A1', @xref_data
a1 = RDoc::Constant.new 'A1', '', ''
n1.add_module_alias n1_k2, n1_k2.name, a1, @xref_data

n1_a1_c = n1.constants.find { |c| c.name == 'A1' }
refute_nil n1_a1_c
Expand All @@ -1301,7 +1302,8 @@ def test_update_aliases_module
n1 = @xref_data.add_module RDoc::NormalModule, 'N1'
n1_n2 = n1.add_module RDoc::NormalModule, 'N2'

n1.add_module_alias n1_n2, 'A1', @xref_data
a1 = RDoc::Constant.new 'A1', '', ''
n1.add_module_alias n1_n2, n1_n2.name, a1, @xref_data

n1_a1_c = n1.constants.find { |c| c.name == 'A1' }
refute_nil n1_a1_c
Expand All @@ -1326,7 +1328,8 @@ def test_update_aliases_reparent
l1_l2 = l1.add_module RDoc::NormalModule, 'L2'
o1 = @xref_data.add_module RDoc::NormalModule, 'O1'

o1.add_module_alias l1_l2, 'A1', @xref_data
a1 = RDoc::Constant.new 'A1', '', ''
o1.add_module_alias l1_l2, l1_l2.name, a1, @xref_data

o1_a1_c = o1.constants.find { |c| c.name == 'A1' }
refute_nil o1_a1_c
Expand Down Expand Up @@ -1358,7 +1361,8 @@ def test_update_aliases_reparent_root
const.record_location top_level
const.is_alias_for = klass

top_level.add_module_alias klass, 'A', top_level
a = RDoc::Constant.new 'A', '', ''
top_level.add_module_alias klass, klass.name, a, top_level

object.add_constant const

Expand Down
6 changes: 4 additions & 2 deletions test/test_rdoc_context.rb
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ def test_add_module
def test_add_module_alias
tl = @store.add_file 'file.rb'

c3_c4 = @c2.add_module_alias @c2_c3, 'C4', tl
c4 = RDoc::Constant.new 'C4', '', ''
c3_c4 = @c2.add_module_alias @c2_c3, @c2_c3.name, c4, tl

alias_constant = @c2.constants.first

Expand All @@ -298,7 +299,8 @@ def test_add_module_alias_top_level

object = top_level.add_class RDoc::NormalClass, 'Object'

top_level.add_module_alias klass, 'A', top_level
a = RDoc::Constant.new 'A', '', ''
top_level.add_module_alias klass, klass.name, a, top_level

refute_empty object.constants

Expand Down
2 changes: 1 addition & 1 deletion test/test_rdoc_generator_darkfish.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def setup

@top_level.add_constant @alias_constant

@klass.add_module_alias @klass, 'A', @top_level
@klass.add_module_alias @klass, @klass.name, @alias_constant, @top_level

@meth = RDoc::AnyMethod.new nil, 'method'
@meth_bang = RDoc::AnyMethod.new nil, 'method!'
Expand Down
146 changes: 146 additions & 0 deletions test/test_rdoc_parser_ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3928,4 +3928,150 @@ def util_two_parsers(first_file_content, second_file_content)
second_file_content, @options, @stats
end

def test_parse_const_third_party
util_parser <<-CLASS
class A
true if B
true if B::C
true if B::C::D

module B
end
end
CLASS

tk = @parser.get_tk

@parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment

a = @top_level.classes.first
assert_equal 'A', a.full_name

visible = @store.all_modules.reject { |mod| mod.suppressed? }
visible = visible.map { |mod| mod.full_name }

assert_equal ['A::B'], visible
end

def test_parse_const_alias_defined_elsewhere
util_parser <<-CLASS
module A
Aliased = Defined
end

module A
class Defined
end
end
CLASS

@parser.scan

a = @top_level.modules.first
assert_equal 'A', a.full_name
aliased = a.constants.first
assert_equal 'A::Aliased', aliased.full_name
assert_equal [], a.modules.map(&:full_name)
assert_equal ['A::Defined', 'A::Aliased'], a.classes.map(&:full_name)
assert_equal ['A::Aliased'], a.constants.map(&:full_name)

visible = @store.all_modules.reject { |mod| mod.suppressed? }
visible = visible.map { |mod| mod.full_name }

assert_equal ['A'], visible
end

def test_parse_const_alias_defined_far_away
util_parser <<-CLASS
module A
Aliased = ::B::C::Defined
end

module B
module C
class Defined
end
end
end
CLASS

@parser.scan

a = @top_level.modules.first
assert_equal 'A', a.full_name
assert_empty a.classes
assert_empty a.modules
assert_equal ['A::Aliased'], a.constants.map(&:full_name)

defined = @store.find_class_named 'B::C::Defined'
assert_equal 'B::C::Defined', defined.full_name

aliased = @store.find_class_named 'B::C::Aliased'
assert_equal 'B::C::Aliased', aliased.full_name

visible = @store.all_modules.reject { |mod| mod.suppressed? }
visible = visible.map { |mod| mod.full_name }

assert_equal ['A', 'B', 'B::C'], visible
end

def test_parse_const_alias_defined_elsewhere
util_parser <<-CLASS
module A
Aliased = Defined
end

module A
class Defined
end
end
CLASS

@parser.scan

a = @top_level.modules.first
assert_equal 'A', a.full_name
aliased = a.constants.first
assert_equal 'A::Aliased', aliased.full_name

visible = @store.all_modules.reject { |mod| mod.suppressed? }
visible = visible.map { |mod| mod.full_name }

assert_equal ['A'], visible
end

def test_parse_const_alias_defined_far_away
util_parser <<-CLASS
module A
Aliased = ::B::C::Defined
end

module B
module C
class Defined
end
end
end
CLASS

@parser.scan

a = @top_level.modules.first
assert_equal 'A', a.full_name
assert_empty a.classes
assert_empty a.modules
assert_equal ['A::Aliased'], a.constants.map(&:full_name)

defined = @store.find_class_named 'B::C::Defined'
assert_equal 'B::C::Defined', defined.full_name

aliased = @store.find_class_named 'B::C::Aliased'
assert_equal 'B::C::Aliased', aliased.full_name

visible = @store.all_modules.reject { |mod| mod.suppressed? }
visible = visible.map { |mod| mod.full_name }

assert_equal ['A', 'B', 'B::C'], visible
end

end
Loading