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   70250 use Object::Pad;
  1         10  
  1         5  
5              
6 1     1   573 class IO::AsyncX::Notifier :isa(IO::Async::Notifier);
  1         16320  
  1         42  
7              
8             our $VERSION = '0.002';
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_field => ...)
19             # or ->new(example_field => ...)
20             has $example_field;
21             # This will be updated by ->configure (or ->new) in a similar fashion
22             use Ryu::Observable;
23             has $observable_field { Ryu::Observable->new };
24              
25             # You can have as many other fields as you want, main limitation
26             # at the moment is that they have to be scalars.
27              
28             method current_values () {
29             'Example field: ' . $example_field,
30             ' and observable set to ' . $observable_field->as_string
31             }
32             }
33             my $obj = Example->new(
34             example_field => 'xyz',
35             observable_field => '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   200 use mro qw(c3);
  1         2  
  1         6  
47 1     1   466 use Syntax::Keyword::Try;
  1         1031  
  1         5  
48 1     1   63 use Scalar::Util ();
  1         1  
  1         553  
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 3443 method configure (%args) {
  4         6  
  4         9  
  4         4  
65             # This does nothing until we have finished Object::Pad instantiation
66 4 100       10 return unless $prepared;
67              
68             # We only care about fields 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         14 my $class = Object::Pad::MOP::Class->for_class(ref $self);
72              
73             # Ordering is enforced to make behaviour more predictable
74             FIELD:
75 3         26 for my $k (sort keys %args) {
76             try {
77             # Only scalar fields are supported currently
78             my $field = $class->get_field('$' . $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 = $field->value($self))) {
84             if($current->isa('Ryu::Observable')) {
85             $current->set_string($v);
86             next FIELD;
87             }
88             }
89              
90             $field->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 field/;
94             }
95 4         10 }
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         25 $self->next::method(%args);
101             }
102              
103             1;
104              
105             __END__