File Coverage

blib/lib/Lingua/GLE/Num2Word.pm
Criterion Covered Total %
statement 63 64 98.4
branch 32 34 94.1
condition 7 9 77.7
subroutine 9 10 90.0
pod 2 2 100.0
total 113 119 94.9


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; eval: (folding-mode 1); coding:utf-8; -*-
2              
3             package Lingua::GLE::Num2Word;
4             # ABSTRACT: Number to word conversion in Irish (Gaeilge)
5              
6 1     1   109502 use 5.16.0;
  1         3  
7 1     1   4 use utf8;
  1         2  
  1         11  
8 1     1   21 use warnings;
  1         1  
  1         40  
9              
10             # {{{ use block
11              
12 1     1   5 use Carp;
  1         2  
  1         59  
13 1     1   581 use Export::Attrs;
  1         9215  
  1         5  
14              
15             # }}}
16             # {{{ variable declarations
17              
18             our $VERSION = '0.2603300';
19              
20             # Irish (Gaeilge) uses a decimal counting system in modern usage.
21             # The counting form uses the "a" prefix before unit digits.
22             # Going up to 999_999_999.
23              
24             my @units = qw(náid a_haon a_dó a_trí a_ceathair a_cúig a_sé a_seacht a_hocht a_naoi);
25             my @tens = (undef, 'a_deich', 'fiche', 'tríocha', 'daichead', 'caoga',
26             'seasca', 'seachtó', 'ochtó', 'nócha');
27              
28             # }}}
29              
30             # {{{ num2gle_cardinal convert number to text
31              
32             sub num2gle_cardinal :Export {
33 23     23 1 387940 my $num = shift;
34              
35 23 100 66     1093 croak 'You should specify a number from interval [0, 999_999_999]'
      66        
      100        
36             if !defined $num
37             || $num !~ m{\A\d+\z}xms
38             || $num < 0
39             || $num > 999_999_999;
40              
41             # Zero
42 21 100       74 return 'náid' if $num == 0;
43              
44 20         41 my @parts;
45              
46             # Millions
47 20 100       55 if ($num >= 1_000_000) {
48 2         9 my $millions = int($num / 1_000_000);
49 2 100       11 push @parts, _cardinal_below_1000($millions) if $millions > 1;
50 2         5 push @parts, 'milliún';
51 2         5 $num %= 1_000_000;
52             }
53              
54             # Thousands
55 20 100       52 if ($num >= 1000) {
56 3         13 my $thousands = int($num / 1000);
57 3 100       14 push @parts, _cardinal_below_1000($thousands) if $thousands > 1;
58 3         10 push @parts, 'míle';
59 3         10 $num %= 1000;
60             }
61              
62             # Remainder below 1000
63 20 100       58 if ($num > 0) {
64 17         47 push @parts, _cardinal_below_1000($num);
65             }
66              
67 20         74 my $result = join(' ', @parts);
68 20         102 $result =~ s/_/ /g;
69 20         282 return $result;
70 1     1   323 }
  1         1  
  1         15  
71              
72             # }}}
73             # {{{ _cardinal_below_1000 internal: handle 1-999
74              
75             sub _cardinal_below_1000 {
76 19     19   52 my $num = shift;
77              
78 19 50       50 return if $num == 0;
79              
80 19         34 my @parts;
81              
82             # Hundreds
83 19 100       54 if ($num >= 100) {
84 5         18 my $h = int($num / 100);
85 5 100       34 if ($h == 1) {
86 2         7 push @parts, 'céad';
87             }
88             else {
89 3         16 push @parts, $units[$h], 'céad';
90             }
91 5         15 $num %= 100;
92             }
93              
94             # Tens and units
95 19 100       56 if ($num > 0) {
96 17         43 push @parts, _cardinal_below_100($num);
97             }
98              
99 19         68 return @parts;
100             }
101              
102             # }}}
103             # {{{ _cardinal_below_100 internal: handle 1-99
104              
105             sub _cardinal_below_100 {
106 17     17   34 my $num = shift;
107              
108 17 50       43 return if $num == 0;
109              
110             # 1-9: counting form
111 17 100       44 if ($num < 10) {
112 4         18 return $units[$num];
113             }
114              
115             # 10: a deich
116 13 100       35 if ($num == 10) {
117 1         3 return 'a_deich';
118             }
119              
120             # 11-19: unit + déag (12 uses dhéag)
121 12 100       34 if ($num < 20) {
122 3         7 my $u = $num - 10;
123 3 100       9 my $deag = ($u == 2) ? 'dhéag' : 'déag';
124 3         26 return $units[$u] . ' ' . $deag;
125             }
126              
127             # 20-99
128 12         28 my $t = int($num / 10);
129 12         20 my $u = $num % 10;
130              
131 12 100       27 if ($u == 0) {
132 2         9 return $tens[$t];
133             }
134              
135             # tens + a + unit
136 10         53 return $tens[$t] . ' ' . $units[$u];
137             }
138              
139             # }}}
140              
141             # {{{ capabilities declare supported features
142              
143             sub capabilities {
144             return {
145 0     0 1   cardinal => 1,
146             ordinal => 0,
147             };
148             }
149              
150             # }}}
151             1;
152              
153             __END__