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.

plist(@parameters)

Given a list of parameters, returns a hash (not a hashref) of their values, first looking in the parameters, then looking for children of the same name and returning their labels if necessary. This allows us to specify a parameter for a given object either like this:

object (parm1=value1, parm2 = value2)

or like this:

object
   parm1 "value1"
   parm2 "value2"
   

It just depends on what you find more readable at the time. For this to work during payload build, though, the children have to be built first, which isn't the default - so you have to call $self->build_children before using this in the payload build.

This is really useful if you're wrapping a module that uses a hash to initialize its object. Like, say, LWP::UserAgent.

parm_css (parameter), set_css_values (hashref, parameter_string), prepare_css_value (hashref, name), get_css_value (hashref, name)

CSS is characterized by a sort of "parameter tree", where many parameters can be seen as nested in a hierarchy. Take fonts, for example. A font has a size, a name, a bolded flag, and so on. To specify a font, then, we end up with things like font-name, font-size, font-bold, etc. In CSS, we can also group those things together and get something like font="name: Times; size: 20", and that is equivalent to font-name="Times", font-size="20". See?

This function does the same thing with the parameters of a node. If you give it a name "font" it will find /font-*/ as well, and munge the values into the "font" value. It returns a hashref containing the entire hierarchy of these things, and it will also interpret any string-type parameters in the higher levels, e.g. font="size: 20; name: Times" will go into {size=>20, name=>'Times'}. Honestly, I love this way of handling parameters in CSS.

If you give a name "font-size" it will also find any font="size: 20" specification and retrieve the appropriate value.

It won't decompose multiple hierarchical levels starting from a string (e.g. something like font="size: {type: 3}" will not be parsed for font-size-type, because you'd need curly brackets or something anyway, and this ain't JSON, it's just simple CSS-like parameter addressing.

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].

list_parameter ($name)

Sometimes, instead of having e.g. position-x and position-y parameters, it's easier to have something like p=40 20 or dim=20x20. We can use the list_parameter function to obtain a list of any numbers separated by non-number characters. (Note that due to the line parser using commas to separate the parameters themselves, the separator can't be a comma. Unless you want to write a different line parser, in which case, go you!)

So the separator characters can be: !@#$%^&*|:;~x and space.

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. The last result is returned as our result (this means that the overall tree may have a return value if you set things up right).

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.

subs()

Returns all our direct children named 'sub', plus the same thing from our parent. Our answers mask our parent's.

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.