File Coverage

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