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__
|
---|