File Coverage

blib/lib/App/Math/Tutor/Cmd/VulFrac/Cmd/Add.pm
Criterion Covered Total %
statement 18 80 22.5
branch 0 22 0.0
condition 0 33 0.0
subroutine 6 9 66.6
pod n/a
total 24 144 16.6


line stmt bran cond sub pod time code
1             package App::Math::Tutor::Cmd::VulFrac::Cmd::Add;
2              
3 1     1   6576 use warnings;
  1         2  
  1         37  
4 1     1   4 use strict;
  1         1  
  1         35  
5              
6 1     1   5 use vars qw(@ISA $VERSION);
  1         1  
  1         66  
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.005';
15              
16 1     1   5 use Moo;
  1         1  
  1         7  
17 1     1   298 use MooX::Cmd;
  1         2  
  1         7  
18 1     1   1562 use MooX::Options;
  1         2  
  1         9  
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: " . join( ", ", @fail ) . ", pick any of " . join( ", ", keys %result_formats );
54             \%rf;
55             },
56             format => "s@",
57             autosplit => ",",
58             repeatable => 1,
59             short => "r",
60             );
61              
62 0     0     sub _build_command_names { qw(add sub); }
63              
64             my $a_plus_b = sub {
65             PolyNum->new(
66             operator => $_[0],
67             values => [ splice @_, 1 ]
68             );
69             };
70             my $a_mult_b = sub {
71             ProdNum->new(
72             operator => $_[0],
73             values => [ splice @_, 1 ]
74             );
75             };
76              
77             sub _operands_ok
78             {
79 0     0     my ( $self, $op, @operands ) = @_;
80 0 0         $self->has_result_format or return 1;
81 0           my $s = shift @operands;
82 0           while (@operands)
83             {
84 0           my $b = shift @operands;
85 0           my $a = $s->_reduce;
86 0           $b = $b->_reduce;
87 0           my $gcd = VulFrac->new(
88             num => $a->denum,
89             denum => $b->denum
90             )->_gcd;
91 0           my ( $fa, $fb ) = ( $b->{denum} / $gcd, $a->{denum} / $gcd );
92 0           my ( $xa, $xb ) = (
93             VulFrac->new(
94             num => int( $a_mult_b->( '*', $a->num, $fa ) ),
95             denum => int( $a_mult_b->( '*', $a->denum, $fa ) ),
96             sign => $a->sign
97             ),
98             VulFrac->new(
99             num => int( $a_mult_b->( '*', $b->num, $fb ) ),
100             denum => int( $a_mult_b->( '*', $b->denum, $fb ) ),
101             sign => $b->sign
102             )
103             );
104 0           $s = VulFrac->new(
105             num => int( $a_plus_b->( $op, $xa->sign * $xa->num, $xb->sign * $xb->num ) ),
106             denum => $xa->denum
107             );
108             }
109 0           my ( $max_num, $max_denum ) = ( @{ $_[0]->format } );
  0            
110 0           my %result_format = %{ $self->result_format };
  0            
111 0 0 0       $s->_gcd > 1 or return 0 if defined $result_format{reducable} and $result_format{reducable};
      0        
112 0           $s = $s->_reduce;
113 0 0 0       $s->num <= $max_num or return 0 if defined $result_format{keep} and $result_format{keep};
      0        
114 0 0 0       $s->denum <= $max_denum or return 0 if defined $result_format{keep} and $result_format{keep};
      0        
115 0           1;
116             }
117              
118             sub _build_exercises
119             {
120 0     0     my ($self) = @_;
121 0           my $neg = $self->negativable;
122              
123 0           my (@tasks);
124 0           foreach my $i ( 1 .. $self->quantity )
125             {
126 0           my @line;
127 0           foreach my $j ( 0 .. 1 )
128             {
129 0           REDO: my ( $a, $b ) = $self->get_vulgar_fractions(2);
130 0 0         $self->_operands_ok( $j ? '-' : '+', $a, $b ) or goto REDO;
    0          
131 0           push @line, [ $a, $b ];
132             }
133 0           push @tasks, \@line;
134             }
135              
136 0           my $exercises = {
137             section => "Vulgar fraction addition / subtraction",
138             caption => 'Fractions',
139             label => 'vulgar_fractions_addition',
140             header => [ [ 'Vulgar Fraction Addition', 'Vulgar Fraction Subtraction' ] ],
141             solutions => [],
142             challenges => [],
143             };
144             # use Text::TabularDisplay;
145             # my $table = Text::TabularDisplay->new( 'Bruch -> Dez', 'Dez -> Bruch' );
146 0           foreach my $line (@tasks)
147             {
148 0           my ( @solution, @challenge );
149              
150 0           foreach my $i ( 0 .. 1 )
151             {
152 0           my ( $a, $b ) = @{ $line->[$i] };
  0            
153 0 0         my $op = $i ? '-' : '+';
154 0 0 0       $op eq '-' and $a < $b and ( $b, $a ) = ( $a, $b ) unless $neg;
      0        
155 0           push @challenge, sprintf( '$ %s = $', $a_plus_b->( $op, $a, $b ) );
156              
157 0           my @way; # remember Frank Sinatra :)
158 0           push @way, $a_plus_b->( $op, $a, $b );
159              
160 0 0 0       ( $a, $b ) = ( $a->_reduce, $b = $b->_reduce ) and push @way, $a_plus_b->( $op, $a, $b )
      0        
161             if ( $a->_gcd > 1 or $b->_gcd > 1 );
162              
163 0           my $gcd = VulFrac->new(
164             num => $a->denum,
165             denum => $b->denum
166             )->_gcd;
167 0           my ( $fa, $fb ) = ( $b->{denum} / $gcd, $a->{denum} / $gcd );
168              
169 0           my ( $xa, $xb ) = (
170             VulFrac->new(
171             num => $a_mult_b->( '*', $a->num, $fa ),
172             denum => $a_mult_b->( '*', $a->denum, $fa ),
173             sign => $a->sign
174             ),
175             VulFrac->new(
176             num => $a_mult_b->( '*', $b->num, $fb ),
177             denum => $a_mult_b->( '*', $b->denum, $fb ),
178             sign => $b->sign
179             )
180             );
181 0           push @way, $a_plus_b->( $op, $xa, $xb );
182 0           $xa = VulFrac->new(
183             num => int( $xa->num ),
184             denum => int( $xa->denum ),
185             sign => $xa->sign
186             );
187 0           $xb = VulFrac->new(
188             num => int( $xb->num ),
189             denum => int( $xb->denum ),
190             sign => $xb->sign
191             );
192 0           push @way, $a_plus_b->( $op, $xa, $xb );
193              
194 0           my $s = VulFrac->new(
195             num => $a_plus_b->( $op, $xa->sign * $xa->num, $xb->sign * $xb->num ),
196             denum => $xa->denum
197             );
198              
199 0           push @way, $s;
200 0           $s = VulFrac->new(
201             num => int( $s->num ),
202             denum => $s->denum,
203             sign => $s->sign
204             );
205 0           push @way, "" . $s;
206 0 0 0       $s->_gcd > 1 and $s = $s->_reduce and push @way, $s;
207              
208 0 0 0       $s->num > $s->denum and $s->denum > 1 and push @way, $s->_stringify(1);
209              
210 0           push( @solution, '$ ' . join( " = ", @way ) . ' $' );
211             }
212              
213 0           push( @{ $exercises->{solutions} }, \@solution );
  0            
214 0           push( @{ $exercises->{challenges} }, \@challenge );
  0            
215             }
216              
217 0           $exercises;
218             }
219              
220             =head1 LICENSE AND COPYRIGHT
221              
222             Copyright 2010-2014 Jens Rehsack.
223              
224             This program is free software; you can redistribute it and/or modify it
225             under the terms of either: the GNU General Public License as published
226             by the Free Software Foundation; or the Artistic License.
227              
228             See http://dev.perl.org/licenses/ for more information.
229              
230             =cut
231              
232             1;