Skip to content

Commit 2e836d2

Browse files
authored
Merge pull request #599 from aycabta/ignore-constants-discovered-in-passing
Ignore constants discovered in passing
2 parents b547654 + 0de925c commit 2e836d2

File tree

8 files changed

+215
-26
lines changed

8 files changed

+215
-26
lines changed

lib/rdoc/context.rb

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -407,13 +407,18 @@ def add_class_or_module mod, self_hash, all_hash
407407
mod.section = current_section # TODO declaring context? something is
408408
# wrong here...
409409
mod.parent = self
410+
mod.full_name = nil
410411
mod.store = @store
411412

412413
unless @done_documenting then
413414
self_hash[mod.name] = mod
414415
# this must be done AFTER adding mod to its parent, so that the full
415416
# name is correct:
416417
all_hash[mod.full_name] = mod
418+
if @store.unmatched_constant_alias[mod.full_name] then
419+
to, file = @store.unmatched_constant_alias[mod.full_name]
420+
add_module_alias mod, mod.name, to, file
421+
end
417422
end
418423

419424
mod
@@ -510,41 +515,53 @@ def add_module(class_type, name)
510515
add_class_or_module mod, @modules, @store.modules_hash
511516
end
512517

518+
##
519+
# Adds a module by +RDoc::NormalModule+ instance. See also #add_module.
520+
521+
def add_module_by_normal_module(mod)
522+
add_class_or_module mod, @modules, @store.modules_hash
523+
end
524+
513525
##
514526
# Adds an alias from +from+ (a class or module) to +name+ which was defined
515527
# in +file+.
516528

517-
def add_module_alias from, name, file
529+
def add_module_alias from, from_name, to, file
518530
return from if @done_documenting
519531

520-
to_name = child_name name
532+
to_full_name = child_name to.name
521533

522534
# if we already know this name, don't register an alias:
523535
# see the metaprogramming in lib/active_support/basic_object.rb,
524536
# where we already know BasicObject is a class when we find
525537
# BasicObject = BlankSlate
526-
return from if @store.find_class_or_module to_name
538+
return from if @store.find_class_or_module to_full_name
539+
540+
unless from
541+
@store.unmatched_constant_alias[child_name(from_name)] = [to, file]
542+
return to
543+
end
527544

528-
to = from.dup
529-
to.name = name
530-
to.full_name = nil
545+
new_to = from.dup
546+
new_to.name = to.name
547+
new_to.full_name = nil
531548

532-
if to.module? then
533-
@store.modules_hash[to_name] = to
534-
@modules[name] = to
549+
if new_to.module? then
550+
@store.modules_hash[to_full_name] = new_to
551+
@modules[to.name] = new_to
535552
else
536-
@store.classes_hash[to_name] = to
537-
@classes[name] = to
553+
@store.classes_hash[to_full_name] = new_to
554+
@classes[to.name] = new_to
538555
end
539556

540557
# Registers a constant for this alias. The constant value and comment
541558
# will be updated later, when the Ruby parser adds the constant
542-
const = RDoc::Constant.new name, nil, to.comment
559+
const = RDoc::Constant.new to.name, nil, new_to.comment
543560
const.record_location file
544561
const.is_alias_for = from
545562
add_constant const
546563

547-
to
564+
new_to
548565
end
549566

550567
##

lib/rdoc/parser/ruby.rb

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def create_module_alias container, constant, rhs_name # :nodoc:
307307
container.find_module_named rhs_name
308308
end
309309

310-
container.add_module_alias mod, constant.name, @top_level if mod
310+
container.add_module_alias mod, rhs_name, constant, @top_level
311311
end
312312

313313
##
@@ -356,12 +356,15 @@ def get_class_or_module container, ignore_constants = false
356356
given_name << name_t[:text]
357357

358358
is_self = name_t[:kind] == :on_op && name_t[:text] == '<<'
359+
new_modules = []
359360
while !is_self && (tk = peek_tk) and :on_op == tk[:kind] and '::' == tk[:text] do
360361
prev_container = container
361362
container = container.find_module_named name_t[:text]
362363
container ||=
363364
if ignore_constants then
364-
RDoc::Context.new
365+
c = RDoc::NormalModule.new name_t[:text]
366+
new_modules << [prev_container, c]
367+
c
365368
else
366369
c = prev_container.add_module RDoc::NormalModule, name_t[:text]
367370
c.ignore unless prev_container.document_children
@@ -386,7 +389,7 @@ def get_class_or_module container, ignore_constants = false
386389

387390
skip_tkspace false
388391

389-
return [container, name_t, given_name]
392+
return [container, name_t, given_name, new_modules]
390393
end
391394

