<commit_before>package MyValidate;
use strict;
use warnings;

# TODO: pod

=pod

validata $data hash against $profile

 my $result = MyValidate->check( {
 	email	=> '<EMAIL>',
	surname	=> '<NAME>',
 }, {
 	email	=> [ \&MyValidate::EMAIL ],

	surname	=> [ sub {
		return if $_[1] =~ /^\w+$/;
		return 'SURNAME';
	}, ],

	# cross validate fields:
	''	=> [ sub {
		my( $res, $data ) = @_;
		return if defined $data->{email} 
			|| defined $data->{name};
		return 'ANY';
	}, ],
 });

check Multiple data sets:

 my $validator = MyValidate->new({
 	profile => $profile,
 });
 my $result1 = $validator->check( $data1 );
 my $result2 = $validator->check( $data2 );

tries to be compatible with FormValidator::Simple::Result

=cut

sub new {
	my( $proto, $a ) = @_;
	my $self = bless {
		profile	=> {},
		ref $proto ? %$proto : (), # allow cloning
		$a ? %$a : (),
		errors	=> {},
	}, ref $proto || $proto;
}

sub check {
	my( $proto, $data, $a ) = @_;

	my $self = $proto->new( $a );
	my $profile = $self->{profile};

	foreach my $f ( keys %$profile ){
		next if $f eq '';

		my $v = exists $data->{$f} ? $data->{$f} : undef;
		$self->_check_field( $profile, $f, $v );
	}

	# cross_validate when individual fields were ok:
	if( ! %{$self->{errors}} && exists $profile->{''} ){
		$self->_check_field( $profile, '', $data );
	}

	$self;
}

sub _check_field {
	my( $self, $profile, $field, $data ) = @_;

	foreach my $check ( @{$profile->{$field}} ){
		my $err = &$check( $self, $data );
		push @{$self->{errors}{$field}}, $err if $err;
	}
}

sub invalid {
	return [ keys %{$_[0]->{errors}} ] if @_ == 1;

	return unless exists $_[0]->{errors}{$_[1]};
	$_[0]->{errors}{$_[1]};
}

sub missing {
	my $self = shift;

	if( @_ ){
		return unless exists $self->{errors}{$_[1]};
		return grep { $_ eq 'NON_BLANK' } @{ $self->{errors}{$_[1]}};
	} else {
		my @missing;
		foreach my $f ( keys %{$self->{errors}} ){
			foreach my $e ( @{ $self->{errors}{$f}} ){
				next unless $f eq 'NON_BLANK';
				push @missing, $f;
				last;
			}
		}
		return \@missing;
	}
}

sub error { shift->invalid( @_ ) }
<commit_msg>MyValidate: allow multiple errors per check<commit_after>package MyValidate;
use strict;
use warnings;

# TODO: pod

=pod

validata $data hash against $profile

 my $result = MyValidate->check( {
 	email	=> '<EMAIL>',
	surname	=> '<NAME>',
 }, {
 	email	=> [ \&MyValidate::EMAIL ],

	surname	=> [ sub {
		return if $_[1] =~ /^\w+$/;
		return 'SURNAME';
	}, ],

	# cross validate fields:
	''	=> [ sub {
		my( $res, $data ) = @_;
		return if defined $data->{email} 
			|| defined $data->{name};
		return 'ANY';
	}, ],
 });

check Multiple data sets:

 my $validator = MyValidate->new({
 	profile => $profile,
 });
 my $result1 = $validator->check( $data1 );
 my $result2 = $validator->check( $data2 );

tries to be compatible with FormValidator::Simple::Result

=cut

sub new {
	my( $proto, $a ) = @_;
	my $self = bless {
		profile	=> {},
		ref $proto ? %$proto : (), # allow cloning
		$a ? %$a : (),
		errors	=> {},
	}, ref $proto || $proto;
}

sub check {
	my( $proto, $data, $a ) = @_;

	my $self = $proto->new( $a );
	my $profile = $self->{profile};

	foreach my $f ( keys %$profile ){
		next if $f eq '';

		my $v = exists $data->{$f} ? $data->{$f} : undef;
		$self->_check_field( $profile, $f, $v );
	}

	# cross_validate when individual fields were ok:
	if( ! %{$self->{errors}} && exists $profile->{''} ){
		$self->_check_field( $profile, '', $data );
	}

	$self;
}

sub _check_field {
	my( $self, $profile, $field, $data ) = @_;

	foreach my $check ( @{$profile->{$field}} ){
		my @err = &$check( $self, $data );
		push @{$self->{errors}{$field}}, @err if @err;
	}
}

sub invalid {
	return [ keys %{$_[0]->{errors}} ] if @_ == 1;

	return unless exists $_[0]->{errors}{$_[1]};
	$_[0]->{errors}{$_[1]};
}

sub missing {
	my $self = shift;

	if( @_ ){
		return unless exists $self->{errors}{$_[1]};
		return grep { $_ eq 'NON_BLANK' } @{ $self->{errors}{$_[1]}};
	} else {
		my @missing;
		foreach my $f ( keys %{$self->{errors}} ){
			foreach my $e ( @{ $self->{errors}{$f}} ){
				next unless $f eq 'NON_BLANK';
				push @missing, $f;
				last;
			}
		}
		return \@missing;
	}
}

sub error { shift->invalid( @_ ) }

{'fraction_non_alphanumeric': 0.22994779307071667, 'fraction_numerical': 0.006169909824394874, 'mean_word_length': 3.3186475409836067, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6492828', 'n_tokens_mistral': 1754, 'n_tokens_neox': 1646, 'n_words': 425}