Bivio::Type::Integer
# Copyright (c) 1999-2007 bivio Software, Inc. All rights reserved. # $Id$ package Bivio::Type::Integer; use strict; use Bivio::Base 'Type.Number'; use Bivio::TypeError; # C<Bivio::Type::Integer> is a number used for "small integer" # computations, e.g. byte counts and list_display_size. # An <Bivio::Type::Integer> always fits into a perl int. It # may be subclassed to create a subrange as all methods use # L<get_min|"get_min"> and L<get_max|"get_max"> to get the # boundaries for the integer. # Dynamic subranges may be created using L<new|"new">. my($_IDI) = __PACKAGE__->instance_data_index; sub compare_defined { my(undef, $left, $right) = @_; # Returns the numeric comparison (E<lt>=E<gt>) of I<left> to I<right>. return $left <=> $right; } sub from_literal { my($proto, $value) = @_; # Parses I<value> as a string. Verifies I<value> is a number and within min/max # of this Integer type. Accepts any input and will not die as a result of # invalid values, e.g. C<undef>. # # On success, returns an C<int>. # # Special case if passed C<undef>, which result in C<undef> being # returned. # # On failure, returns the tuple (C<undef>, I<type_error>), where # I<type_error> is one of the following L<Bivio::TypeError|Bivio::TypeError> # values: # # # INTEGER # # The syntax is not valid for an integer, i.e. doesn't match # the regex /^[-+]?\d+$/. # # NUMBER_RANGE # # The syntax is correct, but the resultant integer is outside the bounds of # this integer type. $proto->internal_from_literal_warning unless wantarray; # Null (blank) string and null are same thing. return undef unless defined($value) && $value =~ /\S/; # Get rid of all blanks to be nice to user $value =~ s/\s+//g;; # remove trailing 0 decimals $value =~ s/(\d)\.0+$/$1/; return (undef, Bivio::TypeError->INTEGER) unless $value =~ /^[-+]?\d+$/; # Return as a string, so we avoid perl turning 0 into ''. return $proto->get_min <= $value && $proto->get_max >= $value ? int($value).'' : (undef, Bivio::TypeError->NUMBER_RANGE); } sub get_decimals { # Returns 0 return 0; } sub get_max { my($proto) = @_; # Returns '999999999' if called with a class name. # Static subranges should override this method if their max is different. # I<Remember that this method returns a string!> # # The max for dynamic subranges will be retrieved from the type's # L<new|"new"> value. return '999999999' unless ref($proto); return $proto->[$_IDI]->{max}; } sub get_min { my($proto) = @_; # Returns '-999999999' if called with a class name. # Static subranges should override this method if their min is different. # I<Remember that this method returns a string!> # # The min for dynamic subranges will be retrieved from the type's # L<new|"new"> value. return '-999999999' unless ref($proto); return $proto->[$_IDI]->{min}; } sub get_precision { my($proto) = @_; # Returns the maximum number of decimal digits in # L<get_min|"get_min"> or L<get_max|"get_max"> whichever is greater. my($min, $max) = ($proto->get_min, $proto->get_max); my($n) = length($min) > length($max) ? $min : $max; return $n < 0 ? length($n) - 1 : length($n); } sub get_width { my($proto) = @_; # Returns the length of L<get_min|"get_min"> or L<get_max|"get_max"> # whichever is greater. my($min, $max) = ($proto->get_min, $proto->get_max); return length($min) > length($max) ? length($min) : length($max); } sub is_odd { my($proto, $value) = @_; return $value % 2; } sub new { my($proto, $min, $max) = @_; # Creates a new subrange between I<min> and I<max>, inclusive. # If either limit is undef, uses the value for this class. ($min) = defined($min) ? __PACKAGE__->from_literal($min) : __PACKAGE__->get_min; Bivio::Die->die('invalid min value') unless defined($min); ($max) = defined($max) ? __PACKAGE__->from_literal($max) : __PACKAGE__->get_max; Bivio::Die->die('invalid max value') unless defined($max); Bivio::Die->die('min greater than max') unless $min <= $max; my($self) = $proto->SUPER::new; $self->[$_IDI] = { # get_min and get_max return strings min => "$min", max => "$max", }; return $self; } sub to_json { return shift->to_literal(shift); } 1;