Hello community,

here is the log from the commit of package perl-Future for openSUSE:Factory 
checked in at 2017-12-08 13:01:26
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/perl-Future (Old)
 and      /work/SRC/openSUSE:Factory/.perl-Future.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "perl-Future"

Fri Dec  8 13:01:26 2017 rev:5 rq:555057 version:0.37

Changes:
--------
--- /work/SRC/openSUSE:Factory/perl-Future/perl-Future.changes  2017-06-26 
15:56:18.133488703 +0200
+++ /work/SRC/openSUSE:Factory/.perl-Future.new/perl-Future.changes     
2017-12-08 13:01:47.736134241 +0100
@@ -1,0 +2,32 @@
+Thu Dec  7 06:23:35 UTC 2017 - [email protected]
+
+- updated to 0.37
+   see /usr/share/doc/packages/perl-Future/Changes
+
+  0.37    2017/11/28 15:39:22
+          [CHANGES]
+           * Finally got around to removing the old Makefile.PL
+  
+          [BUGFIXES]
+           * Fix for convergent futures that lose strong references during
+             cancellation (RT120468)
+           * ->without_cancel shouldn't retain the originating future after
+             completion (RT122920)
+
+-------------------------------------------------------------------
+Tue Nov 28 06:22:55 UTC 2017 - [email protected]
+
+- updated to 0.36
+   see /usr/share/doc/packages/perl-Future/Changes
+
+  0.36    2017/11/27 22:04:52
+          [CHANGES]
+           * Added ->retain method (RT123711)
+           * Fixed some typoes in docs (RT118309)
+           * Added ->state method (RT120759)
+          
+          [BUGFIXES]
+           * Ensure that ->without_cancel still strongly holds a reference to
+             its parent future (RT122920)
+
+-------------------------------------------------------------------

Old:
----
  Future-0.35.tar.gz

New:
----
  Future-0.37.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ perl-Future.spec ++++++
--- /var/tmp/diff_new_pack.bDXHl2/_old  2017-12-08 13:01:48.832094660 +0100
+++ /var/tmp/diff_new_pack.bDXHl2/_new  2017-12-08 13:01:48.832094660 +0100
@@ -17,7 +17,7 @@
 
 
 Name:           perl-Future
-Version:        0.35
+Version:        0.37
 Release:        0
 %define cpan_name Future
 Summary:        Represent an Operation Awaiting Completion
@@ -31,7 +31,7 @@
 BuildRequires:  perl
 BuildRequires:  perl-macros
 BuildRequires:  perl(Carp) >= 1.25
-BuildRequires:  perl(Module::Build)
+BuildRequires:  perl(Module::Build) >= 0.400400
 BuildRequires:  perl(Test::Fatal)
 BuildRequires:  perl(Test::Identity)
 BuildRequires:  perl(Test::More) >= 0.88

++++++ Future-0.35.tar.gz -> Future-0.37.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/Build.PL new/Future-0.37/Build.PL
--- old/Future-0.35/Build.PL    2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/Build.PL    2017-11-28 16:41:25.000000000 +0100
@@ -3,8 +3,6 @@
 
 use Module::Build;
 
-use constant HAVE_M_B_TEST_REQUIRES => $Module::Build::VERSION >= '0.4004';
-
 # This version of Future contains an important bugfix around weak references
 # in sequence Futures. Unfortunately, a lot of existing CPAN code is known to
 # rely on this behaviour, and will break if this module is upgraded.
