diff --git a/ChangeLog b/ChangeLog index 3944e7966a..96586ac867 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Tue Dec 4 16:47:46 2012 Eric Hodel + + * lib/rdoc/parser/changelog.rb: Added a ChangeLog parser to RDoc. + * lib/rdoc/parser.rb: ditto + * test/rdoc/test_rdoc_parser_changelog.rb: Test for above. + Tue Dec 4 16:23:32 2012 Nobuyoshi Nakada * marshal.c (path2class, path2module): use PRIsVALUE. diff --git a/lib/rdoc/parser.rb b/lib/rdoc/parser.rb index bf9ab77218..685736fd28 100644 --- a/lib/rdoc/parser.rb +++ b/lib/rdoc/parser.rb @@ -268,6 +268,7 @@ end # simple must come first in order to show up last in the parsers list require 'rdoc/parser/simple' require 'rdoc/parser/c' +require 'rdoc/parser/changelog' require 'rdoc/parser/markdown' require 'rdoc/parser/rd' require 'rdoc/parser/ruby' diff --git a/lib/rdoc/parser/changelog.rb b/lib/rdoc/parser/changelog.rb new file mode 100644 index 0000000000..98174406ed --- /dev/null +++ b/lib/rdoc/parser/changelog.rb @@ -0,0 +1,110 @@ +require 'time' + +class RDoc::Parser::ChangeLog < RDoc::Parser + + include RDoc::Parser::Text + + parse_files_matching(/(\/|\\|\A)ChangeLog[^\/\\]*\z/) + + def create_document groups + doc = RDoc::Markup::Document.new + doc.file = @top_level + + doc << RDoc::Markup::Heading.new(1, File.basename(@file_name)) + doc << RDoc::Markup::BlankLine.new + + groups.each do |day, entries| + doc << RDoc::Markup::Heading.new(2, day) + doc << RDoc::Markup::BlankLine.new + + doc.concat create_entries entries + end + + doc + end + + def create_entries entries + out = [] + + entries.each do |entry, items| + out << RDoc::Markup::Heading.new(3, entry) + out << RDoc::Markup::BlankLine.new + + out << create_items(items) + end + + out + end + + def create_items items + list = RDoc::Markup::List.new :NOTE + + items.each do |item| + title, body = item.split /:\s*/, 2 + paragraph = RDoc::Markup::Paragraph.new body + list_item = RDoc::Markup::ListItem.new title, paragraph + list << list_item + end + + list + end + + def group_entries entries + entries.group_by do |title, body| + Time.parse(title).strftime "%Y-%m-%d" + end + end + + def parse_entries + entries = {} + entry_name = nil + entry_body = [] + + @content.each_line do |line| + case line + when /^\w.*/ then + entries[entry_name] = entry_body if entry_name + + entry_name = $& + + begin + Time.parse entry_name + rescue ArgumentError + entry_name = nil + end + + entry_body = [] + when /^(\t| {8})\*\s*(.*)/ then + entry_body << $2 + when /^(\t| {8})\s*(.*)/ then + continuation = $2 + next unless last = entry_body.last + + if last =~ /\s\z/ then + last << continuation + else + last << ' ' << continuation + end + end + end + + entries[entry_name] = entry_body if entry_name + + entries.delete nil + + entries + end + + def scan + entries = parse_entries + grouped_entries = group_entries entries + + doc = create_document grouped_entries + + @top_level.comment = doc + + @top_level + end + +end + diff --git a/test/rdoc/test_rdoc_parser_changelog.rb b/test/rdoc/test_rdoc_parser_changelog.rb new file mode 100644 index 0000000000..597b395a9f --- /dev/null +++ b/test/rdoc/test_rdoc_parser_changelog.rb @@ -0,0 +1,212 @@ +require 'rdoc/test_case' + +class TestRDocParserChangeLog < RDoc::TestCase + + def setup + super + + @tempfile = Tempfile.new 'ChangeLog' + @top_level = @store.add_file @tempfile.path + @options = RDoc::Options.new + @stats = RDoc::Stats.new @store, 0 + end + + def teardown + @tempfile.close + end + + def mu_pp obj + s = '' + s = PP.pp obj, s + s = s.force_encoding Encoding.default_external if defined? Encoding + s.chomp + end + + def test_class_can_parse + parser = RDoc::Parser::ChangeLog + + assert_equal parser, parser.can_parse('ChangeLog') + + assert_equal parser, parser.can_parse(@tempfile.path) + end + + def test_create_document + parser = util_parser + + groups = { + '2012-12-04' => [ + ['Tue Dec 4 08:33:46 2012 Eric Hodel ', + %w[a:one b:two]], + ['Tue Dec 4 08:32:10 2012 Eric Hodel ', + %w[c:three d:four]]], + '2012-12-03' => [ + ['Mon Dec 3 20:28:02 2012 Koichi Sasada ', + %w[e:five f:six]]], + } + + expected = + doc( + head(1, File.basename(@tempfile.path)), + blank_line, + head(2, '2012-12-04'), + blank_line, + head(3, 'Tue Dec 4 08:33:46 2012 Eric Hodel '), + blank_line, + list(:NOTE, item('a', para('one')), item('b', para('two'))), + head(3, 'Tue Dec 4 08:32:10 2012 Eric Hodel '), + blank_line, + list(:NOTE, item('c', para('three')), item('d', para('four'))), + head(2, '2012-12-03'), + blank_line, + head(3, 'Mon Dec 3 20:28:02 2012 Koichi Sasada '), + blank_line, + list(:NOTE, item('e', para('five')), item('f', para('six'))), + ) + expected.file = @top_level + + assert_equal expected, parser.create_document(groups) + end + + def test_create_entries + parser = util_parser + + entries = [ + ['Tue Dec 1 02:03:04 2012 Eric Hodel ', + %w[a:one b:two]], + ['Tue Dec 5 06:07:08 2012 Eric Hodel ', + %w[c:three d:four]], + ] + + expected = [ + head(3, 'Tue Dec 1 02:03:04 2012 Eric Hodel '), + blank_line, + list(:NOTE, item('a', para('one')), item('b', para('two'))), + head(3, 'Tue Dec 5 06:07:08 2012 Eric Hodel '), + blank_line, + list(:NOTE, item('c', para('three')), item('d', para('four'))), + ] + + assert_equal expected, parser.create_entries(entries) + end + + def test_create_items + parser = util_parser + + items = [ + 'README.EXT: Converted to RDoc format', + 'README.EXT.ja: ditto', + ] + + expected = + list(:NOTE, + item('README.EXT', + para('Converted to RDoc format')), + item('README.EXT.ja', + para('ditto'))) + + assert_equal expected, parser.create_items(items) + end + + def test_group_entries + parser = util_parser + + entries = { + 'Tue Dec 4 08:33:46 2012 Eric Hodel ' => + %w[one two], + 'Tue Dec 4 08:32:10 2012 Eric Hodel ' => + %w[three four], + 'Mon Dec 3 20:28:02 2012 Koichi Sasada ' => + %w[five six], + } + + expected = { + '2012-12-04' => [ + ['Tue Dec 4 08:33:46 2012 Eric Hodel ', + %w[one two]], + ['Tue Dec 4 08:32:10 2012 Eric Hodel ', + %w[three four]]], + '2012-12-03' => [ + ['Mon Dec 3 20:28:02 2012 Koichi Sasada ', + %w[five six]]], + } + + assert_equal expected, parser.group_entries(entries) + end + + def test_parse_entries + parser = util_parser <<-ChangeLog +Tue Dec 4 08:33:46 2012 Eric Hodel + + * README.EXT: Converted to RDoc format + * README.EXT.ja: ditto + +Mon Dec 3 20:28:02 2012 Koichi Sasada + + * compile.c (iseq_specialized_instruction): + change condition of using `opt_send_simple'. + More method invocations can be simple. + +Other note that will be ignored + + ChangeLog + + expected = { + 'Tue Dec 4 08:33:46 2012 Eric Hodel ' => [ + 'README.EXT: Converted to RDoc format', + 'README.EXT.ja: ditto', + ], + 'Mon Dec 3 20:28:02 2012 Koichi Sasada ' => [ + 'compile.c (iseq_specialized_instruction): change condition of ' + + 'using `opt_send_simple\'. More method invocations can be simple.', + ], + } + + assert_equal expected, parser.parse_entries + end + + def test_scan + parser = util_parser <<-ChangeLog +Tue Dec 4 08:32:10 2012 Eric Hodel + + * lib/rdoc/ri/driver.rb: Fixed ri page display for files with + extensions. + * test/rdoc/test_rdoc_ri_driver.rb: Test for above + +Mon Dec 3 20:37:22 2012 Koichi Sasada + + * vm_exec.c: check VM_COLLECT_USAGE_DETAILS. + + ChangeLog + + parser.scan + + expected = doc( + head(1, File.basename(@tempfile.path)), + blank_line, + head(2, '2012-12-04'), + blank_line, + head(3, 'Tue Dec 4 08:32:10 2012 Eric Hodel '), + blank_line, + list(:NOTE, + item('lib/rdoc/ri/driver.rb', para('Fixed ri page display for ' + + 'files with extensions.')), + item('test/rdoc/test_rdoc_ri_driver.rb', para('Test for above'))), + head(2, '2012-12-03'), + blank_line, + head(3, 'Mon Dec 3 20:37:22 2012 Koichi Sasada '), + blank_line, + list(:NOTE, + item('vm_exec.c', para('check VM_COLLECT_USAGE_DETAILS.')))) + + expected.file = @top_level + + assert_equal expected, @top_level.comment + end + + def util_parser content = '' + RDoc::Parser::ChangeLog.new \ + @top_level, @tempfile.path, content, @options, @stats + end + +end +