File Coverage

blib/lib/Data/Hopen/G/Runnable.pm
Criterion Covered Total %
statement 49 52 96.1
branch 10 10 100.0
condition 8 8 100.0
subroutine 13 14 100.0
pod 2 2 100.0
total 82 86 97.6


line stmt bran cond sub pod time code
1             # Data::Hopen::G::Runnable - parent class for anything runnable in a hopen graph
2             package Data::Hopen::G::Runnable;
3 14     14   7006 use strict;
  14         29  
  14         431  
4 14     14   80 use Data::Hopen::Base;
  14         30  
  14         90  
5              
6             our $VERSION = '0.000018';
7              
8 14     14   3736 use Data::Hopen;
  14         31  
  14         681  
9 14     14   3265 use Data::Hopen::Scope::Hash;
  14         37  
  14         662  
10 14     14   88 use Data::Hopen::Util::Data qw(forward_opts);
  14         28  
  14         687  
11 14     14   80 use Data::Hopen::Util::NameSet;
  14         28  
  14         402  
12 14     14   72 use Hash::Merge;
  14         25  
  14         709  
13              
14             # Docs {{{1
15              
16             =head1 NAME
17              
18             Data::Hopen::G::Runnable - parent class for runnable things in a hopen graph
19              
20             =head1 SYNOPSIS
21              
22             Anything with L inherits from this. TODO should this be a role?
23              
24             =head1 ATTRIBUTES
25              
26             =head2 need
27              
28             (B)
29             Inputs this Runnable requires.
30             A L, with the restriction that C may not
31             contain regexes. ("Sorry, I can't run unless you give me every variable
32             in the world that starts with Q." I don't think so!)
33             Or maybe later an arrayref? TODO.
34              
35             =head2 scope
36              
37             If defined, a L that will have the final say on the
38             data used by L. This is the basis of the fine-grained override
39             mechanism in hopen.
40              
41             =head2 want
42              
43             (B)
44             Inputs this Runnable accepts but does not require.
45             A L, which may include regexes.
46             Or maybe later an arrayref? TODO.
47              
48             =cut
49              
50             # }}}1
51              
52 14     14   106 use parent 'Data::Hopen::G::Entity';
  14         27  
  14         94  
53             use Class::Tiny {
54             # NOTE: want and need are not currently used.
55 0         0 want => sub { Data::Hopen::Util::NameSet->new },
56 0         0 need => sub { Data::Hopen::Util::NameSet->new },
57              
58 58         589 scope => sub { Data::Hopen::Scope::Hash->new },
59 14     14   1422 };
  14         37  
  14         131  
60              
61             =head1 FUNCTIONS
62              
63             =head2 run
64              
65             Run the operation, whatever that means. Returns a new hashref.
66             Usage:
67              
68             my $hrOutputs = $op->run([options])
69              
70             Options are:
71              
72             =over
73              
74             =item -context
75              
76             A L or subclass including the inputs the caller wants to
77             pass to the Runnable. The L of the Runnable itself may override
78             values in the C.
79              
80             =item -phase
81              
82             If given, the phase that is currently under way in a build-system run.
83              
84             =item -visitor
85              
86             If given, an instance that supports C and C calls.
87             A L instance invokes those calls after processing each
88             goal or other node, respectively. They are invoked I the goal or
89             node has run. They are, however, given access to the L
90             that the node used for its inputs, in the C<$node_inputs> parameter. Example:
91              
92             $visitor->visit_goal($goal, $node_inputs);
93              
94             The return value from C or C is ignored.
95              
96             =item -nocontext
97              
98             If C<< -nocontext=>1 >> is specified, don't link a context scope into
99             this one. May not be specified together with C<-context>.
100              
101             =back
102              
103             See the source for this function, which contains as an example of setting the
104             scope.
105              
106             =cut
107              
108             sub run {
109 114     114 1 26505 my ($self, %args) = getparameters('self', [qw(; context phase visitor nocontext)], @_);
110 114         7883 my $context_scope = $args{context}; # which may be undef - that's OK
111 114 100 100     822 croak "Can't combine -context and -nocontext" if $args{context} && $args{nocontext};
112              
113             # Link the outer scope to our scope
114 113 100       2865 my $saver = $args{nocontext} ? undef : $self->scope->outerize($context_scope);
115              
116 113     79   786 hlog { '->', ref($self), $self->name, 'input', Dumper($self->scope->as_hashref) } 3;
  79         386  
117              
118 113         1173 my $retval = $self->_run(forward_opts(\%args, {'-'=>1}, qw[phase visitor]));
119              
120 105 100       778 die "$self\->_run() did not return a hashref" unless ref $retval eq 'HASH';
121             # Prevent errors about `non-hashref 1` or `invalid key`.
122              
123 104     74   746 hlog { '<-', ref $self, $self->name, 'output', Dumper($retval) } 3;
  74         312  
124              
125 104         883 return $retval;
126             } #run()
127              
128             =head2 _run
129              
130             The internal method that implements L. Must be implemented by
131             subclasses. When C<_run> is called, C<< $self->scope >> has been hooked
132             to the context scope, if any.
133              
134             Parameters are C<-phase> and C<-visitor>, and are always passed by name
135             (C<< -phase=>$p, -visitor=>$v >>). C<_run> is always called in scalar context,
136             and B return a new hashref.
137              
138             I recommend starting your C<_run> function with:
139              
140             my ($self, %args) = getparameters('self', [qw(; phase visitor)], @_);
141              
142             and working from there.
143              
144             =cut
145              
146             sub _run {
147             # uncoverable subroutine
148 0     0   0 die('Unimplemented'); # uncoverable statement
149             }
150              
151             =head2 passthrough
152              
153             Returns a new hashref of this Runnable's local values, as defined
154             by L. Usage:
155              
156             my $hashref = $runnable->passthrough([-context => $outer_scope]);
157             # To use $outer_scope as the context
158             my $hashref = $runnable->passthrough(-nocontext => 1);
159             # To ignore the context
160              
161             Other valid options include L<-levels|Data::Hopen::Scope/$levels>.
162              
163             =cut
164              
165             sub passthrough {
166 57     57 1 1730 my ($self, %args) = getparameters('self', ['*'], @_);
167 57         3495 my $outer_scope = $args{context}; # which may be undef - that's OK
168 57 100 100     298 croak "Can't combine -context and -nocontext" if $args{context} && $args{nocontext};
169              
170             # Link the outer scope to our scope
171 56 100       195 my $saver = $args{nocontext} ? undef : $self->scope->outerize($outer_scope);
172              
173             # Copy the names
174 56   100     167 my $levels = $args{levels} // 'local';
175 56         96 my @names = @{$self->scope->names(-levels=>$levels)};
  56         1164  
176 56         803 my $retval = {};
177 56         3713 $retval->{$_} = $self->scope->find($_, -levels=>$levels) foreach @names;
178              
179 56         221 return $retval;
180             } #passthrough()
181              
182             1;
183             __END__