File Coverage

blib/lib/Test/WriteVariants/Context.pm
Criterion Covered Total %
statement 56 125 44.8
branch 4 22 18.1
condition 0 6 0.0
subroutine 18 40 45.0
pod 13 13 100.0
total 91 206 44.1


line stmt bran cond sub pod time code
1             package Test::WriteVariants::Context;
2              
3 4     4   40 use strict;
  4         12  
  4         121  
4 4     4   21 use warnings;
  4         8  
  4         2071  
5              
6             =head1 NAME
7              
8             Test::WriteVariants::Context - representation of test context
9              
10             =head1 DESCRIPTION
11              
12             Contexts are used to abstract e.g. ambience or relations between
13             opportunities and and their application.
14              
15             =head1 METHODS
16              
17             =head2 new
18              
19             A Context is an ordered list of various kinds of named values (such as
20             environment variables, our vars) possibly including other Context objects.
21              
22             Values can be looked up by name. The first match will be returned.
23              
24             =cut
25              
26             my $ContextClass = __PACKAGE__;
27              
28             sub new
29             {
30 13     13 1 26 my $class = shift;
31 13 100       39 $class = ref $class if ref $class;
32 13         71 return bless [@_], $class;
33             }
34              
35             =head2 new_composite
36              
37             see Test::WriteVariants::Context::BaseItem
38              
39             =cut
40              
41 0     0 1 0 sub new_composite { shift->new(@_) } # see Test::WriteVariants::Context::BaseItem
42              
43             =head2 push_var
44              
45             add a var to an existing config
46              
47             =cut
48              
49             sub push_var
50             {
51 0     0 1 0 my ($self, $var) = @_;
52 0         0 push @$self, $var;
53 0         0 return;
54             }
55              
56             sub _new_var
57             {
58 0     0   0 my ($self, $t, $n, $v, %e) = @_;
59 0         0 my $var = $t->new($n, $v, %e);
60 0         0 return $self->new($var); # wrap var item in a context list
61             }
62              
63             =head2 new_env_var
64              
65             instantiates new context using an environment variable
66              
67             =head2 new_our_var
68              
69             instantiates new context using a global variable
70              
71             =head2 new_module_use
72              
73             instantiates new context using a module
74              
75             =head2 new_meta_info
76              
77             instantiates new context used to convey information between plugins
78              
79             =cut
80              
81 0     0 1 0 sub new_env_var { shift->_new_var($ContextClass . '::EnvVar', @_) }
82 0     0 1 0 sub new_our_var { shift->_new_var($ContextClass . '::OurVar', @_) }
83 0     0 1 0 sub new_module_use { shift->_new_var($ContextClass . '::ModuleUse', @_) }
84 0     0 1 0 sub new_meta_info { shift->_new_var($ContextClass . '::MetaInfo', @_) }
85              
86             =head2 get_code
87              
88             collects code from members
89              
90             =cut
91              
92             # XXX should ensure that a given type+name is only output once (the latest one)
93             sub get_code
94             {
95 40     40 1 56 my $self = shift;
96 40         54 my @code;
97 40         84 for my $setting (reverse @$self)
98             {
99 48 100       114 push @code, (ref $setting) ? $setting->get_code : $setting;
100             }
101 40         134 return join "", @code;
102             }
103              
104             =head2 get_var
105              
106             search backwards through list of settings, stop at first match
107              
108             =cut
109              
110             sub get_var
111             {
112 0     0 1   my ($self, $name, $type) = @_;
113 0           for my $setting (reverse @$self)
114             {
115 0 0         next unless $setting;
116 0           my @value = $setting->get_var($name, $type);
117 0 0         return $value[0] if @value;
118             }
119 0           return;
120             }
121              
122             =head2 get_env_var
123              
124             search backwards through list of settings, stop at first match (implies EnvVar)
125              
126             =head2 get_our_var
127              
128             search backwards through list of settings, stop at first match (implies OurVar)
129              
130             =head2 get_module_use
131              
132             search backwards through list of settings, stop at first match (implies ModuleUse)
133              
134             =head2 get_meta_info
135              
136             search backwards through list of settings, stop at first match (implies MetaInfo)
137              
138             =cut
139              
140 0     0 1   sub get_env_var { my ($self, $name) = @_; return $self->get_var($name, $ContextClass . '::EnvVar') }
  0            
141 0     0 1   sub get_our_var { my ($self, $name) = @_; return $self->get_var($name, $ContextClass . '::OurVar') }
  0            
142 0     0 1   sub get_module_use { my ($self, $name) = @_; return $self->get_var($name, $ContextClass . '::ModuleUse') }
  0            
143 0     0 1   sub get_meta_info { my ($self, $name) = @_; return $self->get_var($name, $ContextClass . '::MetaInfo') }
  0            
