File Coverage

File:lib/Yukki/Types.pm
Coverage:100.0%

linestmtbrancondsubpodtimecode
1package Yukki::Types;
2
3
6
6
37
16
use v5.24;
4
6
6
6
18
6
20
use utf8;
5
6
6
135
use Type::Library -base, -declare => qw(
7    LoginName AccessLevel
8    NavigationLinks NavigationMenuMap
9    BaseURL BaseURLEnum BreadcrumbLinks RepositoryMap
10    PluginConfig PluginList
11    PrivilegesMap
12    EmailAddress YukkiSettings
13    YukkiWebSettings YukkiSettingsAnonymous
14
6
6
8
32
);
15
6
6
6
6622
9
18
use Type::Utils qw( declare as where message coerce enum from via class_type );
16
17
6
6
6
3712
9
19
use Types::Standard qw( Str Int ArrayRef Maybe HashRef Dict );
18
6
6
6
5500
155354
39
use Types::URI qw( Uri );
19
20
6
6
6
3228
22378
178
use Email::Address;
21
6
6
6
35
9
339
use List::Util qw( first all );
22
23
6
6
6
1051
7130
33
use namespace::clean;
24
25# ABSTRACT: standard types for use in Yukki
26
27 - 44
=head1 SYNOPSIS

  use Yukki::Types qw( LoginName AccessLevel );

  has login_name => ( isa => LoginName );
  has access_level => ( isa => AccessLevel );

=head1 DESCRIPTION

A standard type library for Yukki.

=head1 TYPES

=head2 LoginName

This is a valid login name. Login names may only contain letters and numbers, as of this writing.

=cut
45
46declare LoginName,
47    as Str,
48    where { /^[a-zA-Z0-9_-]{3,20}$/ },
49    message { "login name $_ must only contain letters and numbers" };
50
51 - 59
=head2 AccessLevel

This is a valid access level. This includes any of the following values:

  read
  write
  none

=cut
60
61enum AccessLevel, [qw( read write none )];
62
63 - 73
=head2 NavigationLinks

This is an array of hashes formatted like:

  {
      label => 'Label',
      href  => '/link/to/somewhere',
      sort  => 40,
  }

=cut
74
75declare NavigationLinks,
76    as ArrayRef[
77        Dict[
78            label => Str,
79            href  => Str|Uri,
80            sort  => Maybe[Int],
81        ],
82    ];
83
84 - 88
=head2 NavigationMenuMap

This is a hash of L</NavigationLinks>.

=cut
89
90declare NavigationMenuMap,
91    as HashRef[ NavigationLinks ];
92
93 - 97
=head2 BaseURL

This is either an absolute URL or the words C<SCRIPT_NAME> or C<REWRITE>.

=cut
98
99enum BaseURLEnum, [qw( SCRIPT_NAME REWRITE )];
100
101declare BaseURL, as BaseURLEnum|Uri;
102
103coerce BaseURL,
104    from Str,
105    via {
106        $_ !~ /^(?:SCRIPT_NAME|REWRITE)$/
107            && URI->new($_)
108    };
109
110 - 119
=head2 BreadcrumbLinks

This is an array of hashes formatted like:

  {
      label => 'Label',
      href  => '/link/to/somewhere',
  }

=cut
120
121declare BreadcrumbLinks,
122    as ArrayRef[
123        Dict[
124            label => Str,
125            href  => Str,
126        ],
127    ];
128
129 - 133
=head2 RepositoryMap

This is a hash of L<Yukki::Settings::Repository> objects.

=cut
134
135my $Repository = class_type 'Yukki::Settings::Repository';
136declare RepositoryMap,
137    as HashRef[$Repository];
138
139coerce RepositoryMap,
140    from HashRef,
141    via {
142        my $source = $_;
143        +{
144            map { $_ => Yukki::Settings::Repository->new($source->{$_}) }
145                keys %$source
146        }
147    };
148
149 - 153
=head2 PrivilegeMap

This is a hash of L<Yukki::Settings::Privileges> objects.

=cut
154
155my $Privileges = class_type 'Yukki::Settings::Privileges';
156declare PrivilegesMap,
157    as HashRef[$Privileges];
158
159coerce PrivilegesMap,
160    from HashRef,
161    via {
162        my $source = $_;
163        +{
164            map { $_ => Yukki::Settings::Privileges->new($source->{$_}) }
165                keys %$source
166        }
167    };
168
169 - 173
=head2 PluginConfig

A plugin configuration is an array of hashes. Each hash must have at least one key named "module" defined.

=cut
174
175declare PluginConfig,
176    as ArrayRef[HashRef],
177    where { all { defined $_->{module} } @$_ };
178
179 - 183
=head2 PluginList

A plugin list is a loaded set of plugin objects.

=cut
184
185my $Plugin = class_type 'Yukki::Web::Plugin';
186declare PluginList,
187    as ArrayRef[$Plugin],
188    message {
189        return 'It is not an array of objects.' unless ref $_ eq 'ARRAY';
190        my $bad = first { not blessed $_ or not $_->isa('Yukki::Web::Plugin') }
191                        @$_;
192        $bad = blessed $bad if blessed $bad;
193        return "It contains $bad, which is not a Yukki::Web::Plugin.";
194    };
195
196 - 204
=head1 COERCIONS

In addition to the types above, these coercions are provided for other types.

=head2 EmailAddress

Coerces a C<Str> into an L<Email::Address>.

=cut
205
206class_type EmailAddress, { class => 'Email::Address' };
207coerce EmailAddress,
208    from Str,
209    via { (Email::Address->parse($_))[0] };
210
211 - 215
=head2 YukkiSettings

Coerces a C<HashRef> into this object by passing the value to the constructor.

=cut
216
217class_type YukkiSettings, { class => 'Yukki::Settings' };
218coerce YukkiSettings,
219    from HashRef,
220    via { Yukki::Settings->new($_) };
221
222 - 226
=head2 YukkiWebSettings

Coerces a C<HashRef> into a L<Yukki::Web::Settings>.

=cut
227
228class_type YukkiWebSettings, { class => 'Yukki::Web::Settings' };
229coerce YukkiWebSettings,
230    from HashRef,
231    via { Yukki::Web::Settings->new($_) };
232
233 - 237
=head2 YukkiSettingsAnonymous

Coerces a C<HashRef> into this object by passing the value to the constructor.

=cut
238
239class_type YukkiSettingsAnonymous, { class => 'Yukki::Settings::Anonymous' };
240coerce YukkiSettingsAnonymous,
241    from HashRef,
242    via { Yukki::Settings::Anonymous->new($_) };
243
2441;