Data-Bucketeer

 view release on metacpan or  search on metacpan

lib/Data/Bucketeer.pm  view on Meta::CPAN

#pod
#pod   my $cost = $buck->result_for( 701 ); # cost is 3
#pod
#pod By default, the values I<exclusive minima>.  For example, above, you end up
#pod with a result of C<3> by having an input C<strictly greater than> 500, and
#pod C<less than or equal to> 500.  If you want to use a different operator, you can
#pod specify it like this:
#pod
#pod   my $buck = Data::Bucketeer->new( '>=', {
#pod        1 => 10,
#pod      101 => 5,
#pod      201 => 4,
#pod      501 => 3,
#pod     1001 => 2,
#pod   });
#pod
#pod   my $cost = $buck->result_for( 701 ); # cost is 3
#pod
#pod This distinction can be useful when dealing with non-integers.  The understood
#pod operators are:
#pod
#pod =for :list
#pod * >
#pod * >=
#pod * <=
#pod * <
#pod
#pod If the result value is a code reference, it will be invoked with C<$_> set to
#pod the input.  This can be used for dynamically generating results, or to throw
#pod exceptions.  Here is a contrived example of exception-throwing:
#pod
#pod   my $greeting = Data::Bucketeer->new( '>=', {
#pod     '-Inf' => sub { die "secs-into-day must be between 0 and 86399; got $_" },
#pod
#pod          0 => "Good evening.",
#pod     28_800 => "Good morning.",
#pod     43_200 => "Good afternoon.",
#pod     61_200 => "Good evening.",
#pod
#pod     86_400 => sub { die "secs-into-day must be between 0 and 86399; got $_" },
#pod   });
#pod
#pod =cut

sub new {
  my ($class, @rest) = @_;
  unshift @rest, '>' if ref $rest[0];

  my ($type, $buckets) = @rest;

  my @non_num = grep { ! Scalar::Util::looks_like_number($_) or /NaN/i }
                keys %$buckets;

  croak "non-numeric bucket boundaries: @non_num" if @non_num;

  my $guts = bless {
    buckets => $buckets,
    picker  => $class->__picker_for($type),
  };

  return bless $guts => $class;
}

my %operator = (
  '>' => sub {
    my ($self, $this) = @_;
    first { $this > $_ } sort { $b <=> $a } keys %{ $self->{buckets} };
  },
  '>=' => sub {
    my ($self, $this) = @_;
    first { $this >= $_ } sort { $b <=> $a } keys %{ $self->{buckets} };
  },

  '<=' => sub {
    my ($self, $this) = @_;
    first { $this <= $_ } sort { $a <=> $b } keys %{ $self->{buckets} };
  },
  '<' => sub {
    my ($self, $this) = @_;
    first { $this < $_ } sort { $a <=> $b } keys %{ $self->{buckets} };
  },
);

sub __picker_for {
  my ($self, $type) = @_;
  return($operator{ $type } || croak("unknown bucket operator: $type"));
}

#pod =method result_for
#pod
#pod   my $result = $buck->result_for( $input );
#pod
#pod This returns the result for the given input, as described L<above|/OVERVIEW>.
#pod
#pod =cut

sub result_for {
  my ($self, $input) = @_;

  my ($bound, $result) = $self->bound_and_result_for($input);

  return $result;
}

#pod =method bound_and_result_for
#pod
#pod   my ($bound, $result) = $buck->bound_and_result_for( $input );
#pod
#pod This returns two values:  the boundary key whose result was used, and the
#pod result itself.
#pod
#pod Using the item quantity price above, for example:
#pod
#pod   my $buck = Data::Bucketeer->new({
#pod        0 => 10,
#pod      100 => 5,
#pod      200 => 4,
#pod      500 => 3,
#pod     1000 => 2,
#pod   });
#pod

 view all matches for this distribution
 view release on metacpan -  search on metacpan

( run in 1.096 second using v1.00-cache-2.02-grep-82fe00e-cpan-1925d2aa809 )