=head1 NAME

Devel::Assert - assertions support for perls >= 5.8.1

=head1 DEPRECATION

This version is deprecated, you should use 1.00 now. It uses internal Perl API that is much more
rubust then the clunky Devel::Declare interface. This old branch remains here only to support older
5.8.1 - 5.12.5 perls.

=head1 SYNOPSIS

	use Devel::Assert;
	sub my_sqrt{
		my $num = shift;
		
		assert($num > 0);
		return sqrt($num);
	}
	#this will fail with built-in sqrt's message, 'cos of assert() is compiled as no-op
	my_sqrt(-12);
	
	use Devel::Assert -all, -verbose;
	sub my_sqrt{
		my $num = shift;
		
		assert($num > 0);
		return sqrt($num);
	}
	#this will fail with "Assertion '$num > 0' failed
	#	guessing variables... $num = '-12'
	#	at ..., line ..."
	my_sqrt(-12);


=head1 FEATURES

=over 2

=item *

assert() function is replaced with no-op at compile stage for release builds

=item *

precise diagnostics for what and where happened

=item *

Not a source filter (magic for syntax is provided by L<Devel::Declare>)

=back

=head1 DESCRIPTION

When writing code, you always make some assumptions (correct or not) about incoming data,
results of internal or external function call, etc. Using assertions is a way to document 
these assumptions, thus making your program more reliable by forcing them. 

	#	old way:
	#data should be non-empty array
	my @values = process_data(@data); #values contains same element count as data
	
	#	new way:
	assert(scalar @data);
	my @values = process_data(@data);
	assert(scalar @data == scalar @values);

But what about more code to execute? Often unnecessary code is beeing cut of by postfixing it 
with 'if DEBUG' (and declaring DEBUG as a constant), but for L<Devel::Assert> that isn't necessary.
C<assert> call is only really compiled for debug builds - by changing just a 
single import line, you can make all them no-ops, causing no overhead 
(except for compile time, of course). 

	#	old way:
	sub DEBUG () { 1 }
	die 'no data given' if DEBUG && !@data;
	my @values = process_data(@data);
	die 'wrong count' if DEBUG && (scalar @data != scalar @values);
	
	#	new way:
	use Devel::Assert -all;
	assert(scalar @data);
	my @values = process_data(@data);
	assert(scalar @data == scalar @values);

Furthermore, by using C<-verbose> mode, you can not only get description of
where failure occured, but also what has exactly failed.

	#	old way:
	die 'no data given' if DEBUG && !@data;
	my @values = process_data(@data);
	if (DEBUG && (scalar @data != scalar @values)){
	  require Data::Dumper;
	  Data::Dumper->import('Dumper');
	  die "Data and values count mismatch: ".Dumper(\@data).Dumper(\@values);
	}
	
	#	new way:
	use Devel::Assert -all, -verbose;
	assert(scalar @data);
	my @values = process_data(@data);
	assert(scalar @data == scalar @values);

So, the more debug info you need - the less code you write.

=head1 CONFIGURATION

When you're use'ing L<Devel::Assert>, you should specify parsing mode for
B<assert> call. That's done by passing one of the following to C<import>:

=over 4

=item C<-all>

Starting with this point, all assert() calls are really done and your assertions are checked
for all subsequently compiled modules, regardless of their import() option.
This can be used in your main program, for example, before any other modules used
(global debug mode).

=item C<-none>

Starting with this point, all assert() calls are changed to no-op
for all subsequently compiled modules, regardless of their import() option.
This can be used in your main program, for example, before any other modules used
(global release mode).

Note: first occurence of C<-all> or C<-none> takes precedence of all further ones.

=item any boolean 'true'

In this module, assert() calls are really done and your assertions are checked (debug mode).

=item any boolean 'false' (or nothing)

In this module, assert() calls are changed to no-op (release mode).

=item C<-verbose>

This is special control value, that can be added to normal options.
In the C<-verbose> mode, in case of assertion failure, L<Devel::Assert> will
try to dump all B<lexical> variables that are mentioned in failed code.
That's done through L<Data::Dumper> and L<PadWalker> - without
these modules, C<-verbose> mode will fall back to default behaviour, with warning emitted.

Here is sample output:

	Assertion ' scalar @y < $x ' failed, trying to determine acting variables...
	$x = 3;
	@y = (
		1,
		2,
		{ '4' => 'HASH(0x3d913c)' }
	);
	...and all this happened at test.pl line 10
		main::__ANON__() called at test.pl line 13
		main::z() called at test.pl line 17

=back

=head1 DISABLING ASSERTIONS

To temporary disable assertions (at compile time, turning them to no-ops),
you can do the following trick:

	no Devel::Assert;
	<some code with assertions that would not trigger even under '-all'>
	use Devel::Assert q/1/;
	<code with assertions turned on>

Note: 'no Devel::Assert' is B<not> lexically scoped. It's effect prolongates
till module end or next 'use Devel::Assert'.

=head1 FAILURE HOOKS & RUN-TIME CONFIGURATION

In case of assertion failure, depending on C<-verbose> flag was set or not,
L<Devel::Assert> calls some internal callbacks that generates messages that you see by default.
By calling (always fully qualified) sub C<set_options>, you can change default behavior. Also, through
the same call, you can change C<-verbose> status at run-time.

	Devel::Assert::set_options(
		verbose      => 1,
		hook_terse   => \&some_sub,
		hook_verbose => \&another_sub,
	);

=over 4

=item C<verbose>

Change assertions verbosity status at run-time

=item C<hook_terse>

Called with one or two arguments. First one is always a failed
assertion text ('$num > 0'). Second, if present, is a message generated from
C<hook_verbose>.

Default behaviour for C<hook_terse> is to call C<Carp::confess>.

=item C<hook_verbose>

Called with one argument - failed assertion text. Overriding this seems to be of little
use, and provided here only for completeness.

By default, calls C<hook_terse> with arguments described above.

=back

=head1 CAVEATS

One subroutine - C<assert> - is exported to the caller namespace.

Parser detail - you B<must> specify parentheses for assert call:

	assert 3 < 5;	#wrong!
	assert (3 < 5);	#ok

=head1 SEE ALSO

L<assertions> - for perls >= 5.9.0 only, different syntax (code attributes).

L<Carp::Assert> - requires nasty 'if DEBUG' suffix.

=head1 AUTHOR

Sergey Aleynikov <sergey.aleynikov@gmail.com>

=head1 LICENSE

Copyright (c) 2009 by Sergey Aleynikov.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

Some part for parser are taken from L<Devel::Declare::Context::Simple>, (c) Rhesa Rozendaal (?).

=cut