144              
145             {
146              
147             package Test::WriteVariants::Context::BaseItem;
148 4     4   24 use strict;
  4         6  
  4         70  
149 4     4   17 use warnings;
  4         9  
  4         1367  
150             require Data::Dumper;
151             require Carp;
152              
153             # base class for an item (a name-value-type triple)
154              
155             sub new
156             {
157 0     0     my ($class, $name, $value) = @_;
158              
159 0           my $self = bless {} => $class;
160 0           $self->name($name);
161 0           $self->value($value);
162              
163 0           return $self;
164             }
165              
166             sub name
167             {
168 0     0     my $self = shift;
169 0 0         $self->{name} = shift if @_;
170 0           return $self->{name};
171             }
172              
173             sub value
174             {
175 0     0     my $self = shift;
176 0 0         $self->{value} = shift if @_;
177 0           return $self->{value};
178             }
179              
180             sub get_code
181             {
182 0     0     return '';
183             }
184              
185             sub get_var
186             {
187 0     0     my ($self, $name, $type) = @_;
188 0 0 0       return if $type && !$self->isa($type); # empty list
189 0 0         return if $name ne $self->name; # empty list
190 0           return $self->value; # scalar
191             }
192              
193             sub quote_values_as_perl
194             {
195 0     0     my $self = shift;
196             ## no critic (BuiltinFunctions::ProhibitComplexMappings)
197             my @perl_values = map {
198 0           my $val = Data::Dumper->new([$_])->Terse(1)->Purity(1)->Useqq(1)->Sortkeys(1)->Dump;
  0            
199 0           chomp $val;
200 0           $val;
201             } @_;
202 0 0 0       Carp::confess("quote_values_as_perl called with multiple items in scalar context (@perl_values)")
203             if @perl_values > 1 && !wantarray;
204 0 0         return $perl_values[0] unless wantarray;
205 0           return @perl_values;
206             }
207              
208             # utility method to get a new composite when you only have a value object
209 0     0     sub new_composite { $ContextClass->new(@_) }
210              
211             } # ::BaseItem
212              
213             {
214              
215             package Test::WriteVariants::Context::EnvVar;
216 4     4   27 use strict;
  4         9  
  4         80  
217 4     4   18 use warnings;
  4         8  
  4         99  
218 4     4   18 use base 'Test::WriteVariants::Context::BaseItem';
  4         7  
  4         1302  
219              
220             # subclass representing a named environment variable
221              
222             sub get_code
223             {
224 0     0     my $self = shift;
225 0           my $name = $self->{name};
226 0           my @lines;
227 0 0         if (defined $self->{value})
228             {
229 0           my $perl_value = $self->quote_values_as_perl($self->{value});
230 0           push @lines, sprintf('BEGIN { $ENV{%s} = %s; }', $name, $perl_value);
231 0           push @lines, sprintf('END { delete $ENV{%s} } # for VMS', $name);
232             }
233             else
234             {
235             # we treat undef to mean the ENV var should not exist in %ENV
236 0           push @lines, sprintf('local $ENV{%s};', $name); # preserve old value for VMS
237 0           push @lines, 'BEGIN {';
238 0           push @lines, sprintf('delete $ENV{%s};', $name); # delete from %ENV
239 0           push @lines, '}';
240             }
241 0           return join "\n", @lines, '';
242             }
243             }
244              
245             {
246              
247             package Test::WriteVariants::Context::OurVar;
248 4     4   26 use strict;
  4         6  
  4         69  
249 4     4   18 use warnings;
  4         7  
  4         131  
250 4     4   19 use base 'Test::WriteVariants::Context::BaseItem';
  4         5  
  4         708  
251              
252             # subclass representing a named 'our' variable
253              
254             sub get_code
255             {
256 0     0     my $self = shift;
257 0           my $perl_value = $self->quote_values_as_perl($self->{value});
258 0           return sprintf 'our $%s = %s;%s', $self->{name}, $perl_value, "\n";
259             }
260             }
261              
262             {
263              
264             package Test::WriteVariants::Context::ModuleUse;
265 4     4   24 use strict;
  4         9  
  4         82  
266 4     4   20 use warnings;
  4         9  
  4         126  
267 4     4   22 use base 'Test::WriteVariants::Context::BaseItem';
  4         10  
  4         891  
268              
269             # subclass representing 'use $name (@$value)'
270              
271             sub get_code
272             {
273 0     0     my $self = shift;
274 0           my @imports = $self->quote_values_as_perl(@{$self->{value}});
  0            
275 0           return sprintf 'use %s (%s);%s', $self->{name}, join(", ", @imports), "\n";
276             }
277             }
278              
279             {
280              
281             package Test::WriteVariants::Context::MetaInfo;
282 4     4   27 use strict;
  4         9  
  4         108  
283 4     4   23 use warnings;
  4         8  
  4         134  
284 4     4   23 use base 'Test::WriteVariants::Context::BaseItem';
  4         19  
  4         600  
285              
286             # subclass that doesn't generate any code
287             # It's just used to convey information between plugins
288             }
289              
290             1;
291              
292             __END__