| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# App::hopen::Gen - base class for hopen generators |
|
2
|
|
|
|
|
|
|
package App::hopen::Gen; |
|
3
|
1
|
|
|
1
|
|
537
|
use Data::Hopen qw(:default *QUIET); |
|
|
1
|
|
|
|
|
6
|
|
|
|
1
|
|
|
|
|
130
|
|
|
4
|
1
|
|
|
1
|
|
10
|
use strict; use warnings; |
|
|
1
|
|
|
1
|
|
2
|
|
|
|
1
|
|
|
|
|
19
|
|
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
21
|
|
|
5
|
1
|
|
|
1
|
|
10
|
use Data::Hopen::Base; |
|
|
1
|
|
|
|
|
9
|
|
|
|
1
|
|
|
|
|
7
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.000013'; # TRIAL |
|
8
|
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
1273
|
use parent 'Data::Hopen::Visitor'; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
6
|
|
|
10
|
|
|
|
|
|
|
use Class::Tiny qw(proj_dir dest_dir), { |
|
11
|
|
|
|
|
|
|
architecture => '', |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
# private |
|
14
|
|
|
|
|
|
|
_assets => undef, # A Data::Hopen::G::DAG of the assets |
|
15
|
3
|
|
|
|
|
43
|
_assetop_by_asset => sub { +{} }, # Indexed by refaddr($asset) |
|
16
|
1
|
|
|
1
|
|
1934
|
}; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
10
|
|
|
17
|
|
|
|
|
|
|
|
|
18
|
1
|
|
|
1
|
|
1245
|
use App::hopen::Asset; |
|
|
1
|
|
|
|
|
4
|
|
|
|
1
|
|
|
|
|
41
|
|
|
19
|
1
|
|
|
1
|
|
7
|
use App::hopen::BuildSystemGlobals; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
137
|
|
|
20
|
1
|
|
|
1
|
|
8
|
use App::hopen::Util::String qw(eval_here); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
54
|
|
|
21
|
1
|
|
|
1
|
|
8
|
use Data::Hopen::G::DAG; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
46
|
|
|
22
|
1
|
|
|
1
|
|
5
|
use Data::Hopen::Util::Data qw(forward_opts); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
48
|
|
|
23
|
1
|
|
|
1
|
|
574
|
use File::pushd qw(pushd); |
|
|
1
|
|
|
|
|
1325
|
|
|
|
1
|
|
|
|
|
53
|
|
|
24
|
1
|
|
|
1
|
|
14
|
use Path::Class (); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
20
|
|
|
25
|
1
|
|
|
1
|
|
9
|
use Scalar::Util qw(refaddr); |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
1168
|
|
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
# Docs {{{1 |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
=head1 NAME |
|
30
|
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
App::hopen::Gen - Base class for hopen generators |
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
The code that generates blueprints for specific build systems |
|
36
|
|
|
|
|
|
|
lives under C<App::hopen::Gen>. L<App::hopen> calls modules |
|
37
|
|
|
|
|
|
|
under C<App::hopen::Gen> to create the blueprints. Those modules must |
|
38
|
|
|
|
|
|
|
implement the interface defined here. |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head2 proj_dir |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
(Required) A L<Path::Class::Dir> instance specifying the root directory of |
|
45
|
|
|
|
|
|
|
the project. |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
=head2 dest_dir |
|
48
|
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
(Required) A L<Path::Class::Dir> instance specifying where the generated output |
|
50
|
|
|
|
|
|
|
(e.g., blueprint or other files) should be written. |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head2 _assets (Internal) |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
A L<Data::Hopen::G::DAG> of L<App::hopen::G::AssetOp> instances representing |
|
55
|
|
|
|
|
|
|
the L<App::Hopen::Asset>s to be created when a build is run. |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 FUNCTIONS |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
A generator (C<App::hopen::Gen> subclass) is a Visitor plus some. |
|
60
|
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
B<Note>: |
|
62
|
|
|
|
|
|
|
The generator does not have access to L<Data::Hopen::G::Link> instances. |
|
63
|
|
|
|
|
|
|
That lack of access is the primary distinction between Ops and Links. |
|
64
|
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=cut |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# }}}1 |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
=head2 asset |
|
70
|
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
Called by an Op (L<App::hopen::G::Op> subclass) to add an asset |
|
72
|
|
|
|
|
|
|
(L<App::hopen::G::AssetOp> instance) to the build. Usage: |
|
73
|
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
$Generator->asset([-asset=>]$asset, [-from=>]$from[, [-how=>]$how]); |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
If C<$how> is specified, it will be saved in the C<AssetOp> for use later. |
|
77
|
|
|
|
|
|
|
Later calls with the same asset and a defined C<$how> will overwrite the |
|
78
|
|
|
|
|
|
|
C<how> value in the C<AssetOp>. Specify 'UNDEF' as the C<$how> to |
|
79
|
|
|
|
|
|
|
expressly undefine a C<how>. |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
Returns the C<AssetOp>. |
|
82
|
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=cut |
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub asset { |
|
86
|
12
|
|
|
12
|
1
|
78
|
my ($self, %args) = getparameters('self', [qw(asset; how)], @_); |
|
87
|
12
|
|
|
0
|
|
1125
|
hlog { 'Generator adding asset at',refaddr($args{asset}),$args{asset} } 3; |
|
|
0
|
|
|
|
|
0
|
|
|
88
|
|
|
|
|
|
|
|
|
89
|
12
|
|
|
|
|
350
|
my $existing_op = $self->_assetop_by_asset->{refaddr($args{asset})}; |
|
90
|
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
# Update an existing op |
|
92
|
12
|
50
|
|
|
|
82
|
if(defined $existing_op) { |
|
93
|
0
|
0
|
0
|
|
|
0
|
if( ($args{how}//'') eq 'UNDEF') { |
|
|
|
0
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
0
|
$existing_op->how(undef); |
|
95
|
|
|
|
|
|
|
} elsif(defined $args{how}) { |
|
96
|
0
|
|
|
|
|
0
|
$existing_op->how($args{how}); |
|
97
|
|
|
|
|
|
|
} |
|
98
|
0
|
|
|
|
|
0
|
return $existing_op; |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# Need to create an op. First, load its class. |
|
102
|
12
|
|
|
|
|
50
|
my $class = $self->_assetop_class; |
|
103
|
|
|
|
|
|
|
|
|
104
|
12
|
|
|
|
|
60
|
eval_here <<EOT; |
|
105
|
|
|
|
|
|
|
require $class; |
|
106
|
|
|
|
|
|
|
EOT |
|
107
|
12
|
50
|
|
|
|
66
|
die "$@" if $@; |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# Create a new op |
|
110
|
12
|
|
|
|
|
51
|
my $op = $class->new(name => 'Op:<<' . $args{asset}->target . '>>', |
|
111
|
|
|
|
|
|
|
forward_opts(\%args, qw(asset how))); |
|
112
|
12
|
|
|
|
|
323
|
$self->_assetop_by_asset->{refaddr($args{asset})} = $op; |
|
113
|
12
|
|
|
|
|
269
|
$self->_assets->add($op); |
|
114
|
12
|
|
|
|
|
3013
|
return $op; |
|
115
|
|
|
|
|
|
|
} #asset() |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=head2 connect |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Add a dependency edge between two assets or goals. Any assets must have already |
|
120
|
|
|
|
|
|
|
been added using L</asset>. Usage: |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
$Generator->connect([-from=>]$from, [-to=>$to]); |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
TODO add missing assets automatically? |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
TODO rename the asset-graph public interface so it's more clear that it's |
|
127
|
|
|
|
|
|
|
the asset graph and not the command graph. |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
=cut |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub connect { |
|
132
|
12
|
|
|
12
|
1
|
141
|
my ($self, %args) = getparameters('self', [qw(from to)], @_); |
|
133
|
12
|
|
|
|
|
875
|
my %nodes; |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# Get the nodes if we were passed assets. |
|
136
|
12
|
|
|
|
|
31
|
foreach my $field (qw(from to)) { |
|
137
|
24
|
100
|
|
|
|
110
|
if(eval { $args{$field}->DOES('App::hopen::Asset') }) { |
|
|
24
|
|
|
|
|
155
|
|
|
138
|
15
|
|
|
|
|
273
|
$nodes{$field} = $self->_assetop_by_asset->{refaddr($args{$field})}; |
|
139
|
|
|
|
|
|
|
} else { |
|
140
|
9
|
|
|
|
|
28
|
$nodes{$field} = $args{$field}; |
|
141
|
|
|
|
|
|
|
} |
|
142
|
|
|
|
|
|
|
} |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# TODO better error messages |
|
145
|
12
|
50
|
|
|
|
78
|
croak "No From node for asset " . refaddr($args{from}) unless $nodes{from}; |
|
146
|
12
|
50
|
|
|
|
195
|
croak "No To node for asset " . refaddr($args{to}) unless $nodes{to}; |
|
147
|
12
|
|
|
|
|
337
|
$self->_assets->connect($nodes{from}, $nodes{to}); |
|
148
|
|
|
|
|
|
|
} #connect() |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=head2 asset_default_goal |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
Read-only accessor for the default goal of the asset graph |
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=cut |
|
155
|
|
|
|
|
|
|
|
|
156
|
4
|
|
|
4
|
1
|
81
|
sub asset_default_goal () { shift->_assets->default_goal } |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
=head2 run_build |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
Runs the build tool for which this generator has created blueprint files. |
|
161
|
|
|
|
|
|
|
Runs the tool with the destination directory as the current dir. |
|
162
|
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=cut |
|
164
|
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
sub run_build { |
|
166
|
0
|
0
|
|
0
|
1
|
0
|
my $self = shift or croak 'Need an instance'; |
|
167
|
0
|
|
|
|
|
0
|
my $abs_dir = $DestDir->absolute; |
|
168
|
|
|
|
|
|
|
# NOTE: You have to call this *before* pushd() or chdir(), because |
|
169
|
|
|
|
|
|
|
# it may be a relative path, and absolute() converts with respect |
|
170
|
|
|
|
|
|
|
# to cwd at the time of the call. |
|
171
|
0
|
|
|
|
|
0
|
my $dir = pushd($abs_dir); |
|
172
|
0
|
0
|
|
|
|
0
|
say "Building in ${abs_dir}..." unless $QUIET; |
|
173
|
0
|
|
|
|
|
0
|
$self->_run_build(); |
|
174
|
|
|
|
|
|
|
} #run_build() |
|
175
|
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
=head2 BUILD |
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
Constructor. |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
=cut |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub BUILD { |
|
183
|
6
|
|
|
6
|
1
|
772
|
my ($self, $args) = @_; |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# Enforce the required argument types |
|
186
|
|
|
|
|
|
|
croak "Need a project directory (Path::Class::Dir)" |
|
187
|
6
|
50
|
|
|
|
14
|
unless eval { $self->proj_dir->DOES('Path::Class::Dir') }; |
|
|
6
|
|
|
|
|
163
|
|
|
188
|
|
|
|
|
|
|
croak "Need a destination directory (Path::Class::Dir)" |
|
189
|
6
|
50
|
|
|
|
114
|
unless eval { $self->dest_dir->DOES('Path::Class::Dir') }; |
|
|
6
|
|
|
|
|
131
|
|
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# Create the asset graph |
|
192
|
6
|
|
|
|
|
79
|
$self->_assets(hnew DAG => 'asset graph'); |
|
193
|
6
|
|
|
|
|
6203
|
$self->_assets->goal('__R_asset_default_goal'); |
|
194
|
|
|
|
|
|
|
# Create and set default goal |
|
195
|
|
|
|
|
|
|
} #BUILD() |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
=head1 FUNCTIONS TO BE IMPLEMENTED BY SUBCLASSES |
|
198
|
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
=head2 _assetop_class |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
(Required) Returns the name of the L<App::hopen::G::AssetOp> subclass that |
|
202
|
|
|
|
|
|
|
should be used to represent assets in the C<_assets> graph. |
|
203
|
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
=cut |
|
205
|
|
|
|
|
|
|
|
|
206
|
0
|
|
|
0
|
|
0
|
sub _assetop_class { ... } |
|
207
|
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
=head2 default_toolset |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
(Required) Returns the package stem of the default toolset for this generator. |
|
211
|
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
When a hopen file invokes C<use language "Foo">, hopen will load |
|
213
|
|
|
|
|
|
|
C<< App::hopen::T::<stem>::Foo >>. C<< <stem> >> is the return |
|
214
|
|
|
|
|
|
|
value of this function unless the user has specified a different toolset. |
|
215
|
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
As a sanity check, hopen will first try to load C<< App::hopen::T::<stem> >>, |
|
217
|
|
|
|
|
|
|
so make sure that is a valid package. |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=cut |
|
220
|
|
|
|
|
|
|
|
|
221
|
0
|
|
|
0
|
1
|
0
|
sub default_toolset { ... } |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
=head2 finalize |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
(Optional) |
|
226
|
|
|
|
|
|
|
Do whatever the generator wants to do to finish up. By default, no-op. |
|
227
|
|
|
|
|
|
|
Is provided the L<Data::Hopen::G::DAG> instance as a parameter. Usage: |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
$generator->finalize(-phase=>$Phase, -graph=>$Build, |
|
230
|
|
|
|
|
|
|
-data=>$data) |
|
231
|
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
C<$dag> is the command graph, and C<$data> is the output from the |
|
233
|
|
|
|
|
|
|
command graph. |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
C<finalize> is always called with named parameters. |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=cut |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
0
|
1
|
|
sub finalize { } |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=head2 _run_build |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
(Optional) |
|
244
|
|
|
|
|
|
|
Implementation of L</run_build>. The default does not die, but does warn(). |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=cut |
|
247
|
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub _run_build { |
|
249
|
0
|
|
|
0
|
|
0
|
warn "This generator is not configured to run a build tool. Sorry!"; |
|
250
|
|
|
|
|
|
|
} #_run_build() |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
=head2 visit_goal |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
Add a target corresponding to the name of the goal. Usage: |
|
255
|
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
$Generator->visit_goal($node, $node_inputs); |
|
257
|
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
This happens while the command graph is being run. |
|
259
|
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
This can be overriden by a generator that wants to handle |
|
261
|
|
|
|
|
|
|
L<Data::Hopen::G::Goal> nodes differently. |
|
262
|
|
|
|
|
|
|
For example, the generator may want to change the goal's C<outputs>. |
|
263
|
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
=cut |
|
265
|
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub visit_goal { |
|
267
|
3
|
|
|
3
|
1
|
9710
|
my ($self, %args) = getparameters('self', [qw(goal node_inputs)], @_); |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# --- Add the goal to the asset graph --- |
|
270
|
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
#my $asset_goal = $self->_assets->goal($args{goal}->name); |
|
272
|
|
|
|
|
|
|
my $phony_asset = App::hopen::Asset->new( |
|
273
|
|
|
|
|
|
|
target => $args{goal}->name, |
|
274
|
3
|
|
|
|
|
263
|
made_by => $self, |
|
275
|
|
|
|
|
|
|
); |
|
276
|
3
|
|
|
|
|
61
|
my $phony_node = $self->asset(-asset => $phony_asset, -how => ''); |
|
277
|
|
|
|
|
|
|
# \p how defined but falsy => it's a goal |
|
278
|
3
|
|
|
|
|
32
|
$self->connect($phony_node, $self->asset_default_goal); |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
# Pull the inputs. TODO refactor out the code in common with |
|
281
|
|
|
|
|
|
|
# AhG::Cmd::input_assets(). |
|
282
|
|
|
|
|
|
|
my $hrSourceFiles = |
|
283
|
3
|
|
50
|
|
|
1279
|
$args{node_inputs}->find(-name => 'made', |
|
284
|
|
|
|
|
|
|
-set => '*', -levels => 'local') // {}; |
|
285
|
|
|
|
|
|
|
die 'No input files to goal ' . $args{goal}->name |
|
286
|
3
|
50
|
|
|
|
669
|
unless scalar keys %$hrSourceFiles; |
|
287
|
|
|
|
|
|
|
|
|
288
|
3
|
|
|
|
|
12
|
my $lrSourceFiles = $hrSourceFiles->{(keys %$hrSourceFiles)[0]}; |
|
289
|
3
|
|
|
0
|
|
22
|
hlog { 'found inputs to goal', $args{goal}->name, Dumper($lrSourceFiles) } 2; |
|
|
0
|
|
|
|
|
0
|
|
|
290
|
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
# TODO? verify that all the assets are actually in the graph first? |
|
292
|
3
|
|
|
|
|
35
|
$self->connect($_, $phony_node) foreach @$lrSourceFiles; |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
} #visit_goal() |
|
295
|
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
=head2 visit_node |
|
297
|
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
(Optional) |
|
299
|
|
|
|
|
|
|
Do whatever the generator wants to do with a L<Data::Hopen::G::Node> that |
|
300
|
|
|
|
|
|
|
is not a Goal (see L</visit_goal>). By default, no-op. Usage: |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
$generator->visit_node($node) |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=cut |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
9
|
1
|
|
sub visit_node { } |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
1; |
|
309
|
|
|
|
|
|
|
__END__ |
|
310
|
|
|
|
|
|
|
# vi: set fdm=marker: # |