File Coverage

blib/lib/Decl.pm
Criterion Covered Total %
statement 205 238 86.1
branch 70 98 71.4
condition 21 37 56.7
subroutine 37 45 82.2
pod 29 29 100.0
total 362 447 80.9


line stmt bran cond sub pod time code
1             package Decl;
2            
3 12     12   382237 use warnings;
  12         32  
  12         410  
4 12     12   73 use strict;
  12         22  
  12         431  
5 12     12   65 use base qw(Decl::EventContext Decl::Node);
  12         29  
  12         6401  
6 12     12   15757 use Filter::Util::Call;
  12         16108  
  12         969  
7             #use Parse::Indented;
8             #use Parse::RecDescent::Simple;
9 12     12   8022 use Decl::Parser;
  12         52  
  12         483  
10 12     12   204 use Decl::Util;
  12         31  
  12         1224  
11 12     12   9040 use Decl::DefaultParsers;
  12         38  
  12         460  
12 12     12   7320 use Decl::StandardFilters;
  12         35  
  12         292  
13 12     12   7318 use Decl::NodalValuator;
  12         38  
  12         326  
14 12     12   91 use File::Spec;
  12         20  
  12         251  
15 12     12   57 use Data::Dumper;
  12         21  
  12         520  
16 12     12   69 use Scalar::Util qw(blessed);
  12         23  
  12         567  
17 12     12   63 use Carp;
  12         22  
  12         3911  