@@ -51,11 +49,8 @@
 
 my $build = Module::Build->new(
    module_name => 'Future',
-   ( HAVE_M_B_TEST_REQUIRES ? "test_requires" : "configure_requires" ) => {
-      'Test::Identity' => 0,
-      'Test::Fatal' => 0,
-      'Test::More' => '0.88', # done_testing
-      'Test::Refcount' => 0,
+   configure_requires => {
+      'Module::Build' => "0.4004", # test_requires
    },
    requires => {
       'perl' => '5.008', # fails on 5.6 smokers; no idea why
@@ -63,6 +58,12 @@
       'Test::Builder::Module' => 0,
       'Time::HiRes' => 0,
    },
+   test_requires => {
+      'Test::Identity' => 0,
+      'Test::Fatal' => 0,
+      'Test::More' => '0.88', # done_testing
+      'Test::Refcount' => 0,
+   },
    meta_merge => {
       # It's unlikely at the time of writing that any CPAN client actually
       # pays attention to this field, but it's nice to declare it on CPAN
@@ -74,7 +75,6 @@
    },
    auto_configure_requires => 0, # Don't add M::B
    license => 'perl',
-   create_makefile_pl => 'traditional',
    create_license => 1,
    create_readme  => 1,
    meta_merge => {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/Changes new/Future-0.37/Changes
--- old/Future-0.35/Changes     2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/Changes     2017-11-28 16:41:25.000000000 +0100
@@ -1,5 +1,25 @@
 Revision history for Future
 
+0.37    2017/11/28 15:39:22
+        [CHANGES]
+         * Finally got around to removing the old Makefile.PL
+
+        [BUGFIXES]
+         * Fix for convergent futures that lose strong references during
+           cancellation (RT120468)
+         * ->without_cancel shouldn't retain the originating future after
+           completion (RT122920)
+
+0.36    2017/11/27 22:04:52
+        [CHANGES]
+         * Added ->retain method (RT123711)
+         * Fixed some typoes in docs (RT118309)
+         * Added ->state method (RT120759)
+        
+        [BUGFIXES]
+         * Ensure that ->without_cancel still strongly holds a reference to
+           its parent future (RT122920)
+
 0.35    2017/06/23 20:37:57
         [CHANGES]
          * Link to YAPC::EU talk video in SEE ALSO
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/MANIFEST new/Future-0.37/MANIFEST
--- old/Future-0.35/MANIFEST    2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/MANIFEST    2017-11-28 16:41:25.000000000 +0100
@@ -7,7 +7,6 @@
 lib/Future/Utils.pm
 lib/Test/Future.pm
 LICENSE
-Makefile.PL
 MANIFEST                       This list of files
 META.json
 META.yml
@@ -35,6 +34,7 @@
 t/34utils-repeat-foreach.t
 t/35utils-map-void.t
 t/36utils-map.t
-t/40mutext.t
+t/40mutex.t
 t/50test-future.t
+t/90legacy.t
 t/99pod.t
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/META.json new/Future-0.37/META.json
--- old/Future-0.35/META.json   2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/META.json   2017-11-28 16:41:25.000000000 +0100
@@ -10,10 +10,15 @@
    ],
    "meta-spec" : {
       "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec";,
-      "version" : "2"
+      "version" : 2
    },
    "name" : "Future",
    "prereqs" : {
+      "configure" : {
+         "requires" : {
+            "Module::Build" : "0.4004"
+         }
+      },
       "runtime" : {
          "requires" : {
             "Carp" : "1.25",
@@ -34,19 +39,19 @@
    "provides" : {
       "Future" : {
          "file" : "lib/Future.pm",
-         "version" : "0.35"
+         "version" : "0.37"
       },
       "Future::Mutex" : {
          "file" : "lib/Future/Mutex.pm",
-         "version" : "0.35"
+         "version" : "0.37"
       },
       "Future::Utils" : {
          "file" : "lib/Future/Utils.pm",
-         "version" : "0.35"
+         "version" : "0.37"
       },
       "Test::Future" : {
          "file" : "lib/Test/Future.pm",
-         "version" : "0.35"
+         "version" : "0.37"
       }
    },
    "release_status" : "stable",
@@ -56,6 +61,6 @@
       ],
       "x_IRC" : "irc://irc.perl.org/#io-async"
    },
-   "version" : "0.35",
-   "x_serialization_backend" : "JSON::PP version 2.27400"
+   "version" : "0.37",
+   "x_serialization_backend" : "JSON::PP version 2.94"
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/META.yml new/Future-0.37/META.yml
--- old/Future-0.35/META.yml    2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/META.yml    2017-11-28 16:41:25.000000000 +0100
@@ -7,8 +7,10 @@
   Test::Identity: '0'
   Test::More: '0.88'
   Test::Refcount: '0'
+configure_requires:
+  Module::Build: '0.4004'
 dynamic_config: 1
-generated_by: 'Module::Build version 0.422, CPAN::Meta::Converter version 
2.150005'
+generated_by: 'Module::Build version 0.422, CPAN::Meta::Converter version 
2.150010'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -17,16 +19,16 @@
 provides:
   Future:
     file: lib/Future.pm
-    version: '0.35'
+    version: '0.37'
   Future::Mutex:
     file: lib/Future/Mutex.pm
-    version: '0.35'
+    version: '0.37'
   Future::Utils:
     file: lib/Future/Utils.pm
-    version: '0.35'
+    version: '0.37'
   Test::Future:
     file: lib/Test/Future.pm
-    version: '0.35'
+    version: '0.37'
 requires:
   Carp: '1.25'
   Test::Builder::Module: '0'
@@ -35,5 +37,5 @@
 resources:
   IRC: irc://irc.perl.org/#io-async
   license: http://dev.perl.org/licenses/
-version: '0.35'
+version: '0.37'
 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/Makefile.PL new/Future-0.37/Makefile.PL
--- old/Future-0.35/Makefile.PL 2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/Makefile.PL 1970-01-01 01:00:00.000000000 +0100
@@ -1,17 +0,0 @@
-# Note: this file was auto-generated by Module::Build::Compat version 0.4220
-require 5.008;
-use ExtUtils::MakeMaker;
-WriteMakefile
-(
-  'NAME' => 'Future',
-  'VERSION_FROM' => 'lib/Future.pm',
-  'PREREQ_PM' => {
-                   'Carp' => '1.25',
-                   'Test::Builder::Module' => 0,
-                   'Time::HiRes' => 0
-                 },
-  'INSTALLDIRS' => 'site',
-  'EXE_FILES' => [],
-  'PL_FILES' => {}
-)
-;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/README new/Future-0.37/README
--- old/Future-0.35/README      2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/README      2017-11-28 16:41:25.000000000 +0100
@@ -219,6 +219,59 @@
     blessed Future reference, an immediate fail future is returned instead
     to complain about this fact.
 
+METHODS
+
+    As there are a lare number of methods on this class, they are
+    documented here in several sections.
+
+INSPECTION METHODS
+
+    The following methods query the internal state of a Future instance
+    without modifying it or otherwise causing side-effects.
+
+ is_ready
+
+       $ready = $future->is_ready
+
+    Returns true on a leaf future if a result has been provided to the done
+    method, failed using the fail method, or cancelled using the cancel
+    method.
+
+    Returns true on a convergent future if it is ready to yield a result,
+    depending on its component futures.
+
+ is_done
+
+       $done = $future->is_done
+
+    Returns true on a future if it is ready and completed successfully.
+    Returns false if it is still pending, failed, or was cancelled.
+
+ is_failed
+
+       $failed = $future->is_failed
+
+    Since version 0.26.
+
+    Returns true on a future if it is ready and it failed. Returns false if
+    it is still pending, completed successfully, or was cancelled.
+
+ is_cancelled
+
+       $cancelled = $future->is_cancelled
+
+    Returns true if the future has been cancelled by cancel.
+
+ state
+
+       $str = $future->state
+
+    Since version 0.36.
+
+    Returns a string describing the state of the future, as one of the
+    three states named above; namely done, failed or cancelled, or pending
+    if it is none of these.
+
 IMPLEMENTATION METHODS
 
     These methods would primarily be used by implementations of
@@ -281,28 +334,11 @@
     cancelled when the original future is cancelled. This method does
     nothing if the future is already complete.
 
- is_cancelled
-
-       $cancelled = $future->is_cancelled
-
-    Returns true if the future has been cancelled by cancel.
-
 USER METHODS
 
     These methods would primarily be used by users of asynchronous
     interfaces, on objects returned by such an interface.
 
- is_ready
-
-       $ready = $future->is_ready
-
-    Returns true on a leaf future if a result has been provided to the done
-    method, failed using the fail method, or cancelled using the cancel
-    method.
-
-    Returns true on a convergent future if it is ready to yield a result,
-    depending on its component futures.
-
  on_ready
 
        $future->on_ready( $code )
@@ -323,13 +359,6 @@
 
     Returns the $future.
 
- is_done
-
-       $done = $future->is_done
-
-    Returns true on a future if it is ready and completed successfully.
-    Returns false if it is still pending, failed, or was cancelled.
-
  get
 
        @result = $future->get
@@ -386,15 +415,6 @@
 
     Returns the $future.
 
- is_failed
-
-       $failed = $future->is_failed
-
-    Since version 0.26.
-
-    Returns true on a future if it is ready and it failed. Returns false if
-    it is still pending, completed successfully, or was cancelled.
-
  failure
 
        $exception = $future->failure
@@ -685,6 +705,32 @@
     operation that is being shared among multiple sequences; cancelling one
     should not prevent the others from running too.
 
+ retain
+
+       $f = $f->retain
+
+    Since version 0.36.
+
+    Creates a reference cycle which causes the future to remain in memory
+    until it completes. Returns the invocant future.
+
+    In normal situations, a Future instance does not strongly hold a
+    reference to other futures that it is feeding a result into, instead
+    relying on that to be handled by application logic. This is normally
+    fine because some part of the application will retain the top-level
+    Future, which then strongly refers to each of its components down in a
+    tree. However, certain design patterns, such as mixed Future-based and
+    legacy callback-based API styles might end up creating Futures simply
+    to attach callback functions to them. In that situation, without
+    further attention, the Future may get lost due to having no strong
+    references to it. Calling ->retain on it creates such a reference which
+    ensures it persists until it completes. For example:
+
+       Future->needs_all( $fA, $fB )
+          ->on_done( $on_done )
+          ->on_fail( $on_fail )
+          ->retain;
+
 CONVERGENT FUTURES
 
     The following constructors all take a list of component futures, and
@@ -834,10 +880,11 @@
     Since version 0.28.
 
     Accessors that return the tracing timestamps from the instance. These
-    give the time the instance was contructed ("birth" time, btime) and the
-    time the result was determined (the "ready" time, rtime). Each result
-    is returned as a two-element ARRAY ref, containing the epoch time in
-    seconds and microseconds, as given by Time::HiRes::gettimeofday.
+    give the time the instance was constructed ("birth" time, btime) and
+    the time the result was determined (the "ready" time, rtime). Each
+    result is returned as a two-element ARRAY ref, containing the epoch
+    time in seconds and microseconds, as given by
+    Time::HiRes::gettimeofday.
 
     In order for these times to be captured, they have to be enabled by
     setting $Future::TIMES to a true value. This is initialised true at the
@@ -865,7 +912,7 @@
 
     This method is invoked internally by various methods that are about to
     save a callback CODE reference supplied by the user, to be invoked
-    later. The default implementation simply returns the callback agument
+    later. The default implementation simply returns the callback argument
     as-is; the method is provided to allow users to provide extra
     behaviour. This can be done by applying a method modifier of the around
     kind, so in effect add a chain of wrappers. Each wrapper can then
@@ -1146,6 +1193,9 @@
 
 SEE ALSO
 
+      * Promises - an implementation of the "Promise/A+" pattern for
+      asynchronous programming
+
       * curry - Create automatic curried method call closures for any class
       or object
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/lib/Future/Mutex.pm 
new/Future-0.37/lib/Future/Mutex.pm
--- old/Future-0.35/lib/Future/Mutex.pm 2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/lib/Future/Mutex.pm 2017-11-28 16:41:25.000000000 +0100
@@ -8,7 +8,7 @@
 use strict;
 use warnings;
 
-our $VERSION = '0.35';
+our $VERSION = '0.37';
 
 use Future;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/lib/Future/Utils.pm 
new/Future-0.37/lib/Future/Utils.pm
--- old/Future-0.35/lib/Future/Utils.pm 2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/lib/Future/Utils.pm 2017-11-28 16:41:25.000000000 +0100
@@ -8,7 +8,7 @@
 use strict;
 use warnings;
 
-our $VERSION = '0.35';
+our $VERSION = '0.37';
 
 use Exporter 'import';
 # Can't import the one from Exporter as it relies on package inheritance
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/lib/Future.pm 
new/Future-0.37/lib/Future.pm
--- old/Future-0.35/lib/Future.pm       2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/lib/Future.pm       2017-11-28 16:41:25.000000000 +0100
@@ -1,7 +1,7 @@
 #  You may distribute under the terms of either the GNU General Public License
 #  or the Artistic License (the same terms as Perl itself)
 #
-#  (C) Paul Evans, 2011-2016 -- [email protected]
+#  (C) Paul Evans, 2011-2017 -- [email protected]
 
 package Future;
 
@@ -9,7 +9,7 @@
 use warnings;
 no warnings 'recursion'; # Disable the "deep recursion" warning
 
-our $VERSION = '0.35';
+our $VERSION = '0.37';
 
 use Carp qw(); # don't import croak
 use Scalar::Util qw( weaken blessed reftype );
@@ -466,7 +466,98 @@
    }
 }
 
-sub _state
+=head1 METHODS
+
+As there are a lare number of methods on this class, they are documented here
+in several sections.
+
+=cut
+
+=head1 INSPECTION METHODS
+
+The following methods query the internal state of a Future instance without
+modifying it or otherwise causing side-effects.
+
+=cut
+
+=head2 is_ready
+
+   $ready = $future->is_ready
+
+Returns true on a leaf future if a result has been provided to the C<done>
+method, failed using the C<fail> method, or cancelled using the C<cancel>
+method.
+
+Returns true on a convergent future if it is ready to yield a result,
+depending on its component futures.
+
+=cut
+
+sub is_ready
+{
+   my $self = shift;
+   return $self->{ready};
+}
+
+=head2 is_done
+
+   $done = $future->is_done
+
+Returns true on a future if it is ready and completed successfully. Returns
+false if it is still pending, failed, or was cancelled.
+
+=cut
+
+sub is_done
+{
+   my $self = shift;
+   return $self->{ready} && !$self->{failure} && !$self->{cancelled};
+}
+
+=head2 is_failed
+
+   $failed = $future->is_failed
+
+I<Since version 0.26.>
+
+Returns true on a future if it is ready and it failed. Returns false if it is
+still pending, completed successfully, or was cancelled.
+
+=cut
+
+sub is_failed
+{
+   my $self = shift;
+   return $self->{ready} && !!$self->{failure}; # boolify
+}
+
+=head2 is_cancelled
+
+   $cancelled = $future->is_cancelled
+
+Returns true if the future has been cancelled by C<cancel>.
+
+=cut
+
+sub is_cancelled
+{
+   my $self = shift;
+   return $self->{cancelled};
+}
+
+=head2 state
+
+   $str = $future->state
+
+I<Since version 0.36.>
+
+Returns a string describing the state of the future, as one of the three
+states named above; namely C<done>, C<failed> or C<cancelled>, or C<pending>
+if it is none of these.
+
+=cut
+
+sub state
 {
    my $self = shift;
    return !$self->{ready}     ? "pending" :
@@ -502,7 +593,7 @@
 
    if( ref $self ) {
       $self->{cancelled} and return $self;
-      $self->{ready} and Carp::croak "${\$self->__selfstr} is already 
".$self->_state." and cannot be ->done";
+      $self->{ready} and Carp::croak "${\$self->__selfstr} is already 
".$self->state." and cannot be ->done";
       $self->{subs} and Carp::croak "${\$self->__selfstr} is not a leaf 
Future, cannot be ->done";
       $self->{result} = [ @_ ];
       $self->_mark_ready( "done" );
@@ -517,9 +608,12 @@
    return $self;
 }
 
+my $warned_done_cb;
 sub done_cb
 {
    my $self = shift;
+   $warned_done_cb or
+      $warned_done_cb++, warnings::warnif( deprecated => "Future->done_cb is 
now deprecated; use ->curry::done or sub {...}" );
    return sub { $self->done( @_ ) };
 }
 
@@ -549,7 +643,7 @@
 
    if( ref $self ) {
       $self->{cancelled} and return $self;
-      $self->{ready} and Carp::croak "${\$self->__selfstr} is already 
".$self->_state." and cannot be ->fail'ed";
+      $self->{ready} and Carp::croak "${\$self->__selfstr} is already 
".$self->state." and cannot be ->fail'ed";
       $self->{subs} and Carp::croak "${\$self->__selfstr} is not a leaf 
Future, cannot be ->fail'ed";
       $self->{failure} = [ $exception, @details ];
       $self->_mark_ready( "fail" );
@@ -570,9 +664,12 @@
    return $self;
 }
 
+my $warned_fail_cb;
 sub fail_cb
 {
    my $self = shift;
+   $warned_fail_cb or
+      $warned_fail_cb++, warnings::warnif( deprecated => "Future->fail_cb is 
now deprecated; use ->curry::fail or sub {...}" );
    return sub { $self->fail( @_ ) };
 }
 
@@ -637,20 +734,6 @@
    return $self;
 }
 
-=head2 is_cancelled
-
-   $cancelled = $future->is_cancelled
-
-Returns true if the future has been cancelled by C<cancel>.
-
-=cut
-
-sub is_cancelled
-{
-   my $self = shift;
-   return $self->{cancelled};
-}
-
 =head1 USER METHODS
 
 These methods would primarily be used by users of asynchronous interfaces, on
@@ -658,25 +741,6 @@
 
 =cut
 
-=head2 is_ready
-
-   $ready = $future->is_ready
-
-Returns true on a leaf future if a result has been provided to the C<done>
-method, failed using the C<fail> method, or cancelled using the C<cancel>
-method.
-
-Returns true on a convergent future if it is ready to yield a result,
-depending on its component futures.
-
-=cut
-
-sub is_ready
-{
-   my $self = shift;
-   return $self->{ready};
-}
-
 =head2 on_ready
 
    $future->on_ready( $code )
@@ -724,21 +788,6 @@
    return $self;
 }
 
-=head2 is_done
-
-   $done = $future->is_done
-
-Returns true on a future if it is ready and completed successfully. Returns
-false if it is still pending, failed, or was cancelled.
-
-=cut
-
-sub is_done
-{
-   my $self = shift;
-   return $self->{ready} && !$self->{failure} && !$self->{cancelled};
-}
-
 =head2 get
 
    @result = $future->get
@@ -856,23 +905,6 @@
    return $self;
 }
 
-=head2 is_failed
-
-   $failed = $future->is_failed
-
-I<Since version 0.26.>
-
-Returns true on a future if it is ready and it failed. Returns false if it is
-still pending, completed successfully, or was cancelled.
-
-=cut
-
-sub is_failed
-{
-   my $self = shift;
-   return $self->{ready} && !!$self->{failure}; # boolify
-}
-
 =head2 failure
 
    $exception = $future->failure
@@ -989,9 +1021,12 @@
    return $self;
 }
 
