{ my @ruleset; sub define_rules { my $rules = shift; for my $rp ( split /\n\n/, $rules ) { my @rules = grep !/^#/, split /\n/, $rp; s/#.*// for @rules; s/^\s+// for @rules; s/\s+$// for @rules; my $fam_pat = shift @rules; my %rules = map { my( $when ) = $_->[0] =~ /(.*):/; # will be undef if no colon defined $when or $when = ''; ( $when => $_->[1] ) } map { /(.*)\bkey\s*=\s*(.*)/ ? [ $1, $2 ] : () } @rules; push @ruleset, [ $fam_pat, \%rules, ]; } } # $key = get_key_by_rules( $family, $family_release ); # if it matches a rule but the rule doesn't specify a key to return, # this function returns its first argument (i.e. $family). # if no match occurs, it returns undef; but your ruleset should # probably have a catch-all condition at the end so this never happens. sub get_key_by_rules { my( $major, $minor ) = @_; defined $minor or $minor = ''; for my $ruleset ( @ruleset ) { my( $maj_pat, $rules_hr, $default ) = @$ruleset; if ( $major =~ /$maj_pat/ ) { if ( exists $rules_hr->{$minor} ) { my $ret = $rules_hr->{$minor}; return $ret gt '' ? $ret : $major; } elsif ( exists $rules_hr->{''} ) { my $ret = $rules_hr->{''}; return $ret gt '' ? $ret : $major; } else { return(); } } } return(); } }