File Coverage

blib/lib/Stancer/Core/Types/Helper.pm
Criterion Covered Total %
statement 90 91 98.9
branch 41 42 97.6
condition 3 3 100.0
subroutine 23 23 100.0
pod 7 7 100.0
total 164 166 98.8


line stmt bran cond sub pod time code
1             package Stancer::Core::Types::Helper;
2              
3 73     73   131976 use 5.020;
  73         285  
4 73     73   504 use strict;
  73         234  
  73         2221  
5 73     73   376 use warnings;
  73         185  
  73         5908  
6              
7             # ABSTRACT: Internal types helpers
8             our $VERSION = '1.0.3'; # VERSION
9              
10 73     73   71516 use DateTime;
  73         45274176  
  73         5158  
11 73     73   934 use Scalar::Util qw(blessed);
  73         203  
  73         6299  
12 73     73   51734 use MooX::Types::MooseLike qw();
  73         145532  
  73         2357  
13              
14 73     73   637 use namespace::clean;
  73         164  
  73         760  
15              
16 73     73   21826 use Exporter qw(import);
  73         187  
  73         88808  
17              
18             our @EXPORT_OK = qw(coerce_boolean coerce_date coerce_datetime coerce_instance create_instance_type error_message);
19             our %EXPORT_TAGS = ('all' => \@EXPORT_OK);
20              
21              
22             sub coerce_boolean {
23             return sub {
24 87     87   473214 my $value = shift;
25              
26 87 100       1161 return if not defined $value;
27 57 100       381 return 1 if "$value" eq 'true';
28 56 100       499 return 0 if "$value" eq 'false';
29 55         1360 return $value;
30 51     51 1 446428 };
31             }
32              
33              
34             sub coerce_date {
35             return sub {
36 27     27   12693 my $value = shift;
37 27         73 my $blessed = blessed($value);
38              
39 27 100       264 return if not defined $value;
40              
41 19 100       70 if (defined $blessed) {
42 5 100       38 return if $blessed ne 'DateTime';
43 4         24 return $value->clone()->truncate(to => 'day');
44             }
45              
46 14         209 my ($y, $m, $d) = split qr/-/sm, $value;
47              
48 14 100       181 return DateTime->new(year => $y, month => $m, day => $d)->truncate(to => 'day') if defined $d;
49 1         7 return DateTime->from_epoch(epoch => $value)->truncate(to => 'day');
50 18     18 1 3444 };
51             }
52              
53              
54             sub coerce_datetime {
55             return sub {
56 257     257   13074 my $value = shift;
57              
58 257 100       2861 return if not defined $value;
59              
60 176         1607 my $config = Stancer::Config->init();
61 176         941 my %data = (
62             epoch => $value,
63             );
64 176         438 my $blessed = blessed($value);
65              
66 176 100       587 if (defined $blessed) {
67 7 100       56 return if $blessed ne 'DateTime';
68 6         195 return $value;
69             }
70              
71 169 100 100     5517 if (defined $config && defined $config->default_timezone) {
72 126         3890 $data{time_zone} = $config->default_timezone;
73             }
74              
75 169         2801 return DateTime->from_epoch(%data);
76 98     98 1 59614 };
77             }
78              
79              
80             sub coerce_instance {
81 83     83 1 3205 my $class = shift;
82              
83             return sub {
84 210     210   10356 my $value = shift;
85 210         662 my $blessed = blessed($value);
86              
87 210 100       3043 return $value if not defined $value;
88              
89 112 100       522 if (defined $blessed) {
90 44 100       1088 return $value if $blessed eq $class;
91 1         6 return;
92             }
93              
94 68         2538 return $class->new($value);
95 83         857 };
96             }
97              
98              
99             sub create_instance_type {
100 480     480 1 808 my $type = shift;
101 480         1025 my $class = 'Stancer::' . $type;
102 480         747 my $name = $type;
103              
104 480         982 $name =~ s/:://gsm;
105              
106             return {
107             name => $name . 'Instance',
108             exception => 'Stancer::Exceptions::Invalid' . $name . 'Instance',
109             test => sub {
110 173     173   93288 my $instance = shift;
111              
112 173 100       644 return if not defined $instance;
113 165 100       581 return if not blessed $instance;
114 149         1203 return $instance->isa($class);
115             },
116             message => sub {
117 32     32   67 my $instance = shift;
118              
119 32 100       137 return 'No instance given.' if not defined $instance;
120 24 100       218 return sprintf '"%s" is not blessed.', $instance if not blessed $instance;
121 8         228 return sprintf '%s is not an instance of "%s".', $instance, $class;
122             },
123 480         4430 };
124             }
125              
126              
127             sub error_message {
128 1169     1169 1 10228 my $message = shift;
129              
130             return sub {
131 169     169   43982 my $value = shift;
132              
133 169 100       533 if (defined $value) {
134 145         431 $value = q/"/ . $value . q/"/;
135             } else {
136 24         70 $value = 'undef';
137             }
138              
139 169         2314 return sprintf $message, $value, @_;
140 1169         9388 };
141             }
142              
143              
144             sub register_types {
145 428     428 1 1536 my ($defs, $package) = @_;
146              
147 428         880 for my $def (@{ $defs }) {
  428         1410  
148 2572 100       6361 if (defined $def->{exception}) {
149 1830         3547 my $class = $def->{exception};
150 1830         3030 my $message = $def->{message};
151              
152             $def->{message} = sub {
153 131 50   131   36521 if (ref $message eq 'CODE') {
154 131         450 $class->throw(message => $message->(@_));
155             }
156              
157 0         0 $class->throw(message => $message);
158 1830         7516 };
159             }
160             }
161              
162 428         2837 return MooX::Types::MooseLike::register_types($defs, $package);
163             }
164              
165             1;
166              
167             __END__
168              
169             =pod
170              
171             =encoding UTF-8
172              
173             =head1 NAME
174              
175             Stancer::Core::Types::Helper - Internal types helpers
176              
177             =head1 VERSION
178              
179             version 1.0.3
180              
181             =head1 FUNCTIONS
182              
183             =head2 C<< coerce_boolean() : I<CODE> >>
184              
185             Helper function for C<Bool> type attribute.
186              
187             =head2 C<< coerce_date() : I<CODE> >>
188              
189             Helper function for C<DateTime> type attribute.
190              
191             =head2 C<< coerce_datetime() : I<CODE> >>
192              
193             Helper function for C<DateTime> type attribute.
194              
195             =head2 C<< coerce_instance() : I<CODE> >>
196              
197             Helper function for instances type attribute.
198              
199             =head2 C<< create_instance_type(I<$prefix>) >>
200              
201             Helper function to create an "InstanceOf" type.
202              
203             =head2 C<< error_message(I<$message>) >>
204              
205             =head2 C<< error_message(I<$message>, I<@args>) >>
206              
207             Helper function to be used in a type definition:
208              
209             {
210             ...
211             message => error_message('%s is not an integer'),
212             ...
213             }
214              
215             It will produce:
216              
217             '"something" is not an integer'
218             # or with an undefined value
219             'undef is not an integer'
220              
221             If I<@args> is provided, it will passed to C<sprintf> internal function.
222              
223             {
224             ...
225             name => 'Char',
226             message => error_message('Must be exactly %2$d characters, tried with %1$s.'),
227             ...
228             }
229              
230             Will produce for a C<Char[20]> attribute:
231              
232             'Must be exactly 20 characters, tried with "something".'
233              
234             =head2 C<< register_types( I<$types>, I<$package> ) >>
235              
236             Install the given types within the package.
237              
238             This will use C< MooX::Types::MooseLike::register_types() >.
239              
240             =head1 USAGE
241              
242             =head2 Logging
243              
244              
245              
246             We use the L<Log::Any> framework for logging events.
247             You may tell where it should log using any available L<Log::Any::Adapter> module.
248              
249             For example, to log everything to a file you just have to add a line to your script, like this:
250             #! /usr/bin/env perl
251             use Log::Any::Adapter (File => '/var/log/payment.log');
252             use Stancer::Core::Types::Helper;
253              
254             You must import C<Log::Any::Adapter> before our libraries, to initialize the logger instance before use.
255              
256             You can choose your log level on import directly:
257             use Log::Any::Adapter (File => '/var/log/payment.log', log_level => 'info');
258              
259             Read the L<Log::Any> documentation to know what other options you have.
260              
261             =cut
262              
263             =head1 SECURITY
264              
265             =over
266              
267             =item *
268              
269             Never, never, NEVER register a card or a bank account number in your database.
270              
271             =item *
272              
273             Always uses HTTPS in card/SEPA in communication.
274              
275             =item *
276              
277             Our API will never give you a complete card/SEPA number, only the last four digits.
278             If you need to keep track, use these last four digit.
279              
280             =back
281              
282             =cut
283              
284             =head1 BUGS
285              
286             Please report any bugs or feature requests on the bugtracker website
287             L<https://gitlab.com/wearestancer/library/lib-perl/-/issues> or by email to
288             L<bug-stancer@rt.cpan.org|mailto:bug-stancer@rt.cpan.org>.
289              
290             When submitting a bug or request, please include a test-file or a
291             patch to an existing test-file that illustrates the bug or desired
292             feature.
293              
294             =head1 AUTHOR
295              
296             Joel Da Silva <jdasilva@cpan.org>
297              
298             =head1 COPYRIGHT AND LICENSE
299              
300             This software is Copyright (c) 2018-2024 by Stancer / Iliad78.
301              
302             This is free software, licensed under:
303              
304             The Artistic License 2.0 (GPL Compatible)
305              
306             =cut