package Tree::Transform::Transformer;
use Moose;
use MooseX::AttributeHelpers;
use Params::Validate ':all';
use Tree::Transform::Utils;
use Tree::Transform::Context;
use Tree::XPathEngine;
use Carp::Clan qw(^Tree::Transform);
has 'rules_package' => (is => 'ro', isa => 'ClassName');
has 'context_stack' => (
metaclass => 'Collection::Array',
is => 'rw',
isa => 'ArrayRef[Tree::Transform::Context]',
default => sub { [] },
provides => {
last => 'context',
push => 'enter',
pop => 'leave',
empty => 'has_context',
},
);
has 'engine' => (
is => 'ro',
isa => 'Tree::XPathEngine',
default => sub { Tree::XPathEngine->new() },
);
sub it { $_[0]->context->current_node }
sub transform {
my ($self,$tree)=@_;
return $self->apply_rules($tree->xpath_get_root_node);
}
sub apply_rules {
my ($self,@nodes)=@_;
unless (@nodes) {
unless ($self->has_context) {
carp 'apply_rules called without nodes nor context!';
return;
}
@nodes=$self->it->xpath_get_child_nodes();
};
$self->enter(Tree::Transform::Context->new(node_list=>\@nodes));
my @ret;
for my $node (@nodes) {
$self->context->current_node($node);
my $rule=$self->find_rule();
push @ret,$rule->($self);
}
$self->leave;
return @ret;
}
sub find_rule {
my ($self,$context)=@_;
$context||=$self->context;
my $store=Tree::Transform::Utils::_rules_store($self->rules_package);
my $rules=$store->{by_match};
my @candidates=
sort { $b->{priority} <=> $a->{priority} }
grep { $self->rule_matches($_) } @$rules;
if (@candidates > 1 and
$candidates[0]->{priority} ==
$candidates[1]->{priority}) {
croak "Ambiguous rule application";
}
elsif (@candidates == 0) {
croak "No valid rule";
}
return $candidates[0]->{action};
}
sub rule_matches {
my ($self,$rule,$context)=@_;
$context||=$self->context;
my $node=$context->current_node;
my $path=$rule->{match};
my $base_node=$node;
while (1) {
if ($self->engine->matches($node,$path,$base_node)) {
return 1;
}
if ($base_node->xpath_is_document_node) {
return;
}
$base_node=$base_node->xpath_get_parent_node;
}
return;
}
__PACKAGE__->meta->make_immutable;no Moose;1;
__END__