File Coverage

lib/Morpheus/Plugin/Content.pm
Criterion Covered Total %
statement 138 138 100.0
branch 19 26 73.0
condition n/a
subroutine 46 46 100.0
pod 0 4 0.0
total 203 214 94.8


line stmt bran cond sub pod time code
1             package Morpheus::Plugin::Content;
2             {
3             $Morpheus::Plugin::Content::VERSION = '0.46';
4             }
5              
6             # ABSTRACT: base class for plugins that evaluate user defined perl configs
7              
8              
9 5     5   41 use strict;
  5         13  
  5         230  
10              
11 5     5   28 use Morpheus::Utils qw(normalize);
  5         269  
  5         811  
12 5     5   31 use Digest::MD5 qw(md5_hex);
  5         10  
  5         299  
13 5     5   25 use Symbol qw(delete_package);
  5         11  
  5         4530  
14              
15             sub _package ($$) {
16 338     338   551 my ($self, $token) = @_;
17 338         1667 my $md5_self = md5_hex("$self");
18 338         1032 my $md5 = md5_hex($token);
19 338         964 $token =~ s/[^\w]/_/g;
20 338         533 $token = substr($token, 0, 64); # max identifier length is limited in perl
21 338         1542 return "Morpheus::Sandbox::${md5_self}::${token}_${md5}";
22             }
23              
24             sub DESTROY {
25 1     1   10 local $@;
26 1         2 my ($self) = @_;
27 1         42 my $md5_self = md5_hex("$self");
28 1         6 my $sandbox = "Morpheus::Sandbox::${md5_self}";
29 5     5   36 my $stash = do { no strict qw(refs); \%{"${sandbox}::"}; };
  5         10  
  5         6718  
  1         2  
  1         621  
  1         9  
30 1         2 for (keys %$stash) {
31 1 0       37 /^(.*)::$/ or next;
32 1         5 delete_package($sandbox."::$1");
33             }
34 1         2 delete_package($sandbox);
35             }
36              
37             sub content ($$) {
38 1     1 0 402 my ($self, $token) = @_;
39 1         5 die;
40             }
41              
42             sub _process ($$) {
43 240     240   349 my ($self, $token) = @_;
44 240 100       926 return if exists $self->{cache}->{$token};
45              
46 167         408 my $package = $self->_package($token);
47 167         523 my $content = $self->content($token);
48 167 100       725 return unless $content;
49              
50             # a partial evaluation support
51 26         93 $self->{cache}->{$token} = undef;
52             # this line makes it possible to properly process config blocks like
53             #############################
54             # $X = 5;
55             # $Y = morph("X") + 1; # 6
56             #############################
57            
58 26         47 my $pragma = "";
59 26 50       212 $pragma = qq{# line 1 "$token"} if $token =~ m{^[/\w\.\-]+$}; # looks like a file name
60              
61 3     3   24 my @eval = eval qq{
  3     3   8  
  3     1   122  
  3     1   16  
  3     1   5  
  3     1   2290  
  26     1   1866  
  1     1   7  
  1     1   2  
  1     1   32  
  1     1   4  
  1     1   2  
  1     1   284  
  1     1   5  
  1     1   2  
  1     1   30  
  1     1   5  
  1     1   2  
  1     1   328  
  1     1   6  
  1     1   1  
  1     1   31  
  1     1   6  
  1     1   2  
  1     1   317  
  1     1   7  
  1     1   2  
  1     1   31  
  1     1   6  
  1     1   1  
  1     1   318  
  1     1   7  
  1         3  
  1         35  
  1         7  
  1         2  
  1         384  
  1         7  
  1         1  
  1         34  
  1         5  
  1         3  
  1         286  
  1         10  
  1         3  
  1         47  
  1         6  
  1         2  
  1         372  
  1         10  
  1         2  
  1         41  
  1         6  
  1         2  
  1         363  
62             no strict;
63             no warnings;
64             package $package;
65             $pragma
66             $content
67             };
68 26 50       498 die if $@;
69              
70 26         561 $self->{cache}->{$token} = $self->_get($token);
71 26 100       91 unless (defined $self->{cache}->{$token}) {
72 22 50       59 if (@eval == 1) {
73 22         122 ($self->{cache}->{$token}) = @eval;
74             } else {
75 1         6 $self->{cache}->{$token} = {@eval};
76             }
77 22         111 $self->{cache}->{$token} = normalize($self->{cache}->{$token});
78             }
79 26 50       466 die "'$token': config block should return or define something" unless defined $self->{cache}->{$token};
80             }
81              
82             # get a value from the stash or from cache
83             sub _get ($$) {
84 265     265   385 my ($self, $token) = @_;
85 265 100       2864 return $self->{cache}->{$token} if defined $self->{cache}->{$token};
86              
87             # maybe a partially evaluated config block
88 172         479 my $package = $self->_package($token);
89 5     5   38 my $stash = do { no strict 'refs'; \%{"${package}::"} };
  5         12  
  5         1655  
  172         232  
  172         259  
  172         2827  
90 172         378 my $value;
91 172         565 for (keys %$stash) {
92 55 50       147 next unless $_;
93 55         143 my $glob = \$stash->{$_};
94 55 100       64 if (defined *{$glob}{HASH}) {
  55 100       484  
  52 100       102  
95             # warn "\%$_ defined at $token\n";
96 4         13 *{$glob} = normalize(*{$glob}{HASH});
  4         9  
  4         47  
97 4         18 $value->{$_} = $glob;
98 49         175 } elsif (defined *{$glob}{ARRAY}) {
99             # warn "\@$_ defined at $token\n";
100 4         366 $value->{$_} = $glob;
101 49         54 } elsif (defined ${*{$glob}}) {
102 22         54 $value->{$_} = normalize(${*{$glob}});
  22         27  
  22         83  
103             }
104             }
105 172         1063 return $value;
106             }
107              
108             sub list ($$) {
109 1     1 0 8 return (); # override it
110             }
111              
112             sub get ($$) {
113 240     240 0 388 my ($self, $token) = @_;
114 240         722 $self->_process($token);
115 240         681 return $self->_get($token);
116             }
117              
118             sub new {
119 5     5 0 12 my $class = shift;
120 5         458 bless { cache => {} } => $class;
121             }
122              
123             1;
124              
125             __END__