File Coverage

blib/lib/Math/SMA.pm
Criterion Covered Total %
statement 45 45 100.0
branch 9 10 90.0
condition 2 2 100.0
subroutine 6 6 100.0
pod 1 2 50.0
total 63 65 96.9


line stmt bran cond sub pod time code
1             package Math::SMA;
2 2     2   40366 use Scalar::Util qw(looks_like_number);
  2         4  
  2         220  
3 2     2   1230 use Moo;
  2         35177  
  2         14  
4 2     2   7073 use namespace::autoclean;
  2         26975  
  2         12  
5              
6             our $VERSION = '0.01';
7             $VERSION = eval $VERSION;
8              
9             has size => (
10             is =>'ro',
11             isa => sub { die "$_[0] is not an integer!" unless(looks_like_number($_[0]) && $_[0] >= 1)},
12             required => '1',
13             );
14              
15             has last_avg => (
16             is =>'ro',
17             isa => sub { die "$_[0] is not a number!" unless looks_like_number $_[0]},
18             writer => '_set_last_avg',
19             );
20              
21             has precision => (
22             is => 'rw',
23             isa => sub { die "$_[0] is not a number!" unless looks_like_number $_[0]},
24             default => 2,
25             );
26              
27             has values => (
28             is => 'ro',
29             isa => sub { die "$_[0] is not an array ref!" unless ref($_[0]) eq 'ARRAY'},
30             default => sub { [] },
31             );
32              
33              
34             sub BUILD
35             {
36 4     4 0 46 my $self = shift();
37 4         17 my $values = $self->values();
38 4         14 my $size = $self->size();
39              
40 4 50       12 return unless defined $values;
41              
42             #perfectly valid to pass in values to constructor
43             #however, not valid to have more values than size()
44 4 100       5 if(@{$values} > $size){
  4         16  
45 2         4 @{$values} = splice(@{$values}, -1 * $size);
  2         6  
  2         9  
46             }
47            
48 4         18 $self->_set_last_avg($self->_raw_average());
49              
50             }
51              
52             sub sma
53             {
54 12     12 1 6814 my ($self, $current) = @_;
55 12         42 my $last = $self->last_avg();
56 12         25 my $values = $self->values();
57 12         28 my $size = $self->size();
58 12         351 my $prec = $self->precision();
59 12         806 my $obsolete;
60             my $avg;
61              
62 12 100       97 return sprintf("%.${prec}f",$last) unless defined $current;
63 8 100       40 die "sma() works on numbers only!" unless looks_like_number $current;
64              
65 7         9 push(@{$values}, $current);
  7         19  
66              
67             #return simple avg if not enough periods
68 7 100       11 if(@{$values} <= $size){
  7         19  
69 5         16 $self->_set_last_avg($self->_raw_average());
70 5         125 return sprintf("%.${prec}f", $self->last_avg());
71             }
72              
73 2         5 $obsolete = shift(@{$values});
  2         5  
74              
75 2         10 $avg = $last - ($obsolete/$size) + ($current/$size);
76 2         65 $self->_set_last_avg($avg);
77              
78 2         45 return sprintf("%.${prec}f", $avg);
79             }
80              
81              
82             sub _raw_average
83             {
84 9     9   14 my $self = shift();
85 9   100     11 my $size = @{$self->values()} || 1;
86 9         15 my $total = 0;
87 9         11 foreach (@{$self->values}){
  9         26  
88 19         32 $total += $_;
89             }
90 9         221 return $total / $size;
91             }
92              
93              
94              
95             1;
96              
97             __END__