File Coverage

blib/lib/Log/Stack.pm
Criterion Covered Total %
statement 66 67 98.5
branch 15 18 83.3
condition 4 8 50.0
subroutine 11 11 100.0
pod 5 6 83.3
total 101 110 91.8


line stmt bran cond sub pod time code
1 1     1   34416 use strictures 2;
  1         8  
  1         40  
2              
3             package Log::Stack;
4              
5             # ABSTRACT: Cache log messages and throw them later
6              
7 1     1   471 use Moo;
  1         1  
  1         7  
8 1     1   220 use Carp qw(croak);
  1         5  
  1         56  
9 1     1   3 use Scalar::Util qw(blessed);
  1         1  
  1         682  
10              
11             our $VERSION = '0.001'; # VERSION
12              
13              
14             has _stack => (
15             is => 'lazy',
16             default => sub { [] },
17             clearer => 1,
18             );
19              
20             has _target => (
21             is => 'ro',
22             );
23              
24             has _defaults => (
25             is => 'ro',
26             default => sub { {} },
27             );
28              
29             has _hooks => (
30             is => 'ro',
31             default => sub { {} },
32             );
33              
34             has _initialized => (
35             is => 'rw',
36             default => 0,
37             );
38              
39             sub _exechook {
40 28     28   31 my ($self, $hook, @args) = @_;
41 28 100       66 return unless $self->_hooks->{$hook};
42 6         6 foreach my $code (@{ $self->_hooks->{$hook} }) {
  6         14  
43 6         11 $code->($self, @args);
44             }
45             }
46              
47              
48             sub BUILDARGS {
49 7     7 0 89228 my $class = shift;
50 7         7 my ($target, %defaults);
51 7 100       22 $target = shift if @_ % 2;
52 7         9 %defaults = @_;
53             return {
54 7         112 _target => $target,
55             _defaults => \%defaults,
56             }
57             }
58              
59              
60             sub set {
61 2     2 1 496 my ($self, %vals) = @_;
62 2         5 foreach my $key (keys %vals) {
63 2         8 $self->_defaults->{$key} = delete $vals{$key};
64             }
65             }
66              
67              
68             sub log {
69 17     17 1 4404 my ($self, $level, $msg, %rest) = @_;
70 17 100       47 unless ($self->_initialized) {
71 10         15 $self->_exechook('init');
72 10         19 $self->_initialized(1);
73             }
74 17         10 foreach my $key (keys %{ $self->_defaults }) {
  17         45  
75 3 50       5 next if exists $rest{$key};
76 3         6 my $val = $self->_defaults->{$key};
77 3 100       9 if (ref $val eq 'CODE') {
78 1         3 $rest{$key} = scalar($val->($level, $msg));
79             } else {
80 2         3 $rest{$key} = $val;
81             }
82             }
83 17         18 push @{ $self->_stack } => [ $level, $msg, %rest ];
  17         300  
84             }
85              
86              
87             sub throw {
88 6     6 1 3047 my ($self, $target) = @_;
89 6 100       5 return unless @{ $self->_stack };
  6         111  
90 5   66     48 $target //= $self->_target;
91 5 100 33     23 if (ref $target eq 'CODE') {
    50          
92 4         7 $self->_exechook('before');
93 4         6 while (my $msg = shift @{ $self->_stack }) {
  10         149  
94 6         41 $target->(@$msg);
95             }
96 4         23 $self->_exechook('after');
97             } elsif (blessed $target and $target->can('log')) {
98 1         3 $self->_exechook('before');
99 1         1 while (my $msg = shift @{ $self->_stack }) {
  3         50  
100 2         15 $target->log(@$msg);
101             }
102 1         8 $self->_exechook('after');
103             } else {
104 0         0 croak "Logging target must be a blessed object with a log method or a CodeRref";
105             }
106 5         11 $self->_exechook('cleanup');
107 5         16 $self->_initialized(0);
108             }
109              
110              
111             sub flush {
112 3     3 1 2130 my $self = shift;
113 3         47 $self->_clear_stack;
114 3         329 $self->_exechook('cleanup');
115 3         10 $self->_initialized(0);
116             }
117              
118              
119             sub hook {
120 4     4 1 27 my ($self, %def) = @_;
121 4         18 foreach my $name (keys %def) {
122 4         6 my $code = $def{$name};
123 4 50       7 croak "Hook for $name must be a CodeRef" unless ref $code eq 'CODE';
124 4   50     17 $self->_hooks->{$name} //= [];
125 4         3 push @{ $self->_hooks->{$name} } => $code;
  4         13  
126             }
127             }
128              
129              
130              
131             1;
132              
133             __END__