File Coverage

blib/lib/Data/Object/Attributes.pm
Criterion Covered Total %
statement 62 65 95.3
branch 38 40 95.0
condition 2 3 66.6
subroutine 13 13 100.0
pod 0 2 0.0
total 115 123 93.5


line stmt bran cond sub pod time code
1             package Data::Object::Attributes;
2              
3 1     1   29664 use 5.014;
  1         3  
4              
5 1     1   5 use strict;
  1         2  
  1         17  
6 1     1   4 use warnings;
  1         1  
  1         19  
7 1     1   4 use registry;
  1         2  
  1         5  
8 1     1   4710 use routines;
  1         1  
  1         5  
9              
10 1     1   1469 use Moo;
  1         2  
  1         5  
11              
12             our $VERSION = '0.05'; # VERSION
13              
14             # BUILD
15              
16             my $builders = {};
17              
18 20     20   118646 fun import($class, @args) {
  20         27  
19 20 50       161 my $has = (my $target = caller)->can('has') or return;
20              
21 1     1   318 no strict 'refs';
  1         2  
  1         28  
22 1     1   4 no warnings 'redefine';
  1         1  
  1         89  
23              
24 20         79 *{"${target}::has"} = generate([$class, $target], $has);
  20         71  
25              
26 20         1420 return;
27             }
28              
29 20     20 0 34 fun generate($info, $orig) {
  20         33  
30             # generate "has" keyword
31              
32 20     20   96 return fun(@args) { @_ = options($info, @args); goto $orig };
  20         1101  
  20         29  
  20         49  
  20         71  
33             }
34              
35             $builders->{new} = fun($info, $name, %opts) {
36             if (delete $opts{new}) {
37             $opts{builder} = "new_${name}";
38             $opts{lazy} = 1;
39             }
40              
41             return (%opts);
42             };
43              
44             $builders->{bld} = fun($info, $name, %opts) {
45             $opts{builder} = delete $opts{bld};
46              
47             return (%opts);
48             };
49              
50             $builders->{clr} = fun($info, $name, %opts) {
51             $opts{clearer} = delete $opts{clr};
52              
53             return (%opts);
54             };
55              
56             $builders->{crc} = fun($info, $name, %opts) {
57             $opts{coerce} = delete $opts{crc};
58              
59             return (%opts);
60             };
61              
62             $builders->{def} = fun($info, $name, %opts) {
63             $opts{default} = delete $opts{def};
64              
65             return (%opts);
66             };
67              
68             $builders->{hnd} = fun($info, $name, %opts) {
69             $opts{handles} = delete $opts{hnd};
70              
71             return (%opts);
72             };
73              
74             $builders->{isa} = fun($info, $name, %opts) {
75             return (%opts) if ref($opts{isa});
76              
77             my $registry = registry::access($info->[1]);
78              
79             return (%opts) if !$registry;
80              
81             my $constraint = $registry->lookup($opts{isa});
82              
83             return (%opts) if !$constraint;
84              
85             $opts{isa} = $constraint;
86              
87             return (%opts);
88             };
89              
90             $builders->{lzy} = fun($info, $name, %opts) {
91             $opts{lazy} = delete $opts{lzy};
92              
93             return (%opts);
94             };
95              
96             $builders->{opt} = fun($info, $name, %opts) {
97             delete $opts{opt};
98              
99             $opts{required} = 0;
100              
101             return (%opts);
102             };
103              
104             $builders->{pre} = fun($info, $name, %opts) {
105             $opts{predicate} = delete $opts{pre};
106              
107             return (%opts);
108             };
109              
110             $builders->{rdr} = fun($info, $name, %opts) {
111             $opts{reader} = delete $opts{rdr};
112              
113             return (%opts);
114             };
115              
116             $builders->{req} = fun($info, $name, %opts) {
117             delete $opts{req};
118              
119             $opts{required} = 1;
120              
121             return (%opts);
122             };
123              
124             $builders->{tgr} = fun($info, $name, %opts) {
125             $opts{trigger} = delete $opts{tgr};
126              
127             return (%opts);
128             };
129              
130             $builders->{use} = fun($info, $name, %opts) {
131             if (my $use = delete $opts{use}) {
132             $opts{builder} = $builders->{use_builder}->($info, $name, @$use);
133             $opts{lazy} = 1;
134             }
135              
136             return (%opts);
137             };
138              
139             $builders->{use_builder} = fun($info, $name, $sub, @args) {
140 1     1   2097 return fun($self) {
  1         3  
141 1         4 @_ = ($self, @args);
142              
143 1 50       7 my $point = $self->can($sub) or do {
144 0         0 require Carp;
145              
146 0         0 my $class = $info->[1];
147              
148 0         0 Carp::confess("has '$name' cannot 'use' method '$sub' via package '$class'");
149             };
150              
151 1         16 goto $point;
152             };
153             };
154              
155             $builders->{wkr} = fun($info, $name, %opts) {
156             $opts{weak_ref} = delete $opts{wkr};
157              
158             return (%opts);
159             };
160              
161             $builders->{wrt} = fun($info, $name, %opts) {
162             $opts{writer} = delete $opts{wrt};
163              
164             return (%opts);
165             };
166              
167 20     20 0 56 fun options($info, $name, %opts) {
  20         24  
168 20 100       42 %opts = (is => 'rw') unless %opts;
169              
170 20 100       54 %opts = (%opts, $builders->{new}->($info, $name, %opts)) if defined $opts{new};
171 20 100       41 %opts = (%opts, $builders->{bld}->($info, $name, %opts)) if defined $opts{bld};
172 20 100       42 %opts = (%opts, $builders->{clr}->($info, $name, %opts)) if defined $opts{clr};
173 20 100       35 %opts = (%opts, $builders->{crc}->($info, $name, %opts)) if defined $opts{crc};
174 20 100       45 %opts = (%opts, $builders->{def}->($info, $name, %opts)) if defined $opts{def};
175 20 100       37 %opts = (%opts, $builders->{hnd}->($info, $name, %opts)) if defined $opts{hnd};
176 20 100       34 %opts = (%opts, $builders->{isa}->($info, $name, %opts)) if defined $opts{isa};
177 20 100       34 %opts = (%opts, $builders->{lzy}->($info, $name, %opts)) if defined $opts{lzy};
178 20 100       39 %opts = (%opts, $builders->{opt}->($info, $name, %opts)) if defined $opts{opt};
179 20 100       33 %opts = (%opts, $builders->{pre}->($info, $name, %opts)) if defined $opts{pre};
180 20 100       36 %opts = (%opts, $builders->{rdr}->($info, $name, %opts)) if defined $opts{rdr};
181 20 100       42 %opts = (%opts, $builders->{req}->($info, $name, %opts)) if defined $opts{req};
182 20 100       32 %opts = (%opts, $builders->{tgr}->($info, $name, %opts)) if defined $opts{tgr};
183 20 100       40 %opts = (%opts, $builders->{use}->($info, $name, %opts)) if defined $opts{use};
184 20 100       38 %opts = (%opts, $builders->{wkr}->($info, $name, %opts)) if defined $opts{wkr};
185 20 100       60 %opts = (%opts, $builders->{wrt}->($info, $name, %opts)) if defined $opts{wrt};
186              
187 20 100 66     66 $name = "+$name" if delete $opts{mod} || delete $opts{modify};
188              
189 20         71 return ($name, %opts);
190             }
191              
192             1;
193              
194             =encoding utf8
195              
196             =head1 NAME
197              
198             Data::Object::Attributes
199              
200             =cut
201              
202             =head1 ABSTRACT
203              
204             Attribute Builder for Perl 5
205              
206             =cut
207              
208             =head1 SYNOPSIS
209              
210             package Example;
211              
212             use Moo;
213              
214             use Data::Object::Attributes;
215              
216             has 'data';
217              
218             package main;
219              
220             my $example = Example->new;
221              
222             =cut
223              
224             =head1 DESCRIPTION
225              
226             This package provides options for defining class attributes. Specifically, this
227             package wraps the C<has> attribute keyword and adds shortcuts and enhancements.
228             If no directives are specified, the attribute is declared as C<read-write> and
229             C<optional>.
230              
231             =cut
232              
233             =head1 SCENARIOS
234              
235             This package supports the following scenarios:
236              
237             =cut
238              
239             =head2 has-bld
240              
241             package Example::HasBld;
242              
243             use Moo;
244             use routines;
245              
246             use Data::Object::Attributes;
247              
248             has data => (
249             is => 'ro',
250             bld => 1
251             );
252              
253             method _build_data() {
254              
255             return time;
256             }
257              
258             package main;
259              
260             my $example = Example::HasBld->new;
261              
262             This package supports the C<bld> and C<builder> directives, expects a C<1>, a
263             method name, or coderef and builds the attribute value if it wasn't provided to
264             the constructor. See the L<Moo> documentation for more details.
265              
266             =cut
267              
268             =head2 has-clr
269              
270             package Example::HasClr;
271              
272             use Moo;
273              
274             use Data::Object::Attributes;
275              
276             has data => (
277             is => 'ro',
278             clr => 1
279             );
280              
281             package main;
282              
283             my $example = Example::HasClr->new(data => time);
284              
285             # $example->clear_data;
286              
287             This package supports the C<clr> and C<clearer> directives expects a C<1> or a
288             method name of the clearer method. See the L<Moo> documentation for more
289             details.
290              
291             =cut
292              
293             =head2 has-crc
294              
295             package Example::HasCrc;
296              
297             use Moo;
298              
299             use Data::Object::Attributes;
300              
301             has data => (
302             is => 'ro',
303             crc => sub {'0'}
304             );
305              
306             package main;
307              
308             my $example = Example::HasCrc->new(data => time);
309              
310             This package supports the C<crc> and C<coerce> directives denotes whether an
311             attribute's value should be automatically coerced. See the L<Moo> documentation
312             for more details.
313              
314             =cut
315              
316             =head2 has-def
317              
318             package Example::HasDef;
319              
320             use Moo;
321              
322             use Data::Object::Attributes;
323              
324             has data => (
325             is => 'ro',
326             def => '0'
327             );
328              
329             package main;
330              
331             my $example = Example::HasDef->new;
332              
333             This package supports the C<def> and C<default> directives expects a
334             non-reference or a coderef to be used to build a default value if one is not
335             provided to the constructor. See the L<Moo> documentation for more details.
336              
337             =cut
338              
339             =head2 has-hnd
340              
341             package Example::Time;
342              
343             use Moo;
344             use routines;
345              
346             method maketime() {
347              
348             return time;
349             }
350              
351             package Example::HasHnd;
352              
353             use Moo;
354              
355             use Data::Object::Attributes;
356              
357             has data => (
358             is => 'ro',
359             hnd => ['maketime']
360             );
361              
362             package main;
363              
364             my $example = Example::HasHnd->new(data => Example::Time->new);
365              
366             This package supports the C<hnd> and C<handles> directives denotes the methods
367             created on the object which dispatch to methods available on the attribute's
368             object. See the L<Moo> documentation for more details.
369              
370             =cut
371              
372             =head2 has-is
373              
374             package Example::HasIs;
375              
376             use Moo;
377              
378             use Data::Object::Attributes;
379              
380             has data => (
381             is => 'ro'
382             );
383              
384             package main;
385              
386             my $example = Example::HasIs->new(data => time);
387              
388             This package supports the C<is> directive, used to denote whether the attribute
389             is read-only or read-write. See the L<Moo> documentation for more details.
390              
391             =cut
392              
393             =head2 has-isa
394              
395             package Example::HasIsa;
396              
397             use Moo;
398             use registry;
399              
400             use Data::Object::Attributes;
401              
402             has data => (
403             is => 'ro',
404             isa => 'Str' # e.g. Types::Standard::Str
405             );
406              
407             package main;
408              
409             my $example = Example::HasIsa->new(data => time);
410              
411             This package supports the C<isa> directive, used to define the type constraint
412             to validate the attribute against. See the L<Moo> documentation for more
413             details.
414              
415             =cut
416              
417             =head2 has-lzy
418              
419             package Example::HasLzy;
420              
421             use Moo;
422              
423             use Data::Object::Attributes;
424              
425             has data => (
426             is => 'ro',
427             def => sub {time},
428             lzy => 1
429             );
430              
431             package main;
432              
433             my $example = Example::HasLzy->new;
434              
435             This package supports the C<lzy> and C<lazy> directives denotes whether the
436             attribute will be constructed on-demand, or on-construction. See the L<Moo>
437             documentation for more details.
438              
439             =cut
440              
441             =head2 has-mod
442              
443             package Example::Has;
444              
445             use Moo;
446              
447             use Data::Object::Attributes;
448              
449             has data => (
450             is => 'rw',
451             opt => 1
452             );
453              
454             package Example::HasMod;
455              
456             use Moo;
457              
458             use Data::Object::Attributes;
459              
460             extends 'Example::Has';
461              
462             has data => (
463             is => 'ro',
464             req => 1,
465             mod => 1
466             );
467              
468             package main;
469              
470             my $example = Example::HasMod->new;
471              
472             This package supports the C<mod> and C<modify> directives denotes whether a
473             pre-existing attribute's definition is being modified. This ability is not
474             supported by the L<Moo> object superclass.
475              
476             =cut
477              
478             =head2 has-new
479              
480             package Example::HasNew;
481              
482             use Moo;
483             use routines;
484              
485             use Data::Object::Attributes;
486              
487             has data => (
488             is => 'ro',
489             new => 1
490             );
491              
492             fun new_data($self) {
493              
494             return time;
495             }
496              
497             package main;
498              
499             my $example = Example::HasNew->new(data => time);
500              
501             This package supports the C<new> directive, if truthy, denotes that the
502             attribute will be constructed on-demand, i.e. is lazy, with a builder named
503             new_{attribute}. This ability is not supported by the L<Moo> object superclass.
504              
505             =cut
506              
507             =head2 has-opt
508              
509             package Example::HasOpt;
510              
511             use Moo;
512              
513             use Data::Object::Attributes;
514              
515             has data => (
516             is => 'ro',
517             opt => 1
518             );
519              
520             package main;
521              
522             my $example = Example::HasOpt->new(data => time);
523              
524             This package supports the C<opt> and C<optional> directives, used to denote if
525             an attribute is optional or required. See the L<Moo> documentation for more
526             details.
527              
528             =cut
529              
530             =head2 has-pre
531              
532             package Example::HasPre;
533              
534             use Moo;
535              
536             use Data::Object::Attributes;
537              
538             has data => (
539             is => 'ro',
540             pre => 1
541             );
542              
543             package main;
544              
545             my $example = Example::HasPre->new(data => time);
546              
547             This package supports the C<pre> and C<predicate> directives expects a C<1> or
548             a method name and generates a method for checking the existance of the
549             attribute. See the L<Moo> documentation for more details.
550              
551             =cut
552              
553             =head2 has-rdr
554              
555             package Example::HasRdr;
556              
557             use Moo;
558              
559             use Data::Object::Attributes;
560              
561             has data => (
562             is => 'ro',
563             rdr => 'get_data'
564             );
565              
566             package main;
567              
568             my $example = Example::HasRdr->new(data => time);
569              
570             This package supports the C<rdr> and C<reader> directives denotes the name of
571             the method to be used to "read" and return the attribute's value. See the
572             L<Moo> documentation for more details.
573              
574             =cut
575              
576             =head2 has-req
577              
578             package Example::HasReq;
579              
580             use Moo;
581              
582             use Data::Object::Attributes;
583              
584             has data => (
585             is => 'ro',
586             req => 1 # required
587             );
588              
589             package main;
590              
591             my $example = Example::HasReq->new(data => time);
592              
593             This package supports the C<req> and C<required> directives, used to denote if
594             an attribute is required or optional. See the L<Moo> documentation for more
595             details.
596              
597             =cut
598              
599             =head2 has-tgr
600              
601             package Example::HasTgr;
602              
603             use Moo;
604             use routines;
605              
606             use Data::Object::Attributes;
607              
608             has data => (
609             is => 'ro',
610             tgr => 1
611             );
612              
613             method _trigger_data() {
614             $self->{triggered} = 1;
615              
616             return $self;
617             }
618              
619             package main;
620              
621             my $example = Example::HasTgr->new(data => time);
622              
623             This package supports the C<tgr> and C<trigger> directives expects a C<1> or a
624             coderef and is executed whenever the attribute's value is changed. See the
625             L<Moo> documentation for more details.
626              
627             =cut
628              
629             =head2 has-use
630              
631             package Example::HasUse;
632              
633             use Moo;
634             use routines;
635              
636             use Data::Object::Attributes;
637              
638             has data => (
639             is => 'ro',
640             use => ['service', 'time']
641             );
642              
643             method service($type, @args) {
644             $self->{serviced} = 1;
645              
646             return time if $type eq 'time';
647             }
648              
649             package main;
650              
651             my $example = Example::HasUse->new;
652              
653             This package supports the C<use> directive denotes that the attribute will be
654             constructed on-demand, i.e. is lazy, using a custom builder meant to perform
655             service construction. This directive exists to provide a simple dependency
656             injection mechanism for class attributes. This ability is not supported by the
657             L<Moo> object superclass.
658              
659             =cut
660              
661             =head2 has-wkr
662              
663             package Example::HasWkr;
664              
665             use Moo;
666              
667             use Data::Object::Attributes;
668              
669             has data => (
670             is => 'ro',
671             wkr => 1
672             );
673              
674             package main;
675              
676             my $data = do {
677             my ($a, $b);
678              
679             $a = { time => time };
680             $b = { time => $a };
681              
682             $a->{time} = $b;
683             $a
684             };
685              
686             my $example = Example::HasWkr->new(data => $data);
687              
688             This package supports the C<wkr> and C<weak_ref> directives is used to denote if
689             the attribute's value should be weakened. See the L<Moo> documentation for more
690             details.
691              
692             =cut
693              
694             =head2 has-wrt
695              
696             package Example::HasWrt;
697              
698             use Moo;
699              
700             use Data::Object::Attributes;
701              
702             has data => (
703             is => 'ro',
704             wrt => 'set_data'
705             );
706              
707             package main;
708              
709             my $example = Example::HasWrt->new;
710              
711             This package supports the C<wrt> and C<writer> directives denotes the name of
712             the method to be used to "write" and return the attribute's value. See the
713             L<Moo> documentation for more details.
714              
715             =cut
716              
717             =head1 AUTHOR
718              
719             Al Newkirk, C<awncorp@cpan.org>
720              
721             =head1 LICENSE
722              
723             Copyright (C) 2011-2019, Al Newkirk, et al.
724              
725             This is free software; you can redistribute it and/or modify it under the terms
726             of the The Apache License, Version 2.0, as elucidated in the L<"license
727             file"|https://github.com/iamalnewkirk/data-object-attributes/blob/master/LICENSE>.
728              
729             =head1 PROJECT
730              
731             L<Wiki|https://github.com/iamalnewkirk/data-object-attributes/wiki>
732              
733             L<Project|https://github.com/iamalnewkirk/data-object-attributes>
734              
735             L<Initiatives|https://github.com/iamalnewkirk/data-object-attributes/projects>
736              
737             L<Milestones|https://github.com/iamalnewkirk/data-object-attributes/milestones>
738              
739             L<Contributing|https://github.com/iamalnewkirk/data-object-attributes/blob/master/CONTRIBUTE.md>
740              
741             L<Issues|https://github.com/iamalnewkirk/data-object-attributes/issues>
742              
743             =cut