| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # Copyright (c) 2011-17, Mitchell Cooper | 
| 2 |  |  |  |  |  |  | # | 
| 3 |  |  |  |  |  |  | # Evented::Object: a simple yet featureful base class event framework. | 
| 4 |  |  |  |  |  |  | # https://github.com/cooper/evented-object | 
| 5 |  |  |  |  |  |  | # | 
| 6 |  |  |  |  |  |  | package Evented::Object::Collection; # leave this package name the same FOREVER. | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 13 |  |  | 13 |  | 95 | use warnings; | 
|  | 13 |  |  |  |  | 24 |  | 
|  | 13 |  |  |  |  | 433 |  | 
| 9 | 13 |  |  | 13 |  | 66 | use strict; | 
|  | 13 |  |  |  |  | 24 |  | 
|  | 13 |  |  |  |  | 229 |  | 
| 10 | 13 |  |  | 13 |  | 59 | use utf8; | 
|  | 13 |  |  |  |  | 24 |  | 
|  | 13 |  |  |  |  | 74 |  | 
| 11 | 13 |  |  | 13 |  | 391 | use 5.010; | 
|  | 13 |  |  |  |  | 45 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 13 |  |  | 13 |  | 118 | use Scalar::Util qw(weaken blessed); | 
|  | 13 |  |  |  |  | 43 |  | 
|  | 13 |  |  |  |  | 791 |  | 
| 14 | 13 |  |  | 13 |  | 96 | use List::Util qw(min max); | 
|  | 13 |  |  |  |  | 37 |  | 
|  | 13 |  |  |  |  | 1453 |  | 
| 15 | 13 |  |  | 13 |  | 92 | use Carp qw(carp); | 
|  | 13 |  |  |  |  | 24 |  | 
|  | 13 |  |  |  |  | 23631 |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | our $VERSION = '5.67'; | 
| 18 |  |  |  |  |  |  | our $events  = $Evented::Object::events; | 
| 19 |  |  |  |  |  |  | our $props   = $Evented::Object::props; | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | my $dummy; | 
| 22 |  |  |  |  |  |  | my %boolopts = map { $_ => 1 } qw(safe return_check fail_continue); | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | sub new { | 
| 25 | 13 |  |  | 13 | 0 | 109 | return bless { | 
| 26 |  |  |  |  |  |  | pending         => {}, | 
| 27 |  |  |  |  |  |  | default_names   => {}, | 
| 28 |  |  |  |  |  |  | names           => {} | 
| 29 |  |  |  |  |  |  | }, shift; | 
| 30 |  |  |  |  |  |  | } | 
| 31 |  |  |  |  |  |  |  | 
| 32 |  |  |  |  |  |  | sub push_callbacks { | 
| 33 | 13 |  |  | 13 | 0 | 43 | my ($collection, $callbacks, $names) = @_; | 
| 34 | 13 |  |  |  |  | 82 | my $pending  = $collection->{pending}; | 
| 35 | 13 |  |  |  |  | 32 | my $my_names = $collection->{names}; | 
| 36 |  |  |  |  |  |  |  | 
| 37 |  |  |  |  |  |  | # add to pending callbacks and callback name-to-ID mapping. | 
| 38 | 13 |  |  |  |  | 105 | @$pending { keys %$callbacks } = values %$callbacks; | 
| 39 | 13 |  |  |  |  | 74 | @$my_names{ keys %$names     } = values %$names; | 
| 40 |  |  |  |  |  |  |  | 
| 41 |  |  |  |  |  |  | # set default names for any callback names which were not found | 
| 42 |  |  |  |  |  |  | $collection->{default_names}{ $_->[2]{name} } ||= $_->[2]{id} | 
| 43 | 13 |  | 33 |  |  | 291 | for values %$callbacks; | 
| 44 |  |  |  |  |  |  | } | 
| 45 |  |  |  |  |  |  |  | 
| 46 |  |  |  |  |  |  | # | 
| 47 |  |  |  |  |  |  | #   Available fire options | 
| 48 |  |  |  |  |  |  | #   ---------------------- | 
| 49 |  |  |  |  |  |  | # | 
| 50 |  |  |  |  |  |  | #   safe            calls all callbacks within eval blocks. | 
| 51 |  |  |  |  |  |  | #                   consumes no parameter. | 
| 52 |  |  |  |  |  |  | # | 
| 53 |  |  |  |  |  |  | #   return_check    causes the event to ->stop if any callback returns false | 
| 54 |  |  |  |  |  |  | #                   BUT IT WAITS until all have been fired. so if one returns false, | 
| 55 |  |  |  |  |  |  | #                   the rest will be called, but $fire->stopper will be true afterward. | 
| 56 |  |  |  |  |  |  | #                   consumes no parameter. | 
| 57 |  |  |  |  |  |  | # | 
| 58 |  |  |  |  |  |  | #   caller          specify an alternate [caller 1] value, mostly for internal use. | 
| 59 |  |  |  |  |  |  | #                   parameter = caller(1) info wrapped in an array reference. | 
| 60 |  |  |  |  |  |  | # | 
| 61 |  |  |  |  |  |  | #   fail_continue   if 'safe' is enabled and a callback raises an exception, it will | 
| 62 |  |  |  |  |  |  | #                   by default ->stop the fire. this option tells it to continue instead. | 
| 63 |  |  |  |  |  |  | #                   consumes no parameter. | 
| 64 |  |  |  |  |  |  | # | 
| 65 |  |  |  |  |  |  | #   data            some data to fire with the event. esp. good for things that might be | 
| 66 |  |  |  |  |  |  | #                   useful at times but not accessed frequently enough to be an argument. | 
| 67 |  |  |  |  |  |  | #                   parameter = the data. | 
| 68 |  |  |  |  |  |  | # | 
| 69 |  |  |  |  |  |  | sub fire { | 
| 70 | 13 |  |  | 13 | 1 | 59 | my ($collection, @options) = @_; | 
| 71 |  |  |  |  |  |  |  | 
| 72 |  |  |  |  |  |  | # handle options. | 
| 73 | 13 |  |  |  |  | 114 | my ($caller, $data) = $collection->{caller}; | 
| 74 | 13 |  |  |  |  | 71 | while (@options) { | 
| 75 | 13 |  |  |  |  | 41 | my $opt = shift @options; | 
| 76 |  |  |  |  |  |  |  | 
| 77 | 13 | 100 |  |  |  | 53 | if ($opt eq 'caller')   { $caller = shift @options } # custom caller | 
|  | 11 |  |  |  |  | 25 |  | 
| 78 | 13 | 100 |  |  |  | 79 | if ($opt eq 'data')     { $data   = shift @options } # fire data | 
|  | 2 |  |  |  |  | 6 |  | 
| 79 |  |  |  |  |  |  |  | 
| 80 |  |  |  |  |  |  | # boolean option. | 
| 81 | 13 | 50 |  |  |  | 80 | $collection->{$opt} = 1 if $boolopts{$opt}; | 
| 82 |  |  |  |  |  |  |  | 
| 83 |  |  |  |  |  |  | } | 
| 84 |  |  |  |  |  |  |  | 
| 85 |  |  |  |  |  |  | # create fire object. | 
| 86 | 13 |  | 100 |  |  | 262 | my $fire = Evented::Object::EventFire->new( | 
| 87 |  |  |  |  |  |  | caller     => $caller ||= [caller 1], # $fire->caller | 
| 88 |  |  |  |  |  |  | data       => $data,                  # $fire->data | 
| 89 |  |  |  |  |  |  | collection => $collection | 
| 90 |  |  |  |  |  |  | ); | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | # if it hasn't been sorted, do so now. | 
| 93 | 13 | 50 |  |  |  | 101 | $collection->sort if not $collection->{sorted}; | 
| 94 | 13 | 50 |  |  |  | 59 | my $callbacks = $collection->{sorted} or return $fire; | 
| 95 |  |  |  |  |  |  |  | 
| 96 |  |  |  |  |  |  | # if return_check is enabled, add a callback to be fired last that will | 
| 97 |  |  |  |  |  |  | # check the return values. this is basically hackery using a dummy object. | 
| 98 | 13 | 50 |  |  |  | 55 | if ($collection->{return_check}) { | 
| 99 | 0 |  |  |  |  | 0 | my $cb = { | 
| 100 |  |  |  |  |  |  | name   => 'eventedObject.returnCheck', | 
| 101 |  |  |  |  |  |  | caller => $caller, | 
| 102 |  |  |  |  |  |  | code   => \&_return_check | 
| 103 |  |  |  |  |  |  | }; | 
| 104 | 0 |  | 0 |  |  | 0 | my $group = [ | 
| 105 |  |  |  |  |  |  | $dummy ||= Evented::Object->new, | 
| 106 |  |  |  |  |  |  | 'returnCheck', | 
| 107 |  |  |  |  |  |  | [], | 
| 108 |  |  |  |  |  |  | "$dummy/returnCheck" | 
| 109 |  |  |  |  |  |  | ]; | 
| 110 | 0 |  |  |  |  | 0 | push @$callbacks, [ | 
| 111 |  |  |  |  |  |  | -inf,           # [0] $priority | 
| 112 |  |  |  |  |  |  | $group,         # [1] $group | 
| 113 |  |  |  |  |  |  | $cb             # [2] $cb | 
| 114 |  |  |  |  |  |  | ]; | 
| 115 | 0 |  |  |  |  | 0 | $cb->{id} = "$$group[3]/$$cb{name}"; | 
| 116 | 0 |  |  |  |  | 0 | $collection->{pending}{ $cb->{id} } = $cb; | 
| 117 |  |  |  |  |  |  | } | 
| 118 |  |  |  |  |  |  |  | 
| 119 |  |  |  |  |  |  | # call them. | 
| 120 | 13 |  |  |  |  | 60 | return $collection->_call_callbacks($fire); | 
| 121 |  |  |  |  |  |  |  | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  |  | 
| 124 |  |  |  |  |  |  | # sorts the callbacks, trying its best to listen to before and after. | 
| 125 |  |  |  |  |  |  | sub sort : method { | 
| 126 | 13 |  |  | 13 | 1 | 105 | my $collection = shift; | 
| 127 | 13 | 50 |  |  |  | 77 | return unless $collection->{pending}; | 
| 128 | 13 |  |  |  |  | 28 | my %callbacks = %{ $collection->{pending} }; | 
|  | 13 |  |  |  |  | 79 |  | 
| 129 | 13 |  |  |  |  | 39 | my (@sorted, %done, %waited); | 
| 130 |  |  |  |  |  |  |  | 
| 131 |  |  |  |  |  |  | # iterate over the callback sets, | 
| 132 |  |  |  |  |  |  | # which are array refs of [ priority, group, cb ] | 
| 133 | 13 |  |  |  |  | 45 | my @callbacks = values %callbacks; | 
| 134 | 13 |  |  |  |  | 65 | while (my $set = shift @callbacks) { | 
| 135 | 37 |  |  |  |  | 94 | my ($priority, $group, $cb) = @$set; | 
| 136 | 37 |  |  |  |  | 75 | my $cb_id    = $cb->{id}; | 
| 137 | 37 |  |  |  |  | 58 | my $group_id = $group->[3]; | 
| 138 |  |  |  |  |  |  |  | 
| 139 | 37 | 50 |  |  |  | 95 | next if $done{$cb_id}; | 
| 140 |  |  |  |  |  |  |  | 
| 141 |  |  |  |  |  |  | # a real priority exists already. | 
| 142 | 37 | 100 | 66 |  |  | 227 | if (defined $priority && $priority ne 'nan') { | 
| 143 | 22 |  |  |  |  | 43 | push @sorted, $set; | 
| 144 | 22 |  |  |  |  | 45 | $done{$cb_id} = 1; | 
| 145 | 22 |  |  |  |  | 70 | next; | 
| 146 |  |  |  |  |  |  | } | 
| 147 |  |  |  |  |  |  |  | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | # TODO: if before and afters cannot be resolved, the callback dependencies | 
| 150 |  |  |  |  |  |  | # are currently skipped. maybe there should be a way to specify that a callback | 
| 151 |  |  |  |  |  |  | # dependency is REQUIRED, meaning to skip the callback entirely if it cannot | 
| 152 |  |  |  |  |  |  | # be done. or maybe something more sophisticated that can prioritize the | 
| 153 |  |  |  |  |  |  | # befores and afters in this way. for now though, we will just try to not | 
| 154 |  |  |  |  |  |  | # specify impossible befores and afters. | 
| 155 |  |  |  |  |  |  |  | 
| 156 |  |  |  |  |  |  |  | 
| 157 |  |  |  |  |  |  |  | 
| 158 |  |  |  |  |  |  | # callback priority determination can be postponed until another's | 
| 159 |  |  |  |  |  |  | # priority is determined. the maxmium number of times one particular | 
| 160 |  |  |  |  |  |  | # callback can be postponed is the number of total callbacks. | 
| 161 | 15 |  |  |  |  | 28 | my $wait_max = keys %callbacks; | 
| 162 |  |  |  |  |  |  |  | 
| 163 | 15 |  |  |  |  | 36 | my $name_to_id = $collection->_group_names($group_id); | 
| 164 |  |  |  |  |  |  | my $get_befores_afters = sub { | 
| 165 | 25 |  |  | 25 |  | 46 | my ($key, @results) = shift; | 
| 166 | 25 | 100 |  |  |  | 60 | my $list = $cb->{$key} or return; | 
| 167 | 19 | 100 |  |  |  | 50 | $list = [ $list ] if ref $list ne 'ARRAY'; | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | # for each callback name, find its priority. | 
| 170 | 19 |  |  |  |  | 38 | foreach my $their_name (@$list) { | 
| 171 |  |  |  |  |  |  |  | 
| 172 |  |  |  |  |  |  | # map callback name to id, id to cbref, and cbref to priority. | 
| 173 | 29 | 100 |  |  |  | 64 | my $their_id = $name_to_id->{$their_name} or next; | 
| 174 | 17 | 50 |  |  |  | 39 | my $their_cb = $callbacks{$their_id}      or next; | 
| 175 | 17 |  |  |  |  | 27 | my $their_p  = $their_cb->[0]; | 
| 176 |  |  |  |  |  |  |  | 
| 177 |  |  |  |  |  |  | # if their priority is nan, | 
| 178 |  |  |  |  |  |  | # we have to wait until it is determined. | 
| 179 | 17 | 100 |  |  |  | 42 | if ($their_p eq 'nan') { | 
| 180 | 10 |  |  |  |  | 23 | my $wait_key = "$cb_id $their_id"; | 
| 181 |  |  |  |  |  |  | push @callbacks, $set | 
| 182 | 10 | 100 |  |  |  | 40 | unless $waited{$key}++ > $wait_max; | 
| 183 | 10 |  |  |  |  | 28 | return 1; | 
| 184 |  |  |  |  |  |  | } | 
| 185 |  |  |  |  |  |  |  | 
| 186 | 7 |  |  |  |  | 18 | push @results, $their_p; | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  |  | 
| 189 | 9 |  |  |  |  | 33 | return (undef, @results); | 
| 190 | 15 |  |  |  |  | 65 | }; | 
| 191 |  |  |  |  |  |  |  | 
| 192 | 15 | 100 |  |  |  | 33 | my ($next, @befores) = $get_befores_afters->('before'); next if $next; | 
|  | 15 |  |  |  |  | 56 |  | 
| 193 | 10 | 100 |  |  |  | 18 | ($next, my @afters ) = $get_befores_afters->('after');  next if $next; | 
|  | 10 |  |  |  |  | 57 |  | 
| 194 |  |  |  |  |  |  |  | 
| 195 |  |  |  |  |  |  | # figure the ideal priority. | 
| 196 | 5 | 50 | 66 |  |  | 26 | if (@befores && @afters) { | 
|  |  | 100 |  |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 197 | 0 |  |  |  |  | 0 | my $a_refpoint = min @afters; | 
| 198 | 0 |  |  |  |  | 0 | my $b_refpoint = max @befores; | 
| 199 | 0 |  |  |  |  | 0 | $priority      = ($a_refpoint + $b_refpoint) / 2; | 
| 200 |  |  |  |  |  |  | } | 
| 201 |  |  |  |  |  |  |  | 
| 202 |  |  |  |  |  |  | # only before. just have 1 higher priority. | 
| 203 |  |  |  |  |  |  | elsif (@befores) { | 
| 204 | 3 |  |  |  |  | 18 | my $refpoint = max @befores; | 
| 205 | 3 |  |  |  |  | 16 | $priority    = ++$refpoint; | 
| 206 |  |  |  |  |  |  | } | 
| 207 |  |  |  |  |  |  |  | 
| 208 |  |  |  |  |  |  | # only after. | 
| 209 |  |  |  |  |  |  | elsif (@afters) { | 
| 210 | 2 |  |  |  |  | 27 | my $refpoint = min @afters; | 
| 211 | 2 |  |  |  |  | 7 | $priority    = --$refpoint; | 
| 212 |  |  |  |  |  |  | } | 
| 213 |  |  |  |  |  |  |  | 
| 214 | 5 | 50 |  |  |  | 27 | $priority = 0 if $priority eq 'nan'; | 
| 215 |  |  |  |  |  |  |  | 
| 216 |  |  |  |  |  |  | # done with this callback. | 
| 217 | 5 |  |  |  |  | 11 | $set->[0] = $priority; | 
| 218 | 5 |  |  |  |  | 9 | push @sorted, $set; | 
| 219 | 5 |  |  |  |  | 40 | $done{$cb_id} = 1; | 
| 220 |  |  |  |  |  |  |  | 
| 221 |  |  |  |  |  |  | } | 
| 222 |  |  |  |  |  |  |  | 
| 223 |  |  |  |  |  |  | # the final sort by numerical priority. | 
| 224 | 13 |  |  |  |  | 79 | $collection->{sorted} = [ sort { $b->[0] <=> $a->[0] } @sorted ]; | 
|  | 24 |  |  |  |  | 86 |  | 
| 225 |  |  |  |  |  |  |  | 
| 226 |  |  |  |  |  |  | } | 
| 227 |  |  |  |  |  |  |  | 
| 228 |  |  |  |  |  |  | # Nov. 22, 2013 revision | 
| 229 |  |  |  |  |  |  | # ---------------------- | 
| 230 |  |  |  |  |  |  | # | 
| 231 |  |  |  |  |  |  | #   collection      a set of callbacks about to be fired. they might belong to multiple | 
| 232 |  |  |  |  |  |  | #                   objects or maybe even multiple events. they can each have their own | 
| 233 |  |  |  |  |  |  | #                   arguments, and they all have their own options, code references, etc. | 
| 234 |  |  |  |  |  |  | # | 
| 235 |  |  |  |  |  |  | #        group      represents the group to which a callback belongs. a group consists of | 
| 236 |  |  |  |  |  |  | #                   the associated evented object, event name, and arguments. | 
| 237 |  |  |  |  |  |  | # | 
| 238 |  |  |  |  |  |  | # This revision eliminates all of these nested structures by reworking the way | 
| 239 |  |  |  |  |  |  | # a callback collection works. A collection should be an array of callbacks. | 
| 240 |  |  |  |  |  |  | # This array, unlike before, will contain an additional element: an array | 
| 241 |  |  |  |  |  |  | # reference representing the "group." | 
| 242 |  |  |  |  |  |  | # | 
| 243 |  |  |  |  |  |  | #   @collection = ( | 
| 244 |  |  |  |  |  |  | #       [ $priority, $group, $cb ], | 
| 245 |  |  |  |  |  |  | #       [ $priority, $group, $cb ], | 
| 246 |  |  |  |  |  |  | #       ... | 
| 247 |  |  |  |  |  |  | #   ) | 
| 248 |  |  |  |  |  |  | # | 
| 249 |  |  |  |  |  |  | #   $group =                                $cb = | 
| 250 |  |  |  |  |  |  | #   [ $eo, $event_name, $args, $id ]        { code, caller, %opts } | 
| 251 |  |  |  |  |  |  | # | 
| 252 |  |  |  |  |  |  | # This format has several major advantages over the former one. Specifically, | 
| 253 |  |  |  |  |  |  | # it makes it very simple to determine which callbacks will be called in the | 
| 254 |  |  |  |  |  |  | # future, which ones have been called already, how many are left, etc. | 
| 255 |  |  |  |  |  |  | # | 
| 256 |  |  |  |  |  |  |  | 
| 257 |  |  |  |  |  |  | # call the passed callback priority sets. | 
| 258 |  |  |  |  |  |  | sub _call_callbacks { | 
| 259 | 13 |  |  | 13 |  | 44 | my ($collection, $fire) = @_; | 
| 260 | 13 |  |  |  |  | 71 | my $ef_props = $fire->{$props}; | 
| 261 |  |  |  |  |  |  |  | 
| 262 |  |  |  |  |  |  | # store the collection. | 
| 263 | 13 | 50 |  |  |  | 84 | my $remaining = $collection->{sorted} or return; | 
| 264 | 13 |  |  |  |  | 39 | $ef_props->{collection} = $collection; | 
| 265 |  |  |  |  |  |  |  | 
| 266 |  |  |  |  |  |  | # call each callback. | 
| 267 | 13 |  |  |  |  | 52 | while (my $entry = shift @$remaining) { | 
| 268 | 26 |  |  |  |  | 68 | my ($priority, $group, $cb) = @$entry; | 
| 269 | 26 |  |  |  |  | 68 | my ($eo, $event_name, $args, $group_id) = @$group; | 
| 270 |  |  |  |  |  |  |  | 
| 271 |  |  |  |  |  |  | # sanity check! | 
| 272 | 26 | 50 | 33 |  |  | 217 | blessed $eo && $eo->isa('Evented::Object') or return; | 
| 273 |  |  |  |  |  |  |  | 
| 274 |  |  |  |  |  |  | # callback name-to-ID mapping is specific to each group. | 
| 275 | 26 |  |  |  |  | 109 | $ef_props->{callback_ids} = $collection->_group_names($group_id); | 
| 276 |  |  |  |  |  |  |  | 
| 277 |  |  |  |  |  |  | # increment the callback counter. | 
| 278 | 26 |  |  |  |  | 51 | $ef_props->{callback_i}++; | 
| 279 |  |  |  |  |  |  |  | 
| 280 |  |  |  |  |  |  | # set the evented object of this callback. | 
| 281 |  |  |  |  |  |  | # set the event name of this callback. | 
| 282 | 26 |  |  |  |  | 52 | $ef_props->{object}             = $eo; weaken($ef_props->{object});     # $fire->object | 
|  | 26 |  |  |  |  | 100 |  | 
| 283 | 26 |  |  |  |  | 48 | $ef_props->{name}               = $event_name;                          # $fire->event_name | 
| 284 |  |  |  |  |  |  |  | 
| 285 |  |  |  |  |  |  | # store identifiers. | 
| 286 | 26 |  |  |  |  | 75 | $ef_props->{callback_id}        = my $cb_id = $cb->{id}; | 
| 287 | 26 |  |  |  |  | 47 | $ef_props->{group_id}           = $group_id; | 
| 288 |  |  |  |  |  |  |  | 
| 289 |  |  |  |  |  |  | # create info about the call. | 
| 290 | 26 |  |  |  |  | 49 | $ef_props->{callback_name}      = $cb->{name};                          # $fire->callback_name | 
| 291 | 26 |  |  |  |  | 54 | $ef_props->{callback_priority}  = $priority;                            # $fire->callback_priority | 
| 292 | 26 | 100 |  |  |  | 73 | $ef_props->{callback_data}      = $cb->{data} if defined $cb->{data};   # $fire->callback_data | 
| 293 |  |  |  |  |  |  |  | 
| 294 |  |  |  |  |  |  | # this callback has been called already. | 
| 295 | 26 | 50 |  |  |  | 101 | next if $ef_props->{called}{$cb_id}; | 
| 296 |  |  |  |  |  |  |  | 
| 297 |  |  |  |  |  |  | # this callback has probably been cancelled. | 
| 298 | 26 | 100 |  |  |  | 91 | next unless $collection->{pending}{$cb_id}; | 
| 299 |  |  |  |  |  |  |  | 
| 300 |  |  |  |  |  |  |  | 
| 301 |  |  |  |  |  |  | # determine arguments. | 
| 302 |  |  |  |  |  |  | # | 
| 303 |  |  |  |  |  |  | # no compat <3.0: used to always have obj unless specified with no_obj or later no_fire_obj. | 
| 304 |  |  |  |  |  |  | # no compat <2.9: with_obj -> eo_obj | 
| 305 |  |  |  |  |  |  | # compat: all later version had a variety of with_obj-like-options below. | 
| 306 |  |  |  |  |  |  | # | 
| 307 | 25 |  |  |  |  | 55 | my @cb_args = @$args; | 
| 308 | 25 |  |  |  |  | 91 | my $include_obj = grep $cb->{$_}, qw(with_eo with_obj with_evented_obj eo_obj); | 
| 309 | 25 | 50 |  |  |  | 99 | unshift @cb_args, $fire unless $cb->{no_fire_obj}; | 
| 310 | 25 | 50 |  |  |  | 61 | unshift @cb_args, $eo   if $include_obj; | 
| 311 |  |  |  |  |  |  |  | 
| 312 |  |  |  |  |  |  | # set return values. | 
| 313 |  |  |  |  |  |  | $ef_props->{last_return}            =   # set last return value. | 
| 314 |  |  |  |  |  |  | $ef_props->{return}{$cb_id}         =   # set this callback's return value. | 
| 315 |  |  |  |  |  |  |  | 
| 316 |  |  |  |  |  |  | # call the callback with proper arguments. | 
| 317 | 0 |  |  |  |  | 0 | $collection->{safe} ? eval { $cb->{code}(@cb_args) } | 
| 318 | 25 | 50 |  |  |  | 110 | :        $cb->{code}(@cb_args); | 
| 319 |  |  |  |  |  |  |  | 
| 320 |  |  |  |  |  |  | # set $fire->called($cb) true, and set $fire->last to the callback's name. | 
| 321 | 25 |  |  |  |  | 5048 | $ef_props->{called}{$cb_id} = 1; | 
| 322 | 25 |  |  |  |  | 60 | $ef_props->{last_callback}  = $cb->{name}; | 
| 323 |  |  |  |  |  |  |  | 
| 324 |  |  |  |  |  |  | # no longer pending. | 
| 325 | 25 |  |  |  |  | 55 | delete $collection->{pending}{$cb_id}; | 
| 326 |  |  |  |  |  |  |  | 
| 327 |  |  |  |  |  |  | # stop if eval failed. | 
| 328 | 25 | 50 | 33 |  |  | 92 | if ($collection->{safe} and my $err = $@) { | 
| 329 | 0 |  |  |  |  | 0 | chomp $err; | 
| 330 |  |  |  |  |  |  | $ef_props->{error}{$cb_id} = # not used for anything | 
| 331 | 0 |  |  |  |  | 0 | $ef_props->{exception}     = $err; | 
| 332 | 0 | 0 |  |  |  | 0 | $fire->stop($err) unless $collection->{fail_continue}; | 
| 333 |  |  |  |  |  |  | } | 
| 334 |  |  |  |  |  |  |  | 
| 335 |  |  |  |  |  |  | # if stop is true, $fire->stop was called. stop the iteration. | 
| 336 | 25 | 100 |  |  |  | 142 | if ($ef_props->{stop}) { | 
| 337 | 1 |  |  |  |  | 3 | $ef_props->{stopper} = $cb->{name}; # set $fire->stopper. | 
| 338 | 1 |  |  |  |  | 3 | last; | 
| 339 |  |  |  |  |  |  | } | 
| 340 |  |  |  |  |  |  |  | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  |  | 
| 343 |  |  |  |  |  |  | # dispose of things that are no longer needed. | 
| 344 | 13 |  |  |  |  | 77 | delete @$ef_props{ qw( | 
| 345 |  |  |  |  |  |  | callback_name callback_priority | 
| 346 |  |  |  |  |  |  | callback_data callback_i object | 
| 347 |  |  |  |  |  |  | collection | 
| 348 |  |  |  |  |  |  | ) }; | 
| 349 |  |  |  |  |  |  |  | 
| 350 |  |  |  |  |  |  | # return the event object. | 
| 351 | 13 |  |  |  |  | 30 | $ef_props->{complete} = 1; | 
| 352 | 13 |  |  |  |  | 133 | return $fire; | 
| 353 |  |  |  |  |  |  |  | 
| 354 |  |  |  |  |  |  | } | 
| 355 |  |  |  |  |  |  |  | 
| 356 |  |  |  |  |  |  | sub _group_names { | 
| 357 | 41 |  |  | 41 |  | 91 | my ($collection, $group_id) = @_; | 
| 358 | 41 |  | 66 |  |  | 146 | return $collection->{group_names}{$group_id} ||= do { | 
| 359 | 14 |  | 50 |  |  | 54 | my $names_from_group = $collection->{names}{$group_id} || {}; | 
| 360 | 14 |  |  |  |  | 28 | my $default_names    = $collection->{default_names}; | 
| 361 | 14 |  |  |  |  | 120 | my %names = (%$default_names, %$names_from_group); | 
| 362 | 14 |  |  |  |  | 79 | \%names | 
| 363 |  |  |  |  |  |  | } | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | sub _return_check { | 
| 367 | 0 |  |  | 0 |  |  | my $fire    = shift; | 
| 368 | 0 | 0 |  |  |  |  | my %returns = %{ $fire->{$props}{return} || {} }; | 
|  | 0 |  |  |  |  |  |  | 
| 369 | 0 |  |  |  |  |  | foreach my $cb_id (keys %returns) { | 
| 370 | 0 | 0 |  |  |  |  | next if $returns{$cb_id}; | 
| 371 | 0 |  |  |  |  |  | return $fire->stop("$cb_id returned false with return_check enabled"); | 
| 372 |  |  |  |  |  |  | } | 
| 373 | 0 |  |  |  |  |  | return 1; | 
| 374 |  |  |  |  |  |  | } | 
| 375 |  |  |  |  |  |  |  | 
| 376 |  |  |  |  |  |  | 1; | 
| 377 |  |  |  |  |  |  |  | 
| 378 |  |  |  |  |  |  | =head1 NAME | 
| 379 |  |  |  |  |  |  |  | 
| 380 |  |  |  |  |  |  | B - represents a group of pending | 
| 381 |  |  |  |  |  |  | L callbacks. | 
| 382 |  |  |  |  |  |  |  | 
| 383 |  |  |  |  |  |  | =head1 DESCRIPTION | 
| 384 |  |  |  |  |  |  |  | 
| 385 |  |  |  |  |  |  | L are returned by the evented object 'prepare' methods. They | 
| 386 |  |  |  |  |  |  | represent a group of callbacks that are about to be fired. Using collections | 
| 387 |  |  |  |  |  |  | allows you to prepare a fire ahead of time before executing it. You can also | 
| 388 |  |  |  |  |  |  | fire events with special options this way. | 
| 389 |  |  |  |  |  |  |  | 
| 390 |  |  |  |  |  |  | =head1 METHODS | 
| 391 |  |  |  |  |  |  |  | 
| 392 |  |  |  |  |  |  |  | 
| 393 |  |  |  |  |  |  | =head2 $col->fire(@options) | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | Fires the pending callbacks with the specified options, if any. If the callbacks | 
| 396 |  |  |  |  |  |  | have not yet been sorted, they are sorted before the event is fired. | 
| 397 |  |  |  |  |  |  |  | 
| 398 |  |  |  |  |  |  | $eo->prepare(some_event => @arguments)->fire('safe'); | 
| 399 |  |  |  |  |  |  |  | 
| 400 |  |  |  |  |  |  | B | 
| 401 |  |  |  |  |  |  |  | 
| 402 |  |  |  |  |  |  | =over | 
| 403 |  |  |  |  |  |  |  | 
| 404 |  |  |  |  |  |  | =item * | 
| 405 |  |  |  |  |  |  |  | 
| 406 |  |  |  |  |  |  | B<@options> - I, a mixture of boolean and key:value options for the | 
| 407 |  |  |  |  |  |  | event fire. | 
| 408 |  |  |  |  |  |  |  | 
| 409 |  |  |  |  |  |  | =back | 
| 410 |  |  |  |  |  |  |  | 
| 411 |  |  |  |  |  |  | B<@options> - fire options | 
| 412 |  |  |  |  |  |  |  | 
| 413 |  |  |  |  |  |  | =over | 
| 414 |  |  |  |  |  |  |  | 
| 415 |  |  |  |  |  |  | =item * | 
| 416 |  |  |  |  |  |  |  | 
| 417 |  |  |  |  |  |  | B - I, use an alternate C<[caller 1]> value for the event | 
| 418 |  |  |  |  |  |  | fire. This is typically only used internally. | 
| 419 |  |  |  |  |  |  |  | 
| 420 |  |  |  |  |  |  | =item * | 
| 421 |  |  |  |  |  |  |  | 
| 422 |  |  |  |  |  |  | B - I, if true, the event will yield that it was stopped | 
| 423 |  |  |  |  |  |  | if any of the callbacks return a false value. Note however that if one callbacks | 
| 424 |  |  |  |  |  |  | returns false, the rest will still be called. The fire object will only yield | 
| 425 |  |  |  |  |  |  | stopped status after all callbacks have been called and any number of them | 
| 426 |  |  |  |  |  |  | returned false. | 
| 427 |  |  |  |  |  |  |  | 
| 428 |  |  |  |  |  |  | =item * | 
| 429 |  |  |  |  |  |  |  | 
| 430 |  |  |  |  |  |  | B - I, wrap all callback calls in C for safety. if any of | 
| 431 |  |  |  |  |  |  | them fail, the event will be stopped at that point with the error. | 
| 432 |  |  |  |  |  |  |  | 
| 433 |  |  |  |  |  |  | =item * | 
| 434 |  |  |  |  |  |  |  | 
| 435 |  |  |  |  |  |  | B - I, if C above is enabled, this tells the fire | 
| 436 |  |  |  |  |  |  | to continue even if one of the callbacks fails. This could be dangerous if any | 
| 437 |  |  |  |  |  |  | of the callbacks expected a previous callback to be done when it actually | 
| 438 |  |  |  |  |  |  | failed. | 
| 439 |  |  |  |  |  |  |  | 
| 440 |  |  |  |  |  |  | =item * | 
| 441 |  |  |  |  |  |  |  | 
| 442 |  |  |  |  |  |  | B - I, a scalar value that can be fetched by | 
| 443 |  |  |  |  |  |  | C<< $fire->data >> from within the callbacks. Good for data that might be useful | 
| 444 |  |  |  |  |  |  | sometimes but not frequently enough to deserve a spot in the argument list. If | 
| 445 |  |  |  |  |  |  | C is a hash reference, its values can be fetched conveniently with | 
| 446 |  |  |  |  |  |  | C<< $fire->data('key') >>. | 
| 447 |  |  |  |  |  |  |  | 
| 448 |  |  |  |  |  |  | =back | 
| 449 |  |  |  |  |  |  |  | 
| 450 |  |  |  |  |  |  | =head2 $col->sort | 
| 451 |  |  |  |  |  |  |  | 
| 452 |  |  |  |  |  |  | Sorts the callbacks according to C, C, and C options. | 
| 453 |  |  |  |  |  |  |  | 
| 454 |  |  |  |  |  |  | =head1 AUTHOR | 
| 455 |  |  |  |  |  |  |  | 
| 456 |  |  |  |  |  |  | L | 
| 457 |  |  |  |  |  |  |  | 
| 458 |  |  |  |  |  |  | Copyright E 2011-2017. Released under New BSD license. | 
| 459 |  |  |  |  |  |  |  | 
| 460 |  |  |  |  |  |  | Comments, complaints, and recommendations are accepted. Bugs may be reported on | 
| 461 |  |  |  |  |  |  | L. |