Class: RDoc::Parser::ChangeLog

Inherits:
Parser
  • Object
show all
Includes:
Text
Defined in:
lib/rdoc/parser/changelog.rb

Overview

A ChangeLog file parser.

This parser converts a ChangeLog into an RDoc::Markup::Document. When viewed as HTML a ChangeLog page will have an entry for each day's entries in the sidebar table of contents.

This parser is meant to parse the MRI ChangeLog, but can be used to parse any GNU style Change Log.

Defined Under Namespace

Modules: Git

Instance Method Summary collapse

Instance Method Details

#continue_entry_body(entry_body, continuation) ⇒ Object

Attaches the continuation of the previous line to the entry_body.

Continued function listings are joined together as a single entry. Continued descriptions are joined to make a single paragraph.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/rdoc/parser/changelog.rb', line 28

def continue_entry_body(entry_body, continuation)
  return unless last = entry_body.last

  if last =~ /\)\s*\z/ and continuation =~ /\A\(/
    last.sub!(/\)\s*\z/, ',')
    continuation = continuation.sub(/\A\(/, '')
  end

  if last =~ /\s\z/
    last << continuation
  else
    last << ' ' + continuation
  end
end

#create_document(groups) ⇒ Object

Creates an RDoc::Markup::Document given the groups of ChangeLog entries.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rdoc/parser/changelog.rb', line 46

def create_document(groups)
  doc = Markup::Document.new
  doc.omit_headings_below = 2
  doc.file = @top_level

  doc << Markup::Heading.new(1, File.basename(@file_name))
  doc << Markup::BlankLine.new

  groups.sort_by do |day,| day end.reverse_each do |day, entries|
    doc << Markup::Heading.new(2, day.dup)
    doc << Markup::BlankLine.new

    doc.concat create_entries entries
  end

  doc
end

#create_entries(entries) ⇒ Object

Returns a list of ChangeLog entries an RDoc::Markup nodes for the given entries.



68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/rdoc/parser/changelog.rb', line 68

def create_entries(entries)
  out = []

  entries.each do |entry, items|
    out << Markup::Heading.new(3, entry)
    out << Markup::BlankLine.new

    out << create_items(items)
  end

  out
end

#create_items(items) ⇒ Object

Returns an RDoc::Markup::List containing the given items in the ChangeLog



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/rdoc/parser/changelog.rb', line 85

def create_items(items)
  list = Markup::List.new :NOTE

  items.each do |item|
    item =~ /\A(.*?(?:\([^)]+\))?):\s*/

    title = $1
    body = $'

    paragraph = Markup::Paragraph.new body
    list_item = Markup::ListItem.new title, paragraph
    list << list_item
  end

  list
end

#group_entries(entries) ⇒ Object

Groups entries by date.



105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rdoc/parser/changelog.rb', line 105

def group_entries(entries)
  @time_cache ||= {}
  entries.group_by do |title, _|
    begin
      time = @time_cache[title]
      (time || parse_date(title)).strftime '%Y-%m-%d'
    rescue NoMethodError, ArgumentError
      time, = title.split '  ', 2
      parse_date(time).strftime '%Y-%m-%d'
    end
  end
end

#parse_date(date) ⇒ Object

Parse date in ISO-8601, RFC-2822, or default of Git



121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/rdoc/parser/changelog.rb', line 121

def parse_date(date)
  case date
  when /\A\s*(\d+)-(\d+)-(\d+)(?:[ T](\d+):(\d+):(\d+) *([-+]\d\d):?(\d\d))?\b/
    Time.new($1, $2, $3, $4, $5, $6, ("#{$7}:#{$8}" if $7))
  when /\A\s*\w{3}, +(\d+) (\w{3}) (\d+) (\d+):(\d+):(\d+) *(?:([-+]\d\d):?(\d\d))\b/
    Time.new($3, $2, $1, $4, $5, $6, ("#{$7}:#{$8}" if $7))
  when /\A\s*\w{3} (\w{3}) +(\d+) (\d+) (\d+):(\d+):(\d+) *(?:([-+]\d\d):?(\d\d))\b/
    Time.new($3, $1, $2, $4, $5, $6, ("#{$7}:#{$8}" if $7))
  when /\A\s*\w{3} (\w{3}) +(\d+) (\d+):(\d+):(\d+) (\d+)\b/
    Time.new($6, $1, $2, $3, $4, $5)
  else
    raise ArgumentError, "bad date: #{date}"
  end
end

#parse_entries ⇒ Object

Parses the entries in the ChangeLog.

Returns an Array of each ChangeLog entry in order of parsing.

A ChangeLog entry is an Array containing the ChangeLog title (date and committer) and an Array of ChangeLog items (file and function changed with description).

An example result would be:

[ 'Tue Dec  4 08:33:46 2012  Eric Hodel  <[email protected]>',
 [ 'README.EXT:  Converted to RDoc format',
   'README.EXT.ja:  ditto']]


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/rdoc/parser/changelog.rb', line 151

def parse_entries
  @time_cache ||= {}

  if /\A((?:.*\n){,3})commit\s/ =~ @content
    class << self; prepend Git; end
    parse_info($1)
    return parse_entries
  end

  entries = []
  entry_name = nil
  entry_body = []

  @content.each_line do |line|
    case line
    when /^\s*$/
      next
    when /^\w.*/
      entries << [entry_name, entry_body] if entry_name

      entry_name = $&

      begin
        time = parse_date entry_name
        @time_cache[entry_name] = time
      rescue ArgumentError
        entry_name = nil
      end

      entry_body = []
    when /^(\t| {8})?\*\s*(.*)/ # "\t* file.c (func): ..."
      entry_body << $2.dup
    when /^(\t| {8})?\s*(\(.*)/ # "\t(func): ..."
      entry = $2

      if entry_body.last =~ /:/
        entry_body << entry.dup
      else
        continue_entry_body entry_body, entry
      end
    when /^(\t| {8})?\s*(.*)/
      continue_entry_body entry_body, $2
    end
  end

  entries << [entry_name, entry_body] if entry_name

  entries.reject! do |(entry, _)|
    entry == nil
  end

  entries
end

#scan ⇒ Object

Converts the ChangeLog into an RDoc::Markup::Document



208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/rdoc/parser/changelog.rb', line 208

def scan
  @time_cache = {}

  entries = parse_entries
  grouped_entries = group_entries entries

  doc = create_document grouped_entries
  comment = Comment.new(@content)
  comment.document = doc
  @top_level.comment = comment

  @top_level
end