File: | lib/Yukki/Types.pm |
Coverage: | 100.0% |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | package 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 | |||||||
46 | declare 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 | |||||||
61 | enum 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 | |||||||
75 | declare 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 | |||||||
90 | declare 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 | |||||||
99 | enum BaseURLEnum, [qw( SCRIPT_NAME REWRITE )]; | ||||||
100 | |||||||
101 | declare BaseURL, as BaseURLEnum|Uri; | ||||||
102 | |||||||
103 | coerce 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 | |||||||
121 | declare 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 | |||||||
135 | my $Repository = class_type 'Yukki::Settings::Repository'; | ||||||
136 | declare RepositoryMap, | ||||||
137 | as HashRef[$Repository]; | ||||||
138 | |||||||
139 | coerce 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 | |||||||
155 | my $Privileges = class_type 'Yukki::Settings::Privileges'; | ||||||
156 | declare PrivilegesMap, | ||||||
157 | as HashRef[$Privileges]; | ||||||
158 | |||||||
159 | coerce 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 | |||||||
175 | declare 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 | |||||||
185 | my $Plugin = class_type 'Yukki::Web::Plugin'; | ||||||
186 | declare 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 | |||||||
206 | class_type EmailAddress, { class => 'Email::Address' }; | ||||||
207 | coerce 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 | |||||||
217 | class_type YukkiSettings, { class => 'Yukki::Settings' }; | ||||||
218 | coerce 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 | |||||||
228 | class_type YukkiWebSettings, { class => 'Yukki::Web::Settings' }; | ||||||
229 | coerce 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 | |||||||
239 | class_type YukkiSettingsAnonymous, { class => 'Yukki::Settings::Anonymous' }; | ||||||
240 | coerce YukkiSettingsAnonymous, | ||||||
241 | from HashRef, | ||||||
242 | via { Yukki::Settings::Anonymous->new($_) }; | ||||||
243 | |||||||
244 | 1; |