File Coverage

blib/lib/Ordeal/Model.pm
Criterion Covered Total %
statement 105 121 86.7
branch 17 34 50.0
condition 3 9 33.3
subroutine 22 24 91.6
pod 7 7 100.0
total 154 195 78.9


line stmt bran cond sub pod time code
1             package Ordeal::Model;
2              
3             # vim: ts=3 sts=3 sw=3 et ai :
4              
5 5     5   387971 use 5.020;
  5         66  
6 5     5   26 use strict;
  5         11  
  5         120  
7 5     5   42 use warnings;
  5         9  
  5         281  
8             { our $VERSION = '0.003'; }
9              
10 5     5   2780 use English qw< -no_match_vars >;
  5         16987  
  5         30  
11 5     5   2232 use Ouch;
  5         2396  
  5         25  
12 5     5   2567 use Mo qw< default >;
  5         2612  
  5         27  
13 5     5   4954 use Path::Tiny;
  5         12  
  5         228  
14 5     5   26 use Scalar::Util qw< blessed >;
  5         12  
  5         216  
15 5     5   2620 use Module::Runtime qw< use_module require_module is_module_name >;
  5         9314  
  5         27  
16              
17 5     5   2615 use Ordeal::Model::ChaCha20;
  5         14  
  5         187  
18 5     5   2100 use Ordeal::Model::Evaluator;
  5         12  
  5         214  
19 5     5   2318 use Ordeal::Model::Parser;
  5         12  
  5         255  
20              
21 5     5   36 use experimental qw< signatures postderef >;
  5         10  
  5         21  
22 5     5   678 no warnings qw< experimental::signatures experimental::postderef >;
  5         10  
  5         5405  
23              
24             has 'backend';
25             has random_source => (
26             default => sub {
27             require Ordeal::Model::ChaCha20;
28             return Ordeal::Model::ChaCha20->new;
29             }
30             );
31              
32 1     1   2 sub _backend_factory ($package, $name, @args) {
  1         2  
  1         3  
  1         2  
  1         2  
33 1         11 $name = $package->resolve_backend_name($name);
34 1         43 return use_module($name)->new(@args);
35             }
36              
37 0     0   0 sub _default_backend ($package) {
  0         0  
  0         0  
38 0         0 require Ordeal::Model::Backend::PlainFile;
39 0         0 return Ordeal::Model::Backend::PlainFile->new;
40             }
41              
42 3     3 1 3155 sub evaluate ($self, $what, %args) {
  3         4  
  3         6  
  3         7  
  3         5  
43 3 50       12 my $ast = ref($what) ? $what : $self->parse($what);
44 2         24 return Ordeal::Model::Evaluator::EVALUATE(
45             ast => $ast,
46             model => $self,
47             random_source => $self->_random_source(%args),
48             );
49             }
50              
51 4     4 1 5674 sub get_card ($self, $id) { return $self->backend->card($id) }
  4         8  
  4         7  
  4         5  
  4         26  
52 7     7 1 20714 sub get_deck ($self, $id) { return $self->backend->deck($id) }
  7         15  
  7         12  
  7         9  
  7         22  
53 0     0 1 0 sub get_deck_ids ($self) { return $self->backend->decks }
  0         0  
  0         0  
  0         0  
54              
55 4     4 1 1637 sub new ($package, @rest) {
  4         14  
  4         13  
  4         8  
56 4 50 33     44 my %args = (@_ && ref($_[0])) ? %{$rest[0]} : @rest;
  0         0  
57 4         12 my $backend;
58 4 100       21 if (defined(my $b = $args{backend})) {
    50          
    50          
59             $backend = blessed($b) ? $args{backend}
60 3 0       26 : (ref($b) eq 'ARRAY') ? $package->_backend_factory(@$b)
    50          
61             : ouch 400, 'invalid backend';
62             }
63             elsif (scalar(keys %args) == 0) {
64 0         0 $backend = $package->_default_backend;
65             }
66             elsif (scalar(keys %args) == 1) {
67 1         4 my ($name, $as) = %args;
68 1 50       6 my @args = ref($as) eq 'ARRAY' ? @$as : %$as;
69 1         4 $backend = $package->_backend_factory($name, @args);
70             }
71             else {
72 0         0 ouch 400, 'too many arguments to initialize Model';
73             }
74              
75 4         154 return $package->SUPER::new(backend => $backend);
76             }
77              
78 3     3 1 5 sub parse ($self, $text) {
  3         4  
  3         5  
  3         5  
79 3 100       10 ouch 400, 'undefined input expression to parse()' unless defined $text;
80 2         8 return Ordeal::Model::Parser::PARSE($text);
81             }
82              
83 2     2   7 sub _random_source ($self, %args) {
  2         6  
  2         4  
  2         3  
84 2 50       6 return $args{random_source} if $args{random_source};
85              
86             return Ordeal::Model::ChaCha20->new->restore($args{random_source_state})
87 2 50       6 if defined $args{random_source_state};
88              
89             return Ordeal::Model::ChaCha20->new(seed => $args{seed})
90 2 50       32 if defined $args{seed};
91              
92 0         0 return $self->random_source;
93             }
94              
95 1     1 1 3 sub resolve_backend_name ($package, $name) {
  1         2  
  1         2  
  1         2  
96 1   33     5 $package = ref($package) || $package;
97 1         4 my $invalid_error = "invalid name '$name' for module resolution";
98              
99             # if it has "::" *inside* but does not start with them, use directly
100 1 50 33     8 if (($name =~ s{\A - }{}mxs) || ($name =~ m{\A [^:]+ ::})) {
101 0 0       0 is_module_name($name) or ouch 400, $invalid_error;
102 0         0 return $name;
103             }
104              
105             # otherwise, remove any leading "::"
106 1         3 $name =~ s{\A ::}{}mxs;
107 1 50       4 is_module_name($name) or ouch 400, $invalid_error;
108              
109             # look for classes inside "backend" kind
110 1         49 my %flag;
111 1         6 for my $base ($package, __PACKAGE__) {
112 1 50       5 next if $flag{$base}++;
113 1         5 my $class = $base . '::Backend::' . $name;
114 1 50       3 eval { require_module($class) } and return $class;
  1         3  
115             }
116              
117 0           ouch 400, "cannot resolve '$name' to a backend module package";
118             }
119              
120             1;