File Coverage

blib/lib/Ordeal/Model.pm
Criterion Covered Total %
statement 105 121 86.7
branch 19 34 55.8
condition 3 9 33.3
subroutine 22 24 91.6
pod 7 7 100.0
total 156 195 80.0


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 6     6   466202 use 5.020;
  6         81  
6 6     6   36 use strict;
  6         12  
  6         139  
7 6     6   30 use warnings;
  6         12  
  6         330  
8             { our $VERSION = '0.004'; }
9              
10 6     6   3261 use English qw< -no_match_vars >;
  6         20160  
  6         32  
11 6     6   2506 use Ouch;
  6         2606  
  6         33  
12 6     6   7432 use Mo qw< default >;
  6         3169  
  6         34  
13 6     6   6515 use Path::Tiny;
  6         11572  
  6         289  
14 6     6   39 use Scalar::Util qw< blessed >;
  6         10  
  6         266  
15 6     6   3112 use Module::Runtime qw< use_module require_module is_module_name >;
  6         11079  
  6         34  
16              
17 6     6   3246 use Ordeal::Model::ChaCha20;
  6         16  
  6         219  
18 6     6   2503 use Ordeal::Model::Evaluator;
  6         17  
  6         258  
19 6     6   2693 use Ordeal::Model::Parser;
  6         17  
  6         299  
20              
21 6     6   43 use experimental qw< signatures postderef >;
  6         12  
  6         29  
22 6     6   910 no warnings qw< experimental::signatures experimental::postderef >;
  6         12  
  6         6619  
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 2     2   5 sub _backend_factory ($package, $name, @args) {
  2         5  
  2         5  
  2         4  
  2         4  
33 2         19 $name = $package->resolve_backend_name($name);
34 2         87 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 3405 sub evaluate ($self, $what, %args) {
  3         7  
  3         6  
  3         6  
  3         6  
43 3 50       12 my $ast = ref($what) ? $what : $self->parse($what);
44 2         11 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 5334 sub get_card ($self, $id) { return $self->backend->card($id) }
  4         6  
  4         7  
  4         17  
  4         13  
52 9     9 1 23989 sub get_deck ($self, $id) { return $self->backend->deck($id) }
  9         20  
  9         16  
  9         15  
  9         33  
53 0     0 1 0 sub get_deck_ids ($self) { return $self->backend->decks }
  0         0  
  0         0  
  0         0  
54              
55 5     5 1 1827 sub new ($package, @rest) {
  5         16  
  5         15  
  5         10  
56 5 50 33     55 my %args = (@_ && ref($_[0])) ? %{$rest[0]} : @rest;
  0         0  
57 5         12 my $backend;
58 5 100       26 if (defined(my $b = $args{backend})) {
    50          
    50          
59             $backend = blessed($b) ? $args{backend}
60 4 50       33 : (ref($b) eq 'ARRAY') ? $package->_backend_factory(@$b)
    100          
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       5 my @args = ref($as) eq 'ARRAY' ? @$as : %$as;
69 1         5 $backend = $package->_backend_factory($name, @args);
70             }
71             else {
72 0         0 ouch 400, 'too many arguments to initialize Model';
73             }
74              
75 5         118 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       14 ouch 400, 'undefined input expression to parse()' unless defined $text;
80 2         9 return Ordeal::Model::Parser::PARSE($text);
81             }
82              
83 2     2   3 sub _random_source ($self, %args) {
  2         14  
  2         6  
  2         3  
84 2 50       7 return $args{random_source} if $args{random_source};
85              
86             return Ordeal::Model::ChaCha20->new->restore($args{random_source_state})
87 2 50       5 if defined $args{random_source_state};
88              
89             return Ordeal::Model::ChaCha20->new(seed => $args{seed})
90 2 50       29 if defined $args{seed};
91              
92 0         0 return $self->random_source;
93             }
94              
95 2     2 1 4 sub resolve_backend_name ($package, $name) {
  2         4  
  2         4  
  2         4  
96 2   33     11 $package = ref($package) || $package;
97 2         10 my $invalid_error = "invalid name '$name' for module resolution";
98              
99             # if it has "::" *inside* but does not start with them, use directly
100 2 50 33     17 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 2         9 $name =~ s{\A ::}{}mxs;
107 2 50       8 is_module_name($name) or ouch 400, $invalid_error;
108              
109             # look for classes inside "backend" kind
110 2         97 my %flag;
111 2         9 for my $base ($package, __PACKAGE__) {
112 2 50       11 next if $flag{$base}++;
113 2         8 my $class = $base . '::Backend::' . $name;
114 2 50       5 eval { require_module($class) } and return $class;
  2         17  
115             }
116              
117 0           ouch 400, "cannot resolve '$name' to a backend module package";
118             }
119              
120             1;