my $self = shift @_;
my $definitely_used_options = $self->root();
# dry-run of these methods allows us to collect definitely_used_options
foreach my $method (@{ $self->use_cases() }) {
$self->$method();
}
my $possibly_used_options = { 'ENV' => \%ENV };
$self->root( $possibly_used_options );
# the first run of this method allows us to collect possibly_used_options
my $rules = $self->default_options();
$self->load_cmdline_options( { %$definitely_used_options, %$possibly_used_options }, $rules );
$self->root( $definitely_used_options );
my $rules_to_go;
my $attempts = 32;
do {
$rules_to_go = 0;
foreach my $key (keys %$definitely_used_options) {
if(exists $rules->{$key}) {
my $value = $self->substitute( \$rules->{$key} );
# it has to be intelligently (recursively, on by-element basis) merged back into the tree under $self->o($key):
$self->merge_from_rules( $value, \$self->root->{$key} );
if($self->is_fully_substituted_structure($value)) {
#warn "Resolved rule: $key -> ".stringify($value)."\n";
} else {
#warn "Unresolved rule: $key -> ".stringify($value)."\n";
$rules_to_go++;
}
}
}
$attempts--;
#warn "=======================[$rules_to_go rules to go; $attempts attempts to go]=================\n\n";
#warn " definitely_used_options{} contains: ".stringify($definitely_used_options)."\n";
} while($rules_to_go and $attempts);
#warn "=======================[out of the substitution loop]=================\n\n";
my $missing_options = $self->hash_leaves( {}, $self->root, '' );
if(scalar(keys %$missing_options)) {
warn "Missing or incomplete definition of the following options:\n";
foreach my $key (sort keys %$missing_options) {
print "\t$key\n";
}
exit(1);
} else {
#warn "Done parsing options!\n";
}
}