AxKit2
view release on metacpan or search on metacpan
lib/AxKit2/XSP/SimpleTaglib.pm view on Meta::CPAN
package AxKit2::XSP::SimpleTaglib;
require 5.006;
use strict;
use base 'AxKit2::Transformer::XSP';
use Data::Dumper;
eval { require WeakRef; };
eval { require XML::Smart; };
use attributes;
our $VERSION = 0.3;
# utility functions
sub makeSingleQuoted($) { $_ = shift; s/([\\%])/\\$1/g; 'q%'.$_.'%'; }
sub _makeAttributeQuoted(@) { $_ = join(',',@_); s/([\\()])/\\$1/g; '('.$_.')'; }
sub makeVariableName($) { $_ = shift; s/[^a-zA-Z0-9]/_/g; $_; }
my $dumper = new Data::Dumper([]);
$dumper->Quotekeys(0);
$dumper->Terse(1);
$dumper->Indent(0);
# perl attribute handlers
my %handlerAttributes;
use constant PLAIN => 0;
use constant EXPR => 1;
use constant EXPRORNODE => 2;
use constant NODE => 3;
use constant EXPRORNODELIST => 4;
use constant NODELIST => 5;
use constant STRUCT => 6;
# Memory leak ahead! The '&' construct may create circular references, which perl
# can't clean up. But this has only an effect if a taglib is reloaded, which shouldn't
# happen on production machines. Moreover, '&' is rather unusual.
# If you have the WeakRef module installed, this warning does not apply.
sub parseChildStructSpec {
my ($specs, $refs) = @_;
for my $spec ($_[0]) {
my $result = {};
while (length($spec)) {
$spec = substr($spec,1), return $result if (substr($spec,0,1) eq '}');
(my ($type, $token, $next) = ($spec =~ m/^([!\&\@\*\$]?)([^ {}]+)(.|$)/))
|| die("childStruct specification invalid. Parse error at: '$spec'");
substr($spec,0,length($token)+1+($type?1:0)) = '';
#warn("type: $type, token: $token, next: $next, spec: $spec");
my ($realtoken, $params);
if ((($realtoken,$params) = ($token =~ m/^([^\(]+)((?:\([^ \)]+\))+)$/))) {
my $i = 0;
$token = $realtoken;
$$result{$token}{'param'} = { map { $_ => $i++ } ($params =~ m/\(([^ )]+)\)/g) };
}
if ($type eq '&') {
($$result{$token} = $$refs{$token})
|| die("childStruct specification invalid. '&' reference not found.");
die("childStruct specification invalid. '&' cannot be used on '*' nodes.")
if ($$result{$token}{'type'} eq '*');
die("childStruct specification invalid. '&' may only take a reference.")
if $$result{'param'};
eval { WeakRef::weaken($$result{$token}) };
return $result if (!$next || $next eq '}');
next;
}
$$result{$token}{'type'} = $type || '$';
die("childStruct specification invalid. '${type}' cannot be used with '{'.")
if ($next eq '{' and ($type eq '*' || $type eq '!'));
die("childStruct specification invalid. '${type}' cannot be used with '(,,,)'.")
if ($$result{$token}{'param'} and ($type eq '*' || $type eq '!'));
die("childStruct specification invalid. '**' is not supported.")
if ($token eq '*' and $type eq '*');
$$result{''}{'name'} = $token if ($type eq '*');
$$result{$token}{'name'} = $token;
return $result if (!$next || $next eq '}');
($$result{$token}{'sub'} = parseChildStructSpec($spec, { %$refs, $token => $$result{$token} })) || return undef if $next eq '{';
}
return $result;
}
}
sub serializeChildStructSpec {
my ($struct, $refs) = @_;
my $result = '';
my $first = 1;
foreach my $token (keys %$struct) {
next unless length($token);
$result .= ' ' unless $first;
undef $first;
if (exists $$refs{$$struct{$token}}) {
$result .= '&'.$token;
next;
}
$result .= $$struct{$token}{'type'};
$result .= $token;
if (exists $$struct{$token}{'param'}) {
my %keys = reverse %{$$struct{$token}{'param'}};
$result .= '('.join(')(',@keys{0..(scalar(%keys)-1)}).')'
}
$result .= '{'.serializeChildStructSpec($$struct{$token}{'sub'},{ %$refs, $$struct{$token} => undef }).'}'
if exists $$struct{$token}{'sub'};
}
return $result;
}
sub MODIFY_CODE_ATTRIBUTES {
my ($pkg,$sub,@attr) = @_;
return unless defined $sub;
my @rest;
$handlerAttributes{$sub} ||= {};
my $handlerAttributes = $handlerAttributes{$sub};
foreach my $a (@attr) {
#warn("attr: $a");
my ($attr,$param) = ($a =~ m/([^(]*)(?:\((.*)\))?$/);
my $warn = 0;
$attr =~ s/^XSP_// || $warn++;
$param = (defined $param?eval "q($param)":"");
my @param = split(/,/,$param);
if ($attr eq 'expr') {
$$handlerAttributes{'result'} = EXPR;
} elsif ($attr eq 'node') {
( run in 2.275 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )