File Coverage

blib/lib/Params/Dry.pm
Criterion Covered Total %
statement 81 106 76.4
branch 9 30 30.0
condition 0 12 0.0
subroutine 26 27 96.3
pod 4 4 100.0
total 120 179 67.0


line stmt bran cond sub pod time code
1             #* Name: Params::Dry
2             #* Info: Simple Global Params Management System
3             #* Author: Pawel Guspiel (neo77)
4             #*
5             #* First. If you can use any function as in natural languague - you will use and understand it even after few months.
6             #*
7             #* Second. Your lazy life will be easy, and you will reduce a lot of errors if you will have guarancy that your parameter
8             #* for example ,,client'', in whole project means the same ( ex. is defined as string(32) ).
9             #*
10             #* Third. You are lazy, so to have this guarancy, you want to set it, in one and only in one place.
11             #*
12             #* Yes, DRY principle in its pure form!
13             #*
14             #* So all what you can find in this module.
15             #*
16             #* That's all. Easy to use. Easy to manage. Easy to understand.
17             #*
18             #* Additional informations
19             #* 1. I didn't wrote here any special extensions (callbacks, ordered parameter list, evals etc). Params module has to be fast.
20             #* If there will be any extension in future. It will be in separate module.
21             #* 2. Ordered parameters list or named parameter list? Named parameter list. For sure.
22             #* Majority of the time you are spending on READING code, not writing it. So for sure named parameter list is better.
23             #*
24              
25             package Params::Dry;
26             {
27              
28 2     2   25806 use strict;
  2         6  
  2         96  
29 2     2   12 use warnings;
  2         5  
  2         65  
30              
31 2     2   38 use 5.10.0;
  2         23  
  2         141  
32              
33             # --- version ---
34             our $VERSION = 1.20_01;
35              
36             #=------------------------------------------------------------------------ { use, constants }
37              
38 2     2   12 use Carp; # confess
  2         4  
  2         174  
39              
40 2     2   1449 use Params::Dry::Types; # to mark that will reserving this namespace (build in types)
  2         6  
  2         93  
41 2     2   11 use Params::Dry::Types; # to mark that will reserving this namespace (build in types)
  2         4  
  2         66  
42 2     2   1442 use Params::Dry::Types::String; # string extended types
  2         5  
  2         64  
43 2     2   1495 use Params::Dry::Types::Object; # object extended types
  2         5  
  2         60  
44 2     2   1539 use Params::Dry::Types::DateTime; # datetime extended types
  2         5  
  2         311  
45 2     2   1465 use Params::Dry::Types::Number; # number extended types
  2         6  
  2         62  
46 2     2   1544 use Params::Dry::Types::Ref; # ref extended types
  2         6  
  2         63  
47              
48 2     2   14 use constant DEFAULT_TYPE => 1; # default check (for param_op)
  2         4  
  2         131  
49 2     2   10 use constant TRUE => 1; # true
  2         4  
  2         85  
50 2     2   10 use constant FALSE => 0; # and false
  2         4  
  2         94  
51 2     2   11 use constant OK => TRUE; # true
  2         4  
  2         96  
52 2     2   8 use constant NO => FALSE; # false
  2         5  
  2         120  
53              
54             our $Debug = FALSE; # use Debug mode or not
55              
56             #=------------------------------------------------------------------------ { export }
57              
58             # import strict params
59              
60 2     2   1841 use parent 'Exporter';
  2         610  
  2         50  
61              
62             our @EXPORT_OK = qw(__ rq op tdef typedef no_more DEFAULT_TYPE param_rq param_op);
63              
64             our %EXPORT_TAGS = (
65             shorten => [qw(__ rq op tdef no_more DEFAULT_TYPE)],
66             short => [qw(__ rq op typedef no_more DEFAULT_TYPE)],
67             long => [qw(__ param_rq param_op typedef no_more DEFAULT_TYPE)]
68             );
69              
70             #=------------------------------------------------------------------------ { module private functions }
71              
72             #=---------
73             # _error
74             #=---------
75             #* printing error message
76             # RETURN: dies (in case of Debug is making confess)
77             sub _error {
78 10 50   10   123 ( $Params::Dry::Debug ) ? confess( @_ ) : die( @_ );
79             } #+ end of: sub _error
80              
81             #=-----------------------
82             # __get_effective_type
83             #=-----------------------
84             #* counts effective type of type (ex. for super_client base type is client and for client base type is String[20]
85             #* so for super_client final type will be String[20])
86             #* RETURN: final type string
87             sub __get_effective_type {
88 55     55   108 my $param_type = $Params::Dry::Internal::typedefs{ "$_[0]" };
89              
90 55 100       133 if ( $param_type ) {
91              
92 22         69 my @effective_params_list = map { split /\s*\|\s*/, __get_effective_type( $_ ) } split /\s*\|\s*/, $param_type;
  24         49  
93              
94 22         35 return join '|', sort keys %{ { map { $_ => 1 } @effective_params_list } };
  22         27  
  24         173  
95              
96             } else {
97 33         119 return $_[0];
98             } #+ end of: else [ if ( $param_type ) ]
99              
100             } #+ end of: sub __get_effective_type
101              
102             #=--------------------
103             # __check_parameter
104             #=--------------------
105             #* checks validity of the parameter
106             #* RETURN: param value
107             sub __check_parameter {
108 0     0   0 my ( $p_name, $p_type, $p_default, $p_is_required ) = @_;
109              
110             # --- check internal syntax ---
111 0 0       0 _error( "Name of the parameter has to be defined" ) unless $p_name;
112              
113             # --- detect type (set explicite or get it from name?)
114 0 0 0     0 my $counted_param_type = ( !defined( $p_type ) or ( $p_type =~ /^\d+$/ and $p_type == DEFAULT_TYPE ) ) ? $p_name : $p_type;
115              
116             # --- check effective parameter definition
117 0         0 my $effective_param_type = __get_effective_type( $counted_param_type );
118              
119             # --- check effective parameter definition for used name (if exists) and if user is not trying to replace name-type with new one (to keep clean naminigs)
120 0 0       0 if ( $Params::Dry::Internal::typedefs{ "$p_name" } ) {
121 0         0 my $effective_name_type = __get_effective_type( $p_name );
122 0 0       0 _error( "This variable $p_name is used before in code as $p_name type ($effective_name_type) and here you are trying to redefine it to $counted_param_type ($effective_param_type)" )
123             if $effective_name_type ne $effective_param_type;
124             } #+ end of: if ( $Params::Dry::Internal::typedefs...)
125              
126             # --- getting final parameter value ---
127 0   0     0 my $param_value = ( $Params::Dry::Internal::current_params->{ "$p_name" } ) // $p_default // undef;
      0        
128              
129             # --- required / optional
130 0 0       0 if ( !defined( $param_value ) ) {
131 0 0       0 ( $p_is_required ) ? _error( "Parameter '$p_name' is required)" ) : return;
132             } #+ end of: if ( !defined( $param_value...))
133              
134 0         0 my @check_functions = ();
135              
136             # --- prepare all check functions names and its parameters
137 0         0 for my $effective_param_type ( split /\s*\|\s*/, $effective_param_type ) {
138              
139             # --- get package, function and parameters
140 0         0 my ( $type_package, $type_function, $parameters ) = $effective_param_type =~ /^(?:(.+)::)?([^\[]+)(?:\[(.+?)\])?/;
141              
142 0 0       0 my $final_type_package = ( $type_package ) ? 'Params::Dry::Types::' . $type_package : 'Params::Dry::Types';
143              
144 0   0     0 my @type_parameters = split /\s*,\s*/, $parameters // '';
145              
146             # --- set default type unless type ---
147 0 0       0 _error( "Type $counted_param_type ($effective_param_type) is not defined" ) unless $final_type_package->can( "$type_function" );
148              
149 0         0 push @check_functions, { check_function => $final_type_package . '::' . $type_function, type_parameters => \@type_parameters };
150             } #+ end of: for my $effective_param_type...
151              
152             # --- check if is valid
153 0         0 my $is_valid = NO;
154 0         0 for my $check_function_hash ( @check_functions ) {
155 0         0 my $check_function = $check_function_hash->{ 'check_function' };
156 0   0     0 my $type_parameters = $check_function_hash->{ 'type_parameters' } || [];
157             {
158 2     2   1657 no strict 'refs';
  2         6  
  2         990  
  0         0  
159 0 0       0 &$check_function( $param_value, @$type_parameters ) and $is_valid = TRUE;
160             }
161             } #+ end of: for my $check_function_hash...
162 0 0       0 _error( "Parameter '$p_name' is not '$counted_param_type' type (effective: $effective_param_type)" ) unless $is_valid;
163              
164 0         0 $param_value;
165             } #+ end of: sub __check_parameter
166              
167             #=------------------------------------------------------------------------ { module public functions }
168              
169             #=-----
170             # rq
171             #=-----
172             #* check if required parameter exists, if yes check it, if not report error
173             #* RETURN: param value
174             sub rq($;$$) {
175 1     1 1 3 my ( $p_name, $p_type, $p_default ) = @_;
176              
177 1         5 return __check_parameter( $p_name, $p_type, $p_default, TRUE );
178             } #+ end of: sub rq($;$$)
179              
180             #=-----
181             # op
182             #=-----
183             #* check if required parameter exists, if yes check it, if not return undef
184             #* RETURN: param value
185             sub op($;$$) {
186 1     1 1 3 my ( $p_name, $p_type, $p_default ) = @_;
187              
188 1         5 return __check_parameter( $p_name, $p_type, $p_default, FALSE );
189             } #+ end of: sub op($;$$)
190              
191             #=------
192             # tdef
193             #=------
194             #* make relation between name and definition, which can be used to check param types
195             #* RETURN: name of the type
196             sub tdef($$) {
197 10     10 1 9520 my ( $p_name, $p_definition ) = @_;
198              
199 10 100       32 if ( exists $Params::Dry::Internal::typedefs{ $p_name } ) {
200 3 100       12 _error( "Error parameter $p_name already defined as $p_definition" )
201             if __get_effective_type( $Params::Dry::Internal::typedefs{ $p_name } ) ne __get_effective_type( $p_definition );
202             } #+ end of: if ( exists $Params::Dry::Internal::typedefs...)
203              
204             # --- just add new definition
205 9         24 $Params::Dry::Internal::typedefs{ $p_name } = $p_definition;
206              
207 9         23 return $p_name;
208              
209             } #+ end of: sub tdef($$)
210              
211             #=-----
212             # __
213             #=-----
214             #* gets the parameters to internal use
215             # RETURN: first param if params like (object, %params) or undef otherwise
216             sub __ {
217 15 100   15   1094 my $self = ( ( scalar @_ % 2 ) ? shift : undef );
218 15         58 push @Params::Dry::Internal::params_stack, { @_ };
219 15         21 $Params::Dry::Internal::current_params = $Params::Dry::Internal::params_stack[-1];
220              
221 15         28 return $self;
222             } #+ end of: sub __
223              
224             #=----------
225             # no_more
226             #=----------
227             #* mark end of param processing part
228             #* required in case param call during param checking
229             # RETURN: current params
230             sub no_more() {
231              
232 3     3 1 3142 pop @Params::Dry::Internal::params_stack;
233 3         8 $Params::Dry::Internal::current_params = $Params::Dry::Internal::params_stack[-1];
234             } #+ end of: sub no_more
235              
236             # --- add additional names for funtions (long)
237              
238             {
239 2     2   13 no warnings 'once';
  2         4  
  2         204  
240              
241             *param_rq = *rq;
242             *param_op = *op;
243             *typedef = *tdef;
244             };
245             };
246             0115 && 0x4d;
247              
248             # ABSTRACT: Simple Global Params Management System
249              
250             #+ End of Params::Dry
251             __END__