File Coverage

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