File Coverage

blib/lib/Env/Assert.pm
Criterion Covered Total %
statement 63 75 84.0
branch 13 26 50.0
condition 9 15 60.0
subroutine 9 10 90.0
pod 3 3 100.0
total 97 129 75.1


line stmt bran cond sub pod time code
1             ## no critic [ControlStructures::ProhibitPostfixControls]
2             ## no critic [ValuesAndExpressions::ProhibitConstantPragma]
3             ## no critic (ControlStructures::ProhibitCascadingIfElse)
4             package Env::Assert;
5 3     3   730285 use strict;
  3         24  
  3         86  
6 3     3   15 use warnings;
  3         10  
  3         77  
7              
8 3     3   15 use Exporter 'import';
  3         5  
  3         170  
9             our @EXPORT_OK = qw(
10             assert
11             report_errors
12             file_to_desc
13             );
14             our %EXPORT_TAGS = ( 'all' => [qw( assert report_errors file_to_desc )], );
15              
16 3     3   1715 use English qw( -no_match_vars ); # Avoids regex performance penalty in perl 5.18 and earlier
  3         11525  
  3         17  
17 3     3   1107 use Carp;
  3         8  
  3         223  
18              
19             # ABSTRACT: Ensure that the environment variables match what you need, or abort.
20              
21             our $VERSION = '0.008'; # VERSION: generated by DZP::OurPkgVersion
22              
23             use constant {
24 3         3287 ENV_ASSERT_MISSING_FROM_ENVIRONMENT => 1,
25             ENV_ASSERT_INVALID_CONTENT_IN_VARIABLE => 2,
26             ENV_ASSERT_MISSING_FROM_DEFINITION => 3,
27             DEFAULT_PARAMETER_BREAK_AT_FIRST_ERROR => 0,
28             INDENT => q{ },
29 3     3   18 };
  3         5  
30              
31             sub assert {
32 5     5 1 12049 my ( $env, $want, $params ) = @_;
33 5 50       16 $params = {} if !$params;
34 5 50 33     29 croak 'Invalid options. Not a hash' if ( ref $env ne 'HASH' || ref $want ne 'HASH' );
35              
36             # Set default options
37 5   100     19 $params->{'break_at_first_error'} //= DEFAULT_PARAMETER_BREAK_AT_FIRST_ERROR;
38              
39 5         8 my $success = 1;
40 5         8 my %errors;
41 5         7 my $vars = $want->{'variables'};
42 5         8 my $opts = $want->{'options'};
43 5         8 foreach my $var_name ( keys %{$vars} ) {
  5         16  
44 7         15 my $var = $vars->{$var_name};
45 7   50     15 my $required = $var->{'required'} // 1;
46 7   50     13 my $regexp = $var->{'regexp'} // q{.*};
47 7 100 66     256 if ( ( $opts->{'exact'} || $required ) && !defined $env->{$var_name} ) {
    100 66        
48 3         6 $success = 0;
49 3         18 $errors{'variables'}->{$var_name} = {
50             type => ENV_ASSERT_MISSING_FROM_ENVIRONMENT,
51             message => "Variable $var_name is missing from environment",
52             };
53 3 50       9 goto EXIT if ( $params->{'break_at_first_error'} );
54             }
55             elsif ( $env->{$var_name} !~ m/$regexp/msx ) {
56 1         5 $success = 0;
57 1         8 $errors{'variables'}->{$var_name} = {
58             type => ENV_ASSERT_INVALID_CONTENT_IN_VARIABLE,
59             message => "Variable $var_name has invalid content",
60             };
61 1 50       7 goto EXIT if ( $params->{'break_at_first_error'} );
62             }
63             }
64 5 100       15 if ( $opts->{'exact'} ) {
65 4         5 foreach my $var_name ( keys %{$env} ) {
  4         22  
66 6 100       15 if ( !exists $vars->{$var_name} ) {
67 2         3 $success = 0;
68 2         12 $errors{'variables'}->{$var_name} = {
69             type => ENV_ASSERT_MISSING_FROM_DEFINITION,
70             message => "Variable $var_name is missing from description",
71             };
72 2 50       8 goto EXIT if ( $params->{'break_at_first_error'} );
73             }
74             }
75             }
76              
77             EXIT:
78 5         32 return { success => $success, errors => \%errors, };
79             }
80              
81             sub report_errors {
82 3     3 1 7148 my ($errors) = @_;
83 3         5 my $out = q{};
84 3         9 $out .= sprintf "Environment Assert: ERRORS:\n";
85 3         4 foreach my $error_area_name ( sort keys %{$errors} ) {
  3         11  
86 2         10 $out .= sprintf "%s%s:\n", INDENT, $error_area_name;
87 2         3 foreach my $error_key ( sort keys %{ $errors->{$error_area_name} } ) {
  2         9  
88 3         14 $out .= sprintf "%s%s: %s\n", INDENT . INDENT, $error_key, $errors->{$error_area_name}->{$error_key}->{'message'};
89             }
90             }
91 3         8 return $out;
92             }
93              
94             sub file_to_desc {
95 0     0 1 0 my @rows = @_;
96 0         0 my %desc = ( 'options' => {}, 'variables' => {}, );
97 0         0 foreach (@rows) {
98              
99             # This is envassert meta command
100             ## no critic (RegularExpressions::ProhibitComplexRegexes)
101 0 0       0 if (
    0          
    0          
    0          
102             m{
103             ^ [[:space:]]{0,} [#]{2}
104             [[:space:]]{1,} envassert [[:space:]]{1,}
105             [(] opts: [[:space:]]{0,} (? .*) [)]
106             [[:space:]]{0,} $
107             }msx
108             )
109             {
110 0         0 my $opts = _interpret_opts( $LAST_PAREN_MATCH{opts} );
111 0         0 foreach ( keys %{$opts} ) {
  0         0  
112 0         0 $desc{'options'}->{$_} = $opts->{$_};
113             }
114             }
115             elsif (
116             # This is comment row
117             m{
118             ^ [[:space:]]{0,} [#]{1} .* $
119             }msx
120             )
121             {
122 0         0 1;
123             }
124             elsif (
125             # This is empty row
126             m{
127             ^ [[:space:]]{0,} $
128             }msx
129             )
130             {
131 0         0 1;
132             }
133             elsif (
134             # This is env var description
135             m{
136             ^ (? [^=]{1,}) = (? .*) $
137             }msx
138             )
139             {
140 0         0 $desc{'variables'}->{ $LAST_PAREN_MATCH{name} } = { regexp => $LAST_PAREN_MATCH{value} };
141             }
142             }
143 0         0 return \%desc;
144             }
145              
146             # Private subroutines
147              
148             sub _interpret_opts {
149 6     6   9982 my ($opts_str) = @_;
150 6         53 my @opts = split qr{
151             [[:space:]]{0,} [,] [[:space:]]{0,}
152             }msx, $opts_str;
153 6         15 my %opts;
154 6         15 foreach (@opts) {
155 11         43 my ( $key, $val ) = split qr/=/msx;
156 11         31 $opts{$key} = $val;
157             }
158 6         23 return \%opts;
159             }
160              
161             1;
162              
163             __END__