392395
##
@@ -761,7 +764,7 @@ def parse_class container, single, tk, comment
761764
line_no = tk[:line_no]
762765

763766
declaration_context = container
764-
container, name_t, given_name = get_class_or_module container
767+
container, name_t, given_name, = get_class_or_module container
765768

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

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

884+
new_modules = []
881885
if :on_op == peek_tk[:kind] && '::' == peek_tk[:text] then
882886
unget_tk tk
883887

884-
container, name_t, = get_class_or_module container, ignore_constants
888+
container, name_t, _, new_modules = get_class_or_module container, true
885889

886890
name = name_t[:text]
887891
end
@@ -908,6 +912,14 @@ def parse_constant container, tk, comment, ignore_constants = false
908912
end
909913
get_tk
910914

915+
unless ignore_constants
916+
new_modules.each do |prev_c, new_module|
917+
prev_c.add_module_by_normal_module new_module
918+
new_module.ignore unless prev_c.document_children
919+
@top_level.add_to_classes_or_modules new_module
920+
end
921+
end
922+
911923
value = ''
912924
con = RDoc::Constant.new name, value, comment
913925

lib/rdoc/store.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ def message # :nodoc:
116116

117117
attr_accessor :encoding
118118

119+
##
120+
# The lazy constants alias will be discovered in passing
121+
122+
attr_reader :unmatched_constant_alias
123+
119124
##
120125
# Creates a new Store of +type+ that will load or save to +path+
121126

@@ -152,6 +157,8 @@ def initialize path = nil, type = nil
152157

153158
@unique_classes = nil
154159
@unique_modules = nil
160+
161+
@unmatched_constant_alias = {}
155162
end
156163

157164
##

test/test_rdoc_class_module.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1277,7 +1277,8 @@ def test_update_aliases_class
12771277
n1 = @xref_data.add_module RDoc::NormalClass, 'N1'
12781278
n1_k2 = n1.add_module RDoc::NormalClass, 'N2'
12791279

1280-
n1.add_module_alias n1_k2, 'A1', @xref_data
1280+
a1 = RDoc::Constant.new 'A1', '', ''
1281+
n1.add_module_alias n1_k2, n1_k2.name, a1, @xref_data
12811282

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

1304-
n1.add_module_alias n1_n2, 'A1', @xref_data
1305+
a1 = RDoc::Constant.new 'A1', '', ''
1306+
n1.add_module_alias n1_n2, n1_n2.name, a1, @xref_data
13051307

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

1329-
o1.add_module_alias l1_l2, 'A1', @xref_data
1331+
a1 = RDoc::Constant.new 'A1', '', ''
1332+
o1.add_module_alias l1_l2, l1_l2.name, a1, @xref_data
13301333

13311334
o1_a1_c = o1.constants.find { |c| c.name == 'A1' }
13321335
refute_nil o1_a1_c
@@ -1358,7 +1361,8 @@ def test_update_aliases_reparent_root
13581361
const.record_location top_level
13591362
const.is_alias_for = klass
13601363

1361-
top_level.add_module_alias klass, 'A', top_level
1364+
a = RDoc::Constant.new 'A', '', ''
1365+
top_level.add_module_alias klass, klass.name, a, top_level
13621366

13631367
object.add_constant const
13641368

test/test_rdoc_context.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,8 @@ def test_add_module
280280
def test_add_module_alias
281281
tl = @store.add_file 'file.rb'
282282

283-
c3_c4 = @c2.add_module_alias @c2_c3, 'C4', tl
283+
c4 = RDoc::Constant.new 'C4', '', ''
284+
c3_c4 = @c2.add_module_alias @c2_c3, @c2_c3.name, c4, tl
284285

285286
alias_constant = @c2.constants.first
286287

@@ -298,7 +299,8 @@ def test_add_module_alias_top_level
298299

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

301-
top_level.add_module_alias klass, 'A', top_level
302+
a = RDoc::Constant.new 'A', '', ''
303+
top_level.add_module_alias klass, klass.name, a, top_level
302304

303305
refute_empty object.constants
304306

test/test_rdoc_generator_darkfish.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ def setup
3939

4040
@top_level.add_constant @alias_constant
4141

42-
@klass.add_module_alias @klass, 'A', @top_level
42+
@klass.add_module_alias @klass, @klass.name, @alias_constant, @top_level
4343

4444
@meth = RDoc::AnyMethod.new nil, 'method'
4545
@meth_bang = RDoc::AnyMethod.new nil, 'method!'

test/test_rdoc_parser_ruby.rb

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3931,4 +3931,150 @@ def util_two_parsers(first_file_content, second_file_content)
39313931
second_file_content, @options, @stats
39323932
end
39333933