+my $warned_cancel_cb;
 sub cancel_cb
 {
    my $self = shift;
+   $warned_cancel_cb or
+      $warned_cancel_cb++, warnings::warnif( deprecated => "Future->cancel_cb 
is now deprecated; use ->curry::cancel or sub {...}" );
    return sub { $self->cancel };
 }
 
@@ -1487,9 +1522,45 @@
       }
    });
 
+   $new->{orig} = $self; # just to strongref it - RT122920
+   $new->on_ready( sub { undef $_[0]->{orig} } );
+
    return $new;
 }
 
+=head2 retain
+
+   $f = $f->retain
+
+I<Since version 0.36.>
+
+Creates a reference cycle which causes the future to remain in memory until
+it completes. Returns the invocant future.
+
+In normal situations, a C<Future> instance does not strongly hold a reference
+to other futures that it is feeding a result into, instead relying on that to
+be handled by application logic. This is normally fine because some part of
+the application will retain the top-level Future, which then strongly refers
+to each of its components down in a tree. However, certain design patterns,
+such as mixed Future-based and legacy callback-based API styles might end up
+creating Futures simply to attach callback functions to them. In that
+situation, without further attention, the Future may get lost due to having no
+strong references to it. Calling C<< ->retain >> on it creates such a
+reference which ensures it persists until it completes. For example:
+
+   Future->needs_all( $fA, $fB )
+      ->on_done( $on_done )
+      ->on_fail( $on_fail )
+      ->retain;
+
+=cut
+
+sub retain
+{
+   my $self = shift;
+   return $self->on_ready( sub { undef $self } );
+}
+
 =head1 CONVERGENT FUTURES
 
 The following constructors all take a list of component futures, and return a
