SmartMatch::Sugar - Smart match friendly tests.


SmartMatch-Sugar documentation Contained in the SmartMatch-Sugar distribution.

Index


Code Index:

NAME

Top

SmartMatch::Sugar - Smart match friendly tests.

SYNOPSIS

Top

	use SmartMatch::Sugar;

	if ( $data ~~ non_empty_array ) {
		@$data;
	}

	if ( $object ~~ inv_isa("Class") {

	}	

DESCRIPTION

Top

This module provides simple sugary tests that work on the right hand side of a smart match.

EXPORTS

Top

All exports are managed by Sub::Exporter so they can be renamed, aliased, etc.

I suggest using namespace::clean to remove these subroutines from your namespace.

any

Returns true for any value except code references (this doesn't work because smart match will check for reference equality instead of evaluating).

none

Returns false for any value

overloaded

Returns true if the value is an object with overloads. Doesn't return true for class names which have overloads.

Note that putting an overloaded object in a smart match will cause an error unless fallback is true or the object overloads ~~, in which case the matcher sub will not get a chance to work anyway.

stringifies

Returns true if the value is an object with string overloading..

object

Returns true if the value is blessed.

class

Returns true if Class::Inspector thinks the value is a loaded class.

inv_isa $class

Returns true if $object->isa($class). Also works on classes.

The reason this check is not called just isa is because if you import that into an OO class then your object's isa method is now bogus.

inv stands for invocant, it's the least sucky name I could muster.

inv_can $method

Returns true if $object->can($method).

Like inv_isa, also returns true for classes that can $method.

inv_does $role

Returns true if $object->DOES($role). Also works for classes.

non_ref

Returns true if the item is not a ref, but is defined. Similar to non_empty_string but doesn't involve checking the length, or truth.

non_empty_string

Checks that a value is defined, not a reference, and has a non zero string length.

string_length_is $length

Check that the string's length is equal to $length.

array

Check that the value is a non blessed array.

non_empty_array

Check that the value is an array with at least one element.

Will not accept objects.

array_length_is $length

Check that the value is an array and that scalar(@$array) == $length.

Will not accept objects.

even_sized_array

Check that the array is even sized (can be assigned to a hash).

Will not accept objects.

hash

Check that the value is a non blessed hash.

non_empty_hash

Check that the value is a hash with some entries.

Will not accept objects.

hash_size_is $size

Check that the value is a hash with $size entries in it.

Will not accept objects.

match &block

Will match the value against the block. Unlike a raw subroutine, this will not distribute over arrays and hashes.

VERSION CONTROL

Top

This module is maintained using Darcs. You can get the latest version from http://nothingmuch.woobling.org/code, and use darcs send to commit changes.

AUTHOR

Top

Yuval Kogman <nothingmuch@woobling.org>

COPYRIGHT

Top


SmartMatch-Sugar documentation Contained in the SmartMatch-Sugar distribution.

#!/usr/bin/perl

package SmartMatch::Sugar;

use strict;
use warnings;

use Scalar::Util qw(blessed looks_like_number);
use Carp qw(croak);
use Class::Inspector ();

our $VERSION = "0.04";

use Sub::Exporter -setup => {
	exports => [qw(
		any none

		object class inv_isa inv_can inv_does

		overloaded stringifies

		array array_length_is non_empty_array even_sized_array

		hash hash_size_is non_empty_hash

		non_ref string_length_is non_empty_string

		match
	)],
	groups => {
		default  => [ -all ],
		base     => [ qw/any none/ ],
		object   => [ qw/object class inv_isa inv_can inv_does/ ],
		overload => [ qw/overloaded stringifies/ ],
		array    => [ qw/array array_length_is non_empty_array even_sized_array/ ],
		hash     => [ qw/hash hash_size_is non_empty_hash/ ],
		string   => [ qw/non_ref string_length_is non_empty_string/ ],
		match    => [ qw/match/ ],
	},
};

use 5.010;

{
	package SmartMatch::Sugar::Overloaded;
	use overload '~~' => sub { $_[0]->(@_) };
}

sub match (&) { bless $_[0], "SmartMatch::Sugar::Overloaded" }

use constant any => match { not(not(1)) };
use constant none => match { not(not(0)) };

use constant non_empty_string => match {
	defined($_[1])
		and
	not ref($_[1])
		and
	length($_[1])
};

sub string_length_is ($) {
	my $length = _length(shift);

	return match {
		defined($_[1])
			and
		not ref($_[1])
			and
		length($_[1]) == $length
	}
}

use constant non_ref => match {
	defined($_[1])
		and
	not ref($_[1])
};

use overload ();
use constant overloaded => match {
	blessed($_[1])
		and	
	overload::Overloaded($_[1]);
};

use constant stringifies => match {
	blessed($_[1])
		and	
	overload::OverloadedStringify($_[1]);
};

use constant object => match { blessed($_[1]) };

use constant class => match {
	not ref($_[1])
		and
	Class::Inspector->loaded($_[1])
};

sub inv_does ($) {
	my $role = shift;

	return match {
		blessed($_[1]) || ( defined($_[1]) && not(ref($_[1])) )
			and
		$_[1]->DOES($role);
	}
}

sub inv_isa ($) {
	my $class = shift;
	return match {
		blessed($_[1]) || ( defined($_[1]) && not(ref($_[1])) )
			and
		$_[1]->isa($class);
	}
}

sub inv_can ($) {
	my $method = shift;
	return match {
		blessed($_[1]) || ( defined($_[1]) && not(ref($_[1])) )
			and
		$_[1]->can($method);
	}
}
use constant array => match {
	ref($_[1])
		and
	ref($_[1]) eq 'ARRAY'
};

use constant hash => match {
	ref($_[1])
		and
	ref($_[1]) eq 'HASH'
};

use constant non_empty_array => match {
	ref($_[1])
		and
	ref($_[1]) eq 'ARRAY'
		and
	scalar(@{ $_[1] })
};

use constant non_empty_hash => match {
	ref($_[1])
		and
	ref($_[1]) eq 'HASH'
		and
	scalar(keys %{ $_[1] });
};

use constant even_sized_array => match { 
	ref($_[1])
		and
	ref($_[1]) eq 'ARRAY'
		and
	scalar(@{$_[1]}) % 2 == 0
};

sub array_length_is ($) {
	my $length = _length(shift);

	return match {
		ref($_[1])
			and
		ref($_[1]) eq 'ARRAY'
			and
		scalar(@{$_[1]}) == $length
	};
}

sub hash_size_is ($) {
	my $length = _length(shift);

	return match {
		ref($_[1])
			and
		ref($_[1]) eq 'HASH'
			and
		scalar(keys %{$_[1]}) == $length
	};
}

sub _length ($) {
	my $length = shift;

	unless ( looks_like_number($length) and $length >= 0 and int($length) == $length ) {
		croak "Length is not a positive integer";
	}

	return int $length;
}

__PACKAGE__

__END__