File Coverage

blib/lib/Params/Dry.pm
Criterion Covered Total %
statement 84 109 77.0
branch 9 30 30.0
condition 1 14 7.1
subroutine 26 27 96.3
pod 4 4 100.0
total 124 184 67.3


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   32075 use strict;
  2         5  
  2         102  
29 2     2   11 use warnings;
  2         4  
  2         62  
30              
31 2     2   34 use 5.10.0;
  2         17  
  2         132  
32              
33             # --- version ---
34             our $VERSION = 1.20_03;
35              
36             #=------------------------------------------------------------------------ { use, constants }
37              
38 2     2   10 use Carp; # confess
  2         2  
  2         182  
39              
40 2     2   1368 use Params::Dry::Types; # to mark that will reserving this namespace (build in types)
  2         5  
  2         115  
41 2     2   12 use Params::Dry::Types; # to mark that will reserving this namespace (build in types)
  2         5  
  2         61  
42 2     2   1366 use Params::Dry::Types::String; # string extended types
  2         6  
  2         51  
43 2     2   1391 use Params::Dry::Types::Object; # object extended types
  2         4  
  2         51  
44 2     2   1598 use Params::Dry::Types::DateTime; # datetime extended types
  2         4  
  2         55  
45 2     2   1425 use Params::Dry::Types::Number; # number extended types
  2         6  
  2         54  
46 2     2   1364 use Params::Dry::Types::Ref; # ref extended types
  2         4  
  2         70  
47              
48 2     2   43 use constant DEFAULT_TYPE => 1; # default check (for param_op)
  2         2  
  2         116  
49 2     2   9 use constant TRUE => 1; # true
  2         2  
  2         75  
50 2     2   9 use constant FALSE => 0; # and false
  2         3  
  2         85  
51 2     2   10 use constant OK => TRUE; # true
  2         2  
  2         89  
52 2     2   9 use constant NO => FALSE; # false
  2         3  
  2         106  
53              
54             our $Debug = FALSE; # use Debug mode or not
55              
56             #=------------------------------------------------------------------------ { export }
57              
58             # import strict params
59              
60 2     2   1777 use parent 'Exporter';
  2         601  
  2         11  
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     10   26 my ( $package, $filename, $line, $subroutine, $evaltext ) = ( caller( 1 ) )[ 0 .. 3, 6 ];
79              
80 10   50     507 my $message = ' at ' . ( $subroutine || $evaltext || 'no sub' ) . " line $line\n";
81 10         15 my $debug = "\nvim $filename +$line\n\n";
82              
83 10 50       90 ( $Params::Dry::Debug ) ? confess( @_, $message, $debug ) : die( @_, $message );
84             } #+ end of: sub _error
85              
86             #=-----------------------
87             # __get_effective_type
88             #=-----------------------
89             #* counts effective type of type (ex. for super_client base type is client and for client base type is String[20]
90             #* so for super_client final type will be String[20])
91             #* RETURN: final type string
92             sub __get_effective_type {
93 55     55   81 my $param_type = $Params::Dry::Internal::typedefs{ "$_[0]" };
94              
95 55 100       121 if ( $param_type ) {
96              
97 22         48 my @effective_params_list = map { split /\s*\|\s*/, __get_effective_type( $_ ) } split /\s*\|\s*/, $param_type;
  24         78  
98              
99 22         25 return join '|', sort keys %{ { map { $_ => 1 } @effective_params_list } };
  22         23  
  24         205  
100              
101             } else {
102 33         91 return $_[0];
103             } #+ end of: else [ if ( $param_type ) ]
104              
105             } #+ end of: sub __get_effective_type
106              
107             #=--------------------
108             # __check_parameter
109             #=--------------------
110             #* checks validity of the parameter
111             #* RETURN: param value
112             sub __check_parameter {
113 0     0   0 my ( $p_name, $p_type, $p_default, $p_is_required ) = @_;
114              
115             # --- check internal syntax ---
116 0 0       0 _error( "Name of the parameter has to be defined" ) unless $p_name;
117              
118             # --- detect type (set explicite or get it from name?)
119 0 0 0     0 my $counted_param_type = ( !defined( $p_type ) or ( $p_type =~ /^\d+$/ and $p_type == DEFAULT_TYPE ) ) ? $p_name : $p_type;
120              
121             # --- check effective parameter definition
122 0         0 my $effective_param_type = __get_effective_type( $counted_param_type );
123              
124             # --- 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)
125 0 0       0 if ( $Params::Dry::Internal::typedefs{ "$p_name" } ) {
126 0         0 my $effective_name_type = __get_effective_type( $p_name );
127 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)" )
128             if $effective_name_type ne $effective_param_type;
129             } #+ end of: if ( $Params::Dry::Internal::typedefs...)
130              
131             # --- getting final parameter value ---
132 0   0     0 my $param_value = ( $Params::Dry::Internal::current_params->{ "$p_name" } ) // $p_default // undef;
      0        
