File Coverage

blib/lib/App/Math/Tutor/Role/UnitExercise.pm
Criterion Covered Total %
statement 12 35 34.2
branch 0 22 0.0
condition 0 2 0.0
subroutine 4 6 66.6
pod n/a
total 16 65 24.6


line stmt bran cond sub pod time code
1             package App::Math::Tutor::Role::UnitExercise;
2              
3 1     1   590 use warnings;
  1         1  
  1         33  
4 1     1   4 use strict;
  1         1  
  1         33  
5              
6             =head1 NAME
7              
8             App::Math::Tutor::Role::FracExercise - role for exercises in calculation with units
9              
10             =cut
11              
12 1     1   5 use Moo::Role;
  1         1  
  1         6  
13 1     1   273 use MooX::Options;
  1         1  
  1         5  
14              
15             =head1 ATTRIBUTES
16              
17             =head2 relevant_units
18              
19             Specifies relevant units. Option argument can be either a list of units to take care, or
20             starting with an exclamation mark, a list of units to skip.
21              
22             Known units contain time, length, weight, euro, pound, dollar.
23              
24             =cut
25              
26             option "relevant_units" => (
27             is => "lazy",
28             doc => "Specifies the units relevant for the exercise",
29             long_doc => "Specifies the units relevant for the exercise using one or more of: "
30             . "time, length, weight, euro, pound, dollar.",
31             coerce => \&_coerce_relevant_units,
32             format => "s@",
33             autosplit => ",",
34             repeatable => 1,
35             short => "r",
36             );
37              
38             my $single_inst;
39             my $single_redo;
40              
41             around new => sub {
42             my ( $orig, $class, %params ) = @_;
43             my $self = $class->$orig(%params);
44             $single_inst = $self;
45             $single_redo and $self->{relevant_units} = _coerce_relevant_units($single_redo);
46             $self;
47             };
48              
49             sub _build_relevant_units
50             {
51 0     0     [ keys %{ $_[0]->unit_definitions } ];
  0            
52             }
53              
54             sub _coerce_relevant_units
55             {
56 0     0     my ($val) = @_;
57 0 0         $single_inst or return $single_redo = $val;
58 0 0         defined $val or die "Missing argument for relevant_units";
59 0 0         ref $val eq "ARRAY" or die "Invalid type for relevant_units";
60 0 0         my $neg = $val->[0] eq "!" and shift @$val;
61 0 0         @$val or die "Missing elements for relevant_units";
62              
63 0 0         $single_inst or return $val;
64              
65 0           my @brkn;
66 0           foreach my $ru ( @{$val} )
  0            
67             {
68 0 0 0       $neg = $ru eq "!" and next unless defined $neg;
69 0 0         exists $single_inst->unit_definitions->{$ru}
70             or push @brkn, $ru;
71             }
72 0 0         @brkn and die "Non-existing unit type(s): " . join( ", ", @brkn );
73              
74 0 0         $neg or return $val;
75              
76 0           my @neg_list = grep {
77 0           my $item = $_;
78 0 0         grep { $_ ne "!" and $_ ne $item } @{$val}
  0            
  0            
79 0           } keys %{ $single_inst->unit_definitions };
80 0           \@neg_list;
81             }
82              
83             =head2 unit_length
84              
85             Allowes one to limit the "length" of a unit. While some unit categories have
86             many entries (e.g. I<time> - which can result in
87             C<${a} w ${b} d ${c} h ${d} min ${e} s ${f} ms>) - limiting the length would
88             result in not more than C<${unit_length}> elements per number.
89              
90             =cut
91              
92             option "unit_length" => (
93             is => "ro",
94             doc => "Allowes limitation of unit length",
95             format => "i",
96             short => "l",
97             predicate => 1,
98             );
99              
100             =head2 deviation
101              
102             When more than one operand is involved, control I<deviation> using this
103             option. Best results with I<unit_length>.
104              
105             =cut
106              
107             option "deviation" => (
108             is => "ro",
109             doc => "Allowes limit deviation of unit elements by <einheit>",
110             format => "i",
111             short => "d",
112             predicate => 1,
113             );
114              
115             with "App::Math::Tutor::Role::Exercise", "App::Math::Tutor::Role::Unit";
116              
117             our $VERSION = '0.005';
118              
119             =head1 LICENSE AND COPYRIGHT
120              
121             Copyright 2010-2014 Jens Rehsack.
122              
123             This program is free software; you can redistribute it and/or modify it
124             under the terms of either: the GNU General Public License as published
125             by the Free Software Foundation; or the Artistic License.
126              
127             See http://dev.perl.org/licenses/ for more information.
128              
129             =cut
130              
131             1;