File Coverage

blib/lib/IO/AsyncX/Notifier.pm
Criterion Covered Total %
statement 24 24 100.0
branch 2 2 100.0
condition n/a
subroutine 6 6 100.0
pod 1 1 100.0
total 33 33 100.0


line stmt bran cond sub pod time code
1             package IO::AsyncX::Notifier;
2             # ABSTRACT: Combining IO::Async::Notifier with Object::Pad
3              
4 1     1   94519 use Object::Pad;
  1         15  
  1         7  
5              
6 1     1   660 class IO::AsyncX::Notifier extends IO::Async::Notifier;
  1         21155  
  1         115  
7              
8             our $VERSION = '0.001';
9              
10             =head1 NAME
11              
12             IO::AsyncX::Notifier - easier IO::Async::Notifiers with Object::Pad
13              
14             =head1 SYNOPSIS
15              
16             use Object::Pad;
17             class Example isa IO::AsyncX::Notifier {
18             # This will be populated by ->configure(example_slot => ...)
19             # or ->new(example_slot => ...)
20             has $example_slot;
21             # This will be updated by ->configure (or ->new) in a similar fashion
22             use Ryu::Observable;
23             has $observable_slot { Ryu::Observable->new };
24              
25             # You can have as many other slots as you want, main limitation
26             # at the moment is that they have to be scalars.
27              
28             method current_values () {
29             'Example slot: ' . $example_slot,
30             ' and observable set to ' . $observable_slot->as_string
31             }
32             }
33             my $obj = Example->new(
34             example_slot => 'xyz',
35             observable_slot => 'starting value'
36             );
37             print join "\n", $obj->current_values;
38              
39             =head1 DESCRIPTION
40              
41             Provides some helper logic to simplify L-based
42             L subclasses.
43              
44             =cut
45              
46 1     1   309 use mro qw(c3);
  1         4  
  1         11  
47 1     1   727 use Syntax::Keyword::Try;
  1         1471  
  1         6  
48 1     1   90 use Scalar::Util ();
  1         3  
  1         709  
49              
50             # This is a hack to defer ->configure until we have an object
51             has $prepared;
52              
53             ADJUSTPARAMS ($args) {
54             # We set this once after instantiation and never touch it again
55             $prepared = 1;
56              
57             # Here we defer the initial ->configure call
58             $self->configure(%$args);
59              
60             # Since ->configure did the hard work, we can throw away the parameters again
61             %$args = ();
62             }
63              
64 4     4 1 4435 method configure (%args) {
  4         10  
  4         14  
  4         6  
65             # This does nothing until we have finished Object::Pad instantiation
66 4 100       14 return unless $prepared;
67              
68             # We only care about slots in the lowest-level subclass: there
69             # is no support for IaNotifier -> first sub level -> second sub level
70             # yet, since it's usually preferable to inherit directly from IaNotifier
71 3         22 my $class = Object::Pad::MOP::Class->for_class(ref $self);
72              
73             # Ordering is enforced to make behaviour more predictable
74             SLOT:
75 3         40 for my $k (sort keys %args) {
76             try {
77             # Only scalar slots are supported currently
78             my $slot = $class->get_slot('$' . $k);
79              
80             my $v = delete $args{$k};
81             # There isn't a standard protocol for "observable types", so
82             # we only support Ryu::Observable currently.
83             if(Scalar::Util::blessed(my $current = $slot->value($self))) {
84             if($current->isa('Ryu::Observable')) {
85             $current->set_string($v);
86             next SLOT;
87             }
88             }
89              
90             $slot->value($self) = $v;
91             } catch($e) {
92             # We really don't want to hide errors, but this might be good enough for now.
93             die $e unless $e =~ /does not have a slot/;
94             }
95 4         12 }
96              
97             # Anything left over will cause IO::Async::Notifier's implementation to complain
98             # appropriately - note that this means we don't need (or want) the `:strict`
99             # definition on the class itself.
100 3         21 $self->next::method(%args);
101             }
102              
103             1;
104              
105             __END__