File Coverage

blib/lib/XML/Liberal.pm
Criterion Covered Total %
statement 60 64 93.7
branch 14 22 63.6
condition 2 4 50.0
subroutine 16 17 94.1
pod 2 6 33.3
total 94 113 83.1


line stmt bran cond sub pod time code
1             package XML::Liberal;
2              
3 5     5   521170 use strict;
  5         39  
  5         102  
4 5     5   679 use 5.008_001;
  5         14  
5             our $VERSION = '0.32';
6              
7 5     5   22 use base qw( Class::Accessor );
  5         14  
  5         1574  
8 5     5   7373 use Carp;
  5         9  
  5         203  
9 5     5   1609 use UNIVERSAL::require;
  5         4091  
  5         33  
10             use Module::Pluggable::Fast
11 5         26 name => 'remedies',
12             search => [ 'XML::Liberal::Remedy' ],
13 5     5   1747 require => 1;
  5         9730  
14              
15             __PACKAGE__->remedies(); # load remedies now
16             __PACKAGE__->mk_accessors(qw( max_fallback guess_encodings ));
17              
18             our $Debug;
19              
20             sub debug {
21 1692     1692 0 1771 my $self = shift;
22 1692 50       2337 $self->{debug} = shift if @_;
23 1692 50       3907 $self->{debug} || $XML::Liberal::Debug;
24             }
25              
26             sub new {
27 170     170 1 139161 my $class = shift;
28 170   50     453 my $driver = shift || 'LibXML';
29              
30 170         310 my $subclass = "XML::Liberal::$driver";
31 170 50       710 $subclass->require or die $@;
32              
33 170         4481 my %param = @_;
34 170 50       454 $param{max_fallback} = 15 unless defined $param{max_fallback};
35              
36 170         687 $subclass->new(%param);
37             }
38              
39             sub globally_override {
40 25     25 1 36682 my $class = shift;
41 25   50     60 my $driver = shift || 'LibXML';
42              
43 25         63 my $subclass = "XML::Liberal::$driver";
44 25 50       74 $subclass->require or die $@;
45              
46 25         675 $subclass->globally_override;
47              
48 25 100       50 if (defined wantarray) {
49             return XML::Liberal::Destructor->new(
50 24     24   112 sub { $subclass->globally_unoverride },
51 24         112 );
52             }
53              
54 1         2 return;
55             }
56              
57             sub parse_string {
58 170     170 0 388 my $self = shift;
59 170         344 my($xml) = @_;
60              
61             TRY:
62 170         500 for (1 .. $self->max_fallback) {
63 365         2099 my $doc = eval { $self->{parser}->parse_string($xml) };
  365         1151  
64 365 100       124564 return $doc if $doc;
65              
66 195         606 my $error = $self->extract_error($@, \$xml);
67 195         2174 for my $remedy (sort $self->remedies) {
68 1497 50       752073 warn "considering $remedy\n" if $self->debug;
69 1497 100       4120 $remedy->apply($self, $error, \$xml) or next;
70 195 50       17776 warn "--- remedy applied: $xml\n" if $self->debug;
71 195         892 next TRY;
72             }
73              
74             # We've considered all possible remedies for this error, and none
75             # worked, so just throw an exception.
76 0         0 Carp::croak($error->summary);
77             }
78             }
79              
80             sub parse_file {
81 96     96 0 501 my($self, $file) = @_;
82 96 50       3275 open my $fh, "<", $file or croak "$file: $!";
83 96         355 $self->parse_fh($fh);
84             }
85              
86             sub parse_fh {
87 96     96 0 155 my($self, $fh) = @_;
88 96         3905 my $xml = join '', <$fh>;
89 96         516 $self->parse_string($xml);
90             }
91              
92             our $AUTOLOAD;
93             sub AUTOLOAD {
94 0     0   0 my($self, @args) = @_;
95 0         0 (my $meth = $AUTOLOAD) =~ s/.*:://;
96 0         0 $self->{parser}->$meth(@args);
97             }
98              
99             sub DESTROY {
100 170     170   142641 my $self = shift;
101 170         1595 delete $self->{parser};
102             }
103              
104             package XML::Liberal::Destructor;
105              
106             sub new {
107 24     24   40 my($class, $callback) = @_;
108 24         87 bless { cb => $callback }, $class;
109             }
110              
111             sub DESTROY {
112 24     24   36 my $self = shift;
113 24         41 $self->{cb}->();
114             }
115              
116             package XML::Liberal;
117              
118             1;
119             __END__