File Coverage

blib/lib/Text/Roman.pm
Criterion Covered Total %
statement 57 57 100.0
branch 29 30 96.6
condition 9 11 81.8
subroutine 11 11 100.0
pod 5 5 100.0
total 111 114 97.3


line stmt bran cond sub pod time code
1             package Text::Roman;
2             # ABSTRACT: Allows conversion between Roman and Arabic algarisms.
3              
4              
5 6     6   193408 use strict;
  6         16  
  6         344  
6 6     6   299 use warnings qw(all);
  6         17  
  6         284  
7              
8 6     6   35 use Carp qw(carp);
  6         10  
  6         500  
9 6     6   35 use Exporter;
  6         11  
  6         7494  
10              
11             ## no critic (ProhibitAutomaticExportation, ProhibitExplicitISA)
12             our @ISA = qw(Exporter);
13             our %EXPORT_TAGS = (all => [qw(roman int2roman roman2int isroman mroman2int milhar2int ismroman ismilhar)]);
14             our @EXPORT_OK = @{$EXPORT_TAGS{all}};
15              
16             our $VERSION = '3.5'; # VERSION
17              
18             our @RSN = qw/I V X L C D M/; # Roman Simple Numerals
19             our @RCN = qw/IV IX XL XC CD CM/; # Roman Complex Numerals
20             our %R2A;
21             @R2A{@RSN, @RCN} = qw/
22             1 5 10 50 100 500 1000 4 9 40 90 400 900
23             /; # numeric values
24             our %A2R = reverse %R2A; # reverse for convenience
25              
26              
27             ## no critic (RequireArgUnpacking)
28             sub isroman {
29 4247 100   4247 1 10910 local $_ = uc(@_ ? shift : $_);
30              
31 4247 100       26926 return if !/^[@RSN]+$/x;
32 4246 100       33327 return if /([IXCM])\1{3,}|([VLD])\2+/x; # tests repeatability
33 4244         8093 my @re = qw/IXI|XCX|CMC/;
34 4244         9218 for (1 .. $#RSN) {
35 25464         54509 push @re, "$RSN[$_ - 1]$RSN[$_]$RSN[$_ - 1]"; # tests IVI
36 25464         50277 push @re, "$RSN[$_]$RSN[$_ - 1]$RSN[$_]"; # and VIV conditions
37             }
38 4244         20143 my $re = join "|", @re;
39 4244         27885 return !/$re/x;
40             }
41              
42              
43             sub int2roman {
44 4108 100   4108 1 25281 my $n = @_ ? shift : $_;
45             return
46 4108 100 66     38092 if not $n =~ /^[0-9]+$/x
      100        
47             or $n <= 0
48             or $n >= 4000;
49              
50 4105         5607 my $ret = '';
51 4105         17193 for (reverse sort { $a <=> $b } values %R2A) {
  135682         136300  
52 53365         102057 $ret .= $A2R{$_} x int($n / $_);
53 53365         71470 $n %= $_;
54             }
55              
56             return defined(wantarray)
57 4105 100       20585 ? $ret
58             : $_ = $ret;
59             }
60              
61              
62             sub roman2int {
63 4118     4118 1 25880 my $ret = 0;
64 4118         4263 do {
65 4118 100       10977 local $_ = uc(@_ ? shift : $_);
66              
67 4118 100       6455 return unless isroman();
68              
69 4117         7657 my ($r, $_ret) = ($_, 0);
70 4117         7655 while ($r) {
71 28336   66     1939778 $r =~ s/^$_//x and ($ret += $R2A{$_}, last) for @RCN, @RSN;
72 28336 50       66199 return if $ret <= $_ret;
73 28336         63016 $_ret = $ret;
74             }
75             };
76              
77             return defined(wantarray)
78 4117 100       14412 ? $ret
79             : $_ = $ret;
80             }
81              
82              
83             sub ismilhar {
84 9 100   9 1 622 local $_ = uc(@_ ? shift : $_);
85 9 100       198 return unless /^[_@RSN]+$/x;
86              
87 8         39 my @r = split /_/;
88 8   100     28 isroman() || return for @r;
89 7         158 return 1;
90             }
91              
92              
93             sub milhar2int {
94 6     6 1 693 my $ret;
95 6         35 do {
96 6 100       30 local $_ = uc(@_ ? shift : $_);
97              
98 6 100       20 return unless ismilhar();
99              
100 5         23 my @r = split /_/;
101 5         17 $ret = roman2int(pop @r);
102 5         20 $ret += 1000 * roman2int() for @r;
103             };
104              
105             return defined(wantarray)
106 5 100       34 ? $ret
107             : $_ = $ret;
108             }
109              
110              
111             my %deprecated = (
112             ismroman => [ ismilhar => \&ismilhar ],
113             mroman2int => [ milhar2int => \&milhar2int ],
114             roman => [ int2roman => \&int2roman ],
115             );
116              
117             for my $aliased (keys %deprecated) {
118             ## no critic (ProhibitNoStrict)
119 6     6   50 no strict 'refs';
  6         11  
  6         730  
120             *{'Text::Roman::' . $aliased} = sub {
121 3     3   603 carp sprintf(
122             '%s() deprecated, use %s() instead',
123             $aliased, $deprecated{$aliased}->[0]
124             );
125 3         13 goto $deprecated{$aliased}->[1];
126             };
127             }
128              
129             1;
130              
131             __END__