File Coverage

blib/lib/Text/UberText/Parser.pm
Criterion Covered Total %
statement 12 127 9.4
branch 0 48 0.0
condition 0 3 0.0
subroutine 4 16 25.0
pod 5 8 62.5
total 21 202 10.4


line stmt bran cond sub pod time code
1             #
2             # Package Definition
3             #
4              
5             package Text::UberText::Parser;
6              
7             #
8             # Compiler Directives
9             #
10              
11 1     1   12 use strict;
  1         3  
  1         36  
12 1     1   4 use warnings;
  1         2  
  1         28  
13              
14             #
15             # Includes
16             #
17              
18 1     1   1047 use Text::UberText::Tree;
  1         3  
  1         35  
19              
20             #
21             # Global Variables
22             #
23              
24 1     1   9 use vars qw/$DefaultTagChars $DefaultBlockChars $VERSION /;
  1         2  
  1         1158  
25              
26             $VERSION=0.95;
27              
28             $DefaultTagChars={
29             "st" => "[",
30             "et" => "]",
31             };
32              
33             $DefaultBlockChars={
34             "st" => "->",
35             "et" => "<-",
36             };
37              
38             #
39             # Methods
40             #
41              
42             sub new
43             {
44 0     0 1   my ($class)=shift;
45 0           my ($object);
46 0           $object={};
47 0           bless ($object,$class);
48 0           $object->_init(@_);
49 0           return $object;
50             }
51              
52             sub quickie
53             {
54 0     0 1   my ($mainParser)=shift;
55 0           my ($parser,$tree,$uber);
56             # Create a new parser object
57 0           $uber=$mainParser->main();
58 0           $parser=Text::UberText::Parser->new(-noBlocks, -cmdOpt, -main => $uber);
59             # Pass along the main log and dispatch objects to the new parser
60 0           $parser->log($uber->log());
61 0           $parser->dispatch($uber->dispatch());
62 0           $parser->input(@_);
63 0           $tree=$parser->parse();
64 0           $tree->run();
65 0           return $tree->output();
66             }
67              
68             sub input
69             {
70 0     0 1   my ($self)=shift;
71 0           push (@{$self->{input}},@_);
  0            
72 0           return;
73             }
74              
75             sub clear
76             {
77 0     0 1   my ($self)=shift;
78 0           $self->{input}=[];
79 0           return;
80             }
81              
82             sub parse
83             {
84 0     0 1   my ($self)=shift;
85 0           my ($st,$et,$input,$linenum,$nodenum,$x,$level,$chunk,$log,@chars);
86 0           $self->_opts(@_);
87 0 0         if (defined($self->{opts}->{noBlocks}))
88             {
89 0           $self->{tree}=Text::UberText::Tree->new(-noBlocks, -parser => $self);
90             } else {
91 0           $self->{tree}=Text::UberText::Tree->new(-parser => $self);
92             }
93 0           $self->{tree}->dispatch($self->{dispatch});
94 0           $self->{tree}->log($self->{log});
95 0           $st=$DefaultTagChars->{st};
96 0           $et=$DefaultTagChars->{et};
97 0           $input=join("",@{$self->{input}});
  0            
98 0 0         return undef unless ($input);
99 0           (@chars)=split(//,$input);
100 0           $linenum=1;
101 0           $nodenum=1;
102 0           $chunk="";
103 0           $level=0;
104 0           while (@chars)
105             {
106 0           ($x)=shift(@chars);
107 0 0         if ($x eq $st)
    0          
    0          
108             {
109 0           $level++;
110 0 0         if ($level==1)
111             {
112             # Close out the previous node (if any)
113 0           $self->_addNode($chunk,$linenum);
114             # Start a new node
115 0           $chunk=$x;
116 0           $nodenum++;
117 0           next;
118             }
119             } elsif ($x eq $et)
120             {
121 0           $level--;
122 0 0         if ($level==0)
    0          
123             {
124             # Close out the current node
125 0           $chunk.=$x;
126 0           $chunk=$self->_checkCmd($chunk);
127 0           $self->_addNode($chunk,$linenum);
128             # Start a new node
129 0           $chunk="";
130 0           $nodenum++;
131 0           next;
132             } elsif ($level < 0)
133             {
134 0           $self->{log}->write("Parser",
135             "Too many closing brackets",$linenum,"ERROR");
136             }
137             } elsif ($x eq "\n")
138             {
139 0           $linenum++;
140             }
141 0           $chunk.=$x;
142             }
143 0 0         if ($chunk)
144             {
145 0           $self->_addNode($chunk,$linenum);
146             }
147 0 0         if ($level > 0)
148             {
149 0           $self->{log}->write("Parser",
150             "Unmatched opening block",$linenum,"ERROR");
151             }
152 0 0         if ($self->{log})
153             {
154 0 0         if (defined($self->{opts}->{cmdblock}))
155             {
156 0           $self->{log}->write("Parser/cmdblock",
157             "Parsed $linenum lines, $nodenum nodes",
158             $linenum,"NOTICE");
159             } else {
160 0           $self->{log}->write("Parser/main",
161             "Parsed $linenum lines, $nodenum nodes"
162             ,$linenum,"NOTICE");
163             }
164             }
165 0           return $self->{tree};
166             }
167              
168             sub dispatch
169             {
170 0     0 0   my ($self)=shift;
171 0 0         if (@_)
172             {
173 0           $self->{dispatch}=shift;
174             }
175 0           return $self->{dispatch};
176             }
177              
178             sub log
179             {
180 0     0 0   my ($self)=shift;
181 0 0         if (@_)
182             {
183 0           $self->{log}=shift;
184             }
185 0           return $self->{log};
186             }
187              
188             sub main
189             {
190 0     0 0   my ($self)=shift;
191 0 0         if (@_)
192             {
193 0           $self->{main}=shift;
194             }
195 0           return $self->{main};
196             }
197              
198             #
199             # Hidden Methods
200             #
201              
202             sub _init
203             {
204 0     0     my ($self)=shift;
205 0           $self->{blocks}=[];
206 0           while (@_)
207             {
208 0           ($a)=shift;
209 0 0         if ($a eq "-main")
    0          
    0          
210             {
211 0           $self->{main}=shift;
212             } elsif ($a eq "-cmdOpt")
213             {
214 0           $self->{opts}->{cmdblock}=1;
215             } elsif ($a eq "-noBlocks")
216             {
217 0           $self->{opts}->{noblocks}=1;
218             }
219             }
220 0           return;
221             }
222              
223             sub _opts
224             {
225 0     0     my ($self)=shift;
226 0           while (@_)
227             {
228 0           ($a)=shift;
229 0 0         if ($a eq "-noBlocks")
    0          
230             {
231             # Command container blocks are not allowed
232 0           $self->{opts}->{noblocks}=1;
233             } elsif ($a eq "-cmdOpt")
234             {
235 0           print("PARSING IN A COMMAND BLOCK!\n");
236             # We are parsing the option to a command
237 0           $self->{opts}->{cmdblock}=1;
238             }
239             }
240 0           return;
241             }
242              
243             sub _checkCmd
244             {
245 0     0     my ($self)=shift;
246 0 0         if (@_)
247             {
248 0           my ($chunk)=@_;
249 0           my ($st,$et);
250 0           $st=$DefaultBlockChars->{st};
251 0           $et=$DefaultBlockChars->{et};
252 0 0 0       if ($chunk =~ /(^\[\s*$et|$st\s*\]$)/ && $self->{noblocks})
253             {
254 0           $chunk=~s/(^\[\s*$et|$st\s*\]$)//g;
255             }
256 0           return $chunk;
257             }
258             }
259              
260             sub _addNode
261             {
262 0     0     my ($self)=shift;
263 0           my ($text,$line)=@_;
264 0 0         if ($text =~ /^\[.*\]$/s)
    0          
265             {
266             # command node
267 0           $self->{tree}->addNode( -text => $text,
268             -line => $line,
269             -class => "Text::UberText::Node::Command");
270             } elsif ($text ne "")
271             {
272             # text node
273 0           $self->{tree}->addNode( -text => $text,
274             -line => $line,
275             -class => "Text::UberText::Node::Text");
276             } else {
277 0           print("Empty node!\n");
278             # empty node
279             }
280 0           return;
281             }
282              
283             #
284             # Exit Block
285             #
286             1;
287              
288             #
289             # POD Documentation
290             #
291              
292             =head1 NAME
293              
294             Text::UberText::Parser - Main parser for UberText streams
295              
296             =head1 SYNOPSIS
297              
298             Text::UberText::Parser methods are not normally called directly
299              
300             =head1 DESCRIPTION
301              
302             The UberText::Parser module handles the incoming text stream and breaks it
303             up into the text and command nodes. The nodes are then handed off to a
304             Text::UberText::Tree object which creates the Text::UberText::Node objects
305             and inserts them at the appropriate part of the document tree.
306              
307             =head1 METHODS
308              
309             =over 4
310              
311             =item $parser=Text::UberText::Parser->new();
312              
313             Creates a new parser object.
314              
315             =item $parser->input(@array);
316              
317             Takes the passed text and saves it for further parsing. If called multiple
318             times, it appends the new text to any previous text passed.
319              
320             =item $tree=$parser->parse();
321              
322             Runs the parsing routines to break apart the document. The commands and text
323             of the document are seperated into nodes and passed to the Text::UberText::Tree
324             object which places them in the appropriate order. The tree object is
325             then returned so it can be run or further manipulated.
326              
327             =item $parser->clear();
328              
329             Wipes out the internal document input data.
330              
331             =item $parser->quickie(@array);
332              
333             Designed to quickly process small streams (like the values tied to
334             commands or options in a Command node), the quickie method takes the input,
335             and sends it to a new parser object, processes the input, returns a new
336             tree, runs the tree, and then returns the output from the tree object.
337              
338             The quickie method is actually very complex because it needs to create a
339             seperate Tree object, but it also needs to refer back to the main Dispatch
340             and Log objects. Every time a value is used in an option or command, it
341             is treated like an entirely seperate UberText document.
342              
343             =back
344              
345             =head1 AUTHOR
346              
347             Chris Josephes Ecpj1@visi.comE
348              
349             =head1 SEE ALSO
350              
351             L,
352             L
353              
354             =head1 COPYRIGHT
355              
356             Copyright 2002, Chris Josephes. All rights reserved.
357             This module is free software. It may be used, redistributed,
358             and/or modified under the same terms as Perl itself.
359             ~