File Coverage

blib/lib/Math/ModInt/Event/Trap.pm
Criterion Covered Total %
statement 57 57 100.0
branch 16 16 100.0
condition 2 3 66.6
subroutine 16 16 100.0
pod 2 2 100.0
total 93 94 98.9


line stmt bran cond sub pod time code
1             # Copyright (c) 2010-2015 Martin Becker. All rights reserved.
2             # This package is free software; you can redistribute it and/or modify it
3             # under the same terms as Perl itself.
4             #
5             # $Id: Trap.pm 60 2015-05-18 08:47:12Z demetri $
6              
7             package Math::ModInt::Event::Trap;
8              
9 11     11   165 use 5.006;
  11         27  
  11         384  
10 11     11   47 use strict;
  11         85  
  11         313  
11 11     11   44 use warnings;
  11         13  
  11         299  
12 11     11   47 use Carp qw(carp croak);
  11         13  
  11         982  
13              
14             # ----- class data -----
15              
16             BEGIN {
17 11     11   35 our @CARP_NOT = qw(Math::ModInt::Event);
18 11         233 our $VERSION = '0.011';
19             }
20              
21             # Math::ModInt::Event::Trap=ARRAY(...)
22              
23             # ........... index ........... # ............ value ............
24 11     11   47 use constant F_TRAP_ID => 0; # instance ID, used as a weak ref
  11         16  
  11         802  
25 11     11   45 use constant NFIELDS => 1;
  11         19  
  11         428  
26              
27             # ARRAY, element of @handlers:
28              
29             # ........... index ........... # ............ value ............
30 11     11   40 use constant H_TRAP_ID => 0; # instance ID of trap (0 if static)
  11         10  
  11         432  
31 11     11   45 use constant H_EVENT => 1; # event to trap
  11         12  
  11         422  
32 11     11   43 use constant H_HANDLER => 2; # the handler coderef
  11         15  
  11         5544  
33              
34             my $unique = 0;
35             my @handlers = ();
36              
37             my %generic_handlers = (
38             'ignore' => sub { 0 },
39             'warn' =>
40             sub {
41             my ($event, @details) = @_;
42             carp join q[: ], 'warning', $event->description, @details;
43             return 0;
44             },
45             'die' =>
46             sub {
47             my ($event, @details) = @_;
48             croak join q[: ], 'error', $event->description, @details;
49             },
50             );
51              
52             # ----- private subroutines -----
53              
54             sub _discard_handler {
55 12     12   12 my ($trap_id) = @_;
56 12         18 @handlers = grep { $trap_id != $_->[H_TRAP_ID] } @handlers;
  29         124  
57             }
58              
59             sub _add_handler {
60 13     13   15 my ($trap_id, $event, $handler) = @_;
61 13         27 push @handlers, [$trap_id, $event, $handler];
62             }
63              
64             sub _final_trap {
65 36     36   56 my ($event, @details) = @_;
66 36         119 croak join q[: ], $event->description, @details;
67             }
68              
69             # ----- public methods -----
70              
71             sub new {
72 15     15 1 14 my ($class, $event, $handler) = @_;
73 15 100       29 my $is_static = defined wantarray? 0: 1;
74 15 100       22 my $trap_id = $is_static? 0: ++$unique;
75 15 100       32 if (!ref $handler) {
76 5 100 66     23 if (!$handler || !exists $generic_handlers{$handler}) {
77 2         18 $event->UsageError->raise(
78             'bad argument: generic trap type or coderef expected'
79             );
80             }
81 3         7 $handler = $generic_handlers{$handler};
82             }
83 13         21 _add_handler($trap_id, $event, $handler);
84 13 100       25 return if $is_static;
85 12         41 return bless [$trap_id], $class;
86             }
87              
88             sub DESTROY {
89 12     12   2112 my ($this) = @_;
90 12         25 _discard_handler($this->[F_TRAP_ID]);
91             }
92              
93             sub broadcast {
94 114     114 1 172 my ($class, $event, @details) = @_;
95 114         127 my $called = 0;
96 114         253 foreach my $handler (reverse @handlers) {
97 17 100       101 if ($event->isa(ref $handler->[H_EVENT])) {
98 13         10 ++$called;
99 13 100       26 last if !$handler->[H_HANDLER]->($event, @details);
100             }
101             }
102 110 100       350 if (!$event->is_recoverable) {
103 36         70 _final_trap($event, @details);
104             }
105 74         137 return $called;
106             }
107              
108             1;
109              
110             __END__