3934+
def test_parse_const_third_party
3935+
util_parser <<-CLASS
3936+
class A
3937+
true if B
3938+
true if B::C
3939+
true if B::C::D
3940+
3941+
module B
3942+
end
3943+
end
3944+
CLASS
3945+
3946+
tk = @parser.get_tk
3947+
3948+
@parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment
3949+
3950+
a = @top_level.classes.first
3951+
assert_equal 'A', a.full_name
3952+
3953+
visible = @store.all_modules.reject { |mod| mod.suppressed? }
3954+
visible = visible.map { |mod| mod.full_name }
3955+
3956+
assert_equal ['A::B'], visible
3957+
end
3958+
3959+
def test_parse_const_alias_defined_elsewhere
3960+
util_parser <<-CLASS
3961+
module A
3962+
Aliased = Defined
3963+
end
3964+
3965+
module A
3966+
class Defined
3967+
end
3968+
end
3969+
CLASS
3970+
3971+
@parser.scan
3972+
3973+
a = @top_level.modules.first
3974+
assert_equal 'A', a.full_name
3975+
aliased = a.constants.first
3976+
assert_equal 'A::Aliased', aliased.full_name
3977+
assert_equal [], a.modules.map(&:full_name)
3978+
assert_equal ['A::Defined', 'A::Aliased'], a.classes.map(&:full_name)
3979+
assert_equal ['A::Aliased'], a.constants.map(&:full_name)
3980+
3981+
visible = @store.all_modules.reject { |mod| mod.suppressed? }
3982+
visible = visible.map { |mod| mod.full_name }
3983+
3984+
assert_equal ['A'], visible
3985+
end
3986+
3987+
def test_parse_const_alias_defined_far_away
3988+
util_parser <<-CLASS
3989+
module A
3990+
Aliased = ::B::C::Defined
3991+
end
3992+
3993+
module B
3994+
module C
3995+
class Defined
3996+
end
3997+
end
3998+
end
3999+
CLASS
4000+
4001+
@parser.scan
4002+
4003+
a = @top_level.modules.first
4004+
assert_equal 'A', a.full_name
4005+
assert_empty a.classes
4006+
assert_empty a.modules
4007+
assert_equal ['A::Aliased'], a.constants.map(&:full_name)
4008+
4009+
defined = @store.find_class_named 'B::C::Defined'
4010+
assert_equal 'B::C::Defined', defined.full_name
4011+
4012+
aliased = @store.find_class_named 'B::C::Aliased'
4013+
assert_equal 'B::C::Aliased', aliased.full_name
4014+
4015+
visible = @store.all_modules.reject { |mod| mod.suppressed? }
4016+
visible = visible.map { |mod| mod.full_name }
4017+
4018+
assert_equal ['A', 'B', 'B::C'], visible
4019+
end
4020+
4021+
def test_parse_const_alias_defined_elsewhere
4022+
util_parser <<-CLASS
4023+
module A
4024+
Aliased = Defined
4025+
end
4026+
4027+
module A
4028+
class Defined
4029+
end
4030+
end
4031+
CLASS
4032+
4033+
@parser.scan
4034+
4035+
a = @top_level.modules.first
4036+
assert_equal 'A', a.full_name
4037+
aliased = a.constants.first
4038+
assert_equal 'A::Aliased', aliased.full_name
4039+
4040+
visible = @store.all_modules.reject { |mod| mod.suppressed? }
4041+
visible = visible.map { |mod| mod.full_name }
4042+
4043+
assert_equal ['A'], visible
4044+
end
4045+
4046+
def test_parse_const_alias_defined_far_away
4047+
util_parser <<-CLASS
4048+
module A
4049+
Aliased = ::B::C::Defined
4050+
end
4051+
4052+
module B
4053+
module C
4054+
class Defined
4055+
end
4056+
end
4057+
end
4058+
CLASS
4059+
4060+
@parser.scan
4061+
4062+
a = @top_level.modules.first
4063+
assert_equal 'A', a.full_name
4064+
assert_empty a.classes
4065+
assert_empty a.modules
4066+
assert_equal ['A::Aliased'], a.constants.map(&:full_name)
4067+
4068+
defined = @store.find_class_named 'B::C::Defined'
4069+
assert_equal 'B::C::Defined', defined.full_name
4070+
4071+
aliased = @store.find_class_named 'B::C::Aliased'
4072+
assert_equal 'B::C::Aliased', aliased.full_name
4073+
4074+
visible = @store.all_modules.reject { |mod| mod.suppressed? }
4075+
visible = visible.map { |mod| mod.full_name }
4076+
4077+
assert_equal ['A', 'B', 'B::C'], visible
4078+
end
4079+
39344080
end

0 commit comments

Comments
 (0)