package Rose::DB::Object::Metadata::Util; use strict; use Carp(); require Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(perl_hashref perl_arrayref perl_quote_key perl_quote_value hash_key_padding); our %EXPORT_TAGS = (all => \@EXPORT_OK); our $DEFAULT_PERL_INDENT = 4; our $DEFAULT_PERL_BRACES = 'k&r'; our $VERSION = '0.817'; sub perl_hashref { my(%args) = (@_ == 1 ? (hash => $_[0]) : @_); my $inline = defined $args{'inline'} ? $args{'inline'} : ($args{'inline'} = 1); my $indent = defined $args{'indent'} ? $args{'indent'} : ($args{'indent'} = $DEFAULT_PERL_INDENT); my $braces = defined $args{'braces'} ? $args{'braces'} : ($args{'braces'} = $DEFAULT_PERL_BRACES); my $level = defined $args{'level'} ? $args{'level'} : ($args{'level'} = 0); my $no_curlies = delete $args{'no_curlies'}; my $key_padding = $args{'key_padding'} || 0; my $inline_limit = $args{'inline_limit'}; my $sort_keys = $args{'sort_keys'} || sub { lc $_[0] cmp lc $_[1] }; my $hash = delete $args{'hash'}; my $indent_txt = ' ' x ($indent * ($level + 1)); my $sub_indent = ' ' x ($indent * $level); my @pairs; foreach my $key (sort { $sort_keys->($a, $b) } keys %$hash) { push(@pairs, sprintf('%-*s => ', $key_padding, perl_quote_key($key)) . perl_value(value => $hash->{$key}, %args)); } my($inline_perl, $perl); $inline_perl = ($no_curlies ? '' : '{ ') . join(', ', @pairs) . ($no_curlies ? '' : ' }'); if($braces eq 'bsd') { $perl = "\n${sub_indent}" . ($no_curlies ? '' : "{\n"); } elsif($braces eq 'k&r') { $perl = "{\n" unless($no_curlies); } else { Carp::croak 'Invalid ', (defined $args{'braces'} ? '' : 'default '), "brace style: '$braces'"; } $perl .= join(",\n", map { "$indent_txt$_" } @pairs) . ',' . ($no_curlies ? '' : "\n$sub_indent}"); if(defined $inline_limit && length($inline_perl) > $inline_limit) { return $perl; } return $inline ? $inline_perl : $perl; } sub perl_arrayref { my(%args) = (@_ == 1 ? (array => $_[0]) : @_); my $inline = defined $args{'inline'} ? $args{'inline'} : ($args{'inline'} = 1); my $indent = defined $args{'indent'} ? $args{'indent'} : ($args{'indent'} = $DEFAULT_PERL_INDENT); my $braces = defined $args{'braces'} ? $args{'braces'} : ($args{'braces'} = $DEFAULT_PERL_BRACES); my $level = defined $args{'level'} ? $args{'level'} : ($args{'level'} = 0); my $key_padding = $args{'key_padding'} || 0; my $inline_limit = $args{'inline_limit'}; my $sort_keys = $args{'sort_keys'} || sub { lc $_[0] cmp lc $_[1] }; my $array = delete $args{'array'}; my $indent_txt = ' ' x ($indent * ($level + 1)); my $sub_indent = ' ' x ($indent * $level); my @items; foreach my $item (@$array) { push(@items, perl_value(value => $item, %args)); } my($inline_perl, $perl); $inline_perl = '[ ' . join(', ', @items) . ' ]'; if($braces eq 'bsd') { $perl = "\n${sub_indent}\[\n"; } elsif($braces eq 'k&r') { $perl = "[\n"; } else { Carp::croak 'Invalid ', (defined $args{'braces'} ? '' : 'default '), "brace style: '$braces'"; } $perl .= join(",\n", map { "$indent_txt$_" } @items) . ",\n$sub_indent]"; if(defined $inline_limit && length($inline_perl) > $inline_limit) { return $perl; } return $inline ? $inline_perl : $perl; } sub perl_value { my(%args) = (@_ == 1 ? (value => $_[0]) : @_); my $value = delete $args{'value'}; $args{'level'}++; if(my $ref = ref $value) { if($ref eq 'ARRAY') { return perl_arrayref(array => $value, %args); } elsif($ref eq 'HASH') { $args{'key_padding'} = hash_key_padding($value); delete $args{'inline'}; return perl_hashref(hash => $value, %args); } else { return $value; } } return perl_quote_value($value) } sub hash_key_padding { my($hash) = shift; my $max_len = 0; my $min_len = -1; foreach my $name (keys %$hash) { $max_len = length($name) if(length $name > $max_len); $min_len = length($name) if(length $name < $min_len || $min_len < 0); } return $max_len; } sub perl_quote_key { my($key) = shift; return $key if($key =~ /^\d+$/); for($key) { s/'/\\'/g if(/'/); $_ = "'$_'" if(/\W/); } return $key; } sub perl_quote_value { my($val) = shift; for($val) { s/'/\\'/g if(/'/); $_ = "'$_'" unless(/^(?:[1-9]\d*\.?\d*|\.\d+)$/); } return $val; } 1;