File Coverage

blib/lib/AnyEvent/ZeroMQ/Role/WithHandle.pm
Criterion Covered Total %
statement 2 4 50.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 4 6 66.6


line stmt bran cond sub pod time code
1             package AnyEvent::ZeroMQ::Role::WithHandle;
2             BEGIN {
3 3     3   92192 $AnyEvent::ZeroMQ::Role::WithHandle::VERSION = '0.01';
4             }
5             # ABSTRACT: Role for specialized socket types that has_a handle object
6 3     3   2044 use MooseX::Role::Parameterized;
  0            
  0            
7             use MooseX::Types::Moose qw(ArrayRef);
8             use true;
9              
10             use AnyEvent::ZeroMQ::Types qw(SocketType SocketDirection Endpoints);
11             use AnyEvent::ZeroMQ::Handle;
12             use AnyEvent::ZeroMQ::Handle::Role::Generic;
13             use AnyEvent::ZeroMQ::Handle::Role::Readable;
14             use AnyEvent::ZeroMQ::Handle::Role::Writable;
15             use ZeroMQ::Raw;
16             use Try::Tiny;
17             use Carp qw(confess);
18             use namespace::autoclean;
19              
20              
21             parameter 'socket_type' => (
22             is => 'ro',
23             isa => SocketType,
24             required => 1,
25             );
26              
27             parameter 'socket_direction' => (
28             is => 'ro',
29             isa => SocketDirection,
30             required => 1,
31             );
32              
33             role {
34             my $p = shift;
35              
36             my $type = $p->socket_type;
37             my $dir = $p->socket_direction;
38              
39             has 'context' => (
40             is => 'ro',
41             isa => 'ZeroMQ::Raw::Context',
42             required => 1,
43             );
44              
45             has 'connect' => (
46             init_arg => 'connect',
47             isa => Endpoints,
48             default => sub { [] },
49             coerce => 1,
50             traits => ['Array'],
51             handles => {
52             connected_to => 'elements',
53             _connect => 'push',
54             },
55             );
56              
57             has 'bind' => (
58             init_arg => 'bind',
59             isa => Endpoints,
60             default => sub { [] },
61             coerce => 1,
62             traits => ['Array'],
63             handles => {
64             bound_to => 'elements',
65             _bind => 'push',
66             },
67             );
68              
69             my @roles = 'AnyEvent::ZeroMQ::Handle::Role::Generic';
70             push @roles, 'AnyEvent::ZeroMQ::Handle::Role::Readable' if $dir =~ /r/;
71             push @roles, 'AnyEvent::ZeroMQ::Handle::Role::Writable' if $dir =~ /w/;
72             # XXX: we want to apply @roles, but not until after the
73             # parameterized role has been applied. this poses a problem, so
74             # each consumer must do it manually. wtf.
75              
76             # a very simple role metaclass -> method list converter. only
77             # works for these three roles, do not cut-n-paste!
78             my @methods = map { "$_" } map { $_->meta->get_required_method_list } @roles;
79              
80             has 'handle' => (
81             reader => 'handle',
82             isa => 'AnyEvent::ZeroMQ::Handle',
83             lazy_build => 1,
84             handles => [@methods],
85             );
86              
87             after 'bind' => sub {
88             my ($self, $bind_to) = @_;
89             $self->_bind($bind_to);
90             };
91              
92             after 'connect' => sub {
93             my ($self, $connect_to) = @_;
94             $self->_connect($connect_to);
95             };
96              
97             has '_extra_initargs' => (
98             is => 'ro',
99             isa => 'HashRef',
100             required => 1,
101             );
102              
103             method '_build_handle' => sub {
104             my $self = shift;
105              
106             my $socket = ZeroMQ::Raw::Socket->new($self->context, $type);
107              
108             my $h = AnyEvent::ZeroMQ::Handle->new(
109             socket => $socket,
110             %{$self->_extra_initargs || {}},
111             );
112              
113             for my $bind ($self->bound_to){
114             $h->bind($bind);
115             }
116              
117             for my $connect ($self->connected_to){
118             $h->connect($connect);
119             }
120              
121             return $h;
122             };
123              
124             # this does a few things:
125             #
126             # * allow multiple bind/connect pairs to be passed in
127             #
128             # * gather initargs delegated from Handle and save those as
129             # _extra_initargs. in _build_handle, these get passed to the
130             # Handle's constructor, allowing on_read/on_drain/etc. to work
131             # correctly.
132             #
133             # BUG: the only issue is that the on_read and on_drain get $h,
134             # the handle, instead of $self.
135             method 'BUILDARGS' => sub {
136             my ($class, @in) = @_;
137             my %in;
138             while(@in) {
139             my $key = shift @in;
140             my $value = shift @in;
141             if($key eq 'bind' || $key eq 'connect'){
142             $in{$key} ||= [];
143             push @{$in{$key}}, ref $value ? @$value : $value;
144             }
145             else {
146             $in{$key} = $value;
147             }
148             }
149             my %extra;
150             for my $m (grep { !/bind|connect/ } @methods) {
151             $extra{$m} = delete $in{$m} if exists $in{$m};
152             }
153             return { %in, _extra_initargs => \%extra };
154             };
155              
156             method 'BUILD' => sub {
157             my $self = shift;
158             $self->handle; # make sure the handle is ready immediately
159             };
160             };
161              
162             __END__
163             =pod
164              
165             =head1 NAME
166              
167             AnyEvent::ZeroMQ::Role::WithHandle - Role for specialized socket types that has_a handle object
168              
169             =head1 VERSION
170              
171             version 0.01
172              
173             =head1 AUTHOR
174              
175             Jonathan Rockway <jrockway@cpan.org>
176              
177             =head1 COPYRIGHT AND LICENSE
178              
179             This software is copyright (c) 2011 by Jonathan Rockway.
180              
181             This is free software; you can redistribute it and/or modify it under
182             the same terms as the Perl 5 programming language system itself.
183              
184             =cut
185