NAME
Class::Declarative::Node - implements a node in a declarative structure.
VERSION
Version 0.02
SYNOPSIS
Each node in a Class::Declarative
structure is represented by one of these objects. Specific semantics modules subclass these nodes for each of their components.
defines()
Called by Class::Declarative
during import, to find out what xmlapi tags this plugin claims to implement. This is a class method, and by default we've got nothing.
The wantsbody
function governs how iterator
works.
new()
The constructor for a node takes either one or an arrayref containing two texts. If one, it is the entire line-and-body of a node; if the arrayref, the line and the body are already separated. If they're delivered together, they're split before proceeding.
The line and body are retained, although they may be further parsed later. If the body is parsed, its text is discarded and is reconstructed if it's needed for self-description. (This can be suppressed if a non-standard parser is used that has no self-description facility.)
The node's tag is the first word in the line. The tag determines everything pertaining to this entire section of the application, including how its contents are parsed.
tag(), is($tag), name(), line(), hasbody(), body(), elements(), nodes(), payload()
Accessor functions.
parent(), ancestry()
A list of all the tags of nodes above this one, culminating in this one's tag, returned as an arrayref.
parameter($p), option($o), parmlist(), optionlist(), parameter_n(), option_n(), label(), parser(), code(), gencode(), errors(), bracket(), comment()
More accessor functions.
flags({flag=>numeric value, ...}), oflags({flag=>numeric value, ...})
A quick utility to produce an OR'd flag set from a list of parameter words. Pass it a hashref containing numeric values for a set of words, and you'll get back the OR'd sum of the flags found in the parameters. The flags
function does this for the parameters (round parens) and the oflags
function does the same for the options [square brackets].
BUILDING STRUCTURE
load ($string)
The load
method loads declarative specification text into a node by calling the parser appropriate to the node. Multiple loads can be carried out, and will simply add to text already there.
The return value is the list of objects added to the target, if any.
macroinsert ($spec)
This function adds structure to a given node at runtime that won't show up in the node's describe
results. It is used by the macro system (hence the name) but can be used by other runtime structure modifiers that act more or less like macros. The idea is that this structure is meaningful at runtime but is semantically already accounted for in the existing definition, and should always be generated only at runtime.
build(), preprocess(), preprocess_line(), decode_line(), parse_body(), build_payload(), build_children(), add_to_parent(), post_build()
The build
function parses the body of the tag, then builds the payload it defines, then calls build on each child if appropriate, then adds itself to its parent. It provides the hooks preprocess
(checks for macro nature and expresses if so), parse_body
(asks the application to call the appropriate parser for the tag), build_payload
(does nothing by default), build_children
(calls build
on each element), and add_to_parent
(does nothing by default).
If this tag corresponds to a macro, then substitution takes place before parsing, in the preprocess step.
STRUCTURE ACCESS
find($nodename)
Given a node, finds a descendant using a simple XPath-like language. Once you build a recursive-descent parser facility into your language, this sort of thing gets a whole lot easier.
Generation separators are '.', '/', or ':' depending on how you like it. Offsets by number are in round brackets (), while finding children by name is done with square brackets []. Square brackets [name] find tags named "name". Square brackets [name name2] find name lists (which nodes can have, yes), and square brackets with an = or =~ can also search for nodes by other values.
You can also pass the results of a parse (the arrayref tree) in as the path; this allows you to build the parse tree using other tools instead of forcing you to build a string (it also allows a single parse result to be used recursively without having to parse it again).
match($pathelement)
Returns a true value if the node matches the path element specified; otherwise, returns a false value.
first($nodename)
Given a node, finds a descendant with the given tag anywhere in its descent. Uses the same path notation as find
.
search($nodename)
Given a node, finds all descendants with the given tag.
describe, myline
The describe
function is used to get our code back out so we can reparse it later if we want to. It includes the body and any children. The myline
function just does that without the body and children (just the actual line). We could also use this to check the output of the parser, which notoriously just stops on a line if it encounters something it's not expecting.
sketch (), sketch_c()
Returns a thin structure reflecting the nodal structure of the node in question:
['tag',
[['child1', []],
['child2', []]]]
Like that. I'm building it for testing purposes, but it might be useful for something else, too.
go($item)
For callable nodes, this is one way to call them. The default is to call the go methods of all the children of the node, in sequence.
closure(...)
For callable nodes, this is the other way to call them; it returns the closure created during initialization. Note that the default closure is really boring.
iterate()
Returns an Iterator::Simple iterator over the body of the node. If the body is a text body, each call returns a line. If the body is a bracketed code body, it is executed to return an iterable object. Yes, this is neat.
If we're a parser macro, we'll run our special parser over the body instead of the normal parser.
text()
This returns a tokenstream on the node's body permitting a consumer to read a series of words interspersed with formatting commands. The formatting commands are pretty loose - essentially, "blankline" is the only one. Punctuation is treated as letters in words; that is, only whitespace is elided in the tokenization process.
If the node has been parsed, it probably doesn't have a body any more, so this will return a blank tokenstream. On the other hand, if the node is callable, it will be called, and the result will be used as input to the tokenstream - same rules as iterate
above.
content()
This returns the iterated content from iterate(), assembled into lines with as few newlines as possible.
event_context
If the node is an event context (e.g. a window or frame or dialog), this should return the payload of the node. Otherwise, it returns the event_context of the parent node.
root
Returns the parent - all nodes do this. The top node at Class::Declarative
returns itself.
error
Error handling is the part of programming I'm worst at. But you just have to bite the bullet and address your weaknesses, so here is an error marker function. If there's a problem with a node specification, this marks it. Later we'll do something sensible with it. TODO: something sensible.
find_data
The find_data
function finds a data node starting at a given point in the tree. Right now, it's just going to look for nodes by name, but more mature locators should follow eventually.
set(), get(), get_pair()
These provide a place for object constructors to stash useful information. The get
function gets a parameter if the named user variable hasn't been set. It also allows the specification of a default value.
get_pair
gets a pair of named values as an arrayref, with a single arrayref default if neither is found. The individual defaults are assumed to be 0.
AUTHOR
Michael Roberts, <michael at vivtek.com>
BUGS
Please report any bugs or feature requests to bug-class-declarative at rt.cpan.org
, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Class-Declarative. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
LICENSE AND COPYRIGHT
Copyright 2010 Michael Roberts.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.