5
# This is an attamept to write a basic parser for Perl's
6
# POD (Plain old Documentation) format. Ruby code must
7
# co-exist with Perl, and some tasks are easier in Perl
8
# than Ruby because of existing libraries.
10
# One difficult is that Perl POD has no means of identifying
11
# the classes (packages) and methods (subs) with which it
12
# is associated, it is more like literate programming in so
13
# far as it just happens to be in the same place as the code,
16
# We would like to support all the markup the POD provides
17
# so that it will convert happily to HTML. At the moment
18
# I don't think I can do that: time constraints.
21
class RDoc::Parser::PerlPOD < RDoc::Parser
23
parse_files_matching(/.p[lm]$/)
26
# Prepare to parse a perl file
28
def initialize(top_level, file_name, content, options, stats)
31
preprocess = RDoc::Markup::PreProcess.new @file_name, @options.rdoc_include
33
preprocess.handle @content do |directive, param|
34
warn "Unrecognized directive '#{directive}' in #{@file_name}"
39
# Extract the Pod(-like) comments from the code.
40
# At its most basic there will ne no need to distinguish
41
# between the different types of header, etc.
43
# This uses a simple finite state machine, in a very
44
# procedural pattern. I could "replace case with polymorphism"
45
# but I think it would obscure the intent, scatter the
46
# code all over tha place. This machine is necessary
47
# because POD requires that directives be preceded by
48
# blank lines, so reading line by line is necessary,
49
# and preserving state about what is seen is necesary.
53
@top_level.comment ||= ""
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.
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.
66
# First, the "nothing to see here" stuff.
77
@top_level.comment += filter(line)
80
begin_noop = lambda do
84
@top_level.comment += filter(line)
87
# Now for the blocks that process code and comments...
89
transit_to_pod = lambda do
91
when /^=(?:pod|head\d+)/
93
@top_level.comment += filter(line)
95
state = :over_no_blank
96
@top_level.comment += filter(line)
97
when /^=(?:begin|for)/
98
state = :begin_no_blank
102
process_pod = lambda do
106
@top_level.comment += filter(line)
108
state = :code_no_blank
110
$stderr.puts "'=end' unexpected at #{line_number} in #{@file_name}"
112
@top_level.comment += filter(line)
117
process_begin = lambda do
121
@top_level.comment += filter(line)
123
state = :code_no_blank
125
$stderr.puts "'=cut' unexpected at #{line_number} in #{@file_name}"
127
@top_level.comment += filter(line)
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|
142
transitions[state].call
148
# Filter the perl markup that does the same as the rdoc
149
# filtering. Only basic for now. Will probably need a
150
# proper parser to cope with C<<...>> etc
152
return '' if comment =~ /^=pod\s*$/
153
comment.gsub!(/^=pod/, '==')
154
comment.gsub!(/^=head(\d+)/) do
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>');