File Coverage

blib/lib/Pandoc/Walker.pm
Criterion Covered Total %
statement 83 84 98.8
branch 25 28 89.2
condition 19 27 70.3
subroutine 16 17 94.1
pod 4 4 100.0
total 147 160 91.8


line stmt bran cond sub pod time code
1             package Pandoc::Walker;
2 31     31   89148 use strict;
  31         95  
  31         1007  
3 31     31   201 use warnings;
  31         73  
  31         945  
4 31     31   587 use 5.010;
  31         127  
5              
6             our $VERSION = '0.34';
7              
8 31     31   215 use Scalar::Util qw(reftype blessed);
  31         80  
  31         1614  
9 31     31   205 use Carp;
  31         74  
  31         1747  
10              
11 31     31   13133 use parent 'Exporter';
  31         9020  
  31         196  
12             our @EXPORT = qw(walk query transform);
13             our @EXPORT_OK = ( @EXPORT, 'action' );
14              
15             sub _simple_action {
16 3986   50 0   9828 my $action = shift // return sub { };
        3986      
17              
18 3986 100 66     22532 if ( blessed $action and $action->isa('Pandoc::Filter') ) {
    50 33        
19 2         13 $action = $action->action;
20             }
21             elsif ( !ref $action or ref $action ne 'CODE' ) {
22 0   0     0 croak "expected code reference, got: " . ( $action // 'undef' );
23             }
24              
25 3986 100       9356 if (@_) {
26 2066         5340 my @args = @_;
27 2066     1863   10141 return sub { local $_ = $_[0]; $action->( $_[0], @args ) };
  1863         3478  
  1863         4482  
28             }
29             else {
30 1920         5267 return $action;
31             }
32             }
33              
34             sub action {
35 3968     3968 1 7271 my @actions;
36             my @args;
37              
38             # $selector => $action [, @arguments ]
39 3968 100       11802 if ( !ref $_[0] ) {
    100          
40 6   100 1   43 @actions = ( shift, shift // sub { $_ } );
  1         4  
41 6         17 @args = @_;
42             }
43              
44             # { $selector => $code, ... } [, @arguments ]
45             elsif ( ref $_[0] eq 'HASH' ) {
46 22         47 @actions = %{ shift @_ };
  22         107  
47 22         66 @args = @_;
48              
49             # code [, @arguments ]
50             }
51             else {
52 3940         8757 return _simple_action(@_);
53             }
54              
55 28         127 my $n = ( scalar @actions ) / 2 - 1;
56              
57             # check action functions and add arguments
58             $actions[ $_ * 2 + 1 ] = _simple_action( $actions[ $_ * 2 + 1 ], @args )
59 28         170 for 0 .. $n;
60              
61             # TODO: compile selectors for performance
62              
63             sub {
64 106     106   261 my $element = $_[0];
65              
66             # get all matching actions
67             my @matching =
68 71         294 map { $actions[ $_ * 2 + 1 ] }
69 106         286 grep { $element->match( $actions[ $_ * 2 ] ) } 0 .. $n;
  154         780  
70              
71 106         259 my @return = ();
72              
73 106         249 foreach my $action (@matching) {
74 71         190 local $_ = $_[0]; # FIXME: $doc->walk( Section => sub { $_->id } )
75 71         240 @return = ( $action->(@_) );
76             }
77              
78 106 50       413 wantarray ? @return : $return[0];
79             }
80 28         200 }
81              
82             sub transform {
83 3874     3874 1 8713 my $ast = shift;
84 3874         8381 my $action = action(@_);
85              
86 3874   100     15177 my $reftype = reftype($ast) || '';
87              
88 3874 100       10988 if ( $reftype eq 'ARRAY' ) {
    100          
89 1072         3030 for ( my $i = 0 ; $i < @$ast ; ) {
90 1739         3620 my $item = $ast->[$i];
91              
92 1739 100 100     8364 if ( ( reftype $item || '' ) eq 'HASH' and $item->{t} ) {
      100        
93 829         2179 my $res = $action->($item);
94              
95 829 100       2638 if ( defined $res ) {
96             # stop traversal
97 21 100       104 if ( $res eq \undef ) {
98 1         3 $i++;
99             # replace current item with result element(s)
100             } else {
101 20 100 50     132 my @elements = #map { transform($_, $action, @_) }
102             ( reftype $res || '' ) eq 'ARRAY' ? @$res : $res;
103 20         77 splice @$ast, $i, 1, @elements;
104 20         60 $i += scalar @elements;
105             }
106 21         184 next;
107             }
108             }
109 1718         5123 transform( $item, $action );
110 1718         4451 $i++;
111             }
112             }
113             elsif ( $reftype eq 'HASH' ) {
114              
115             # TODO: directly transform an element.
116             # if (blessed $ast and $ast->isa('Pandoc::Elements::Element')) {
117             # } else {
118 1036         4166 foreach ( keys %$ast ) {
119 2056         6201 transform( $ast->{$_}, $action, @_ );
120             }
121              
122             # }
123             }
124              
125 3874         12531 $ast;
126             }
127              
128             sub walk(@) { ## no critic
129 52     52 1 1881 my $ast = shift;
130 52         198 my $action = action(@_);
131             transform( $ast, sub {
132 594     594   1139 local $_ = $_[0];
133 594         1948 my $q = $action->(@_);
134 594 50 66     4142 return (defined $q and $q eq \undef) ? \undef : undef
135 52         389 } );
136             }
137              
138             sub query(@) { ## no critic
139 32     32 1 1577 my $ast = shift;
140 32         100 my $action = action(@_);
141              
142 32         103 my $list = [];
143             transform( $ast, sub {
144 166     166   330 local $_ = $_[0];
145 166         451 my $q = $action->(@_);
146 166 100 100     1002 return $q if !defined $q or $q eq \undef;
147 71         207 push @$list, $q;
148             return
149 32         197 } );
  71         235  
150 32         507 return $list;
151             }
152              
153             1;
154             __END__