use strict; use warnings; package Nothing; sub isa { 0 } package NotHash; use overload '%{}' => sub { {} }; sub new { bless [], shift } package OverHash; use overload '%{}' => sub { {} }; sub new { bless {}, shift } package main; use Tie::Memoize; use Test::More; my @test_cases = ( { name => 'unblessed hash', test => {}, is_hash => 1, }, { name => 'unblessed array', test => [], is_hash => 0, }, { name => q{hash blessed as 'HASH'}, test => bless( {}, 'HASH' ), is_hash => 1, }, { name => q{array blessed as 'HASH'}, test => bless( [], 'HASH' ), is_hash => 0, }, { name => q{hash blessed as 'ARRAY'}, test => bless( {}, 'ARRAY' ), is_hash => 1, }, { name => 'hash in package 0', test => bless( {}, '0' ), is_hash => 1, }, { name => 'array in package 0', test => bless( [], '0' ), is_hash => 0, }, { name => 'hash with ->isa overridden', test => bless( {}, 'Nothing' ), is_hash => 1, }, { name => 'blessed array with %{} overloaded', test => NotHash->new(), is_hash => 1, }, { name => 'blessed hash with %{} overloaded', test => OverHash->new(), is_hash => 1, }, { name => 'tied hash', test => get_tied_hash(), is_hash => 1, }, { name => 'not a reference', test => 'HASH', is_hash => 0, }, ); sub get_tied_hash { tie my %h, 'Tie::Memoize', sub {}; return \%h; } plan 'tests' => scalar @test_cases; foreach my $test ( @test_cases ) { is( !!isHash( $test->{test} ), !!$test->{is_hash}, $test->{name}); } use Scalar::Util qw( reftype blessed ); sub isHash { my $suspected_hash = shift; return 0 if '' eq ref $suspected_hash; return 1 if 'HASH' eq reftype $suspected_hash; if ( blessed $suspected_hash && overload::Method( $suspected_hash, '%{}' ) ) { return 1; } return 0; }