Parent

Methods

RDoc::Parser::PerlPOD

This is an attamept to write a basic parser for Perl’s POD (Plain old Documentation) format. Ruby code must co-exist with Perl, and some tasks are easier in Perl than Ruby because of existing libraries.

One difficult is that Perl POD has no means of identifying the classes (packages) and methods (subs) with which it is associated, it is more like literate programming in so far as it just happens to be in the same place as the code, but need not be.

We would like to support all the markup the POD provides so that it will convert happily to HTML. At the moment I don’t think I can do that: time constraints.

Public Class Methods

new(top_level, file_name, content, options, stats) click to toggle source

Prepare to parse a perl file

    # File lib/rdoc/parser/perl.rb, line 28
28:   def initialize(top_level, file_name, content, options, stats)
29:     super
30: 
31:     preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
32: 
33:     preprocess.handle @content do |directive, param|
34:       warn "Unrecognized directive '#{directive}' in #{@file_name}"
35:     end
36:   end

Public Instance Methods

filter(comment) click to toggle source

Filter the perl markup that does the same as the rdoc filtering. Only basic for now. Will probably need a proper parser to cope with C<<…>> etc

     # File lib/rdoc/parser/perl.rb, line 151
151:   def filter(comment)
152:     return '' if comment =~ /^=pod\s*$/
153:     comment.gsub!(/^=pod/, '==')
154:     comment.gsub!(/^=head(\d+)/) do
155:       "=" * $1.to_i
156:     end
157:     comment.gsub!(/=item/, '');
158:     comment.gsub!(/C<(.*?)>/, '<tt>\1</tt>');
159:     comment.gsub!(/I<(.*?)>/, '<i>\1</i>');
160:     comment.gsub!(/B<(.*?)>/, '<b>\1</b>');
161:     comment
162:   end
scan() click to toggle source

Extract the Pod(-like) comments from the code. At its most basic there will ne no need to distinguish between the different types of header, etc.

This uses a simple finite state machine, in a very procedural pattern. I could “replace case with polymorphism” but I think it would obscure the intent, scatter the code all over tha place. This machine is necessary because POD requires that directives be preceded by blank lines, so reading line by line is necessary, and preserving state about what is seen is necesary.

     # File lib/rdoc/parser/perl.rb, line 51
 51:   def scan
 52: 
 53:     @top_level.comment ||= ""
 54:     state=:code_blank
 55:     line_number = 0
 56:     line = nil
 57: 
 58:     # This started out as a really long nested case statement,
 59:     # which also led to repetitive code.  I'd like to avoid that
 60:     # so I'm using a "table" instead.
 61: 
 62:     # Firstly we need some procs to do the transition and processing
 63:     # work.  Because these are procs they are closures, and they can
 64:     # use variables in the local scope.
 65:     #
 66:     # First, the "nothing to see here" stuff.
 67:     code_noop = lambda do
 68:       if line =~ /^\s+$/
 69:         state = :code_blank
 70:       end
 71:     end
 72: 
 73:     pod_noop = lambda do
 74:       if line =~ /^\s+$/
 75:         state = :pod_blank
 76:       end
 77:       @top_level.comment += filter(line)
 78:     end
 79: 
 80:     begin_noop = lambda do
 81:       if line =~ /^\s+$/
 82:         state = :begin_blank
 83:       end
 84:       @top_level.comment += filter(line)
 85:     end
 86: 
 87:     # Now for the blocks that process code and comments...
 88: 
 89:     transit_to_pod = lambda do
 90:       case line
 91:       when /^=(?:pod|head\d+)/
 92:         state = :pod_no_blank
 93:         @top_level.comment += filter(line)
 94:       when /^=over/
 95:         state = :over_no_blank
 96:         @top_level.comment += filter(line)
 97:       when /^=(?:begin|for)/
 98:         state = :begin_no_blank
 99:       end
100:     end
101: 
102:     process_pod = lambda do
103:       case line
104:       when  /^\s*$/
105:         state = :pod_blank
106:         @top_level.comment += filter(line)
107:       when /^=cut/
108:         state = :code_no_blank
109:       when /^=end/
110:         $stderr.puts "'=end' unexpected at #{line_number} in #{@file_name}"
111:       else
112:         @top_level.comment += filter(line)
113:       end
114:     end
115: 
116: 
117:     process_begin = lambda do
118:       case line
119:       when  /^\s*$/
120:         state = :begin_blank
121:         @top_level.comment += filter(line)
122:       when /^=end/
123:         state = :code_no_blank
124:       when /^=cut/
125:         $stderr.puts "'=cut' unexpected at #{line_number} in #{@file_name}"
126:       else
127:         @top_level.comment += filter(line)
128:       end
129: 
130:     end
131: 
132: 
133:     transitions = { :code_no_blank => code_noop,
134:                     :code_blank => transit_to_pod,
135:                     :pod_no_blank => pod_noop,
136:                     :pod_blank => process_pod,
137:                     :begin_no_blank => begin_noop,
138:                     :begin_blank => process_begin}
139:     @content.each_line do |l|
140:       line = l
141:       line_number += 1
142:       transitions[state].call
143:     end # each line
144: 
145:     @top_level
146:   end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.