File Coverage

blib/lib/IRC/Mode/Set.pm
Criterion Covered Total %
statement 67 67 100.0
branch 9 14 64.2
condition 4 7 57.1
subroutine 22 22 100.0
pod 8 9 88.8
total 110 119 92.4


line stmt bran cond sub pod time code
1             package IRC::Mode::Set;
2             $IRC::Mode::Set::VERSION = '0.091001';
3 1     1   756 use strictures 2;
  1         10  
  1         44  
4 1     1   281 use Carp;
  1         1  
  1         113  
5              
6 1     1   616 use IRC::Mode::Single;
  1         3  
  1         40  
7 1     1   9 use IRC::Toolkit::Modes;
  1         2  
  1         17  
8              
9 1     1   438 use Scalar::Util 'blessed';
  1         2  
  1         111  
10 1     1   741 use Storable 'dclone';
  1         2919  
  1         78  
11              
12 1     1   648 use Moo;
  1         13083  
  1         5  
13              
14             my $str_to_arr = sub {
15             ref $_[0] eq 'ARRAY' ? $_[0] : [ split //, $_[0] ]
16             };
17              
18             has param_always => (
19             lazy => 1,
20             is => 'ro',
21             coerce => $str_to_arr,
22 2     2   795 builder => sub { [ qw/ b k o h v / ] },
23             );
24              
25             has param_on_set => (
26             lazy => 1,
27             is => 'ro',
28             coerce => $str_to_arr,
29 2     2   475 builder => sub { [ 'l' ] },
30             );
31              
32             has mode_array => (
33             lazy => 1,
34             is => 'ro',
35             predicate => 'has_mode_array',
36             builder => sub {
37 3     3   1891 my ($self) = @_;
38 3 50       50 mode_to_array( $self->mode_string,
39             param_always => $self->param_always,
40             param_set => $self->param_on_set,
41             (
42             $self->has_params ? (params => $self->params)
43             : ()
44             ),
45             );
46             },
47             );
48              
49             has params => (
50             lazy => 1,
51             is => 'ro',
52             predicate => 'has_params',
53             coerce => sub {
54             ref $_[0] eq 'ARRAY' ? $_[0] : [ split ' ', $_[0] ]
55             },
56             builder => sub {
57 1 100   1   634 [ map {; defined $_->[2] ? $_->[2] : () } @{ $_[0]->mode_array } ]
  4         20  
  1         23  
58             },
59             );
60              
61              
62 1     1 1 669 sub as_string { $_[0]->mode_string }
63              
64             has mode_string => (
65             lazy => 1,
66             is => 'ro',
67             predicate => 'has_mode_string',
68 5     5   2321 builder => sub { array_to_mode $_[0]->mode_array },
69             );
70              
71              
72             sub split_mode_set {
73 1     1 1 4 my ($self, $max) = @_;
74 1   50     4 $max ||= 4;
75              
76 1         2 my @new;
77 1         2 my @queue = @{ $self->mode_array };
  1         36  
78 1         12 while (@queue) {
79 2         12 my @spl = splice @queue, 0, $max;
80 2         59 push @new, blessed($self)->new(
81             mode_array => [ @spl ],
82             )
83             }
84              
85             @new
86 1         9 }
87              
88              
89             sub clone {
90 1     1 1 3 my ($self) = @_;
91 1         34 (blessed $self)->new(mode_array => dclone($self->mode_array))
92             }
93              
94             sub clone_from_mode {
95 1     1 1 2449 my ($self, $mode) = @_;
96 1         4 my @match = grep {; $_->[1] eq $mode } @{ $self->mode_array };
  7         24  
  1         38  
97 1 50       5 return unless @match;
98 1         69 blessed($self)->new(
99             mode_array => dclone(\@match),
100             )
101             }
102              
103             sub clone_from_params {
104 1     1 1 3 my ($self, $regex) = @_;
105 1         34 my @match = grep {;
106 7 50       54 defined($_->[2]) and $_->[2] =~ m/$regex/
107 1         2 } @{ $self->mode_array };
108 1 50       6 return unless @match;
109 1         94 blessed($self)->new(
110             mode_array => dclone(\@match),
111             )
112             }
113              
114              
115             sub modes_as_objects {
116 1     1 1 3 map {; IRC::Mode::Single->new(@$_) } @{ $_[0]->mode_array };
  4         21  
  1         37  
117             }
118              
119              
120             has _iter => (
121             lazy => 1,
122             is => 'rw',
123 1     1   505 builder => sub { 0 },
124             );
125              
126             sub next {
127 4     4 1 1056 my ($self, %param) = @_;
128 4         79 my $cur = $self->_iter;
129 4         93 $self->_iter($cur+1);
130 4   50     91 my $item = $self->mode_array->[$cur] || return;
131 4 100       67 $param{as_object} ?
132             IRC::Mode::Single->new(@$item)
133             : $item
134             }
135              
136             sub reset {
137 2     2 1 375 my ($self) = @_;
138 2         87 $self->_iter(0);
139 2         11 $self
140             }
141              
142             =pod
143              
144             =for Pod::Coverage BUILD has_\w+
145              
146             =cut
147              
148             sub BUILD {
149 9     9 0 4851 my ($self) = @_;
150 9 50 66     241 confess
151             "Expected to be constructed with either a mode_string or mode_array"
152             unless $self->has_mode_array or $self->has_mode_string;
153             }
154            
155              
156             1;
157              
158             =pod
159              
160             =head1 NAME
161              
162             IRC::Mode::Set - A set of parsed IRC mode changes
163              
164             =head1 SYNOPSIS
165              
166             ## Construct a new set of changes from a mode string:
167             my $from_string = IRC::Mode::Set->new(
168             mode_string => '+o-o+v avenj Joah Gilded',
169              
170             ## Optionally specify modes that take parameters (always or when set)
171             ## Defaults:
172             param_always => 'bkohv',
173             param_on_set => 'l',
174             );
175              
176             my $mode_array = $from_string->mode_array;
177             ## $mode_array looks like:
178             ## [
179             ## [ '+', 'o', 'avenj' ],
180             ## [ '-', 'o', 'Joah' ],
181             ## [ '+', 'v', 'Gilded' ],
182             ## ]
183              
184             ## Iterate over each mode change:
185             while (my $change = $from_string->next) {
186             ## $change is set to each individual array as seen above, in turn
187             }
188              
189             ## Reset ->next() iterator to top:
190             $from_string->reset;
191              
192             ## Like above loop, but get IRC::Mode::Single objects:
193             while (my $this_mode = $from_string->next(as_object => 1) ) {
194             ## $this_mode is an IRC::Mode::Single
195             }
196              
197             ## Construct a new set of changes from an ARRAY
198             ## (such as produced by IRC::Toolkit::Modes):
199             my $from_array = IRC::Mode::Set->new(
200             mode_array => $mode_array,
201             );
202              
203             ## Get an IRC-appropriate string back out:
204             my $str_from_array = $from_array->mode_string;
205              
206             ## Split a Set into multiple Sets with a max of $count items each
207             ## (defaults to 4 changes per set if none specified)
208             my @sets = $from_array->split_mode_set( 3 );
209            
210             ## Create a new Set containing matching items from this Set:
211             my $modes_match = $from_array->clone_from_mode('v');
212             my $args_match = $from_array->clone_from_params('Joah');
213              
214             =head1 DESCRIPTION
215              
216             These objects provide a simple parser interface to IRC mode changes.
217              
218             An understanding of the C directive in C will help
219             immensely -- see L
220              
221             =head2 new
222              
223             my $set = IRC::Mode::Set->new(
224             mode_string => '+o-o avenj Joah',
225             );
226              
227             ## Or with IRC::Toolkit::Modes ->
228             my $mode_array = mode_to_array($string);
229             my $set = IRC::Mode::Set->new(
230             mode_array => $mode_array,
231             );
232              
233             Create a new IRC::Mode::Set from either a string or an ARRAY produced by
234             L.
235              
236             B can be specified (as a string or an ARRAY of modes) to
237             indicate modes that are expected to always take a parameter. Defaults to
238             'bkohv'
239              
240             B can be specified (as a string or an ARRAY of modes) to
241             indicate modes that are expected to take a parameter only when set. Defaults
242             to 'l'
243              
244             See L for an easy way to retrieve these values from a
245             parsed ISUPPORT (005) numeric.
246              
247             =head2 clone
248              
249             Clone the instanced Mode::Set.
250              
251             =head2 clone_from_mode
252              
253             Takes a single mode character.
254              
255             Returns a new Mode::Set composed of only modes in the existing set containing
256             the specified mode character.
257              
258             =head2 clone_from_params
259              
260             Takes a pattern or regexp object.
261              
262             Returns a new Mode::Set composed of only modes in the existing set with
263             parameters matching the pattern.
264              
265             =head2 mode_array
266              
267             Returns the array-of-arrays containing each change in the Set.
268              
269             This is a data structure in the form of:
270              
271             [
272             [ $mode_flag, $mode_char, $param ],
273             ...
274             ]
275              
276             Also see L
277              
278             Predicate: B
279              
280             =head2 modes_as_objects
281              
282             Returns a list of L objects constructed from our current
283             L.
284              
285             =head2 mode_string
286              
287             Returns the string representing the mode change.
288              
289             Predicate: B
290              
291             =head2 as_string
292              
293             B is an alias for B to retain compatibility with
294             L.
295              
296             =head2 params
297              
298             Retrieve only the parameters to the mode change (as an ARRAY)
299              
300             Predicate: B
301              
302             =head2 next
303              
304             Iterates the array-of-arrays composing the Set.
305              
306             Returns the next ARRAY in the set (or empty list if none left).
307              
308             If C<< as_object => 1 >> is specified, an L object is
309             returned.
310              
311             Reset to top by calling L.
312              
313             =head2 reset
314              
315             Resets the L iterator.
316              
317             =head2 split_mode_set
318              
319             Given an integer parameter C<$x>, splits a Set into smaller Sets containing at
320             most C<$x> single mode changes.
321              
322             Defaults to 4, which is a common C setting.
323              
324             =head1 AUTHOR
325              
326             Jon Portnoy
327              
328             =cut