ruby-changes:26311
From: drbrain <ko1@a...>
Date: Thu, 13 Dec 2012 16:59:03 +0900 (JST)
Subject: [ruby-changes:26311] drbrain:r38362 (trunk): * lib/rdoc/class_module.rb: Fixed duplicate comments for classes and
drbrain 2012-12-13 16:58:47 +0900 (Thu, 13 Dec 2012) New Revision: 38362 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38362 Log: * lib/rdoc/class_module.rb: Fixed duplicate comments for classes and modules from C. * test/rdoc/test_rdoc_class_module.rb: Test for the above. * lib/rdoc/parser/c.rb: Reload C variable names to allow proper updates of an ri store for C files. * lib/rdoc/rdoc.rb: ditto. * lib/rdoc/store.rb: ditto. * test/rdoc/test_rdoc_parser_c.rb: Test for the above. * test/rdoc/test_rdoc_store.rb: ditto. Modified files: trunk/ChangeLog trunk/lib/rdoc/class_module.rb trunk/lib/rdoc/parser/c.rb trunk/lib/rdoc/rdoc.rb trunk/lib/rdoc/store.rb trunk/test/rdoc/test_rdoc_class_module.rb trunk/test/rdoc/test_rdoc_parser_c.rb trunk/test/rdoc/test_rdoc_store.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 38361) +++ ChangeLog (revision 38362) @@ -1,3 +1,16 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Thu Dec 13 16:53:10 2012 Eric Hodel <drbrain@s...> + + * lib/rdoc/class_module.rb: Fixed duplicate comments for classes and + modules from C. + * test/rdoc/test_rdoc_class_module.rb: Test for the above. + + * lib/rdoc/parser/c.rb: Reload C variable names to allow proper + updates of an ri store for C files. + * lib/rdoc/rdoc.rb: ditto. + * lib/rdoc/store.rb: ditto. + * test/rdoc/test_rdoc_parser_c.rb: Test for the above. + * test/rdoc/test_rdoc_store.rb: ditto. + Thu Dec 13 14:20:00 2012 Zachary Scott <zachary@z...> * lib/irb*: merge doc from doc/irb/ird.rd and improve overall Index: lib/rdoc/rdoc.rb =================================================================== --- lib/rdoc/rdoc.rb (revision 38361) +++ lib/rdoc/rdoc.rb (revision 38362) @@ -476,9 +476,12 @@ The internal error was: https://github.com/ruby/ruby/blob/trunk/lib/rdoc/rdoc.rb#L476 @store.dry_run = @options.dry_run @store.main = @options.main_page @store.title = @options.title + @store.path = @options.op_dir @start_time = Time.now + @store.load_cache + file_info = parse_files @options.files @options.default_title = "RDoc Documentation" Index: lib/rdoc/store.rb =================================================================== --- lib/rdoc/store.rb (revision 38361) +++ lib/rdoc/store.rb (revision 38362) @@ -69,7 +69,19 @@ class RDoc::Store https://github.com/ruby/ruby/blob/trunk/lib/rdoc/store.rb#L69 # Stores the name of the C variable a class belongs to. This helps wire up # classes defined from C across files. - attr_reader :c_enclosure_classes + attr_reader :c_enclosure_classes # :nodoc: + + attr_reader :c_enclosure_names # :nodoc: + + ## + # Maps C variables to class or module names for each parsed C file. + + attr_reader :c_class_variables + + ## + # Maps C variables to singleton class names for each parsed C file. + + attr_reader :c_singleton_class_variables ## # If true this Store will not write any files @@ -114,15 +126,17 @@ class RDoc::Store https://github.com/ruby/ruby/blob/trunk/lib/rdoc/store.rb#L126 @type = type @cache = { - :ancestors => {}, - :attributes => {}, - :class_methods => {}, - :encoding => @encoding, - :instance_methods => {}, - :main => nil, - :modules => [], - :pages => [], - :title => nil, + :ancestors => {}, + :attributes => {}, + :class_methods => {}, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => @encoding, + :instance_methods => {}, + :main => nil, + :modules => [], + :pages => [], + :title => nil, } @classes_hash = {} @@ -130,12 +144,35 @@ class RDoc::Store https://github.com/ruby/ruby/blob/trunk/lib/rdoc/store.rb#L144 @files_hash = {} @c_enclosure_classes = {} + @c_enclosure_names = {} + + @c_class_variables = {} + @c_singleton_class_variables = {} @unique_classes = nil @unique_modules = nil end ## + # Adds +module+ as an enclosure (namespace) for the given +variable+ for C + # files. + + def add_c_enclosure variable, namespace + @c_enclosure_classes[variable] = namespace + end + + ## + # Adds C variables from an RDoc::Parser::C + + def add_c_variables c_parser + filename = c_parser.top_level.relative_name + + @c_class_variables[filename] = make_variable_map c_parser.classes + + @c_singleton_class_variables[filename] = c_parser.singleton_classes + end + + ## # Adds the file with +name+ as an RDoc::TopLevel to the store. Returns the # created RDoc::TopLevel. @@ -305,6 +342,28 @@ class RDoc::Store https://github.com/ruby/ruby/blob/trunk/lib/rdoc/store.rb#L342 end ## + # Finds the enclosure (namespace) for the given C +variable+. + + def find_c_enclosure variable + @c_enclosure_classes.fetch variable do + break unless name = @c_enclosure_names[variable] + + mod = find_class_or_module name + + unless mod then + loaded_mod = load_class_data name + + file = loaded_mod.in_files.first + file.store = self + + mod = file.add_module RDoc::NormalModule, name + end + + @c_enclosure_classes[variable] = mod + end + end + + ## # Finds the class with +name+ in all discovered classes def find_class_named name @@ -500,22 +559,26 @@ class RDoc::Store https://github.com/ruby/ruby/blob/trunk/lib/rdoc/store.rb#L559 @encoding = load_enc unless @encoding - @cache[:pages] ||= [] - @cache[:main] ||= nil + @cache[:pages] ||= [] + @cache[:main] ||= nil + @cache[:c_class_variables] ||= {} + @cache[:c_singleton_class_variables] ||= {} + + @cache[:c_class_variables].each do |_, map| + map.each do |variable, name| + @c_enclosure_names[variable] = name + end + end @cache rescue Errno::ENOENT end ## - # Loads ri data for +klass_name+ + # Loads ri data for +klass_name+ and hooks it up to this store. def load_class klass_name - file = class_file klass_name - - obj = open file, 'rb' do |io| - Marshal.load io.read - end + obj = load_class_data klass_name obj.store = self @@ -525,6 +588,17 @@ class RDoc::Store https://github.com/ruby/ruby/blob/trunk/lib/rdoc/store.rb#L588 when RDoc::NormalModule then @modules_hash[klass_name] = obj end + end + + ## + # Loads ri data for +klass_name+ + + def load_class_data klass_name + file = class_file klass_name + + obj = open file, 'rb' do |io| + Marshal.load io.read + end rescue Errno::ENOENT => e error = MissingFileError.new(self, file, klass_name) error.set_backtrace e.backtrace @@ -584,6 +658,20 @@ class RDoc::Store https://github.com/ruby/ruby/blob/trunk/lib/rdoc/store.rb#L658 end ## + # Converts the variable => ClassModule map +variables+ from a C parser into + # a variable => class name map. + + def make_variable_map variables + map = {} + + variables.each { |variable, class_module| + map[variable] = class_module.full_name + } + + map + end + + ## # Path to the ri data for +method_name+ in +klass_name+ def method_file klass_name, method_name @@ -688,6 +776,9 @@ class RDoc::Store https://github.com/ruby/ruby/blob/trunk/lib/rdoc/store.rb#L776 @cache[:encoding] = @encoding # this gets set twice due to assert_cache + @cache[:c_class_variables].merge! @c_class_variables + @cache[:c_singleton_class_variables].merge! @c_singleton_class_variables + return if @dry_run marshal = Marshal.dump @cache Index: lib/rdoc/class_module.rb =================================================================== --- lib/rdoc/class_module.rb (revision 38361) +++ lib/rdoc/class_module.rb (revision 38362) @@ -31,7 +31,7 @@ class RDoc::ClassModule < RDoc::Context https://github.com/ruby/ruby/blob/trunk/lib/rdoc/class_module.rb#L31 ## # Comment and the location it came from. Use #add_comment to add comments - attr_reader :comment_location + attr_accessor :comment_location attr_accessor :diagram # :nodoc: @@ -134,6 +134,9 @@ class RDoc::ClassModule < RDoc::Context https://github.com/ruby/ruby/blob/trunk/lib/rdoc/class_module.rb#L134 else normalize_comment comment end + + @comment_location.delete_if { |(_, l)| l == location } + @comment_location << [comment, location] self.comment = original Index: lib/rdoc/parser/c.rb =================================================================== --- lib/rdoc/parser/c.rb (revision 38361) +++ lib/rdoc/parser/c.rb (revision 38362) @@ -123,6 +123,11 @@ class RDoc::Parser::C < RDoc::Parser https://github.com/ruby/ruby/blob/trunk/lib/rdoc/parser/c.rb#L123 include RDoc::Text ## + # Maps C variable names to names of ruby classes or modules + + attr_reader :classes + + ## # C file the parser is parsing attr_accessor :content @@ -150,16 +155,23 @@ class RDoc::Parser::C < RDoc::Parser https://github.com/ruby/ruby/blob/trunk/lib/rdoc/parser/c.rb#L155 attr_reader :singleton_classes ## - # Prepare to parse a C file + # The TopLevel items in the parsed file belong to + + attr_reader :top_level + + ## + # Prepares for parsing a C file. See RDoc::Parser#initialize for details on + # the arguments. - def initialize(top_level, file_name, content, options, stats) + def initialize top_level, file_name, content, options, stats super @known_classes = RDoc::KNOWN_CLASSES.dup - @content = handle_tab_width handle_ifdefs_in(@content) - @classes = {} - @singleton_classes = {} - @file_dir = File.dirname(@file_name) + @content = handle_tab_width handle_ifdefs_in @content + @file_dir = File.dirname @file_name + + @classes = load_variable_map :c_class_variables + @singleton_classes = load_variable_map :c_singleton_class_variables # missing variable => [handle_class_module arguments] @missing_dependencies = {} @@ -386,13 +398,12 @@ class RDoc::Parser::C < RDoc::Parser https://github.com/ruby/ruby/blob/trunk/lib/rdoc/parser/c.rb#L398 def do_includes @content.scan(/rb_include_module\s*\(\s*(\w+?),\s*(\w+?)\s*\)/) do |c,m| - if cls = @classes[c] - m = @known_classes[m] || m + next unless cls = @classes[c] + m = @known_classes[m] || m - comment = RDoc::Comment.new '', @top_level - incl = cls.add_include RDoc::Include.new(m, comment) - incl.record_location @top_level - end + comment = RDoc::Comment.new '', @top_level + incl = cls.add_include RDoc::Include.new(m, comment) + incl.record_location @top_level end end @@ -801,7 +812,7 @@ class RDoc::Parser::C < RDoc::Parser https://github.com/ruby/ruby/blob/trunk/lib/rdoc/parser/c.rb#L812 parent_name = @known_classes[parent] || parent if in_module then - enclosure = @classes[in_module] || @store.c_enclosure_classes[in_module] + enclosure = @classes[in_module] || @store.find_c_enclosure(in_module) if enclosure.nil? and enclosure = @known_classes[in_module] then enc_type = /^rb_m/ =~ in_module ? :module : :class @@ -848,8 +859,8 @@ class RDoc::Parser::C < RDoc::Parser https://github.com/ruby/ruby/blob/trunk/lib/rdoc/parser/c.rb#L859 end @classes[var_name] = cm - @store.c_enclosure_classes[var_name] = cm @known_classes[var_name] = cm.full_name + @store.add_c_enclosure var_name, cm end ## @@ -1005,6 +1016,30 @@ class RDoc::Parser::C < RDoc::Parser https://github.com/ruby/ruby/blob/trunk/lib/rdoc/parser/c.rb#L1016 end ## + # Loads the variable map with the given +name+ from the RDoc::Store, if + # present. + + def load_variable_map map_name + return {} unless files = @store.cache[map_name] + return {} unless name_map = files[@file_name] + + class_map = {} + + name_map.each do |variable, name| + next unless mod = @store.find_class_or_module(name) + + class_map[variable] = if map_name == :c_class_variables then + mod + else + name + end + @known_classes[variable] = name + end + + class_map + end + + ## # Look for directives in a normal comment block: # # /* @@ -1136,6 +1171,9 @@ class RDoc::Parser::C < RDoc::Parser https://github.com/ruby/ruby/blob/trunk/lib/rdoc/parser/c.rb#L1171 do_includes do_aliases do_attrs + + @store.add_c_variables self + @top_level end Index: test/rdoc/test_rdoc_store.rb =================================================================== --- test/rdoc/test_rdoc_store.rb (revision 38361) +++ test/rdoc/test_rdoc_store.rb (revision 38362) @@ -18,6 +18,7 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L18 @klass = @top_level.add_class RDoc::NormalClass, 'Object' @klass.add_comment 'original', @top_level + @klass.record_location @top_level @cmeth = RDoc::AnyMethod.new nil, 'cmethod' @cmeth.singleton = true @@ -87,15 +88,17 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L88 @s.clean_cache_collection ancestors expected = { - :ancestors => ancestors, - :attributes => attrs, - :class_methods => cmethods, - :encoding => nil, - :instance_methods => imethods, - :modules => modules, - :pages => pages, - :main => main, - :title => title, + :ancestors => ancestors, + :attributes => attrs, + :class_methods => cmethods, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => nil, + :instance_methods => imethods, + :modules => modules, + :pages => pages, + :main => main, + :title => title, } @s.save_cache @@ -115,6 +118,38 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L118 refute File.exist?(path), "#{path} exists" end + def test_add_c_enclosure + @s.add_c_enclosure 'cC1', @c1 + + expected = { 'cC1' => @c1 } + + assert_equal expected, @s.c_enclosure_classes + end + + def test_add_c_variables + options = RDoc::Options.new + + c_file = @s.add_file 'ext.c' + + some_ext = c_file.add_class RDoc::NormalClass, 'SomeExt' + c_file.add_class RDoc::SingleClass, 'SomeExtSingle' + + c_parser = RDoc::Parser::C.new c_file, 'ext.c', '', options, nil + + c_parser.classes['cSomeExt'] = some_ext + c_parser.singleton_classes['s_cSomeExt'] = 'SomeExtSingle' + + @s.add_c_variables c_parser + + expected = { 'ext.c' => { 'cSomeExt' => 'SomeExt' } } + + assert_equal expected, @s.c_class_variables + + expected = { 'ext.c' => { 's_cSomeExt' => 'SomeExtSingle' } } + + assert_equal expected, @s.c_singleton_class_variables + end + def test_add_file top_level = @store.add_file 'file.rb' @@ -214,6 +249,31 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L249 refute_empty a1.aliases end + def test_find_c_enclosure + assert_nil @s.find_c_enclosure 'cC1' + + @s.add_c_enclosure 'cC1', @c1 + + assert_equal @c1, @s.find_c_enclosure('cC1') + end + + def test_find_c_enclosure_from_cache + @s.save_class @klass + @s.classes_hash.clear + + assert_nil @s.find_c_enclosure 'cObject' + + @s.c_enclosure_names['cObject'] = 'Object' + + klass = @s.find_c_enclosure('cObject') + assert_equal @klass, klass + + assert_empty klass.comment_location + assert_equal @top_level, klass.parent + + assert_includes @s.c_enclosure_classes, 'cObject' + end + def test_find_class_named assert_equal @c1, @store.find_class_named('C1') @@ -329,11 +389,15 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L389 def test_load_cache cache = { - :encoding => :encoding_value, - :methods => { "Object" => %w[Object#method] }, - :main => @page.full_name, - :modules => %w[Object], - :pages => [], + :c_class_variables => + { 'file.c' => { 'cKlass' => 'Klass' } }, + :c_singleton_class_variables => + { 'file.c' => { 'sKlass' => 'KlassSingle' } }, + :encoding => :encoding_value, + :methods => { "Object" => %w[Object#method] }, + :main => @page.full_name, + :modules => %w[Object], + :pages => [], } Dir.mkdir @tmpdir @@ -348,17 +412,28 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L412 assert_equal :encoding_value, @s.encoding assert_equal 'README.txt', @s.main + + expected = { 'file.c' => { 'cKlass' => 'Klass' } } + assert_equal expected, @s.cache[:c_class_variables] + + expected = { 'file.c' => { 'sKlass' => 'KlassSingle' } } + assert_equal expected, @s.cache[:c_singleton_class_variables] + + expected = { 'cKlass' => 'Klass' } + assert_equal expected, @s.c_enclosure_names end def test_load_cache_encoding_differs skip "Encoding not implemented" unless Object.const_defined? :Encoding cache = { - :encoding => Encoding::ISO_8859_1, - :main => nil, - :methods => { "Object" => %w[Object#method] }, - :modules => %w[Object], - :pages => [], + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => Encoding::ISO_8859_1, + :main => nil, + :methods => { "Object" => %w[Object#method] }, + :modules => %w[Object], + :pages => [], } Dir.mkdir @tmpdir @@ -378,15 +453,17 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L453 def test_load_cache_no_cache cache = { - :ancestors => {}, - :attributes => {}, - :class_methods => {}, - :encoding => nil, - :instance_methods => {}, - :main => nil, - :modules => [], - :pages => [], - :title => nil, + :ancestors => {}, + :attributes => {}, + :class_methods => {}, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => nil, + :instance_methods => {}, + :main => nil, + :modules => [], + :pages => [], + :title => nil, } @s.load_cache @@ -404,6 +481,8 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L481 :modules => %w[Object], # no :pages # no :main + # no :c_class_variables + # no :c_singleton_class_variables } Dir.mkdir @tmpdir @@ -415,14 +494,16 @@ class TestRDocStore < XrefTestCase https://github.com/ruby/ruby/blob/trunk/test/rdoc/test_rdoc_store.rb#L494 @s.load_cache expected = { - :ancestors => {}, - :attributes => {}, - :class_methods => {}, - :encoding => :encoding_value, - :instance_methods => { "Object" => %w[Object#method] }, - :main => nil, - :modules => %w[Object], - :pages => [], + :ancestors => {}, + :attributes => {}, + :class_methods => {}, + :c_class_variables => {}, + :c_singleton_class_variables => {}, + :encoding => :encoding_value, + :instance_methods => { "Object" => %w[Object#method] }, (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/