package Tree::Template::Declare; use strict; use warnings; use Sub::Exporter; use Devel::Caller 'caller_args'; use Carp; use Data::Dumper; use v5.8; our $VERSION='0.1'; { my $exporter=Sub::Exporter::build_exporter({ groups => { default => \&_build_group, }, }); sub import { my ($pack,@rest)=@_; if (@rest) { @_=($pack,-default => {@rest}); } goto $exporter; } } sub _build_group { my ($class,$name,$args,$coll)=@_; my $builder=$args->{builder}; if (!ref($builder)) { my $builder_pkg=$builder; if ($builder_pkg=~m{\A \+(\w+) \z}smx) { $builder_pkg="Tree::Template::Declare::$1"; } eval "require $builder_pkg"; croak "Can't load $builder_pkg: $@" if $@; if ($builder_pkg->can('new')) { $builder=$builder_pkg->new(); } else { $builder=$builder_pkg; } } my $additional_exports={}; if ($builder->can('_additional_exports')) { $additional_exports=$builder->_additional_exports(); } my @current_node=(undef); return { tree => sub(&) { my $tree=$builder->new_tree(); { local $current_node[0]=$tree; $_[0]->(caller_args(1)); } return $builder->finalize_tree($tree); }, node => sub (&) { my $node=$builder->new_node(); { local $current_node[0]=$node; $_[0]->(caller_args(1)); } if ($current_node[0]) { $builder->add_child_node($current_node[0],$node); } return $node; }, name => sub ($) { $builder->set_node_name($current_node[0],$_[0]); return; }, attribs => sub { my %attrs=@_; $builder->set_node_attributes($current_node[0],\%attrs); return; }, %$additional_exports, }; } 1; __END__ =head1 NAME Tree::Template::Declare - easily build tree structures =head1 SYNOPSIS use Tree::Template::Declare builder => '+DAG_Node'; my $tree=tree { node { name 'root'; attribs name => 'none'; node { name 'first'; attribs name => 'number_1'; attribs other => 'some'; }; node { name 'second'; }; }; }; =head1 IMPORTING This module uses L, although it munges the C list before passing it to L. A line like: use Tree::Template::Declare @something; becomes a call to L's export sub like: $export->('Tree::Template::Declare',-default => {@something}); See L's documentation for things like renaming the imports. You can C this module more than once, with different builders and different names for the imports: use Tree::Template::Declare -prefix=> 'x', builder => '+LibXML'; use Tree::Template::Declare -prefix=> 'd', builder => '+DAG_Node'; =head1 AUTHOR Gianni Ceccarelli =cut