@@ -1570,13 +1641,13 @@
 
    weaken( my $weakself = $self );
    my $sub_on_ready = sub {
-      return unless $weakself;
+      return unless my $self = $weakself;
 
       $pending--;
       $pending and return;
 
-      $weakself->{result} = [ @subs ];
-      $weakself->_mark_ready( "wait_all" );
+      $self->{result} = [ @subs ];
+      $self->_mark_ready( "wait_all" );
    };
 
    foreach my $sub ( @subs ) {
@@ -1643,26 +1714,26 @@
 
    weaken( my $weakself = $self );
    my $sub_on_ready = sub {
-      return unless $weakself;
-      return if $weakself->{result} or $weakself->{failure}; # don't recurse 
on child ->cancel
+      return unless my $self = $weakself;
+      return if $self->{result} or $self->{failure}; # don't recurse on child 
->cancel
 
       return if --$pending and $_[0]->{cancelled};
 
       if( $_[0]->{cancelled} ) {
-         $weakself->{failure} = [ "All component futures were cancelled" ];
+         $self->{failure} = [ "All component futures were cancelled" ];
       }
       elsif( $_[0]->{failure} ) {
-         $weakself->{failure} = [ $_[0]->failure ];
+         $self->{failure} = [ $_[0]->failure ];
       }
       else {
-         $weakself->{result}  = [ $_[0]->get ];
+         $self->{result}  = [ $_[0]->get ];
       }
 
       foreach my $sub ( @subs ) {
          $sub->{ready} or $sub->cancel;
       }
 
-      $weakself->_mark_ready( "wait_any" );
+      $self->_mark_ready( "wait_any" );
    };
 
    foreach my $sub ( @subs ) {
@@ -1738,29 +1809,29 @@
 
    weaken( my $weakself = $self );
    my $sub_on_ready = sub {
-      return unless $weakself;
-      return if $weakself->{result} or $weakself->{failure}; # don't recurse 
on child ->cancel
+      return unless my $self = $weakself;
+      return if $self->{result} or $self->{failure}; # don't recurse on child 
->cancel
 
       if( $_[0]->{cancelled} ) {
-         $weakself->{failure} = [ "A component future was cancelled" ];
+         $self->{failure} = [ "A component future was cancelled" ];
          foreach my $sub ( @subs ) {
             $sub->cancel if !$sub->{ready};
          }
-         $weakself->_mark_ready( "needs_all" );
+         $self->_mark_ready( "needs_all" );
       }
       elsif( my @failure = $_[0]->failure ) {
-         $weakself->{failure} = \@failure;
+         $self->{failure} = \@failure;
          foreach my $sub ( @subs ) {
             $sub->cancel if !$sub->{ready};
          }
-         $weakself->_mark_ready( "needs_all" );
+         $self->_mark_ready( "needs_all" );
       }
       else {
          $pending--;
          $pending and return;
 
-         $weakself->{result} = [ map { $_->get } @subs ];
-         $weakself->_mark_ready( "needs_all" );
+         $self->{result} = [ map { $_->get } @subs ];
+         $self->_mark_ready( "needs_all" );
       }
    };
 
@@ -1846,27 +1917,27 @@
 
    weaken( my $weakself = $self );
    my $sub_on_ready = sub {
-      return unless $weakself;
-      return if $weakself->{result} or $weakself->{failure}; # don't recurse 
on child ->cancel
+      return unless my $self = $weakself;
+      return if $self->{result} or $self->{failure}; # don't recurse on child 
->cancel
 
       return if --$pending and $_[0]->{cancelled};
 
       if( $_[0]->{cancelled} ) {
-         $weakself->{failure} = [ "All component futures were cancelled" ];
-         $weakself->_mark_ready( "needs_any" );
+         $self->{failure} = [ "All component futures were cancelled" ];
+         $self->_mark_ready( "needs_any" );
       }
       elsif( my @failure = $_[0]->failure ) {
          $pending and return;
 
-         $weakself->{failure} = \@failure;
-         $weakself->_mark_ready( "needs_any" );
+         $self->{failure} = \@failure;
+         $self->_mark_ready( "needs_any" );
       }
       else {
-         $weakself->{result} = [ $_[0]->get ];
+         $self->{result} = [ $_[0]->get ];
          foreach my $sub ( @subs ) {
             $sub->cancel if !$sub->{ready};
          }
-         $weakself->_mark_ready( "needs_any" );
+         $self->_mark_ready( "needs_any" );
       }
    };
 
@@ -1994,7 +2065,7 @@
 I<Since version 0.28.>
 
 Accessors that return the tracing timestamps from the instance. These give the
-time the instance was contructed ("birth" time, C<btime>) and the time the
+time the instance was constructed ("birth" time, C<btime>) and the time the
 result was determined (the "ready" time, C<rtime>). Each result is returned as
 a two-element ARRAY ref, containing the epoch time in seconds and
 microseconds, as given by C<Time::HiRes::gettimeofday>.
@@ -2048,7 +2119,7 @@
 
 This method is invoked internally by various methods that are about to save a
 callback CODE reference supplied by the user, to be invoked later. The default
-implementation simply returns the callback agument as-is; the method is
+implementation simply returns the callback argument as-is; the method is
 provided to allow users to provide extra behaviour. This can be done by
 applying a method modifier of the C<around> kind, so in effect add a chain of
 wrappers. Each wrapper can then perform its own wrapping logic of the
@@ -2338,6 +2409,11 @@
 
 =item *
 
+L<Promises> - an implementation of the "Promise/A+" pattern for asynchronous
+programming
+
+=item *
+
 L<curry> - Create automatic curried method call closures for any class or
 object
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/lib/Test/Future.pm 
new/Future-0.37/lib/Test/Future.pm
--- old/Future-0.35/lib/Test/Future.pm  2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/lib/Test/Future.pm  2017-11-28 16:41:25.000000000 +0100
@@ -9,7 +9,7 @@
 use warnings;
 use base qw( Test::Builder::Module );
 
-our $VERSION = '0.35';
+our $VERSION = '0.37';
 
 our @EXPORT = qw(
    no_pending_futures
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/01future.t new/Future-0.37/t/01future.t
--- old/Future-0.35/t/01future.t        2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/t/01future.t        2017-11-28 16:41:25.000000000 +0100
@@ -19,6 +19,7 @@
    is_oneref( $future, '$future has refcount 1 initially' );
 
    ok( !$future->is_ready, '$future not yet ready' );
+   is( $future->state, "pending", '$future->state before done' );
 
    my @on_ready_args;
    identical( $future->on_ready( sub { @on_ready_args = @_ } ), $future, 
'->on_ready returns $future' );
@@ -38,6 +39,7 @@
    ok( $future->is_ready, '$future is now ready' );
    ok( $future->is_done, '$future is done' );
    ok( !$future->is_failed, '$future is not failed' );
+   is( $future->state, "done", '$future->state after done' );
    is_deeply( [ $future->get ], [ result => "here" ], 'Results from 
$future->get' );
    is( scalar $future->get, "result", 'Result from scalar $future->get' );
 
@@ -124,6 +126,7 @@
    ok( $future->is_ready, '$future->fail marks future ready' );
    ok( !$future->is_done, '$future->fail does not mark future done' );
    ok( $future->is_failed, '$future->fail marks future as failed' );
+   is( $future->state, "failed", '$future->state after fail' );
 
    is( scalar $future->failure, "Something broke", '$future->failure yields 
exception' );
    my $file = __FILE__;
@@ -259,4 +262,22 @@
    $f->cancel;
 }
 
+# retain
+{
+   my @args;
+   foreach my $method (qw( cancel done fail )) {
+      my $f = Future->new;
+      is_oneref( $f, 'start with refcount 1' );
+
+      is( $f->retain, $f, '->retain returns original Future' );
+
+      is_refcount( $f, 2, 'refcount is now increased' );
+
+      ok( $f->$method( @args ), "can call ->$method" );
+      is_oneref( $f, 'refcount drops when completed' );
+
+      push @args, 'x';
+   }
+}
+
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/02cancel.t new/Future-0.37/t/02cancel.t
--- old/Future-0.35/t/02cancel.t        2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/t/02cancel.t        2017-11-28 16:41:25.000000000 +0100
@@ -6,6 +6,7 @@
 use Test::More;
 use Test::Fatal;
 use Test::Identity;
+use Test::Refcount;
 
 use Future;
 
@@ -40,6 +41,7 @@
    ok( $ready_f->is_cancelled, 'on_ready chained future cnacelled after 
cancel' );
    ok( !$done_f->is_ready, 'on_done chained future not ready after cancel' );
    ok( !$fail_f->is_ready, 'on_fail chained future not ready after cancel' );
+   is( $future->state, "cancelled", '$future->state after ->cancel' );
 
    like( exception { $future->get }, qr/cancelled/, '$future->get throws 
exception by cancel' );
 
@@ -102,7 +104,10 @@
 # without_cancel
 {
    my $f1 = Future->new;
+   is_oneref( $f1, '$f1 has single reference initially' );
+
    my $f2 = $f1->without_cancel;
+   is_refcount( $f1, 2, '$f1 has two references after ->without_cancel' );
 
    $f2->cancel;
    ok( !$f1->is_cancelled, '$f1 not cancelled just because $f2 is' );
@@ -112,6 +117,7 @@
 
    ok( $f3->is_ready, '$f3 ready when $f1 is' );
    is_deeply( [ $f3->get ], [ "result" ], 'result of $f3' );
+   is_oneref( $f1, '$f1 has one reference after done' );
 }
 
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/11wait_any.t 
new/Future-0.37/t/11wait_any.t
--- old/Future-0.35/t/11wait_any.t      2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/t/11wait_any.t      2017-11-28 16:41:25.000000000 +0100
@@ -149,4 +149,23 @@
        '->get on empty wait_any is empty' );
 }
 
+# wait_any instance disappearing partway through cancellation (RT120468)
+{
+   my $f = Future->new;
+
+   my $wait;
+   $wait = Future->wait_any(
+      $f,
+      my $cancelled = Future->new->on_cancel( sub {
+         undef $wait;
+      }),
+   );
+
+   is( exception { $f->done(1) }, undef,
+      'no problems cancelling a Future which clears the original ->wait_any 
ref' );
+
+   ok( $cancelled->is_cancelled, 'cancellation occurred as expected' );
+   ok( $f->is_done, '->wait_any is marked as done' );
+}
+
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/12needs_all.t 
new/Future-0.37/t/12needs_all.t
--- old/Future-0.35/t/12needs_all.t     2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/t/12needs_all.t     2017-11-28 16:41:25.000000000 +0100
@@ -144,4 +144,23 @@
    is_deeply( [ $f->get ], [], '->get on empty needs_all is empty' );
 }
 
+# weakself retention (RT120468)
+{
+   my $f = Future->new;
+
+   my $wait;
+   $wait = Future->needs_all(
+      $f,
+      my $cancelled = Future->new->on_cancel( sub {
+         undef $wait;
+      }),
+   );
+
+   is( exception { $f->fail("oopsie\n") }, undef,
+      'no problems cancelling a Future which clears the original ->needs_all 
ref' );
+
+   ok( $cancelled->is_cancelled, 'cancellation occured as expected' );
+   ok( $f->is_failed, '->needs_all is marked as done' );
+}
+
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/13needs_any.t 
new/Future-0.37/t/13needs_any.t
--- old/Future-0.35/t/13needs_any.t     2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/t/13needs_any.t     2017-11-28 16:41:25.000000000 +0100
@@ -197,4 +197,23 @@
        '->get on empty needs_any is empty' );
 }
 
+# weakself retention (RT120468)
+{
+   my $f = Future->new;
+
+   my $wait;
+   $wait = Future->needs_any(
+      $f,
+      my $cancelled = Future->new->on_cancel( sub {
+         undef $wait;
+      }),
+   );
+
+   is( exception { $f->done(1) }, undef,
+      'no problems cancelling a Future which clears the original ->needs_any 
ref' );
+
+   ok( $cancelled->is_cancelled, 'cancellation occured as expected' );
+   ok( $f->is_done, '->needs_any is marked as done' );
+}
+
 done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/36utils-map.t 
new/Future-0.37/t/36utils-map.t
--- old/Future-0.35/t/36utils-map.t     2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/t/36utils-map.t     2017-11-28 16:41:25.000000000 +0100
@@ -44,6 +44,21 @@
    is_deeply( [ $future->get ], [qw( A B C D E )], '$future->get for 
fmap_concat out of order' );
 }
 
+# fmap_concat concurrent above input
+{
+   my @subf;
+   my $future = fmap_concat {
+      return $subf[$_[0]] = Future->new;
+   } foreach => [ 0 .. 2 ],
+     concurrent => 5;
+
+   $subf[0]->done( "A" );
+   $subf[1]->done( "B" );
+   $subf[2]->done( "C" );
+
+   is_deeply( [ $future->get ], [qw( A B C )], '$future->get for fmap_concat 
concurrent more than input' );
+}
+
 # fmap_concat cancel
 {
    my $f = Future->new;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/40mutex.t new/Future-0.37/t/40mutex.t
--- old/Future-0.35/t/40mutex.t 1970-01-01 01:00:00.000000000 +0100
+++ new/Future-0.37/t/40mutex.t 2017-11-28 16:41:25.000000000 +0100
@@ -0,0 +1,97 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use Future;
+use Future::Mutex;
+
+# done
+{
+   my $mutex = Future::Mutex->new;
+
+   my $f;
+   my $lf = $mutex->enter( sub { $f = Future->new } );
+
+   ok( defined $lf, '->enter returns Future' );
+   ok( defined $f, '->enter on new Mutex runs code' );
+
+   ok( !$lf->is_ready, 'locked future not yet ready' );
+
+   $f->done;
+   ok( $lf->is_ready, 'locked future ready after $f->done' );
+}
+
+# done chaining
+{
+   my $mutex = Future::Mutex->new;
+
+   my $f1;
+   my $lf1 = $mutex->enter( sub { $f1 = Future->new } );
+
+   my $f2;
+   my $lf2 = $mutex->enter( sub { $f2 = Future->new } );
+
+   ok( !defined $f2, 'second enter not invoked while locked' );
+
+   $f1->done;
+   ok( defined $f2, 'second enter invoked after $f1->done' );
+
+   $f2->done;
+   ok( $lf2->is_ready, 'second locked future ready after $f2->done' );
+}
+
+# fail chaining
+{
+   my $mutex = Future::Mutex->new;
+
+   my $f1;
+   my $lf1 = $mutex->enter( sub { $f1 = Future->new } );
+
+   my $f2;
+   my $lf2 = $mutex->enter( sub { $f2 = Future->new } );
+
+   ok( !defined $f2, 'second enter not invoked while locked' );
+
+   $f1->fail( "oops" );
+   ok( defined $f2, 'second enter invoked after $f1->fail' );
+   ok( $lf1->failure, 'first locked future fails after $f1->fail' );
+
+   $f2->done;
+   ok( $lf2->is_ready, 'second locked future ready after $f2->done' );
+}
+
+# immediately done
+{
+   my $mutex = Future::Mutex->new;
+
+   is( $mutex->enter( sub { Future->done( "result" ) } )->get,
+       "result",
+       '$mutex->enter returns immediate result' );
+}
+
+# immediately fail
+{
+   my $mutex = Future::Mutex->new;
+
+   is( $mutex->enter( sub { Future->fail( "oops" ) } )->failure,
+       "oops",
+       '$mutex->enter returns immediate failure' );
+}
+
+# code dies
+{
+   my $mutex = Future::Mutex->new;
+
+   is( $mutex->enter( sub { die "oopsie\n" } )->failure,
+       "oopsie\n",
+       '$mutex->enter returns immediate failure on exception' );
+
+   is( $mutex->enter( sub { Future->done( "unlocked" ) } )->get,
+       "unlocked",
+       '$mutex remains unlocked after exception' );
+}
+
+done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/40mutext.t new/Future-0.37/t/40mutext.t
--- old/Future-0.35/t/40mutext.t        2017-06-23 21:39:17.000000000 +0200
+++ new/Future-0.37/t/40mutext.t        1970-01-01 01:00:00.000000000 +0100
@@ -1,97 +0,0 @@
-#!/usr/bin/perl
-
-use strict;
-use warnings;
-
-use Test::More;
-
-use Future;
-use Future::Mutex;
-
-# done
-{
-   my $mutex = Future::Mutex->new;
-
-   my $f;
-   my $lf = $mutex->enter( sub { $f = Future->new } );
-
-   ok( defined $lf, '->enter returns Future' );
-   ok( defined $f, '->enter on new Mutex runs code' );
-
-   ok( !$lf->is_ready, 'locked future not yet ready' );
-
-   $f->done;
-   ok( $lf->is_ready, 'locked future ready after $f->done' );
-}
-
-# done chaining
-{
-   my $mutex = Future::Mutex->new;
-
-   my $f1;
-   my $lf1 = $mutex->enter( sub { $f1 = Future->new } );
-
-   my $f2;
-   my $lf2 = $mutex->enter( sub { $f2 = Future->new } );
-
-   ok( !defined $f2, 'second enter not invoked while locked' );
-
-   $f1->done;
-   ok( defined $f2, 'second enter invoked after $f1->done' );
-
-   $f2->done;
-   ok( $lf2->is_ready, 'second locked future ready after $f2->done' );
-}
-
-# fail chaining
-{
-   my $mutex = Future::Mutex->new;
-
-   my $f1;
-   my $lf1 = $mutex->enter( sub { $f1 = Future->new } );
-
-   my $f2;
-   my $lf2 = $mutex->enter( sub { $f2 = Future->new } );
-
-   ok( !defined $f2, 'second enter not invoked while locked' );
-
-   $f1->fail( "oops" );
-   ok( defined $f2, 'second enter invoked after $f1->fail' );
-   ok( $lf1->failure, 'first locked future fails after $f1->fail' );
-
-   $f2->done;
-   ok( $lf2->is_ready, 'second locked future ready after $f2->done' );
-}
-
-# immediately done
-{
-   my $mutex = Future::Mutex->new;
-
-   is( $mutex->enter( sub { Future->done( "result" ) } )->get,
-       "result",
-       '$mutex->enter returns immediate result' );
-}
-
-# immediately fail
-{
-   my $mutex = Future::Mutex->new;
-
-   is( $mutex->enter( sub { Future->fail( "oops" ) } )->failure,
-       "oops",
-       '$mutex->enter returns immediate failure' );
-}
-
-# code dies
-{
-   my $mutex = Future::Mutex->new;
-
-   is( $mutex->enter( sub { die "oopsie\n" } )->failure,
-       "oopsie\n",
-       '$mutex->enter returns immediate failure on exception' );
-
-   is( $mutex->enter( sub { Future->done( "unlocked" ) } )->get,
-       "unlocked",
-       '$mutex remains unlocked after exception' );
-}
-
-done_testing;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Future-0.35/t/90legacy.t new/Future-0.37/t/90legacy.t
--- old/Future-0.35/t/90legacy.t        1970-01-01 01:00:00.000000000 +0100
+++ new/Future-0.37/t/90legacy.t        2017-11-28 16:41:25.000000000 +0100
@@ -0,0 +1,52 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use Future;
+
+# done_cb
+{
+   my $f = Future->new;
+
+   my $warnings;
+   local $SIG{__WARN__} = sub { $warnings .= join "", @_; };
+
+   my $cb = $f->done_cb;
+   $cb->( 123 );
+
+   is( $f->get, 123, '$f->get after done_cb invoked' );
+   like( $warnings, qr/ is now deprecated/, 'Deprecation warning occured' );
+}
+
+# fail_cb
+{
+   my $f = Future->new;
+
+   my $warnings;
+   local $SIG{__WARN__} = sub { $warnings .= join "", @_; };
+
+   my $cb = $f->fail_cb;
+   $cb->( "oops\n" );
+
+   is( $f->failure, "oops\n", '$f->failure after fail_cb invoked' );
+   like( $warnings, qr/ is now deprecated/, 'Deprecation warning occured' );
+}
+
+# cancel_cb
+{
+   my $f = Future->new;
+
+   my $warnings;
+   local $SIG{__WARN__} = sub { $warnings .= join "", @_; };
+
+   my $cb = $f->cancel_cb;
+   $cb->();
+
+   ok( $f->is_cancelled, '$f is cancelled after cancel_cb invoked' );
+   like( $warnings, qr/ is now deprecated/, 'Deprecation warning occured' );
+}
+
+done_testing;


Reply via email to