Tie-Reduce

 view release on metacpan or  search on metacpan

lib/Tie/Reduce.pm  view on Meta::CPAN


our $AUTHORITY = 'cpan:TOBYINK';
our $VERSION   = '0.003';

## suppresses warnings

sub import {
	my $class  = shift;
	my $caller = caller;
	eval "package $caller; our (\$a, \$b)";
}

## tie interface

sub TIESCALAR {
	my $class = shift;
	$class->new(@_);
}

sub FETCH {
	ref($_[0]) ne __PACKAGE__
		? $_[0]->get_value
		: $_[0][0];  # shortcut if not subclassed
}

sub STORE {
	# if subclassed
	if (ref($_[0]) ne __PACKAGE__) {
		# take non-optimal route
		my $av = $_[0]->can('assign_value');
		goto $av; # preserve caller
	}
	
	my ($self) = shift;
	my ($new_value) = @_;
	my ($old_value, $coderef) = @$self;

	my ($caller_a, $caller_b) = do {
		my $pkg = caller();
		no strict 'refs';
		\*{$pkg . '::a'}, \*{$pkg . '::b'};
	};
	local (*$caller_a, *$caller_b);
	
	*$caller_a = \$old_value;
	*$caller_b = \$new_value;
	
	$self->[0] = $coderef->($old_value, $new_value);
}

## OO interface

sub new {
	my $class = shift;
	my ($coderef, $initial_value) = @_;
	no warnings 'uninitialized';
	if (ref($coderef) ne 'CODE') {
		require Carp;
		Carp::croak("Expected coderef; got $coderef");
	}
	bless [$initial_value, $coderef] => $class;
}

sub get_value {
	$_[0][0];
}

sub set_value {
	$_[0][0] = $_[1];
}

sub assign_value {
	my ($self) = shift;
	my ($new_value) = @_;
	my $old_value = $self->get_value;

	my ($caller_a, $caller_b) = do {
		my $pkg = caller();
		no strict 'refs';
		\*{$pkg . '::a'}, \*{$pkg . '::b'};
	};
	local (*$caller_a, *$caller_b);
	
	*$caller_a = \$old_value;
	*$caller_b = \$new_value;
	
	$self->set_value( $self->get_coderef->($old_value, $new_value) );
}

sub get_coderef {
	$_[0][1];
}

sub _set_coderef {
	$_[0][1] = $_[1];
}

1;

__END__

=pod

=encoding utf-8

=head1 NAME

Tie::Reduce - a scalar that reduces its old and new values to a single value

=head1 SYNOPSIS

  use Tie::Reduce;
  
  tie my $sum, "Tie::Reduce", sub { $a + $b }, 0;
  
  $sum = 1;
  $sum = 2;
  $sum = 3;
  $sum = 4;
  
  say $sum;  # 10



( run in 0.953 second using v1.01-cache-2.11-cpan-a9496e3eb41 )