18            
19             =head1 NAME
20            
21             Decl - Provides a declarative framework for Perl
22            
23             =head1 VERSION
24            
25             Version 0.11
26            
27             =cut
28            
29             our $VERSION = '0.11';
30            
31             $SIG{__WARN__} = sub {
32             return if $_[0] =~ /Deep recursion.*Parser/; # TODO: Jezus, Maria es minden szentek.
33             #require Carp; Carp::cluck
34             warn $_[0];
35             };
36            
37            
38             =head1 SYNOPSIS
39            
40             This module is a framework for writing Perl code in a declarative manner. What that means right now is that instead of seeing a script as a
41             series of actions to be carried out, you can view the script as a set of objects to be instantiated, then invoked. The syntax for building
42             these objects is intended to be concise and flexible, mostly staying out of your way. Perl code is used to declare actions to be taken once
43             the structure is built, as well as any actions to be taken interactively as the script runs.
44            
45             The original motivation for designing this framework was to provide a more rational way of defining a L user interface. As it is, the
46             data structures making up a Wx GUI are built with painstakingly detailed (and boring) imperative code. There are XML-based GUI specification
47             frameworks, but I wanted to write my own that wasn't XML-based because I hate typing XML even more than I hate writing setup code.
48            
49             Back when I did a lot of GUI work, I'd usually write some pseudocode to describe parts of the UI, then translate it into code by hand.
50             So this year, while noodling around about some tools I'd find useful in my translation business, I thought, well,
51             why not just write a class to interpret that pseudocode description directly?
52            
53             Once I started getting into that in earnest, I realized that the Wx-specific functionality could be spun out into an application-specific
54             (in my new parlance, a "semantic") domain, leaving a core set of functionality that was a general declarative framework. I then realized that
55             the same framework could easily be used to work with domains other than Wx GUIs, such as building PDFs, building Flash applications, doing
56             things with Word documents... All kinds of things. All of those things are currently in pieces on the workbench - except for the Word
57             module, which is ready, if not for prime time, then at least for deep cable midnight airing.
58            
59             Here's a GUI example using something like the Wx domain. This is a pretty simple example, but it gives you a taste of what I'm talking about.
60             Since Decl runs as a source filter, the example below is a working Perl script that replaces roughly 80 lines of the Wx
61             example code it was adapted from. And yes, it runs in my test suite right now.
62            
63             use Wx::Declarative;
64            
65             dialog (xsize=250, ysize=110) "Wx::Declarative dialog sample"
66             field celsius (size=100, x=20, y=20) "0"
67             button celsius (x=130, y=20) "Celsius" { $^fahrenheit = ($^celsius / 100.0) * 180 + 32; }
68             field fahrenheit (size=100, x=20, y=50) "32"
69             button fahrenheit (x=130, y=50) "Fahrenheit" { $^celsius = (($^fahrenheit - 32) / 180.0) * 100; }
70            
71             The main things to look at are as follows: first, yes - syntactically significant indentation. I know it's suspiciously Pythonic, I know all
72             the arguments citing the danger of getting things to line up, and I don't care; this is the way I have always written my pseudocode, and
73             odds are you're no different and you know it. If it makes you feel better, the indentation detection algorithm is pretty flexible, and Perl
74             code within curly braces is exempt from indentation significance. (Not that this example has any multiline code, but you see what I mean.)
75            
76             Second, fields are declared here and their content is exposed as magic variables in the code snippets. You will immediately see that code
77             embedded in a declarative structure goes through a modification pass before being C'd into a sub. So there is a possibility that I
78             have screwed that modification pass up. I don't have an answer for this right now; the point is quick and easy, not perfection (yet).
79             Caveat emptor. It's still a neat feature.
80            
81             There is a standard parser and standard data structure available for tags to use if it suits your purpose - but there's no mandate to use them,
82             and the parser tools are open for use. They're still a little raw, but pretty powerful.
83            
84             A declarative object can report its own source code, and that source code can compile into an equivalent declarative object. This means that dynamically
85             constructed objects or applications can be written out as executable code, and code has introspective capability while in the loaded state. C
86             also has a macro system that allows the construction of code during the build phase; a macro always dumps as its source, not the result of the expansion, so
87             you can capture dynamic behavior that runs dynamically every time.
88            
89             =head1 TUTORIAL
90            
91             For more information about how to use C, you'll probably want to see the tutorial in L
92             instead of this file; the rest of this presentation is devoted to the internal workings of C.
93             (Old literate programming habits, I guess.)
94             Honestly, you can probably just stop here, because if you're not reading the source along with the POD it probably won't make any sense anyway.
95             Go read the tutorial. Not that I've finished it.
96            
97             =head1 SETTING UP THE CLASS STRUCTURE
98            
99             =head2 import, yes_i_am_declarative, import_one
100            
101             The C function is called when the package is imported. It's used for the filter support; don't call it.
102            
103             If semantic classes are supplied in the C command, we're going to instantiate and scan them here. They'll be used to decorate the
104             parse tree appropriately.
105            
106             =cut
107            
108             our %build_handlers = ();
109             our %build_flags = ();
110             our @semantic_classes = ();
111            
112 0     0 1 0 sub yes_i_am_declarative { 1 } # This is probably a childish way of doing this.
113             our $initial_load;
114             sub import
115             {
116 24     24   142 my($type, @arguments) = @_;
117            
118 24 100       78 if (not defined $initial_load) {
119 12         20 $initial_load = 1;
120            
121 12 100 66     102 if (!@arguments || $arguments[0] ne '-nofilter') {
122 1         6 filter_add(bless { start => 1 });
123             } else {
124 11 50       38 shift @arguments if @arguments;
125             }
126 12 100       55 push @arguments, "Decl::Semantics" unless grep { $_ eq "Decl::Semantics" } @arguments;
  11         68  
127             }
128            
129 12     12   17360 use lib "./lib"; # This allows us to test semantic modules without disturbing their production variants that are installed.
  12         13672  
  12         67  
130 24         157 foreach my $import_module (@arguments) {
131 12         46 import_one($import_module);
132             }
133             }
134             sub import_one {
135 12     12 1 24 my ($import_module) = @_;
136            
137             #print "importing $import_module\n";
138 12 0       50 unless (grep { defined $_ and $import_module eq $_ } @semantic_classes) { # Only try to import each semantic class once.
  0 50       0  
139 12     12   6660 eval "use $import_module;";
  12         35  
  12         301  
  12         744  
140 12 50       95 if ($@) {
141 0         0 warn $@;
142             } else {
143 12         39 push @semantic_classes, $import_module;
144 12         1402 eval 'foreach (' . $import_module . '->decl_include()) { import_one $_ }';
145             }
146             }
147             }
148            
149             =head2 class_builders(), find_tagdef($parent, $tag), build_handler ($parent, $tag), register_builder ($node)
150            
151             Given a tag name, C returns a hashref of information about how the tag expects to be treated:
152            
153             * The class its objects should be blessed into, as a coderef to generate the object ('Decl::Node' is the default)
154             * Its line parser, by name ('default-line' is the default)
155             * Its body parser, by name ('default-body' is the default)
156             * A second-level hashref of hashrefs providing overriding semantics for descendants of this tag.
157            
158             If you also provide a hashref, it is assigned to the tag name.
159            
160             The C does the same thing, but specific to the given application - this allows dynamic tag definition.
161            
162             Finally, C is a read-only lookup for a tag in the context of its ancestry that climbs the tree to find the contextual
163             semantics for the tag.
164            
165             =cut
166            
167             our $class_builders; # Note: this is initalized below, after the default parsers are set up.
168            
169 0     0 1 0 sub class_builders { $class_builders; }
170            
171             sub find_tagdef {
172 1845     1845 1 3036 my ($self, $parent, $tag) = @_;
173            
174 1845 100       5154 my $apptag = $self->{build_handlers} ? $self->{build_handlers}->nodes($tag) : undef;
175 1845         5504 my $classtag = $class_builders->nodes($tag);
176            
177 1845 100       4029 my $apptagd = defined $apptag ? $apptag->nodes($parent->{domain}) : undef;
178 1845 100       3833 my $classtagd = defined $classtag ? $classtag->nodes($parent->{domain}) : undef;
179            
180 1845   100     6553 my $tagdef = $apptagd || $classtagd;
181            
182 1845 50 66     8169 $tagdef = $apptag->nodes if not defined $tagdef and defined $apptag;
183 1845 50 66     7606 $tagdef = $classtag->nodes if not defined $tagdef and defined $classtag; #TODO: man, this really doesn't seem right.
184            
185 1845         4080 return $tagdef;
186             }
187            
188             sub build_handler {
189 2722     2722 1 4674 my ($self, $parent, $tag) = @_;
190            
191 2722 100 100     18584 if (defined $parent->{parsemode} and $parent->{parsemode} eq 'vanilla') {
192 1523 100       6704 return (defined $parent->{vanilla_class} ? $parent->{vanilla_class} : 'Decl::Node', undef, 'vanilla');
193             }
194            
195 1199         1447 my $flag;
196 1199         3406 ($tag, $flag) = Decl::Node::splittag ($tag);
197            
198 1199         4154 my $tagdef = $self->find_tagdef($parent, $tag);
199 1199 100       2920 return ($tagdef->label, $tagdef->tag, $tagdef->parameter('body'), $tagdef->parameter('line'), $tagdef->parameter('vanilla')) if defined $tagdef;
200            
201 1114         1575 my $vanilla_class = 'Decl::Node';
202            
203 1114 100       5889 return ($vanilla_class, undef, 'vanilla') unless blessed($parent);
204 646         2480 my $ancestry = $parent->ancestry();
205 646         1636 foreach (@$ancestry) {
206 646         1539 my $t = $self->find_tagdef($parent, $_);
207 646 50 33     14736 if (defined $t and $t->parameter('vanilla')) {
208 0         0 $vanilla_class = $t->parameter('vanilla');
209 0         0 last;
210             }
211             }
212 646         2620 return ($vanilla_class, undef, 'vanilla', undef, $vanilla_class);
213             }
214            
215             sub register_builder {
216 158     158 1 496 my ($self, $class, $domain, $tags) = @_;
217 158 100       483 my $bh_list = ref($self) ? $self->{build_handlers} : $class_builders;
218 158         1127 foreach my $tag_to_add ($tags->nodes()) {
219 278   33     918 my $tag = $bh_list->first($tag_to_add->tag) || $bh_list->load($tag_to_add->tag);
220 278         1228 my $domain_tag = $tag->nodes($domain);
221 278 50       1033 if (not defined $domain_tag) {
222 278         1077 $domain_tag = $tag->load($domain);
223             }
224 278         1272 my $within = $tags->nodes('within');
225 278 50       957 if ($within) {
226 0         0 my $target_within = $domain_tag->load($within->myline());
227 0         0 $domain_tag = $target_within;
228             }
229 278         1761 $domain_tag->set_label($class);
230 278         581 $domain_tag->{parmlist} = \@{$tag_to_add->{parmlist}}; # TODO: maybe a real Node copier at some point? This is hardly going to be the first transformation
  278         923  
231 278         554 $domain_tag->{parameters} = \%{$tag_to_add->{parameters}}; # where this is going to be needed...
  278         890  
232 278         1122 foreach ($tag_to_add->nodes()) {
233 0 0       0 next if $_->is('within');
234 0         0 $domain_tag->load ($_->describe());
235             }
236             }
237             #print STDERR $self->{build_handlers}->describe() if ref($self);
238             }
239            
240             =head2 makenode($ancestry, $code)
241            
242             Finds the right build handler for the tag in question, then builds the right class of node with the code given.
243            
244             =cut
245            
246             sub makenode {
247 975     975 1 2454 my ($self, $parent, $tag, $body) = @_;
248            
249 975         2595 my ($build_class, $domain, $parsemode, $linemode, $vanilla_class) = $self->build_handler($parent, $tag);
250 975         5069 my $newnode = $build_class->new($body);
251 975 100       2314 if ($vanilla_class) {
252 320         640 $newnode->{parsemode} = 'vanilla';
253 320         745 $newnode->{vanilla_class} = $vanilla_class;
254             } else {
255 655         1729 $newnode->{parsemode} = $parsemode;
256             }
257 975 100       3538 if ($newnode->flag('.')) {
    100          
    50          
258 12         31 $newnode->{parsemode} = 'text';
259             } elsif ($newnode->flag('*')) {
260 1         3 $newnode->{parsemode} = 'vanilla';
261             } elsif ($newnode->flag('+')) {
262 0         0 $newnode->{parsemode} = '';
263             }
264 975         2526 $newnode->{domain} = $domain;
265 975         3451 $newnode;
266             }
267            
268             =head2 remakenode($node)
269            
270             If it turns out that things have changed semantically since we split a node out, and the node hasn't been built yet
271             (this is specifically to support the "use" tag), then we can signal that the node should be remade, and we'll build
272             and substitute a new node based on the new semantic environment and using the information available to us in the
273             initially created node.
274            
275             =cut
276            
277             sub remakenode {
278 0     0 1 0 my ($self, $node) = @_;
279            
280 0         0 my $bh = $self->build_handler($self->parent, $self->tag); #$node->ancestry);
281 0         0 my $replacement = $bh->{node}->([$node->tag . $node->flag . " " . $node->line, $node->body]);
282 0         0 $replacement->{parent} = $node->parent;
283 0         0 return $replacement;
284             }
285            
286            
287             =head1 FILTERING SOURCE CODE
288            
289             By default, C runs as a filter. That means it intercepts code coming in and can change it before Perl starts parsing. Needless to say,
290             filters act very cautiously, because the only thing that can parse Perl correctly is Perl (and sometimes even Perl has doubts). So this filter basically just
291             wraps the entire input source in a call to C, which is then parsed and called after the filter returns.
292            
293             =head2 filter
294            
295             The C function is called by the source code filtering process. You probably don't want to call it. But if you've ever wondered
296             how difficult it is to write a source code filter, read it. Hint: I.
297            
298             =cut
299            
300             sub filter
301             {
302 4     4 1 404 my $self = shift;
303 4         3 my $status;
304            
305 4 100       38 if (($status = filter_read()) > 0) {
    100          
306 2 100       10 if ($$self{start}) {
307 1         3 $$self{start} = 0;
308 1         4 $_ = "my \$root = " . __PACKAGE__ . "->new();\n\$root->load(<<'DeclarativeEOF');\n$_";
309             }
310             } elsif (!$$self{start}) { # Called on EOF if we ever saw any code.
311 1         2 $_ = "\nDeclarativeEOF\n\n\$root->start();\n\n";
312 1         2 $$self{start} = 1; # Otherwise we'll repeat the EOF forever.
313 1         2 $status = 1;
314             }
315            
316 4         2394 $status;
317             }
318            
319            
320             =head1 PARSERS
321            
322             The parsing process in C is recursive. The basic form is a tagged line followed by indented text, followed by another tagged line
323             with indented text, and so on. Alternatively, the indented part can be surrounded by brackets.
324            
325             tag [rest of line]
326             indented text
327             indented text
328             indented text
329             tag [rest of line] {
330             bracketed text
331             bracketed text
332             }
333            
334             By default, each tag parses its indented text in the same way, and it's turtles all the way down. Bracketed text, however, is normally I parsed as
335             declarative (or "nodal") structure, but is left untouched for special handling, typically being parsed by Perl and wrapped as a closure.
336            
337             To force content to be handled as text instead of nodal structure, put a period on the end of the tag. Some tags are defined with this as the default;
338             for these you can force normal nodal structure with a '!', or data-only nodal structure with a '*'.
339            
340             However, all this is merely the default. Any tag may also specify a different parser for its own indented text, or may carry out some transformation on the
341             text before invoking the parser. It's up to the tag. The C tag, for instance, treats each indented line as a row in a table.
342            
343             Once the body is handled, the "rest of line" is also parsed into data useful for the node. Again, there is a default parser, which takes a line of the
344             following form:
345            
346             tag name (parameter, parameter=value) [option, option=value] "label or other string text" parser < { bracketed text }
347            
348             Any element of that line may be omitted, except for the tag.
349            
350             =head2 init_parsers()
351            
352             Sets up the registry and builds our default line and body parsers.
353            
354             =cut
355            
356             sub init_parsers {
357 27     27 1 68 my ($self) = @_;
358 27         96 $self->{parsers} = {};
359            
360             #$self->{parsers}->{"default-line"} = $self->init_default_line_parser();
361             #$self->{parsers}->{"default-body"} = $self->init_default_body_parser();
362             #$self->{parsers}->{"locator"} = $self->init_locator_parser();
363             }
364            
365             our %default_parsers = ();
366             $default_parsers{'default-line'} = Decl::DefaultParsers::init_default_line_parser(undef);
367             $default_parsers{'default-body'} = Decl::DefaultParsers::init_default_body_parser(undef);
368             $default_parsers{'locator'} = Decl::DefaultParsers::init_locator_parser(undef);
369            
370            
371             $class_builders = Decl->new_data_with_label('*cbh'); # Have to initialize this after the default parsers are defined...
372            
373             =head2 parser($name)
374            
375             Retrieves a parser from the registry.
376            
377             =cut
378            
379             sub parser {
380 2071     2071 1 4039 my ($self, $parsername) = @_;
381 2071         4230 my $possible = $self->{parsers}->{$parsername};
382 2071 50       4298 return $possible if $possible;
383 2071         6263 $default_parsers{$parsername};
384             }
385            
386             =head2 parse_line ($node)
387            
388             Given a node, finds the line parser for it, and runs it on the node's line.
389            
390             =cut
391            
392             sub parse_line {
393 975     975 1 1763 my ($self, $node, $line) = @_;
394            
395 975         3372 my ($class, $domain, $bodyp, $linep) = $self->build_handler($node->parent, $node->tag);
396 975 50 66     3628 return if defined $linep and $linep eq 'none';
397 975   50     4854 my $p = $self->parser($linep || 'default-line');
398 975         3571 $p->execute($node, $line); # TODO: error handler for incorrect parser specification.
399             }
400            
401             =head2 parse($node, $body)
402            
403             Given a node and body text for it, finds the body parser appropriate to the node's tag and runs it on the node and the body text specified.
404            
405             =cut
406            
407             sub parse {
408 793     793 1 1588 my ($self, $node, $body) = @_;
409            
410 793 100       2792 return if $node->{parsemode} eq 'text';
411            
412 772         2637 my ($class, $domain, $bodyp, $linep) = $self->build_handler($node->parent, $node->tag);
413 772 100 66     2839 $bodyp = 'default-body' if $bodyp eq 'text' and $node->{parsemode} eq 'vanilla';
414 772 100       2788 $bodyp = 'default-body' if $bodyp eq 'vanilla';
415 772   50     2992 my $p = $self->parser($bodyp || 'default-body');
416 772         3106 $p->execute($self, $node, $body);
417             }
418            
419             =head2 parse_using($string, $parser)
420            
421             Given a string and the name of a parser, calls the parser on the string and returns the result.
422            
423             =cut
424            
425             sub parse_using {
426 320     320 1 5091 my ($self, $string, $parser) = @_;
427 320         929 my $p = $self->parser($parser);
428 320 100       1238 return undef unless $p;
429 319         1195 return $p->execute($string);
430             }
431            
432             =head1 TEMPLATE ENGINE
433            
434             The macro system in Decl uses a template engine implemented in Decl::Template. However, the plain vanilla "valuator" (the
435             function used by a given template engine instance to find values for fields with particular names/specs) is replaced in the
436             Decl node environment by a much more powerful valuator. That valuator is implemented in Decl::NodalValuator.
437            
438             We instantiate a template engine with a nodal valuator for use by the macro system here.
439            
440             =cut
441            
442             our $template_engine = Decl::NodalValuator::instantiate();
443            
444             =head1 BUILDING AND MANAGING THE APPLICATION
445            
446             You'd think this would be up at the top, but we had to do a lot of work just to be ready to instantiate a C object.
447            
448             =head2 new, new_data, new_data_with_label
449            
450             The C function is of course called to create a new C object. If you pass it some code, it will load that code
451             immediately.
452            
453             The C is used if you don't want anything to have any semantics or action. It's used for some internal data structures.
454             "Describe" works the same way, not specifying the root tag. This may not be what you want.
455            
456             Finally C allows you to provide a different *-tag for the data; this could be useful for debugging. Or I might
457             get rid of it. I don't know yet. It's only used internally in this module anyway.
458            
459             =cut
460            
461             sub new {
462 27     27 1 9310 my $class = shift;
463 27         319 my $self = $class->SUPER::new('*root');
464 27         110 $self->{id_list} = {};
465 27         83 $self->{next_id} = 1;
466 27         81 $self->{root} = $self;
467            
468 27         129 $self->init_parsers;
469            
470 27         142 $self->{build_handlers} = Decl->new_data_with_label("*bh");
471            
472 27         112 $self->{semantics} = {};
473 27         171 $self->{semtags} = {};
474 27         68 $self->{controller} = '';
475            
476 27         113 foreach (@semantic_classes) { $self->initiate_semantic_class($_); }
  54         177  
477            
478             #print STDERR $class_builders->describe; die;
479            
480 27         230 $self->event_context_init;
481            
482 27 100       113 if (defined $_[0]) {
483 15         104 $self->load($_[0]);
484             }
485 26         173 return $self;
486             }
487            
488             sub new_data_with_label {
489 39     39 1 93 my $class = shift;
490 39         92 my $label = shift;
491 39         161 my $self = $class->new_data(@_);
492 39         84 $self->{tag} = $label;
493 39         109 return $self;
494             }
495            
496             sub new_data {
497 197     197 1 495 my $class = shift;
498 197         1524 my $self = $class->SUPER::new('*data');
499 197         689 $self->{id_list} = {};
500 197         470 $self->{next_id} = 1;
501 197         614 $self->{root} = $self;
502            
503 197         845 $self->{semantics} = {};
504 197         628 $self->{semtags} = {};
505 197         590 $self->{controller} = '';
506 197 100       578 if (defined $_[0]) {
507 158         998 $self->load($_[0]);
508             }
509 197         781 $self->{parsemode} = 'vanilla';
510 197         918 return $self;
511             }
512            
513             =head2 initiate_semantic_class
514            
515             Does what it says on the tin.
516            
517             =cut
518            
519             sub initiate_semantic_class {
520 54     54 1 120 my ($self, $class) = @_;
521 54 50       157 return unless defined $class;
522 54 100       364 return if defined $self->{semtags}->{$class};
523 27         216 my $s = $class->new($self);
524 27         137 $self->{semtags}->{$class} = $s->tag;
525 27 50       173 $self->{controller} = $s->tag unless $self->{controller};
526 27         122 $self->{semantics}->{$s->tag} = $s;
527             }
528            
529             =head2 semantic_handler ($tag)
530            
531             Returns the instance of a semantic module, such as 'core' or 'wx'.
532            
533             =cut
534            
535 20     20 1 119 sub semantic_handler { $_[0]->{semantics}->{$_[1]} }
536            
537            
538             =head2 start
539            
540             This is called from outside to kick off the process defined in this application. The way we handle this is just to ask the first semantic class to start
541             itself. The idea there being that it's probably going to be Wx or something that provides the interface. (It could also be a Web server or something.)
542            
543             The core semantics just execute all the top-level items that are flagged callable.
544            
545             =cut
546            
547             sub start {
548 8     8 1 1052 my ($self, $tag) = @_;
549            
550 8         26 $self->{callable} = 1;
551 8         100 $self->go();
552             #$tag = $self->{controller} unless $tag;
553             #$self->{semantics}->{$tag}->start;
554             }
555            
556            
557             =head2 id($idstring)
558            
559             Wx works with numeric IDs for events, and I presume the other event-based systems do, too. I don't like numbers; they're hard to read and tell apart.
560             So C registers event names for you, assigning application-wide unique numeric IDs you can use in your payload objects.
561            
562             =cut
563            
564             sub id {
565 0     0 1 0 my ($self, $str) = @_;
566            
567 0 0 0     0 if (not defined $str or not $str) {
568 0         0 my $retval = $self->{next_id} ++;
569 0         0 return $retval;
570             }
571 0 0       0 if (not defined $self->{id_list}->{$str}) {
572 0         0 $self->{id_list}->{$str} = $self->{next_id} ++;
573             }
574 0         0 return $self->{id_list}->{$str};
575             }
576            
577            
578             =head2 root()
579            
580             Returns $self; for nodes, returns the parent. The upshot is that by calling C we can get the root of the tree, fast.
581            
582             =cut
583            
584 4804     4804 1 16975 sub root { $_[0] }
585            
586             =head2 mylocation()
587            
588             Special case: returns a slash. (It's the root.)
589            
590             =cut
591            
592 0     0 1 0 sub mylocation { '/'; }
593            
594             =head2 describe([$use])
595            
596             Returns a reconstructed set of source code used to compile this present C object. If it was assembled
597             in parts, you still get the whole thing back. Macro results are not included in this dump (they're presumed to be the result
598             of macros in the tree itself, so they should be regenerated the next time anyway).
599            
600             If you specify a true value for $use, the dump will include a "use" statement at the start in order to make the result an
601             executable Perl script.
602             The dump is always in filter format (if you built it with -nofilter) and contains C's best guess of the
603             semantic modules used. If you're using a "use lib" to affect your %INC, the result won't work right unless you modify it,
604             but if it's all standard modules, the dump result, after loading, should work the same as the original entry.
605            
606             =cut
607            
608             sub describe {
609 4     4 1 2082 my ($self, $macro_ok, $use) = @_;
610            
611 4 100       20 $macro_ok = 0 unless defined $macro_ok;
612            
613 4         9 my $description = '';
614 4 50       16 $description = "use Decl qw(" . join (", ", @semantic_classes) . ");\n\n" if $use;
615            
616 4         22 foreach ($self->elements) {
617 27 100 33     131 if (not ref $_) {
    50          
618 12         27 $description .= $_;
619             } elsif ($_->{macroresult} and not $macro_ok) {
620 0         0 next;
621             } else {
622 15         81 $description .= $_->describe($macro_ok);
623             }
624             }
625            
626 4         23 return $description;
627             }
628            
629             =head2 find_data
630            
631             The C function finds a top-level data node.
632            
633             =cut
634            
635             sub find_data {
636 4     4 1 7 my ($self, $data) = @_;
637 4 50       10 foreach ($self->nodes) { return ($_, $_->tag) if $_->name eq $data; }
  4         18  
638 0 0       0 foreach ($self->nodes) { return ($_, $_->tag) if $_->is($data); }
  0         0  
639 0         0 return (undef, undef);
640             }
641            
642            
643             =head2 write, log
644            
645             Normal nodes send these to their parents if not otherwise set for the node; at the top level, unless otherwise set, we print to STDOUT or STDERR.
646            
647             =cut
648            
649             sub write {
650 0     0 1 0 my $self = shift;
651 0         0 print STDOUT @_;
652             }
653             sub log {
654 0     0 1 0 my $self = shift;
655 0         0 print STDERR @_;
656             }
657            
658             =head1 FILTER REGISTRY
659            
660             A C in Decl is just a function that takes one string and returns another. (TODO: something iterator- and stream-aware, I suppose.)
661             It's used for text blocks. A filter call can take additional parameters as well, but doesn't have to.
662            
663             Filters are called using C on any given node; a search is made for the appropriate filter and it's invoked, if found. If it's not found,
664             then a globally registered filter is called (this permits libraries to contain filters). This filter registry is where that is managed.
665            
666             =head2 register_filter ($name, $coderef, $origin)
667            
668             During load, a module can register a filter with C. (It can happen any other time, too, of course.) To find a registered filter,
669             you can call register_filter without a code reference, and if there is such a filter registered under the name, it will be returned.
670            
671             The C<$origin> parameter is something you can use for debugging.
672            
673             Decl->register_filter('myfilter', sub { ... }, 'where I defined this');
674            
675             =cut
676            
677             our %registered_filters = ();
678             our %registered_filter_origins = ();
679             sub register_filter {
680 36     36 1 93 my ($class, $name, $coderef, $origin) = @_;
681 36 50       94 if (defined $coderef) {
682 36         70 $registered_filters{$name} = $coderef;
683 36         70 $registered_filter_origins{$name} = $origin;
684             }
685 36 50       131 wantarray ? ($registered_filters{$name}, $registered_filter_origins{$name}) : $registered_filters{$name};
686             }
687             Decl::DefaultFilters->init_default_filters();
688            
689             =head2 registered_filters()
690            
691             Returns a sorted list of all global filter names.
692            
693             =cut
694            
695 0     0 1   sub registered_filters { sort keys %registered_filters }
696            
697             =head1 AUTHOR
698            
699             Michael Roberts, C<< >>
700            
701             =head1 BUGS
702            
703             Please report any bugs or feature requests to C, or through
704             the web interface at L. I will be notified, and then you'll
705             automatically be notified of progress on your bug as I make changes.
706            
707            
708            
709            
710             =head1 SUPPORT
711            
712             You can find documentation for this module with the perldoc command.
713            
714             perldoc Decl
715            
716            
717             You can also look for information at:
718            
719             =over 4
720            
721             =item * RT: CPAN's request tracker
722            
723             L
724            
725             =item * AnnoCPAN: Annotated CPAN documentation
726            
727             L
728            
729             =item * CPAN Ratings
730            
731             L
732            
733             =item * Search CPAN
734            
735             L
736            
737             =back
738            
739            
740             =head1 ACKNOWLEDGEMENTS
741            
742            
743             =head1 LICENSE AND COPYRIGHT
744            
745             Copyright 2011 Michael Roberts.
746            
747             This program is free software; you can redistribute it and/or modify it
748             under the terms of either: the GNU General Public License as published
749             by the Free Software Foundation; or the Artistic License.
750            
751             See http://dev.perl.org/licenses/ for more information.
752            
753            
754             =cut
755            
756             1; # End of Decl