1: package Filter::QuasiLiterate;
2: use strict;
3: use Carp;
4: use Filter::Util::Call;
5:
6: sub import
7: {
8: my $me =
9: {
10: sections => { },
11: defining => undef,
12: };
13: filter_add(bless $me);
14: }
15:
16: sub filter
17: {
18: my $me = shift;
19: my $status = filter_read;
20: ($status > 0) or return $status;
21:
22: (/^\s*\#([<>])/ ?
23: (($1 eq '<') ?
24: (/^\s*\#[<>]([a-zA-Z0-9\-.\/: ]+)(\>?)(?:\#.*)?$/ ?
25: (($2 eq '>') ?
26: (exists $me->{sections}->{$1} ?
27: ($_ = $me->{sections}->{$1}) :
28: (croak "QuasiLiterate filter: chunk does not exist: \"$1\"")
29: ) :
30: (push @ {$me->{defining}},
31: (((scalar @ {$me->{defining}}) ? $me->{defining}->[-1] . '.' : '')
32: . $1))
33: ) :
34: (croak "QuasiLiterate filter: invalid command: \"$_\"")
35: ) :
36: (pop @ {$me->{defining}})
37: ) :
38: ((scalar @ {$me->{defining}})? do
39: {
40: foreach my $def (@ {$me->{defining}}) { $me->{sections}->{$def}
41: .= $_ }
42: $_ = '';
43: } :
44: ()));
45:
46: return $status;
47: }
48:
49: =head1 NAME
50:
51: Filter::QuasiLiterate
52:
53: =head1 SYNOPSIS
54:
55: use Filter::QuasiLiterate;
56: #<foo_code
57: # Put code that does foo here.
58: #>
59: #<foo_doc
60: It then does foo, by first calling bar...
61: #>
62: # etc.
63:
64: if ($Run)
65: {
66: #<foo_code>
67: }
68: else
69: {
70: print <<'//'; # Or some other string you're sure won't be a
71: # line in foo_doc
72: #<foo_doc>
73: //
74: }
75: #<nested-section
76: #<bork
77: # now in nested-section.bork
78: bork;
79: #>
80: gork;
81: #>
82:
83: #<nested-section> # Gives bork then gork
84: #<nested-section.bork> # Gives bork by itself
85:
86: #<blorple
87: xyzzy;
88: #>
89: #<baz
90: rumple;
91: #>
92: #<blorple
93: fizzy;
94: #>
95: #<blorple> # Gives xyzzy then fizzy
96:
97:
98: =head1 DESCRIPTION
99:
100: Filter::QuasiLiterate allows you to do quasi-literate programming, using
101: chunks of code / documentation / comments / whatever which can get reused,
102: shuffled arbitrarily, and/or disused. Chunks can also be defined in pieces,
103: and nested. QuasiLiterate commands are indicated by lines with any amount
104: of whitespace, followed by # and then either < or >. They are terminated by
105: newline or #. Chunk names may contain any of the characters a-z, A-Z, 0-9,
106: or [-./: ]. #<chunk-name will start defining a chunk, or adding to it if
107: a chunk with that name already exists. If a chunk is already
108: being defined, the new chunk will have the name outer.inner, where outer and
109: inner are placeholders for the outer and inner chunks. Anything inside the
110: inner chunk is added to both the outer and inner chunks. Chunks can be
111: nested to an infinite (theoretically) number of levels. #> stops defining
112: the innermost chunk. Note that if a nested chunk is added to explicitly,
113: i.e. with a specified name of outer.inner, the outer chunk will I<not> be
114: added to. #<chunk-name> (note the >) includes the contents
115: of a previously defined chunk at the current position.
116:
117: =head1 BUGS
118:
119: There should be more options. Chunks can't be used before their definitions.
120: Documentation could be I<much> better.
121:
122: There are undoubtedly more bugs lurking here somewhere.
123:
124: =head1 SEE ALSO
125:
126: This is the mandatory SEE ALSO section. There is no useful information here. :-)
127:
128: =cut
129:
130: 1;
131:
132: __END__