133              
134             # --- required / optional
135 0 0       0 if ( !defined( $param_value ) ) {
136 0 0       0 ( $p_is_required ) ? _error( "Parameter '$p_name' is required)" ) : return;
137             } #+ end of: if ( !defined( $param_value...))
138              
139 0         0 my @check_functions = ();
140              
141             # --- prepare all check functions names and its parameters
142 0         0 for my $effective_param_type ( split /\s*\|\s*/, $effective_param_type ) {
143              
144             # --- get package, function and parameters
145 0         0 my ( $type_package, $type_function, $parameters ) = $effective_param_type =~ /^(?:(.+)::)?([^\[]+)(?:\[(.+?)\])?/;
146              
147 0 0       0 my $final_type_package = ( $type_package ) ? 'Params::Dry::Types::' . $type_package : 'Params::Dry::Types';
148              
149 0   0     0 my @type_parameters = split /\s*,\s*/, $parameters // '';
150              
151             # --- set default type unless type ---
152 0 0       0 _error( "Type $counted_param_type ($effective_param_type) is not defined" ) unless $final_type_package->can( "$type_function" );
153              
154 0         0 push @check_functions, { check_function => $final_type_package . '::' . $type_function, type_parameters => \@type_parameters };
155             } #+ end of: for my $effective_param_type...
156              
157             # --- check if is valid
158 0         0 my $is_valid = NO;
159 0         0 for my $check_function_hash ( @check_functions ) {
160 0         0 my $check_function = $check_function_hash->{ 'check_function' };
161 0   0     0 my $type_parameters = $check_function_hash->{ 'type_parameters' } || [];
162             {
163 2     2   1734 no strict 'refs';
  2         4  
  2         878  
  0         0  
164 0 0       0 &$check_function( $param_value, @$type_parameters ) and $is_valid = TRUE;
165             }
166             } #+ end of: for my $check_function_hash...
167 0 0       0 _error( "Parameter '$p_name' is not '$counted_param_type' type (effective: $effective_param_type)" ) unless $is_valid;
168              
169 0         0 $param_value;
170             } #+ end of: sub __check_parameter
171              
172             #=------------------------------------------------------------------------ { module public functions }
173              
174             #=-----
175             # rq
176             #=-----
177             #* check if required parameter exists, if yes check it, if not report error
178             #* RETURN: param value
179             sub rq($;$$) {
180 1     1 1 2 my ( $p_name, $p_type, $p_default ) = @_;
181              
182 1         4 return __check_parameter( $p_name, $p_type, $p_default, TRUE );
183             } #+ end of: sub rq($;$$)
184              
185             #=-----
186             # op
187             #=-----
188             #* check if required parameter exists, if yes check it, if not return undef
189             #* RETURN: param value
190             sub op($;$$) {
191 1     1 1 2 my ( $p_name, $p_type, $p_default ) = @_;
192              
193 1         4 return __check_parameter( $p_name, $p_type, $p_default, FALSE );
194             } #+ end of: sub op($;$$)
195              
196             #=------
197             # tdef
198             #=------
199             #* make relation between name and definition, which can be used to check param types
200             #* RETURN: name of the type
201             sub tdef($$) {
202 10     10 1 11292 my ( $p_name, $p_definition ) = @_;
203              
204 10 100       50 if ( exists $Params::Dry::Internal::typedefs{ $p_name } ) {
205 3 100       8 _error( "Error parameter $p_name already defined as $p_definition" )
206             if __get_effective_type( $Params::Dry::Internal::typedefs{ $p_name } ) ne __get_effective_type( $p_definition );
207             } #+ end of: if ( exists $Params::Dry::Internal::typedefs...)
208              
209             # --- just add new definition
210 9         17 $Params::Dry::Internal::typedefs{ $p_name } = $p_definition;
211              
212 9         18 return $p_name;
213              
214             } #+ end of: sub tdef($$)
215              
216             #=-----
217             # __
218             #=-----
219             #* gets the parameters to internal use
220             # RETURN: first param if params like (object, %params) or undef otherwise
221             sub __ {
222 15 100   15   1552 my $self = ( ( scalar @_ % 2 ) ? shift : undef );
223 15         44 push @Params::Dry::Internal::params_stack, { @_ };
224 15         24 $Params::Dry::Internal::current_params = $Params::Dry::Internal::params_stack[-1];
225              
226 15         23 return $self;
227             } #+ end of: sub __
228              
229             #=----------
230             # no_more
231             #=----------
232             #* mark end of param processing part
233             #* required in case param call during param checking
234             # RETURN: current params
235             sub no_more() {
236              
237 3     3 1 4247 pop @Params::Dry::Internal::params_stack;
238 3         7 $Params::Dry::Internal::current_params = $Params::Dry::Internal::params_stack[-1];
239             } #+ end of: sub no_more
240              
241             # --- add additional names for funtions (long)
242              
243             {
244 2     2   11 no warnings 'once';
  2         3  
  2         175  
245              
246             *param_rq = *rq;
247             *param_op = *op;
248             *typedef = *tdef;
249             };
250             };
251             0115 && 0x4d;
252              
253             # ABSTRACT: Simple Global Params Management System
254              
255             #+ End of Params::Dry
256             __END__