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   676224 use strict;
  3         16  
  3         83  
6 3     3   16 use warnings;
  3         6  
  3         76  
7              
8 3     3   13 use Exporter 'import';
  3         6  
  3         208  
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   1532 use English qw( -no_match_vars ); # Avoids regex performance penalty in perl 5.18 and earlier
  3         10791  
  3         15  
17 3     3   1093 use Carp;
  3         8  
  3         258  
18              
19             # ABSTRACT: Ensure that the environment variables match what you need, or abort.
20              
21             our $VERSION = '0.007'; # VERSION: generated by DZP::OurPkgVersion
22              
23             use constant {
24 3         3161 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   29 };
  3         8  
30              
31             sub assert {
32 5     5 1 11060 my ( $env, $want, $params ) = @_;
33 5 50       13 $params = {} if !$params;
34 5 50 33     26 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         6 my %errors;
41 5         7 my $vars = $want->{'variables'};
42 5         9 my $opts = $want->{'options'};
43 5         6 foreach my $var_name ( keys %{$vars} ) {
  5         15  
44 7         13 my $var = $vars->{$var_name};
45 7   50     15 my $required = $var->{'required'} // 1;
46 7   50     15 my $regexp = $var->{'regexp'} // q{.*};
47 7 100 66     245 if ( ( $opts->{'exact'} || $required ) && !defined $env->{$var_name} ) {
    100 66        
48 3         6 $success = 0;
49 3         11 $errors{'variables'}->{$var_name} = {
50             type => ENV_ASSERT_MISSING_FROM_ENVIRONMENT,
51             message => "Variable $var_name is missing from environment",
52             };
53 3 50       10 goto EXIT if ( $params->{'break_at_first_error'} );
54             }
55             elsif ( $env->{$var_name} !~ m/$regexp/msx ) {
56 1         4 $success = 0;
57 1         6 $errors{'variables'}->{$var_name} = {
58             type => ENV_ASSERT_INVALID_CONTENT_IN_VARIABLE,
59             message => "Variable $var_name has invalid content",
60             };
61 1 50       5 goto EXIT if ( $params->{'break_at_first_error'} );
62             }
63             }
64 5 100       14 if ( $opts->{'exact'} ) {
65 4         5 foreach my $var_name ( keys %{$env} ) {
  4         11  
66 6 100       23 if ( !exists $vars->{$var_name} ) {
67 2         3 $success = 0;
68 2         15 $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         20 return { success => $success, errors => \%errors, };
79             }
80              
81             sub report_errors {
82 3     3 1 7116 my ($errors) = @_;
83 3         6 my $out = q{};
84 3         7 $out .= sprintf "Environment Assert: ERRORS:\n";
85 3         6 foreach my $error_area_name ( sort keys %{$errors} ) {
  3         10  
86 2         10 $out .= sprintf "%s%s:\n", INDENT, $error_area_name;
87 2         4 foreach my $error_key ( sort keys %{ $errors->{$error_area_name} } ) {
  2         7  
88 3         13 $out .= sprintf "%s%s: %s\n", INDENT . INDENT, $error_key, $errors->{$error_area_name}->{$error_key}->{'message'};
89             }
90             }
91 3         9 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   9680 my ($opts_str) = @_;
150 6         51 my @opts = split qr{
151             [[:space:]]{0,} [,] [[:space:]]{0,}
152             }msx, $opts_str;
153 6         13 my %opts;
154 6         12 foreach (@opts) {
155 11         42 my ( $key, $val ) = split qr/=/msx;
156 11         36 $opts{$key} = $val;
157             }
158 6         18 return \%opts;
159             }
160              
161             1;
162              
163             __END__