File Coverage

blib/lib/Mom.pm
Criterion Covered Total %
statement 58 73 79.4
branch 26 34 76.4
condition 3 7 42.8
subroutine 8 8 100.0
pod n/a
total 95 122 77.8


line stmt bran cond sub pod time code
1 5     5   298355 use 5.008008;
  5         49  
2 5     5   21 use strict;
  5         8  
  5         82  
3 5     5   18 use warnings;
  5         5  
  5         247  
4              
5              
6             our $AUTHORITY = 'cpan:TOBYINK';
7             our $VERSION = '0.006';
8              
9             use parent qw( MooX::Press );
10 5     5   1809 use Carp qw();
  5         1269  
  5         22  
11 5     5   705476 use Import::Into;
  5         11  
  5         77  
12 5     5   20 use Regexp::Common;
  5         8  
  5         81  
13 5     5   2442  
  5         11239  
  5         20  
14             my $token_re = qr{(?:
15             (?: [^0-9\W]\w* )
16             | \: (?: isa|enum|does|type|handles|with|extends|default|requires|builder|trigger|clearer ) $RE{balanced}
17             | \: (?: role|ro|rwp|rw|bare|private|lazy|required|clearer|builder|trigger|std|common|path|req )
18             | \!
19             )}x;
20              
21             my $me = shift;
22             my $caller = caller;
23 6     6   1221 my $import = join q( ), @_;
24 6         15
25 6         22 my $attr;
26             my %opts = ( factory => undef );
27 6         11 my $kind = 'class';
28 6         16 my %import_types;
29 6         13
30 6         9 $import =~ s/\s+//;
31             while ( $import =~ /^($token_re)/ ) {
32 6         27
33 6         659 my $token = $1;
34             $import = substr($import, length($token));
35 17         43 $import =~ s/\s+//;
36 17         35
37 17         26 if ( $token =~ /^:(role)$/ ) {
38             $kind = 'role';
39 17 100       43 }
40 1         2 if ( $token =~ /^:(common|std|path)$/ ) {
41             $import_types{$1} = 1;
42 17 100       118 }
    100          
    100          
    50          
    50          
    100          
    100          
    50          
    100          
43 1         5 elsif ( $token =~ /^:(extends|with).(.+).$/ ) {
44             $opts{$1} = [ split /\s*,\s*/, $2 ];
45             }
46 1         10 elsif ( $token =~ /^:(rw|ro|rwp|bare|private)$/ ) {
47             $opts{has}{$attr}{is} = $1;
48             }
49 1         6 elsif ( $token =~ /^:(lazy)$/ ) {
50             $opts{has}{$attr}{$1} = 1;
51             }
52 0         0 elsif ( $token =~ /^:(required|req|clearer|trigger|builder)$/ ) {
53             my $o = $1;
54             $o = 'required' if $o eq 'req';
55 0         0 $opts{has}{$attr}{$1} = 1;
56 0 0       0 }
57 0         0 elsif ( $token =~ /^:(enum|handles).(.+).$/ ) {
58             my ( $o, $v ) = ( $1, $2 );
59             push @{ $opts{has}{$attr}{$o} ||= [] }, split /\s*,\s*/, $v;
60 4         13 if ( $o eq 'handles' and $v =~ /^[12]$/ ) {
61 4   50     6 $opts{has}{$attr}{$o} = $v;
  4         34  
62 4 100 66     32 }
63 2         10 }
64             elsif ( $token =~ /^:(isa|does|type|default|builder|trigger|clearer).(.+).$/ ) {
65             $opts{has}{$attr}{$1} = $2;
66             }
67 1         9 elsif ( $token =~ /^:(requires).(.+).$/ ) {
68             push @{ $opts{requires} ||= [] }, split /\s*,\s*/, $2;
69             }
70 0   0     0 elsif ( $token eq '!' ) {
  0         0  
71             $opts{has}{$attr}{required} = 1;
72             }
73 2         16 else {
74             $opts{has}{$attr = $token} = {};
75             }
76 7         62 }
77            
78             if ( $import ) {
79             Carp::croak("Unrecognized syntax: $import");
80 6 50       16 }
81 0         0
82             my @super_args = (
83             factory_package => $me,
84 6         27 type_library => "$me\::Types",
85             prefix => undef,
86             $kind => [ $caller => \%opts ],
87             );
88             $me->SUPER::import( @super_args );
89            
90 6         71 ($kind eq 'role' ? 'Moo::Role' : 'Moo')->_install_subs($caller);
91             'Scalar::Util'->import::into($caller, qw(blessed));
92 6 100       546983 'Carp'->import::into($caller, qw(croak confess carp));
93 6         933
94 6         1255 if ($import_types{std}) {
95             require Types::Standard;
96 6 100       1046 'Types::Standard'->import::into($caller, qw(-types -is -assert));
97 1         12 }
98 1         6
99             if ($import_types{common}) {
100             require Types::Common::Numeric;
101 6 50       11644 'Types::Common::Numeric'->import::into($caller, qw(-types -is -assert));
102 0         0 require Types::Common::String;
103 0         0 'Types::Common::String'->import::into($caller, qw(-types -is -assert));
104 0         0 }
105 0         0
106             if ($import_types{path}) {
107             require Types::Path::Tiny;
108 6 50       18 'Types::Path::Tiny'->import::into($caller, qw(-types -is -assert));
109 0         0 require Path::Tiny;
110 0         0 'Path::Tiny'->import::into($caller);
111 0         0 }
112 0         0
113             'namespace::autoclean'->import::into($caller);
114             }
115 6         34  
116             1;
117              
118              
119             =pod
120              
121             =encoding utf-8
122              
123             =head1 NAME
124              
125             Mom - Moo objects minimally
126              
127             =head1 SYNOPSIS
128              
129             This:
130              
131             use Mom;
132              
133             Is (roughly) a shortcut for:
134              
135             use Moo;
136             use Scalar::Util qw( blessed );
137             use Carp qw( carp croak confess );
138             use namespace::autoclean;
139              
140             But Mom takes care of a lot more. This:
141              
142             use Mom q{ foo bar:rw:type(Int) baz! };
143              
144             Is (roughly) a shortcut for:
145              
146             use Moo;
147             use Scalar::Util qw( blessed );
148             use Carp qw( carp croak confess );
149             use Types::Standard qw();
150             use namespace::autoclean;
151            
152             has foo => ( is => "ro" );
153             has bar => ( is => "rw", isa => Types::Standard::Int );
154             has baz => ( is => "ro", required => 1 );
155              
156             Tokens which don't start with a colon are created as attributes in
157             your package. Tokens starting with a colon are flags that affect either
158             the preceeding attribute or the package as a whole.
159              
160             =head1 DESCRIPTION
161              
162             This documentation assumes familiarity with L<Moo>.
163              
164             =head2 Motivation
165              
166             The documentation for L<MooX::ShortHas> says instead of this:
167              
168             use Moo;
169            
170             has hro => is => ro => required => 1;
171             has hlazy => is => lazy => builder => sub { 2 };
172             has hrwp => is => rwp => required => 1;
173             has hrw => is => rw => required => 1;
174              
175             You can now write this:
176              
177             use Moo;
178             use MooX::ShortHas;
179            
180             ro "hro";
181             lazy hlazy => sub { 2 };
182             rwp "hrwp";
183             rw "hrw";
184              
185             I thought I could go even shorter.
186              
187             use Mom q{ hro! hlazy:lazy:default(2) hrwp!:rwp hrw!:rw };
188              
189             =head1 IMPORT
190              
191             All of Mom's magic happens in the import statement.
192              
193             =head2 Flags Affecting Attributes
194              
195             =over
196              
197             =item C<< :rw >>
198              
199             Like C<< is => "rw" >> in Moo.
200              
201             =item C<< :ro >>
202              
203             Like C<< is => "ro" >> in Moo, though this is already the default.
204              
205             =item C<< :rwp >>
206              
207             Like C<< is => "rwp" >> in Moo
208              
209             =item C<< :bare >>
210              
211             Like C<< is => "bare" >> in Moo
212              
213             =item C<< :lazy >>
214              
215             Like C<< lazy => 1 >> in Moo.
216              
217             =item C<< :required >> or C<< :req >> or C<< ! >>
218              
219             Like C<< required => 1 >> in Moo.
220              
221             =item C<< :clearer >>
222              
223             Like C<< clearer => 1 >> in Moo.
224              
225             =item C<< :clearer(methodname) >>
226              
227             Like C<< clearer => "methodname" >> in Moo.
228              
229             =item C<< :builder >>
230              
231             Like C<< builder => 1 >> in Moo.
232              
233             =item C<< :builder(methodname) >>
234              
235             Like C<< builder => "methodname" >> in Moo.
236              
237             =item C<< :trigger >>
238              
239             Like C<< trigger => 1 >> in Moo.
240              
241             =item C<< :trigger(methodname) >>
242              
243             Like C<< trigger => "methodname" >> in Moo.
244              
245             =item C<< :isa(Class::Name) >>
246              
247             Like C<< isa => InstanceOf[Class::Name] >> in Moo/Types::Standard.
248              
249             =item C<< :does(Role::Name) >>
250              
251             Like C<< isa => ConsumerOf[Role::Name] >> in Moo/Types::Standard.
252              
253             =item C<< :type(TypeName) >>
254              
255             Like C<< isa => TypeName >> in Moo/Types::Standard.
256              
257             =item C<< :enum(list,of,strings) >>
258              
259             Like C<< isa => Enum["list","of","strings"] >> in Moo/Types::Standard.
260              
261             =item C<< :default(value) >>
262              
263             Like C<< default => "value" >> in Moo.
264              
265             For simple (string/numeric) defaults. Doesn't accept coderefs.
266              
267             =item C<< :handles(list,of,methods) >>
268              
269             Like C<< handles => ["list","of","methods"] >> in Moo.
270              
271             Currently no support for a hashref of delegations.
272              
273             =item C<< :handles(1) >> or C<< :handles(2) >>
274              
275             Like L<MooX::Enumeration>.
276              
277             =back
278              
279             =head2 Flags Affecting Package
280              
281             =over
282              
283             =item C<< :role >>
284              
285             Creates a Moo::Role instead of a Moo class.
286              
287             =item C<< :extends(Class::Name) >>
288              
289             Like C<< extends "Class::Name" >> in Moo.
290              
291             =item C<< :with(Role::Name) >>
292              
293             Like C<< with "Role::Name" >> in Moo.
294              
295             =item C<< :requires(list,of,methods) >>
296              
297             Like C<< requires ("list", "of", "methods"); >> in Moo::Role.
298              
299             =item C<< :std >>
300              
301             Like C<< use Types::Standard qw( -types -is -assert ) >>
302              
303             =item C<< :common >>
304              
305             Like:
306              
307             use Types::Common::Numeric qw( -types -is -assert );
308             use Types::Common::String qw( -types -is -assert );
309              
310             =item C<< :path >>
311              
312             Like:
313              
314             use Types::Path::Tiny qw( -types -is -assert );
315             use Path::Tiny qw( path );
316              
317             =back
318              
319             =head1 BUGS
320              
321             Please report any bugs to
322             L<http://rt.cpan.org/Dist/Display.html?Queue=Mom>.
323              
324             =head1 SEE ALSO
325              
326             L<Moo>, L<Types::Standard>.
327              
328             =head1 AUTHOR
329              
330             Toby Inkster E<lt>tobyink@cpan.orgE<gt>.
331              
332             =head1 COPYRIGHT AND LICENCE
333              
334             This software is copyright (c) 2020, 2022 by Toby Inkster.
335              
336             This is free software; you can redistribute it and/or modify it under
337             the same terms as the Perl 5 programming language system itself.
338              
339             =head1 DISCLAIMER OF WARRANTIES
340              
341             THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
342             WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
343             MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
344