summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordakkar <dakkar@thenautilus.net>2009-04-16 22:12:47 +0200
committerdakkar <dakkar@thenautilus.net>2009-04-16 22:12:47 +0200
commitffb0397721a50682b2fc54f53ea6bf94937b21c8 (patch)
tree282283b98e5d03ff2d425edd1c3f42aaec3273c2
parentmake the test more meaningful (diff)
downloadTree-Transform-XSLTish-ffb0397721a50682b2fc54f53ea6bf94937b21c8.tar.gz
Tree-Transform-XSLTish-ffb0397721a50682b2fc54f53ea6bf94937b21c8.tar.bz2
Tree-Transform-XSLTish-ffb0397721a50682b2fc54f53ea6bf94937b21c8.zip
documentation, and a few author-tests
-rw-r--r--Makefile.PL2
-rw-r--r--lib/Tree/Transform/XSLTish.pm103
-rw-r--r--lib/Tree/Transform/XSLTish/Context.pm10
-rw-r--r--lib/Tree/Transform/XSLTish/Transformer.pm119
-rw-r--r--lib/Tree/Transform/XSLTish/Utils.pm11
-rw-r--r--t/00-author-deps.t6
-rw-r--r--t/00-author-pod-cover.t7
-rw-r--r--t/00-author-pod.t6
8 files changed, 261 insertions, 3 deletions
diff --git a/Makefile.PL b/Makefile.PL
index 5f0c3d4..8912266 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -6,9 +6,11 @@ all_from 'lib/Tree/Transform/XSLTish.pm';
requires 'Tree::XPathEngine' => 0,
'Moose' => 0,
+ 'Class::MOP' => 0,
'Params::Validate' => 0,
'Carp::Clan' => 0,
'Sub::Exporter' => 0,
+ 'MooseX::AttributeHelpers' => 0,
;
test_requires 'Test::Most' => 0,
diff --git a/lib/Tree/Transform/XSLTish.pm b/lib/Tree/Transform/XSLTish.pm
index e754cd0..2176aea 100644
--- a/lib/Tree/Transform/XSLTish.pm
+++ b/lib/Tree/Transform/XSLTish.pm
@@ -6,6 +6,7 @@ use Params::Validate ':all';
use Tree::Transform::XSLTish::Utils;
use Tree::Transform::XSLTish::Transformer;
use Carp::Clan qw(^Tree::Transform::XSLTish);
+use v5.8;
our $VERSION='0.1';
@@ -40,7 +41,7 @@ sub tree_rule {
});
# TODO at least one of 'name' and 'match' must be specified
- # TODO default priority mased on match
+ # TODO default priority based on match
my $store=Tree::Transform::XSLTish::Utils::_rules_store(scalar caller);
@@ -117,6 +118,8 @@ Transforming an HTML document:
use strict;
use warnings;
+ engine_class 'XML::XPathEngine';
+
default_rules;
tree_rule match => 'img[@alt="pick"]', action => sub {
@@ -124,13 +127,12 @@ Transforming an HTML document:
};
package main;
- use XML::XPathEngine;
use HTML::TreeBuilder::XPath;
my $tree=HTML::TreeBuilder::XPath->new();
$tree->parse_file('mypage.html');
- my $trans=HtmlTransform->new(engine=>XML::XPathEngine->new());
+ my $trans=HtmlTransform->new();
my ($image_srce)=$trans->transform($tree);
=head1 DESCRIPTION
@@ -153,6 +155,101 @@ that are compatible with the XPath engine; for example,
L<Tree::DAG_Node::XPath> if you use L<Tree::XPathEngine>, or
L<HTML::TreeBuilder::XPath> if you use L<XML::XPathEngine>.
+=head1 EXPORTS
+
+=head2 C<tree_rule>
+
+ tree_rule match => '//node_name',
+ priority => 1,
+ action => sub { ... };
+
+This is the basic fuction to declare a transformation rule; it's
+equivalent to the C<template> element is XSLT. It takes its parameters
+as a hash:
+
+=over 4
+
+=item C<match>
+
+this is equivalent to the C<match> attribute of C<template>: it
+specifies the pattern for the nodes to which this rule applies.
+
+From the L<XSLT spec|http://www.w3.org/TR/xslt.html#NT-Pattern>:
+
+I<A pattern is defined to match a node if and only if there is a
+possible context such that when the pattern is evaluated as an
+expression with that context, the node is a member of the resulting
+node-set. When a node is being matched, the possible contexts have a
+context node that is the node being matched or any ancestor of that
+node, and a context node list containing just the context node.>
+
+=item C<name>
+
+this is equivalent of the C<name> attribute of C<template>: it allows
+calling rules by name (see
+L<call_rule|Tree::Transform::XSLTish::Transformer/call_rule>)
+
+=item C<priority>
+
+this is equivalent of the C<priority> attribute of C<template>;
+currently the "default priority" as specified in the
+L<spec|http://www.w3.org/TR/xslt.html#conflict> is not implemented
+
+=item C<action>
+
+this code-ref will be called (in list context) when the rule is to be
+applied; it can return whatever you want:
+L<call_rule|Tree::Transform::XSLTish::Transformer/call_rule> will
+return the result unchanged,
+L<apply_rules|Tree::Transform::XSLTish::Transformer/apply_rules> will
+return the list of all results of all the applied rules
+
+=back
+
+The C<action> code-ref will be called (by
+L<apply_rules|Tree::Transform::XSLTish::Transformer/apply_rules> or
+L<call_rule|Tree::Transform::XSLTish::Transformer/call_rule>) with a
+L<Tree::Transform::XSLTish::Transformer> object as its only parameter.
+
+=head2 C<default_rules>
+
+This function will declare two rules that mimic the implicit rules of
+XSLT. It's equivalent to:
+
+ tree_rule match => '/', priority => 0, action => sub {$_[0]->apply_rules};
+ tree_rule match => '*', priority => 0, action => sub {$_[0]->apply_rules};
+
+=head2 C<engine_class>
+
+ engine_class 'XML::LibXML::XPathContext';
+
+This function declares that the
+L<Tree::Transform::XSLTish::Transformer> object returned by L</new>
+should use this class to build its XPath engine.
+
+=head2 C<engine_factory>
+
+ engine_factory { My::XPath::Engine->new(params=>$whatever) };
+
+This function declares that the
+L<Tree::Transform::XSLTish::Transformer> object returned by L</new>
+should call the passed code-ref to get its engine.
+
+C<engine_class $classname> is equivalent to C<engine_factory {
+$classname->new }>.
+
+=head2 C<new>
+
+Returns a L<Tree::Transform::XSLTish::Transformer> for the rules
+declared in this package.
+
+=head1 INHERITANCE
+
+L<Stylesheet import|http://www.w3.org/TR/xslt.html#import> is implented
+with the usual Perl inheritance scheme. It should even work with
+L<Class::C3>, since we use L<Class::MOP>'s C<class_precedence_list> to
+get the list of inherited packages.
+
=head1 AUTHOR
Gianni Ceccarelli <dakkar@thenautilus.net>
diff --git a/lib/Tree/Transform/XSLTish/Context.pm b/lib/Tree/Transform/XSLTish/Context.pm
index 2e696a5..0890401 100644
--- a/lib/Tree/Transform/XSLTish/Context.pm
+++ b/lib/Tree/Transform/XSLTish/Context.pm
@@ -7,3 +7,13 @@ has 'node_list' => ( is => 'rw', isa => 'ArrayRef[Object]' );
__PACKAGE__->meta->make_immutable;no Moose;1;
__END__
+
+=head1 NAME
+
+Tree::Transform::XSLTish::Context - helper class
+
+=head1 AUTHOR
+
+Gianni Ceccarelli <dakkar@thenautilus.net>
+
+=cut
diff --git a/lib/Tree/Transform/XSLTish/Transformer.pm b/lib/Tree/Transform/XSLTish/Transformer.pm
index fd61ea6..c4ff53f 100644
--- a/lib/Tree/Transform/XSLTish/Transformer.pm
+++ b/lib/Tree/Transform/XSLTish/Transformer.pm
@@ -150,6 +150,8 @@ sub find_rule_in_package {
elsif (@candidates >= 1) {
return $candidates[0];
}
+
+ return;
}
sub find_rule_by_name_in_package {
@@ -214,3 +216,120 @@ sub DESTROY {
1;
__END__
+
+=head1 NAME
+
+Tree::Transform::XSLTish::Transformer - transformer class for L<Tree::Transform::XSLTish>
+
+=head1 METHODS
+
+=head2 C<new>
+
+ $trans=Tree::Transform::XSLTish::Transformer->new(
+ rules_package => 'Some::Package',
+ engine => $engine_instance,
+ );
+
+You usually don't call this constructor directly, but instead use L<<
+the C<new> function exported by
+Tree::Transform::XSLTish|Tree::Transform::XSLTish/new >>, which passes
+the correct C<rules_package> automatically.
+
+If you don't specify an C<engine>, it will be constructed using the
+class or factory declared in the rules package; if you didn't declare
+anything, it will be an instance of L<Tree::XPathEngine>
+
+=for comment
+
+engine factories are not inherited!
+
+=head2 C<transform>
+
+ @results=$trans->transform($tree);
+
+When you call this function on a tree, the transformer will transform
+it according to your rules and to the L<XSLT processing
+model|http://www.w3.org/TR/xslt.html#section-Processing-Model>.
+
+C<< $trans->transform($node) >> is equivalent to C<<
+$trans->apply_rules($trans->engine->findnodes('/',$node)) >>.
+
+Always call this method in list context.
+
+=head2 C<apply_rules>
+
+ $trans->apply_rules(@nodes);
+
+Just like C<apply-rules> in XSLT, this function will apply the rules
+to the specified nodes, or to the children of the current node if none
+are passed, and return all the results in a single list.
+
+This will die if there are no matching rules, or if there are more
+than one matching rule with highest priority.
+
+Always call this method in list context.
+
+=head2 C<call_rule>
+
+ $trans->call_rule('rule-name');
+
+This fuction will apply the named rule to the current node, and return
+the result.
+
+This will die if there is no rule with the given name.
+
+Always call this method in list context.
+
+=head2 C<it>
+
+ $current_node = $trans->it;
+
+Inside a rule, this fuction will return the node to which the rule is
+being applied.
+
+=head1 INTERNAL FUNCTIONS
+
+These functions should not be called from outside this module.
+
+=head2 C<find_rule>
+
+For each package in the linearized inheritance chain of the rules
+package on which this transformer has been instantiated, calls
+L<find_rule_in_package> and returns the first defined result.
+
+=head2 C<find_rule_in_package>
+
+Gets all the rules having a C<match> attribute, filters those for
+which L<rule_matches> returns true, sorts them priority, and returns
+the one with the highest priority.
+
+Dies if there is more than one rule with the highest priority; returns
+undef if there are no matching rules.
+
+=head2 C<find_rule_by_name>
+
+For each package in the linearized inheritance chain of the rules
+package on which this transformer has been instantiated, calls
+L<find_rule_by_name_in_package> and returns the first defined result.
+
+=head2 C<find_rule_by_name_in_package>
+
+Returns the rule with the given name, if any; returns undef otherwise.
+
+=head2 C<rule_matches>
+
+Evaluates the C<match> XPath expression in a sequence of contexts, to
+see if the current node appears in the resulting node-set. If it does,
+returns true; if there is no such context, returns false.
+
+The first context is the current node; following contexts are each the
+parent node of the previous one.
+
+NOTE: to check whether a node appears in a node-set, we either use the
+C<isSameNode> method, or check the stringifications for equality.
+
+=head1 AUTHOR
+
+Gianni Ceccarelli <dakkar@thenautilus.net>
+
+=cut
diff --git a/lib/Tree/Transform/XSLTish/Utils.pm b/lib/Tree/Transform/XSLTish/Utils.pm
index bed1167..bfb438c 100644
--- a/lib/Tree/Transform/XSLTish/Utils.pm
+++ b/lib/Tree/Transform/XSLTish/Utils.pm
@@ -31,3 +31,14 @@ sub _get_inheritance {
}
1;
+__END__
+
+=head1 NAME
+
+Tree::Transform::XSLTish::Utils - utility functions
+
+=head1 AUTHOR
+
+Gianni Ceccarelli <dakkar@thenautilus.net>
+
+=cut
diff --git a/t/00-author-deps.t b/t/00-author-deps.t
new file mode 100644
index 0000000..f92ec06
--- /dev/null
+++ b/t/00-author-deps.t
@@ -0,0 +1,6 @@
+#!perl
+use Test::Most;
+plan skip_all => "skipping author-only test" unless $ENV{RUN_AUTHOR_TESTS};
+eval "use Test::Dependencies exclude => [qw(Tree::Transform::XSLTish XML::LibXML Moose::Util::TypeConstraints)]";
+
+ok_dependencies();
diff --git a/t/00-author-pod-cover.t b/t/00-author-pod-cover.t
new file mode 100644
index 0000000..9bace3e
--- /dev/null
+++ b/t/00-author-pod-cover.t
@@ -0,0 +1,7 @@
+#!perl
+use Test::Most;
+plan skip_all => "skipping author-only test" unless $ENV{RUN_AUTHOR_TESTS};
+eval "use Test::Pod::Coverage";
+all_pod_coverage_ok({
+ trustme=> [qr(^new_transformer$)],
+});
diff --git a/t/00-author-pod.t b/t/00-author-pod.t
new file mode 100644
index 0000000..5177b0c
--- /dev/null
+++ b/t/00-author-pod.t
@@ -0,0 +1,6 @@
+#!perl
+use Test::Most;
+plan skip_all => "skipping author-only test" unless $ENV{RUN_AUTHOR_TESTS};
+eval "use Test::Pod";
+
+all_pod_files_ok();