File Coverage

blib/lib/Devel/Events/Filter/Size.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package Devel::Events::Filter::Size;
4 1     1   25852 use Moose;
  0            
  0            
5              
6             with qw/Devel::Events::Filter/;
7              
8             our $VERSION = "0.03";
9              
10             use Devel::Size ();
11             #use Devel::Size::Report (); # it breaks
12             use Scalar::Util qw/refaddr reftype/;
13              
14             has fields => (
15             isa => "Any",
16             is => "ro",
17             );
18              
19             has one_field => (
20             isa => "Bool",
21             is => "ro",
22             lazy => 1,
23             default => sub {
24             my $self = shift;
25             defined $self->fields and not ref $self->fields;
26             },
27             );
28              
29             has no_total => (
30             isa => "Bool",
31             is => "rw",
32             );
33              
34             has no_report => (
35             isa => "Bool",
36             is => "rw",
37             default => 1,
38             );
39              
40             sub filter_event {
41             my ( $self, @event ) = @_;
42             my ( $type, @data ) = @event;
43              
44             if ( $self->is_one_field(@event) ) {
45             my $field = $self->get_field(@event);
46              
47             my $ref = { @data }->{ $field };
48              
49             return ( $type, $self->calculate_sizes($ref), @data );
50             } else {
51             my @fields = $self->get_fields(@event);
52              
53             my %sizes;
54             my %fields = map { $_ => [] } @fields;
55              
56             my @data_copy = @data;
57              
58             while ( @data_copy ) {
59             my ( $key, $value ) = splice( @data_copy, 0, 2 );
60             push @{ $fields{$key} }, $value if exists $fields{$key};
61             }
62              
63             foreach my $field ( @fields ) {
64             foreach my $ref ( grep { ref } @{ $fields{$field} ||=[] } ) {
65             push @{ $sizes{$field} }, {
66             refaddr => refaddr($ref),
67             $self->calculate_sizes($ref)
68             };
69             }
70             }
71              
72             return (
73             $type,
74             sizes => \%sizes,
75             @data,
76             );
77             }
78             }
79              
80             sub is_one_field {
81             my ( $self, @event ) = @_;
82             $self->one_field;
83             }
84              
85             sub get_fields {
86             my ( $self, @args ) = @_;
87              
88             my $fields = $self->fields;
89              
90             if ( not ref $fields ) {
91             if ( defined $fields ) {
92             return $fields;
93             } else {
94             my ( $type, @data ) = @args;
95             my ( $i, %seen );
96             return ( grep { !$seen{$_}++ } grep { ++$i % 2 == 1 } @data ); # even fields
97             }
98             } else {
99             if ( reftype $fields eq 'ARRAY' ) {
100             return @$fields;
101             } elsif ( reftype $fields eq 'CODE' ) {
102             $self->$fields(@args);
103             } else {
104             die "Uknown type for field spec: $fields";
105             }
106             }
107             }
108              
109             sub get_field {
110             my ( $self, @args ) = @_;
111             ( $self->get_fields(@args) )[0];
112             }
113              
114             sub calculate_sizes {
115             my ( $self, $ref ) = @_;
116              
117             return (
118             $self->calculate_size($ref),
119             $self->calculate_total_size($ref),
120             $self->calculate_size_report($ref),
121             );
122             }
123              
124             sub calculate_size {
125             my ( $self, $ref ) = @_;
126             return ( size => Devel::Size::size($ref) );
127             }
128              
129             sub calculate_total_size {
130             my ( $self, $ref ) = @_;
131             return if $self->no_total;
132             return ( total_size => Devel::Size::total_size($ref) );
133             }
134              
135             sub calculate_size_report {
136             my ( $self, $ref ) = @_;
137             return if $self->no_report;
138             require Devel::Size::Report; # only use it if necessary, since it breaks for some people.
139             return ( size_report => Devel::Size::Report::report_size($ref) );
140             }
141              
142             __PACKAGE__;
143              
144             __END__
145              
146             =pod
147              
148             =head1 NAME
149              
150             Devel::Events::Filter::Size - Add L<Devel::Size> info to event data.
151              
152             =head1 SYNOPSIS
153              
154             my $f = Devel::Events::Filter::Size->new(
155             handler => $h,
156             fields => [qw/foo bar gorch/], # calculate the size of these fields
157             );
158              
159             # OR
160              
161             my $f = Devel::Events::Filter::Size->new(
162             handler => $h,
163             fields => "object", # just one field
164             );
165              
166             =head1 DESCRIPTION
167              
168             This class uses L<Devel::Size> and optionally L<Devel::Size::Report> to provide
169             size information for data found inside events.
170              
171             Typical usage would be to apply it to the C<object> field in conjunction with
172             L<Devel::Events::Objects>.
173              
174             =head1 ATTRIBUTES
175              
176             =over 4
177              
178             =item fields
179              
180             The fields whose size to check.
181              
182             Can be a single string, or an array reference.
183              
184             When undefined all fields will be computed.
185              
186             =item one_field
187              
188             This parameter controls the placement of the results (top level, or under the
189             C<sizes> field).
190              
191             It defaults to true when C<fields> is a scalar, and false in any other
192             situation.
193              
194             =item no_total
195              
196             When true, L<Devel::Size/total_size> will not be used.
197              
198             Defaults to false.
199              
200             =item no_report
201              
202             When true, L<Devel::Size::Report> will not be used.
203              
204             Defaults to true.
205              
206             =back
207              
208             =head1 METHODS
209              
210             =over 4
211              
212             =item filter_event
213              
214             When C<is_one_field> returns a true value, this method will add a C<size>, and
215             optionally a C<total_size> and C<size_report> field to the event. Otherwise it
216             will add several of these to the C<sizes> field, keyed by the C<refaddr> of the
217             value.
218              
219             Only reference types will have their sizes computed.
220              
221             =item is_one_field
222              
223             Internal method. Used by C<filter_event>
224              
225             =item get_field
226              
227             Returns the fields whose sizes need computing. This is either all fields if
228             C<fields> is undef, or the specified fields.
229              
230             =item get_fields
231              
232             Returns only one field. Used when C<is_one_field> is true.
233              
234             =item calculate_sizes
235              
236             Return an entry with the C<size>, C<total_size> and C<size_report> results.
237              
238             =item calculate_size
239              
240             See L<Devel::Size/size>
241              
242             =item calculate_total_size
243              
244             Optionally uses L<Devel::Size/total_size>, depending on the value of
245             C<no_total>.
246              
247             =item calculate_size_report
248              
249             Optionally loads L<Devel::Size::Report> and uses uses
250             L<Devel::Size::Report/report_size>, depending on the value of C<no_report>.
251              
252             =back
253              
254             =head1 SEE ALSO
255              
256             L<Devel::Events>, L<Devel::Size>, L<Devel::Events::Filter>
257              
258             =head1 AUTHOR
259              
260             Yuval Kogman <nothingmuch@woobling.org>
261              
262             =head1 COPYRIGHT & LICENSE
263              
264             Copyright (c) 2007 Yuval Kogman. All rights reserved
265             This program is free software; you can redistribute it and/or modify it
266             under the terms of the MIT license or the same terms as Perl itself.
267              
268             =cut
269              
270