File Coverage

blib/lib/Mojo/Promise/Role/Some.pm
Criterion Covered Total %
statement 23 23 100.0
branch 10 10 100.0
condition n/a
subroutine 5 5 100.0
pod 1 1 100.0
total 39 39 100.0


line stmt bran cond sub pod time code
1             package Mojo::Promise::Role::Some;
2 1     1   847 use Mojo::Base '-role';
  1         3  
  1         9  
3              
4 1     1   496 use strict;
  1         3  
  1         330  
5              
6             our $VERSION = '1.005';
7              
8             =encoding utf8
9              
10             =head1 NAME
11              
12             Mojo::Promise::Role::Some - Fulfill when a certain number of promises are fulfilled
13              
14             =head1 SYNOPSIS
15              
16             use Mojo::Promise;
17             use Mojo::Util qw(dumper);
18              
19             my @promises = map { Mojo::Promise->new } 0 .. 5;
20             my $some_promise = Mojo::Promise
21             ->with_roles( '+Some' )
22             ->some( \@promises, $count_to_fulfill );
23              
24             $some_promise->then(
25             sub { say dumper( @_ ) }
26             sub { say "Failed!" }
27             );
28              
29             $some_promise->wait;
30              
31             =head1 DESCRIPTION
32              
33             Make a new promise that fulfills with a certain number of its promises
34             fulfill. Fire off several tasks and fulfill when a minimum number of them
35             work out.
36              
37             This should be the Perl expression of the same idea in
38             bluebirdjs (L).
39              
40             =over 4
41              
42             =item some( \@promises, $count )
43              
44             Takes a lists of promises (or thenables) and returns another promise
45             that fulfills when C<$count> promises fulfill. The result is list of
46             array references for the arguments for the fulfilled promises in the
47             order that they were fulfilled.
48              
49             If less than C<$count> promises fulfill then the some promise rejects.
50             The result is list of array references for the arguments for the
51             rejected promises in the order that they were rejected. The number of elements
52             in that list should be the PROMISES - COUNT + 1 since the extra reject
53             is the response that makes it impossible to get to COUNT fulfills.
54              
55             If you pass no promises, the some promise fulfills if you specify
56             C<$count = 0> and rejects otherwise.
57              
58             =cut
59              
60             sub some {
61 9     9 1 40434 my( $self, $promises, $n ) = @_;
62 9         40 my $some = $self->new;
63              
64 9 100       301 return $n == 0 ? $some->resolve : $some->reject if @$promises == 0;
    100          
65 4 100       19 return $some->reject if $n > @$promises;
66              
67 3         6 my $remaining = @$promises;
68              
69 3         7 my( @resolved, @rejected );
70 3         5 foreach my $p ( @$promises ) {
71             $p->then(
72             sub {
73 9     9   2082 $remaining--;
74 9         20 push @resolved, [ @_ ];
75 9 100       27 $some->resolve( @resolved ) if @resolved == $n;
76 9         62 return;
77             },
78             sub {
79             # I keep trying to come up with a situation where
80             # you'd reject $some with fewer rejections, but as
81             # long as the sum of the pending and fulfilled is at
82             # least the minimum count, there's always a chance.
83             # The only way for that to not be true is for there
84             # to be enough rejections to make pending small enough.
85             # That's PROMISES - N + 1. Let's see if I can understand
86             # that the next time I come through this. I still don't
87             # believe it.
88 10     10   3159 $remaining--;
89 10         23 push @rejected, [ @_ ];
90 10 100       41 $some->reject( @rejected ) if @rejected > @$promises - $n;
91 10         159 return;
92             },
93             )
94 19         847 }
95              
96 3         141 return $some;
97             }
98              
99             =back
100              
101             =head1 SEE ALSO
102              
103             L, L, L
104              
105             L
106              
107             =head1 SOURCE AVAILABILITY
108              
109             This source is in Github:
110              
111             https://github.com/briandfoy/mojo-promise-role-higherorder
112              
113             =head1 AUTHOR
114              
115             brian d foy, C<< >>
116              
117             =head1 COPYRIGHT AND LICENSE
118              
119             Copyright © 2018-2021, brian d foy, All Rights Reserved.
120              
121             You may redistribute this under the terms of the Artistic License 2.0.
122              
123             =cut
124              
125             1;