File Coverage

blib/lib/App/Math/Tutor/Cmd/VulFrac/Cmd/Add.pm
Criterion Covered Total %
statement 61 80 76.2
branch 13 22 59.0
condition 13 31 41.9
subroutine 8 9 88.8
pod n/a
total 95 142 66.9


line stmt bran cond sub pod time code
1             package App::Math::Tutor::Cmd::VulFrac::Cmd::Add;
2              
3 1     1   14347 use warnings;
  1         4  
  1         51  
4 1     1   7 use strict;
  1         3  
  1         46  
5              
6 1     1   6 use vars qw(@ISA $VERSION);
  1         2  
  1         102  
7              
8             =head1 NAME
9              
10             App::Math::Tutor::Cmd::VulFrac::Cmd::Add - Plugin for addition and subtraction of vulgar fractions
11              
12             =cut
13              
14             our $VERSION = '0.004';
15              
16 1     1   7 use Moo;
  1         4  
  1         11  
17 1     1   427 use MooX::Cmd;
  1         2  
  1         11  
18 1     1   2668 use MooX::Options;
  1         3  
  1         16  
19              
20             has template_filename => (
21             is => "ro",
22             default => "twocols"
23             );
24              
25             with "App::Math::Tutor::Role::VulFracExercise";
26              
27             my %result_formats = (
28             keep => 1,
29             reducable => 1,
30             );
31              
32             =head1 ATTRIBUTES
33              
34             =head2 result_format
35              
36             Allows controlling of accepted format of exercise output
37              
38             =cut
39              
40             option result_format => (
41             is => "ro",
42             predicate => 1,
43             doc => "Let one specify result format behavior",
44             long_doc => "Let one specify result format behavior, pick one of\n\n"
45             . "reducable: result can be reduced, "
46             . "keep: keep exercise format (after reducing)",
47             coerce => sub {
48             defined $_[0] or return {};
49             "HASH" eq ref $_[0] and return $_[0];
50             my ( @fail, %rf );
51             $rf{$_} = defined $result_formats{$_} or push @fail, $_ foreach @{ $_[0] };
52             @fail
53             and die "Invalid result format: "
54             . join( ", ", @fail )
55             . ", pick any of "
56             . join( ", ", keys %result_formats );
57             return \%rf;
58             },
59             format => "s@",
60             autosplit => ",",
61             repeatable => 1,
62             short => "r",
63             );
64              
65             sub _build_command_names
66             {
67 0     0   0 return qw(add sub);
68             }
69              
70             my $a_plus_b = sub {
71             return
72             PolyNum->new( operator => $_[0],
73             values => [ splice @_, 1 ] );
74             };
75             my $a_mult_b = sub {
76             return
77             ProdNum->new( operator => $_[0],
78             values => [ splice @_, 1 ] );
79             };
80              
81             sub _operands_ok
82             {
83 30     30   68 my ( $self, $op, @operands ) = @_;
84 30 50       148 $self->has_result_format or return 1;
85 0         0 my $s = shift @operands;
86 0         0 while (@operands)
87             {
88 0         0 my $b = shift @operands;
89 0         0 my $a = $s->_reduce;
90 0         0 $b = $b->_reduce;
91 0         0 my $gcd = VulFrac->new(
92             num => $a->denum,
93             denum => $b->denum
94             )->_gcd;
95 0         0 my ( $fa, $fb ) = ( $b->{denum} / $gcd, $a->{denum} / $gcd );
96 0         0 my ( $xa, $xb ) = (
97             VulFrac->new(
98             num => int( $a_mult_b->( '*', $a->num, $fa ) ),
99             denum => int( $a_mult_b->( '*', $a->denum, $fa ) ),
100             sign => $a->sign
101             ),
102             VulFrac->new(
103             num => int( $a_mult_b->( '*', $b->num, $fb ) ),
104             denum => int( $a_mult_b->( '*', $b->denum, $fb ) ),
105             sign => $b->sign
106             )
107             );
108 0         0 $s = VulFrac->new(
109             num => int( $a_plus_b->( $op, $xa->sign * $xa->num, $xb->sign * $xb->num ) ),
110             denum => $xa->denum );
111             }
112 0         0 my ( $max_num, $max_denum ) = ( @{ $_[0]->format } );
  0         0  
113 0         0 my %result_format = %{ $self->result_format };
  0         0  
114 0 0 0     0 $s->_gcd > 1 or return 0 if defined $result_format{reducable} and $result_format{reducable};
      0        
115 0         0 $s = $s->_reduce;
116 0 0 0     0 $s->num <= $max_num or return 0 if defined $result_format{keep} and $result_format{keep};
      0        
117 0 0 0     0 $s->denum <= $max_denum or return 0 if defined $result_format{keep} and $result_format{keep};
      0        
118 0         0 return 1;
119             }
120              
121             sub _build_exercises
122             {
123 1     1   333 my ($self) = @_;
124 1         5 my $neg = $self->negativable;
125              
126 1         3 my (@tasks);
127 1         5 foreach my $i ( 1 .. $self->quantity )
128             {
129 15         17 my @line;
130 15         27 foreach my $j ( 0 .. 1 )
131             {
132 30         93 REDO: my ( $a, $b ) = $self->get_vulgar_fractions(2);
133 30 100       326 $self->_operands_ok( $j ? '-' : '+', $a, $b ) or goto REDO;
    50          
134 30         102 push @line, [ $a, $b ];
135             }
136 15         41 push @tasks, \@line;
137             }
138              
139 1         13 my $exercises = {
140             section => "Vulgar fraction addition / subtraction",
141             caption => 'Fractions',
142             label => 'vulgar_fractions_addition',
143             header => [ [ 'Vulgar Fraction Addition', 'Vulgar Fraction Subtraction' ] ],
144             solutions => [],
145             challenges => [],
146             };
147             # use Text::TabularDisplay;
148             # my $table = Text::TabularDisplay->new( 'Bruch -> Dez', 'Dez -> Bruch' );
149 1         4 foreach my $line (@tasks)
150             {
151 15         23 my ( @solution, @challenge );
152              
153 15         30 foreach my $i ( 0 .. 1 )
154             {
155 30         42 my ( $a, $b ) = @{ $line->[$i] };
  30         79  
156 30 100       78 my $op = $i ? '-' : '+';
157 30 50 100     222 $op eq '-' and $a < $b and ( $b, $a ) = ( $a, $b ) unless $neg;
      100        
158 30         83 push @challenge, sprintf( '$ %s = $', $a_plus_b->( $op, $a, $b ) );
159              
160 30         166 my @way; # remember Frank Sinatra :)
161 30         68 push @way, $a_plus_b->( $op, $a, $b );
162              
163 30 100 50     921 ( $a, $b ) = ( $a->_reduce, $b = $b->_reduce ) and push @way, $a_plus_b->( $op, $a, $b )
      100        
164             if ( $a->_gcd > 1 or $b->_gcd > 1 );
165              
166 30         1212 my $gcd = VulFrac->new(
167             num => $a->denum,
168             denum => $b->denum
169             )->_gcd;
170 30         225 my ( $fa, $fb ) = ( $b->{denum} / $gcd, $a->{denum} / $gcd );
171              
172 30         93 my ( $xa, $xb ) = (
173             VulFrac->new(
174             num => $a_mult_b->( '*', $a->num, $fa ),
175             denum => $a_mult_b->( '*', $a->denum, $fa ),
176             sign => $a->sign
177             ),
178             VulFrac->new(
179             num => $a_mult_b->( '*', $b->num, $fb ),
180             denum => $a_mult_b->( '*', $b->denum, $fb ),
181             sign => $b->sign
182             )
183             );
184 30         988 push @way, $a_plus_b->( $op, $xa, $xb );
185 30         770 $xa = VulFrac->new(
186             num => int( $xa->num ),
187             denum => int( $xa->denum ),
188             sign => $xa->sign
189             );
190 30         1135 $xb = VulFrac->new(
191             num => int( $xb->num ),
192             denum => int( $xb->denum ),
193             sign => $xb->sign
194             );
195 30         602 push @way, $a_plus_b->( $op, $xa, $xb );
196              
197 30         898 my $s = VulFrac->new(
198             num => $a_plus_b->( $op, $xa->sign * $xa->num, $xb->sign * $xb->num ),
199             denum => $xa->denum );
200              
201 30         701 push @way, $s;
202 30         126 $s = VulFrac->new(
203             num => int( $s->num ),
204             denum => $s->denum,
205             sign => $s->sign
206             );
207 30         1591 push @way, "" . $s;
208 30 100 66     295 $s->_gcd > 1 and $s = $s->_reduce and push @way, $s;
209              
210 30 100 66     210 $s->num > $s->denum and $s->denum > 1 and push @way, $s->_stringify(1);
211              
212 30         111 push( @solution, '$ ' . join( " = ", @way ) . ' $' );
213             }
214              
215 15         108 push( @{ $exercises->{solutions} }, \@solution );
  15         183  
216 15         22 push( @{ $exercises->{challenges} }, \@challenge );
  15         54  
217             }
218              
219 1         51 return $exercises;
220             }
221              
222             =head1 LICENSE AND COPYRIGHT
223              
224             Copyright 2010-2014 Jens Rehsack.
225              
226             This program is free software; you can redistribute it and/or modify it
227             under the terms of either: the GNU General Public License as published
228             by the Free Software Foundation; or the Artistic License.
229              
230             See http://dev.perl.org/licenses/ for more information.
231              
232             =cut
233              
234             1;