File Coverage

blib/lib/DBIx/QuickORM/Util/HashBase.pm
Criterion Covered Total %
statement 117 160 73.1
branch 47 70 67.1
condition 13 21 61.9
subroutine 16 24 66.6
pod 1 4 25.0
total 194 279 69.5


line stmt bran cond sub pod time code
1             package DBIx::QuickORM::Util::HashBase;
2 377     377   2789 use strict;
  377         800  
  377         19215  
3 377     377   2397 use warnings;
  377         832  
  377         34671  
4              
5             our $VERSION = '0.000019';
6              
7             #################################################################
8             # #
9             # This is a generated file! Do not modify this file directly! #
10             # Use hashbase_inc.pl script to regenerate this file. #
11             # The script is part of the Object::HashBase distribution. #
12             # Note: You can modify the version number above this comment #
13             # if needed, that is fine. #
14             # #
15             #################################################################
16              
17             {
18 377     377   5327 no warnings 'once';
  377         1429  
  377         58211  
19             $DBIx::QuickORM::Util::HashBase::HB_VERSION = '0.015';
20             *DBIx::QuickORM::Util::HashBase::ATTR_SUBS = \%Object::HashBase::ATTR_SUBS;
21             *DBIx::QuickORM::Util::HashBase::ATTR_LIST = \%Object::HashBase::ATTR_LIST;
22             *DBIx::QuickORM::Util::HashBase::VERSION = \%Object::HashBase::VERSION;
23             *DBIx::QuickORM::Util::HashBase::CAN_CACHE = \%Object::HashBase::CAN_CACHE;
24             }
25              
26              
27             require Carp;
28             {
29 377     377   4460 no warnings 'once';
  377         1660  
  377         95648  
30             $Carp::Internal{+__PACKAGE__} = 1;
31             }
32              
33             BEGIN {
34             {
35             # Make sure none of these get messed up.
36 377     377   1416 local ($SIG{__DIE__}, $@, $?, $!, $^E);
  377         5721  
37 377 50       1220 if (eval { require Class::XSAccessor; Class::XSAccessor->VERSION(1.19); 1 }) {
  377         220745  
  377         1217330  
  377         2277  
38             *CLASS_XS_ACCESSOR = sub() { 1 }
39 377         4041 }
40             else {
41             *CLASS_XS_ACCESSOR = sub() { 0 }
42 0         0 }
43             }
44              
45             # these are not strictly equivalent, but for out use we don't care
46             # about order
47             *_isa = ($] >= 5.010 && require mro) ? \&mro::get_linear_isa : sub {
48 377     377   3165 no strict 'refs';
  377         889  
  377         57424  
49 0         0 my @packages = ($_[0]);
50 0         0 my %seen;
51 0         0 for my $package (@packages) {
52 0         0 push @packages, grep !$seen{$_}++, @{"$package\::ISA"};
  0         0  
53             }
54 0         0 return \@packages;
55             }
56 377 50 33     181440 }
57              
58             my %SPEC = (
59             '^' => {reader => 1, writer => 0, dep_writer => 1, read_only => 0, strip => 1},
60             '-' => {reader => 1, writer => 0, dep_writer => 0, read_only => 1, strip => 1},
61             '>' => {reader => 0, writer => 1, dep_writer => 0, read_only => 0, strip => 1},
62             '<' => {reader => 1, writer => 0, dep_writer => 0, read_only => 0, strip => 1},
63             '+' => {reader => 0, writer => 0, dep_writer => 0, read_only => 0, strip => 1},
64             '~' => {reader => 1, writer => 1, dep_writer => 0, read_only => 0, strip => 1, no_xs => 1},
65             );
66              
67 5540     5540 0 41591 sub spec { \%SPEC }
68              
69             sub import {
70 911     911   13281 my $class = shift;
71 911         2804 my $into = caller;
72 911         4724 $class->do_import($into, @_);
73             }
74              
75             sub do_import {
76 911     911 0 5931 my $class = shift;
77 911         1748 my $into = shift;
78              
79             # Make sure we list the OLDEST version used to create this class.
80 911   33     4599 my $ver = $DBIx::QuickORM::Util::HashBase::HB_VERSION || $DBIx::QuickORM::Util::HashBase::VERSION;
81 911 100 66     8152 $DBIx::QuickORM::Util::HashBase::VERSION{$into} = $ver if !$DBIx::QuickORM::Util::HashBase::VERSION{$into} || $DBIx::QuickORM::Util::HashBase::VERSION{$into} > $ver;
82              
83 911         9600 my $isa = _isa($into);
84 911   100     7268 my $attr_list = $DBIx::QuickORM::Util::HashBase::ATTR_LIST{$into} ||= [];
85 911   100     17500 my $attr_subs = $DBIx::QuickORM::Util::HashBase::ATTR_SUBS{$into} ||= {};
86              
87 911         2184 my @pre_init;
88             my @post_init;
89              
90 911         1996 my $add_new = 1;
91              
92 911 100       29279 if (my $have_new = $into->can('new')) {
93 193   50     798 my $new_lookup = $DBIx::QuickORM::Util::HashBase::NEW_LOOKUP //= {};
94 193 100       1038 $add_new = 0 unless $new_lookup->{$have_new};
95             }
96              
97             my %subs = (
98             ($add_new ? ($class->_build_new($into, \@pre_init, \@post_init)) : ()),
99 911 100       5885 (map %{$DBIx::QuickORM::Util::HashBase::ATTR_SUBS{$_} || {}}, @{$isa}[1 .. $#$isa]),
  145 50       1610  
  911         5223  
100             ($class->args_to_subs($attr_list, $attr_subs, \@_, $into)),
101             );
102              
103 377     377   3600 no strict 'refs';
  377         696  
  377         697666  
104 911         9918 while (my ($k, $v) = each %subs) {
105 15064 100       58067 if (ref($v) eq 'CODE') {
106 10865         16030 *{"$into\::$k"} = $v;
  10865         868319  
107             }
108             else {
109 4199         11207 my ($sub, @args) = @$v;
110 4199         367183 $sub->(@args);
111             }
112             }
113             }
114              
115             sub args_to_subs {
116 911     911 0 11618 my $class = shift;
117 911         2717 my ($attr_list, $attr_subs, $args, $into) = @_;
118              
119 911         10910 my $use_gen = $class->can('gen_accessor') ;
120              
121 911         1969 my %out;
122              
123 911         3488 while (@$args) {
124 5540         22084 my $x = shift @$args;
125 5540         14936 my $p = substr($x, 0, 1);
126              
127 5540   100     24743 my $spec = $class->spec->{$p} || {reader => 1, writer => 1};
128 5540 100       23745 substr($x, 0, 1) = '' if $spec->{strip};
129              
130 5540         21867 push @$attr_list => $x;
131 5540         17596 my ($sub, $attr) = (uc $x, $x);
132              
133 5540     0   70767 $attr_subs->{$sub} = sub() { $attr };
  0         0  
134 5540         21709 $out{$sub} = $attr_subs->{$sub};
135              
136 5540         16802 my $copy = "$attr";
137 5540 100       18367 if ($spec->{reader}) {
138 3889 50       11518 if ($use_gen) {
    50          
139 0         0 $out{$attr} = $class->gen_accessor(reader => $copy, $spec, $args);
140             }
141             elsif (CLASS_XS_ACCESSOR && !$spec->{no_xs}) {
142 3889         17580 $out{$attr} = [\&Class::XSAccessor::newxs_getter, "$into\::$attr", $copy];
143             }
144             else {
145 0     0   0 $out{$attr} = sub { $_[0]->{$attr} };
  0         0  
146             }
147             }
148              
149 5540 100       26933 if ($spec->{writer}) {
    50          
    50          
150 310 50       1455 if ($use_gen) {
    50          
151 0         0 $out{"set_$attr"} = $class->gen_accessor(writer => $copy, $spec, $args);
152             }
153             elsif(CLASS_XS_ACCESSOR && !$spec->{no_xs}) {
154 310         2023 $out{"set_$attr"} = [\&Class::XSAccessor::newxs_setter, "$into\::set_$attr", $copy, 0];
155             }
156             else {
157 0     0   0 $out{"set_$attr"} = sub { $_[0]->{$attr} = $_[1] };
  0         0  
158             }
159             }
160             elsif($spec->{read_only}) {
161 0 0   0   0 $out{"set_$attr"} = $use_gen ? $class->gen_accessor(read_only => $copy, $spec, $args) : sub { Carp::croak("'$attr' is read-only") };
  0         0  
162             }
163             elsif($spec->{dep_writer}) {
164 0 0   0   0 $out{"set_$attr"} = $use_gen ? $class->gen_accessor(dep_writer => $copy, $spec, $args) : sub { Carp::carp("set_$attr() is deprecated"); $_[0]->{$attr} = $_[1] };
  0         0  
  0         0  
165             }
166              
167 5540 50       19425 if ($spec->{custom}) {
168 0         0 my %add = $class->gen_accessor(custom => $copy, $spec, $args);
169 0         0 $out{$_} = $add{$_} for keys %add;
170             }
171             }
172              
173 911         15910 return %out;
174             }
175              
176             sub attr_list {
177 0     0 1 0 my $class = shift;
178              
179 0         0 my $isa = _isa($class);
180              
181 0         0 my %seen;
182 0         0 my @list = grep { !$seen{$_}++ } map {
183 0         0 my @out;
  0         0  
184              
185 0 0 0     0 if (0.004 > ($DBIx::QuickORM::Util::HashBase::VERSION{$_} || 0)) {
186 0         0 Carp::carp("$_ uses an inlined version of DBIx::QuickORM::Util::HashBase too old to support attr_list()");
187             }
188             else {
189 0         0 my $list = $DBIx::QuickORM::Util::HashBase::ATTR_LIST{$_};
190 0 0       0 @out = $list ? @$list : ()
191             }
192              
193 0         0 @out;
194             } reverse @$isa;
195              
196 0         0 return @list;
197             }
198              
199             sub _build_new {
200 863     863   1867 my $class = shift;
201 863         2716 my ($into, $pre_init, $post_init) = @_;
202              
203 863     0   9729 my $add_pre_init = sub(&) { push @$pre_init => $_[-1] };
  0         0  
204 863     0   4335 my $add_post_init = sub(&) { push @$post_init => $_[-1] };
  0         0  
205              
206 863         10074 my $__pre_init = $into->can('_pre_init');
207 863 100   828   12392 my $_pre_init = $__pre_init ? sub { ($__pre_init->(), @$pre_init) } : sub { @$pre_init };
  48         199  
  981         9398  
208              
209 863         24344 my $__post_init = $into->can('_post_init');
210 863 100   883   21590 my $_post_init = $__post_init ? sub { ($__post_init->(), @$post_init) } : sub { @$post_init };
  48         248  
  981         13594  
211              
212             my $new = sub {
213 981     981   2522 my $class = shift;
214              
215 981         1836 my $self;
216              
217 981 100       3225 if (@_ == 1) {
218 117         336 my $arg = shift;
219 117         311 my $type = ref($arg);
220              
221 117 50       324 if ($type eq 'HASH') {
222 117         1133 $self = bless({%$arg}, $class);
223             }
224             else {
225 0 0       0 Carp::croak("Not sure what to do with '$type' in $class constructor")
226             unless $type eq 'ARRAY';
227              
228 0         0 my %proto;
229 0         0 my @attributes = attr_list($class);
230 0         0 while (@$arg) {
231 0         0 my $val = shift @$arg;
232 0 0       0 my $key = shift @attributes or Carp::croak("Too many arguments for $class constructor");
233 0         0 $proto{$key} = $val;
234             }
235              
236 0         0 $self = bless(\%proto, $class);
237             }
238             }
239             else {
240 864         12724 $self = bless({@_}, $class);
241             }
242              
243             $DBIx::QuickORM::Util::HashBase::CAN_CACHE{$class} = $self->can('init')
244 981 100       13056 unless exists $DBIx::QuickORM::Util::HashBase::CAN_CACHE{$class};
245              
246 981         3010 $self->$_() for $_pre_init->();
247 981 100       7613 $self->init() if $DBIx::QuickORM::Util::HashBase::CAN_CACHE{$class};
248 981         2811 $self->$_() for reverse $_post_init->();
249              
250 981         6170 $self;
251 863         222120 };
252              
253 863   100     7899 my $new_lookup = $DBIx::QuickORM::Util::HashBase::NEW_LOOKUP //= {};
254 863         5038 $new_lookup->{$new} = 1;
255              
256 863         1819 my %out;
257              
258             {
259 377     377   4006 no strict 'refs';
  377         1085  
  377         99817  
  863         1636  
260 863 100       1662 $out{new} = $new unless defined(&{"${into}\::new"});
  863         5734  
261 863 100       1745 $out{add_pre_init} = $add_pre_init unless defined(&{"${into}\::add_pre_init"});
  863         6949  
262 863 100       1679 $out{add_post_init} = $add_post_init unless defined(&{"${into}\::add_post_init"});
  863         5814  
263 863 100       1607 $out{_pre_init} = $_pre_init unless defined(&{"${into}\::_pre_init"});
  863         3983  
264 863 100       1729 $out{_post_init} = $_post_init unless defined(&{"${into}\::_post_init"});
  863         3896  
265             }
266              
267 863         8580 return %out;
268             }
269              
270             1;
271              
272             __END__
273              
274             =pod
275              
276             =encoding UTF-8
277              
278             =head1 NAME
279              
280             DBIx::QuickORM::Util::HashBase - Build hash based classes.
281              
282             =head1 SYNOPSIS
283              
284             A class:
285              
286             package My::Class;
287             use strict;
288             use warnings;
289              
290             # Generate 3 accessors
291             use DBIx::QuickORM::Util::HashBase qw/foo -bar ^baz <bat >ban +boo/;
292              
293             # Chance to initialize defaults
294             sub init {
295             my $self = shift; # No other args
296             $self->{+FOO} ||= "foo";
297             $self->{+BAR} ||= "bar";
298             $self->{+BAZ} ||= "baz";
299             $self->{+BAT} ||= "bat";
300             $self->{+BAN} ||= "ban";
301             $self->{+BOO} ||= "boo";
302             }
303              
304             sub print {
305             my $self = shift;
306             print join ", " => map { $self->{$_} } FOO, BAR, BAZ, BAT, BAN, BOO;
307             }
308              
309             Subclass it
310              
311             package My::Subclass;
312             use strict;
313             use warnings;
314              
315             # Note, you should subclass before loading HashBase.
316             use base 'My::Class';
317             use DBIx::QuickORM::Util::HashBase qw/bub/;
318              
319             sub init {
320             my $self = shift;
321              
322             # We get the constants from the base class for free.
323             $self->{+FOO} ||= 'SubFoo';
324             $self->{+BUB} ||= 'bub';
325              
326             $self->SUPER::init();
327             }
328              
329             use it:
330              
331             package main;
332             use strict;
333             use warnings;
334             use My::Class;
335              
336             # These are all functionally identical
337             my $one = My::Class->new(foo => 'MyFoo', bar => 'MyBar');
338             my $two = My::Class->new({foo => 'MyFoo', bar => 'MyBar'});
339             my $three = My::Class->new(['MyFoo', 'MyBar']);
340              
341             # Readers!
342             my $foo = $one->foo; # 'MyFoo'
343             my $bar = $one->bar; # 'MyBar'
344             my $baz = $one->baz; # Defaulted to: 'baz'
345             my $bat = $one->bat; # Defaulted to: 'bat'
346             # '>ban' means setter only, no reader
347             # '+boo' means no setter or reader, just the BOO constant
348              
349             # Setters!
350             $one->set_foo('A Foo');
351              
352             #'-bar' means read-only, so the setter will throw an exception (but is defined).
353             $one->set_bar('A bar');
354              
355             # '^baz' means deprecated setter, this will warn about the setter being
356             # deprecated.
357             $one->set_baz('A Baz');
358              
359             # '<bat' means no setter defined at all
360             # '+boo' means no setter or reader, just the BOO constant
361              
362             $one->{+FOO} = 'xxx';
363              
364             Add pre_init and post-init:
365              
366             B<Note:> These are not provided if you define your own new() method (via a stub
367             at the top).
368              
369             B<Note:> Single inheritence should work with child classes doing the pre/post
370             init subs during construction, so long as all classes in the chain use a
371             generated new(). This will probably explode badly in multiple-inheritence.
372              
373             package My::Class;
374             use strict;
375             use warnings;
376              
377             # Generate 3 accessors
378             use DBIx::QuickORM::Util::HashBase qw/foo -bar ^baz <bat >ban +boo/;
379              
380             # Do more stuff before init, add as many as you like by calling this
381             # multiple times with a different code block each time
382             add_pre_init {
383             ...
384             };
385              
386             # Chance to initialize defaults
387             sub init { ... }
388              
389             # Do stuff after init, add as many as you want, they run in reverse order
390             add_post_init {
391             my $self = shift;
392             ...
393             };
394              
395             sub print {
396             my $self = shift;
397             print join ", " => map { $self->{$_} } FOO, BAR, BAZ, BAT, BAN, BOO;
398             }
399              
400             You can also call add_pre_init and add_post_init as class methods from anywhere
401             to add init and post-init to the class.
402              
403             B<Please note:> This will apply to all future instances of the object created,
404             but not past ones. This is a form of meta-programming and it is easy to abuse.
405             It is also helpful for extending DBIx::QuickORM::Util::HashBase.
406              
407             My::Class->add_pre_init(sub { ... });
408             My::Class->add_post_init(sub { ... });
409              
410             =head1 DESCRIPTION
411              
412             This package is used to generate classes based on hashrefs. Using this class
413             will give you a C<new()> method, as well as generating accessors you request.
414             Generated accessors will be getters, C<set_ACCESSOR> setters will also be
415             generated for you. You also get constants for each accessor (all caps) which
416             return the key into the hash for that accessor. Single inheritance is also
417             supported.
418              
419             =head1 XS ACCESSORS
420              
421             If L<Class::XSAccessor> is installed, it will be used to generate XS getters
422             and setters.
423              
424             =head2 CAVEATS
425              
426             The only caveat noticed so far is that if you take a reference to an objects
427             attribute element: C<< my $ref = \($obj->{foo}) >> then use
428             C<< $obj->set_foo(1) >>, setting C<< $$ref = 2 >> will not longer work, and
429             getting the value via C<< $val = $$ref >> will also not work. This is not a
430             problem when L<Class::XSAccessor> is not used.
431              
432             In practice it will nbe VERY rare for this to be a problem, but it was noticed
433             because it broke a performance optimization in L<Test2::API>.
434              
435             You can request an accessor NOT be xs with the '~' prefix:
436              
437             use DBIx::QuickORM::Util::HashBase '~foo';
438              
439             The sample above generates C<foo()> and C<set_foo()> and they are NOT
440             implemented in XS.
441              
442             =head1 THIS IS A BUNDLED COPY OF HASHBASE
443              
444             This is a bundled copy of L<Object::HashBase>. This file was generated using
445             the
446             C</home/exodist/perl5/perlbrew/perls/main/bin/hashbase_inc.pl>
447             script.
448              
449             =head1 METHODS
450              
451             =head2 PROVIDED BY HASH BASE
452              
453             =over 4
454              
455             =item $it = $class->new(%PAIRS)
456              
457             =item $it = $class->new(\%PAIRS)
458              
459             =item $it = $class->new(\@ORDERED_VALUES)
460              
461             Create a new instance.
462              
463             HashBase will not export C<new()> if there is already a C<new()> method in your
464             packages inheritance chain.
465              
466             B<If you do not want this method you can define your own> you just have to
467             declare it before loading L<DBIx::QuickORM::Util::HashBase>.
468              
469             package My::Package;
470              
471             # predeclare new() so that HashBase does not give us one.
472             sub new;
473              
474             use DBIx::QuickORM::Util::HashBase qw/foo bar baz/;
475              
476             # Now we define our own new method.
477             sub new { ... }
478              
479             This makes it so that HashBase sees that you have your own C<new()> method.
480             Alternatively you can define the method before loading HashBase instead of just
481             declaring it, but that scatters your use statements.
482              
483             The most common way to create an object is to pass in key/value pairs where
484             each key is an attribute and each value is what you want assigned to that
485             attribute. No checking is done to verify the attributes or values are valid,
486             you may do that in C<init()> if desired.
487              
488             If you would like, you can pass in a hashref instead of pairs. When you do so
489             the hashref will be copied, and the copy will be returned blessed as an object.
490             There is no way to ask HashBase to bless a specific hashref.
491              
492             In some cases an object may only have 1 or 2 attributes, in which case a
493             hashref may be too verbose for your liking. In these cases you can pass in an
494             arrayref with only values. The values will be assigned to attributes in the
495             order the attributes were listed. When there is inheritance involved the
496             attributes from parent classes will come before subclasses.
497              
498             =back
499              
500             =head2 HOOKS
501              
502             =over 4
503              
504             =item $self->init()
505              
506             This gives you the chance to set some default values to your fields. The only
507             argument is C<$self> with its indexes already set from the constructor.
508              
509             B<Note:> DBIx::QuickORM::Util::HashBase checks for an init using C<< $class->can('init') >>
510             during construction. It DOES NOT call C<can()> on the created object. Also note
511             that the result of the check is cached, it is only ever checked once, the first
512             time an instance of your class is created. This means that adding an C<init()>
513             method AFTER the first construction will result in it being ignored.
514              
515             =back
516              
517             =head1 ACCESSORS
518              
519             =head2 READ/WRITE
520              
521             To generate accessors you list them when using the module:
522              
523             use DBIx::QuickORM::Util::HashBase qw/foo/;
524              
525             This will generate the following subs in your namespace:
526              
527             =over 4
528              
529             =item foo()
530              
531             Getter, used to get the value of the C<foo> field.
532              
533             =item set_foo()
534              
535             Setter, used to set the value of the C<foo> field.
536              
537             =item FOO()
538              
539             Constant, returns the field C<foo>'s key into the class hashref. Subclasses will
540             also get this function as a constant, not simply a method, that means it is
541             copied into the subclass namespace.
542              
543             The main reason for using these constants is to help avoid spelling mistakes
544             and similar typos. It will not help you if you forget to prefix the '+' though.
545              
546             =back
547              
548             =head2 READ ONLY
549              
550             use DBIx::QuickORM::Util::HashBase qw/-foo/;
551              
552             =over 4
553              
554             =item set_foo()
555              
556             Throws an exception telling you the attribute is read-only. This is exported to
557             override any active setters for the attribute in a parent class.
558              
559             =back
560              
561             =head2 DEPRECATED SETTER
562              
563             use DBIx::QuickORM::Util::HashBase qw/^foo/;
564              
565             =over 4
566              
567             =item set_foo()
568              
569             This will set the value, but it will also warn you that the method is
570             deprecated.
571              
572             =back
573              
574             =head2 NO SETTER
575              
576             use DBIx::QuickORM::Util::HashBase qw/<foo/;
577              
578             Only gives you a reader, no C<set_foo> method is defined at all.
579              
580             =head2 NO READER
581              
582             use DBIx::QuickORM::Util::HashBase qw/>foo/;
583              
584             Only gives you a write (C<set_foo>), no C<foo> method is defined at all.
585              
586             =head2 CONSTANT ONLY
587              
588             use DBIx::QuickORM::Util::HashBase qw/+foo/;
589              
590             This does not create any methods for you, it just adds the C<FOO> constant.
591              
592             =head2 NO XS
593              
594             use DBIx::QuickORM::Util::HashBase qw/~foo/;
595              
596             This enforces that the getter and setter generated for C<foo> will NOT use
597             L<Class::XSAccessor> even if it is installed.
598              
599             =head1 SUBCLASSING
600              
601             You can subclass an existing HashBase class.
602              
603             use base 'Another::HashBase::Class';
604             use DBIx::QuickORM::Util::HashBase qw/foo bar baz/;
605              
606             The base class is added to C<@ISA> for you, and all constants from base classes
607             are added to subclasses automatically.
608              
609             =head1 GETTING A LIST OF ATTRIBUTES FOR A CLASS
610              
611             DBIx::QuickORM::Util::HashBase provides a function for retrieving a list of attributes for an
612             DBIx::QuickORM::Util::HashBase class.
613              
614             =over 4
615              
616             =item @list = DBIx::QuickORM::Util::HashBase::attr_list($class)
617              
618             =item @list = $class->DBIx::QuickORM::Util::HashBase::attr_list()
619              
620             Either form above will work. This will return a list of attributes defined on
621             the object. This list is returned in the attribute definition order, parent
622             class attributes are listed before subclass attributes. Duplicate attributes
623             will be removed before the list is returned.
624              
625             B<Note:> This list is used in the C<< $class->new(\@ARRAY) >> constructor to
626             determine the attribute to which each value will be paired.
627              
628             =back
629              
630             =head1 SOURCE
631              
632             The source code repository for HashBase can be found at
633             F<http://github.com/Test-More/HashBase/>.
634              
635             =head1 MAINTAINERS
636              
637             =over 4
638              
639             =item Chad Granum E<lt>exodist@cpan.orgE<gt>
640              
641             =back
642              
643             =head1 AUTHORS
644              
645             =over 4
646              
647             =item Chad Granum E<lt>exodist@cpan.orgE<gt>
648              
649             =back
650              
651             =head1 COPYRIGHT
652              
653             Copyright 2017 Chad Granum E<lt>exodist@cpan.orgE<gt>.
654              
655             This program is free software; you can redistribute it and/or
656             modify it under the same terms as Perl itself.
657              
658             See F<http://dev.perl.org/licenses/>
659              
660             =cut