File Coverage

blib/lib/AnyEvent/Debounce.pm
Criterion Covered Total %
statement 2 4 50.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 4 6 66.6


line stmt bran cond sub pod time code
1             package AnyEvent::Debounce;
2             BEGIN {
3 1     1   33225 $AnyEvent::Debounce::VERSION = '0.01';
4             }
5             # ABSTRACT: condense multiple temporally-nearby events into one
6 1     1   10231 use Moose;
  0            
  0            
7             use AnyEvent;
8              
9             has 'front_triggered' => (
10             is => 'ro',
11             isa => 'Bool',
12             default => 0,
13             documentation => 'if true, trigger immediately after the first event is received',
14             );
15              
16             has 'always_reset_timer' => (
17             is => 'ro',
18             isa => 'Bool',
19             default => 0,
20             documentation => 'if true, reset the timer after each event',
21             );
22              
23             has 'delay' => (
24             is => 'ro',
25             isa => 'Num',
26             default => 1,
27             documentation => 'number of seconds to wait before considering events separate',
28             );
29              
30             has 'cb' => (
31             is => 'ro',
32             isa => 'CodeRef',
33             required => 1,
34             documentation => 'coderef to run when debounced events are ready',
35             );
36              
37             has '_queued_events' => (
38             traits => ['Array'],
39             reader => 'queued_events',
40             isa => 'ArrayRef',
41             default => sub { [] },
42             lazy => 1,
43             clearer => 'clear_queued_events',
44             handles => { 'queue_event' => 'push', 'event_count' => 'count' },
45             );
46              
47             has 'timer' => (
48             reader => 'timer',
49             lazy_build => 1,
50             );
51              
52             sub _build_timer {
53             my $self = shift;
54             return AnyEvent->timer(
55             after => $self->delay,
56             interval => 0,
57             cb => sub { $self->send_events_now },
58             );
59             }
60              
61             sub send_events_now {
62             my $self = shift;
63             my $events = $self->queued_events;
64             my $count = $self->event_count;
65             $self->clear_timer;
66             $self->clear_queued_events;
67             $self->cb->(@$events) if $count > 0;
68             return;
69             }
70              
71             sub send {
72             my ($self, @args) = @_;
73              
74             my $timer_running = $self->has_timer;
75             $self->clear_timer if $self->always_reset_timer;
76             $self->timer; # resets the timer if we don't have one
77              
78             if($self->front_triggered && !$timer_running){
79             $self->cb->([@args]);
80             }
81             elsif(!$self->front_triggered){
82             $self->queue_event([@args]);
83             }
84             else {
85             # warn "discarding event"
86             }
87              
88             return;
89             }
90              
91             1;
92              
93              
94              
95             =pod
96              
97             =head1 NAME
98              
99             AnyEvent::Debounce - condense multiple temporally-nearby events into one
100              
101             =head1 VERSION
102              
103             version 0.01
104              
105             =head1 SYNOPSIS
106              
107             Create a debouncer:
108              
109             my $damper = AnyEvent::Debounce->new( cb => sub {
110             my (@events) = @_;
111             say "Got ", scalar @events, " event(s) in the batch";
112             say "Got event with args: ", join ',', @$_ for @events;
113             });
114              
115             Send it events in rapid succession:
116              
117             $damper->send(1,2,3);
118             $damper->send(2,3,4);
119              
120             Watch the output:
121              
122             Got 2 events in the batch
123             Got event with args: 1,2,3
124             Got event with args: 2,3,4
125              
126             Send it more evnts:
127              
128             $damper->send(1);
129             sleep 5;
130             $damper->send(2);
131              
132             And notice that there was no need to "debounce" this time:
133              
134             Got 1 event in the batch
135             Got event with args: 1
136              
137             Got 1 event in the batch
138             Got event with args: 2
139              
140             =head1 INITARGS
141              
142             =head1 cb
143              
144             The callback to be called when some events are ready to be handled.
145             Each "event" is an arrayref of the args passed to C<send>.
146              
147             =head1 delay
148              
149             The time to wait after receiving an event before sending it, in case
150             more events happen in the interim.
151              
152             =head1 always_reset_timer
153              
154             Normally, when an event is received and it's the first of a series, a
155             timer is started, and when that timer expires, all events are sent.
156             If you set this initarg to a true value, then the timer is reset after
157             each event is received.
158              
159             For example, if you set the delay to 1, and ten events arrive at 0.5
160             second intervals, then with this flag set to true, you will get one
161             event after 5 seconds. With this flag set to false, you will get an
162             event once a second for 5 seconds.
163              
164             By default, this is false, because setting it to true can lead to
165             events never being sent. (Imagine you set delay to 10 seconds, and
166             someone sends an event ever 9.9 seconds. You'll never get any
167             events.)
168              
169             =head1 front_triggered
170              
171             This flag, when set to true, causes an event to be sent immediately
172             upon receiving the first event. Then, you won't get any events for
173             C<delay> seconds, even if they occur. These events are lost, you will
174             never see them.
175              
176             By default, this is false.
177              
178             If you also set C<always_reset_timer> to true, the same timer-reset
179             logic as described above occurs.
180              
181             =head1 METHODS
182              
183             =head1 send
184              
185             Send an event; the handler callback will get everything you pass in.
186              
187             =head1 REPOSITORY
188              
189             L<http://github.com/jrockway/anyevent-debounce>
190              
191             =head1 AUTHOR
192              
193             Jonathan Rockway <jrockway@cpan.org>
194              
195             =head1 COPYRIGHT AND LICENSE
196              
197             This software is copyright (c) 2011 by Jonathan Rockway.
198              
199             This is free software; you can redistribute it and/or modify it under
200             the same terms as the Perl 5 programming language system itself.
201              
202             =cut
203              
204              
205             __END__
206