diff --git a/Build.PL b/Build.PL index ae927ba..e1d6a7f 100644 --- a/Build.PL +++ b/Build.PL @@ -6,6 +6,7 @@ my $build = Module::Build->new( perl => '5.6.0', Carp => 0, overload => 0, + Moose => 0, }, build_requires => { 'Test::More' => 0, diff --git a/lib/Number/Fraction.pm b/lib/Number/Fraction.pm index ed93aea..b9a935f 100755 --- a/lib/Number/Fraction.pm +++ b/lib/Number/Fraction.pm @@ -115,6 +115,7 @@ use strict; use warnings; use Carp; +use Moose; our $VERSION = '1.14'; @@ -129,8 +130,13 @@ use overload 'abs' => 'abs', fallback => 1; -my %_const_handlers = - (q => sub { return __PACKAGE__->new($_[0]) || $_[1] }); +my %_const_handlers = ( + q => sub { + my $f = eval { __PACKAGE__->new($_[0]) }; + return $_[1] if $@; + return $f; + } +); =head2 import @@ -154,9 +160,19 @@ sub unimport { overload::remove_constant(q => undef); } -=head2 new +has num => ( + is => 'rw', + isa => 'Int', +); + +has den => ( + is => 'rw', + isa => 'Int', +); -Constructor for Number::Fraction object. Takes the following kinds of +=head2 BUILDARGS + +Parameter massager for Number::Fraction object. Takes the following kinds of parameters: =over 4 @@ -191,40 +207,41 @@ Returns C if a Number::Fraction object can't be created. =cut -sub new { +around BUILDARGS => sub { + my $orig = shift; my $class = shift; - my $self; if (@_ >= 2) { - return unless $_[0] =~ /^-?[0-9]+\z/ and $_[1] =~ /^-?[0-9]+\z/; + die unless $_[0] =~ /^-?[0-9]+\z/ and $_[1] =~ /^-?[0-9]+\z/; - $self->{num} = $_[0]; - $self->{den} = $_[1]; + return $class->$orig({ num => $_[0], den => $_[1] }); } elsif (@_ == 1) { if (ref $_[0]) { if (UNIVERSAL::isa($_[0], $class)) { - return $class->new($_[0]->{num}, - $_[0]->{den}); + return $class->$orig({ num => $_[0]->{num}, den => $_[0]->{den} }); } else { - croak "Can't make a $class from a ", - ref $_[0]; - } + die "Can't make a $class from a ", ref $_[0]; + } } else { - return unless $_[0] =~ m|^(-?[0-9]+)(?:/(-?[0-9]+))?\z|; + die unless $_[0] =~ m|^(-?[0-9]+)(?:/(-?[0-9]+))?\z|; - $self->{num} = $1; - $self->{den} = defined $2 ? $2 : 1; + return $class->$orig({ num => $1, den => ( defined $2 ? $2 : 1) }); } } else { - $self->{num} = 0; - $self->{den} = 1; + return $class->$orig({ num => 0, den => 1 }); } +}; - bless $self, $class; +=head2 BUILD - $self->_normalise; +Object initialiser for Number::Fraction. Ensures that fractions are in a +normalised format. - return $self; +=cut + +sub BUILD { + my $self = shift; + $self->_normalise; } sub _normalise { @@ -290,7 +307,7 @@ sub add { if (ref $r) { if (UNIVERSAL::isa($r, ref $l)) { return (ref $l)->new($l->{num} * $r->{den} + $r->{num} * $l->{den}, - $r->{den} * $l->{den}); + $r->{den} * $l->{den}); } else { croak "Can't add a ", ref $l, " to a ", ref $l; } @@ -319,7 +336,7 @@ sub mult { if (ref $r) { if (UNIVERSAL::isa($r, ref $l)) { return (ref $l)->new($l->{num} * $r->{num}, - $l->{den} * $r->{den}); + $l->{den} * $r->{den}); } else { croak "Can't multiply a ", ref $l, " by a ", ref $l; } @@ -348,7 +365,7 @@ sub subtract { if (ref $r) { if (UNIVERSAL::isa($r, ref $l)) { return (ref $l)->new($l->{num} * $r->{den} - $r->{num} * $l->{den}, - $r->{den} * $l->{den}); + $r->{den} * $l->{den}); } else { croak "Can't subtract a ", ref $l, " from a ", ref $l; } @@ -378,7 +395,7 @@ sub div { if (ref $r) { if (UNIVERSAL::isa($r, ref $l)) { return (ref $l)->new($l->{num} * $r->{den}, - $l->{den} * $r->{num}); + $l->{den} * $r->{num}); } else { croak "Can't divide a ", ref $l, " by a ", ref $l; } diff --git a/t/02_create.t b/t/02_create.t index 1433fa9..6e4839a 100644 --- a/t/02_create.t +++ b/t/02_create.t @@ -1,61 +1,61 @@ use Test::More tests => 33; use Number::Fraction; -my $f = Number::Fraction->new('a', 'b'); -ok(!ref $f); +my $f = eval {Number::Fraction->new('a', 'b') }; +ok($@, 'Two non-digits'); -$f = Number::Fraction->new(1, 'c'); -ok(!ref $f); +$f = eval { Number::Fraction->new(1, 'c') }; +ok($@, 'One non-digit'); $f = eval { Number::Fraction->new([]) }; -ok($@); +ok($@, 'Array ref'); $f = Number::Fraction->new('1/2'); -ok(ref $f eq 'Number::Fraction'); -ok($f eq '1/2'); -ok($f == 0.5); +cmp_ok(ref $f, 'eq', 'Number::Fraction', 'String: 1/2'); +cmp_ok($f, 'eq', '1/2', '... as a string'); +cmp_ok($f, '==', 0.5, '... as a number'); $f = Number::Fraction->new(1, 2); -ok(ref $f eq 'Number::Fraction'); -ok($f eq '1/2'); -ok($f == 0.5); +cmp_ok(ref $f, 'eq', 'Number::Fraction', 'Two digits'); +cmp_ok($f, 'eq', '1/2', '... as a string'); +cmp_ok($f, '==', 0.5, '... as a number'); my $f1 = Number::Fraction->new($f); -ok(ref $f1 eq 'Number::Fraction'); -ok($f1 eq '1/2'); -ok($f1 == 0.5); +cmp_ok(ref $f1, 'eq', 'Number::Fraction', 'Number::Fraction'); +cmp_ok($f1, 'eq', '1/2', '... as a string'); +cmp_ok($f1, '==', 0.5, '... as a number'); $f1 = Number::Fraction->new; -ok(ref $f1 eq 'Number::Fraction'); -ok($f1 eq '0'); -ok($f1 == 0); +cmp_ok(ref $f1, 'eq', 'Number::Fraction', 'Empty constructor'); +cmp_ok($f1, 'eq', '0', '... as a string'); +cmp_ok($f1, '==', 0, '... as a number'); my $f2 = Number::Fraction->new(4, 8); -ok(ref $f2 eq 'Number::Fraction'); -ok($f2 eq '1/2'); -ok($f2 == 0.5); +cmp_ok(ref $f2, 'eq', 'Number::Fraction', 'Two more digits'); +cmp_ok($f2, 'eq', '1/2', '... as a string'); +cmp_ok($f2, '==', 0.5, '... as a number'); $f2 = Number::Fraction->new('4/8'); -ok(ref $f2 eq 'Number::Fraction'); -ok($f2 eq '1/2'); -ok($f2 == 0.5); +cmp_ok(ref $f2, 'eq', 'Number::Fraction', 'String: 4/8'); +cmp_ok($f2, 'eq', '1/2', '... as a string'); +cmp_ok($f2, '==', 0.5, '... as a number'); my $f3 = Number::Fraction->new(2, 1); -ok(ref $f3 eq 'Number::Fraction'); -ok($f3 eq '2'); -ok($f3 == 2); +cmp_ok(ref $f3, 'eq', 'Number::Fraction', 'Another two digits'); +cmp_ok($f3, 'eq', '2', '... as a string'); +cmp_ok($f3, '==', 2, '... as a number'); $f3 = Number::Fraction->new('2/1'); -ok(ref $f3 eq 'Number::Fraction'); -ok($f3 eq '2'); -ok($f3 == 2); +cmp_ok(ref $f3, 'eq', 'Number::Fraction', 'String: 2/1'); +cmp_ok($f3, 'eq', '2', '... as a string'); +cmp_ok($f3, '==', 2, '... as a number'); $f3 = Number::Fraction->new(2); -ok(ref $f3 eq 'Number::Fraction'); -ok($f3 eq '2'); -ok($f3 == 2); +cmp_ok(ref $f3, 'eq', 'Number::Fraction', 'Another Number::Fraction'); +cmp_ok($f3, 'eq', '2', '... as a string'); +cmp_ok($f3, '==', 2, '... as a number'); $f3 = Number::Fraction->new('2'); -ok(ref $f3 eq 'Number::Fraction'); -ok($f3 eq '2'); -ok($f3 == 2); +cmp_ok(ref $f3, 'eq', 'Number::Fraction', 'One more digit'); +cmp_ok($f3, 'eq', '2', '... as a string'); +cmp_ok($f3, '==', 2, '... as a number'); diff --git a/t/03_create.t b/t/03_create.t index 642ad74..c56f7d6 100644 --- a/t/03_create.t +++ b/t/03_create.t @@ -1,15 +1,16 @@ -use Test::More tests => 4; +use Test::More tests => 5; use Number::Fraction ':constants'; my $f = '1/2'; -ok(ref $f eq 'Number::Fraction'); -ok($f eq '1/2'); +cmp_ok(ref $f, 'eq', 'Number::Fraction', 'Create from string'); +cmp_ok($f, 'eq', '1/2', 'Created correct string'); +cmp_ok($f, '==', 0.5, 'Created correct number'); no Number::Fraction; $f = '1/2'; -ok(!ref $f); +ok(!ref $f, 'Fail to create from string'); use Number::Fraction ':something'; $f = '1/2'; -ok(!ref $f); +ok(!ref $f, 'Still fail to create from string'); diff --git a/t/12_invalid.t b/t/12_invalid.t index 1eabc0c..2cfe5ad 100644 --- a/t/12_invalid.t +++ b/t/12_invalid.t @@ -1,14 +1,14 @@ use Test::More 'no_plan'; use Number::Fraction; -my $f = Number::Fraction->new("\x{555}"); -ok(!$f); +my $f = eval { Number::Fraction->new("\x{555}") }; +ok($@); -$f = Number::Fraction->new("\x{666}"); -ok(!$f); +$f = eval { Number::Fraction->new("\x{666}") }; +ok($@); -$f = Number::Fraction->new("6\n"); -ok(!$f); +$f = eval { Number::Fraction->new("6\n") }; +ok($@); -$f = Number::Fraction->new("6\n\n"); -ok(!$f); +$f = eval {Number::Fraction->new("6\n\n") }; +ok($@);