File Coverage

blib/lib/Lingua/KIR/Num2Word.pm
Criterion Covered Total %
statement 49 61 80.3
branch 24 32 75.0
condition 17 41 41.4
subroutine 10 11 90.9
pod 3 3 100.0
total 103 148 69.5


line stmt bran cond sub pod time code
1             # For Emacs: -*- mode:cperl; eval: (folding-mode 1); coding:utf-8 -*-
2              
3             package Lingua::KIR::Num2Word;
4             # ABSTRACT: Number to word conversion in Kyrgyz
5              
6 1     1   81189 use 5.16.0;
  1         3  
7 1     1   4 use utf8;
  1         1  
  1         12  
8 1     1   19 use warnings;
  1         1  
  1         48  
9              
10             # {{{ use block
11              
12 1     1   5 use Carp;
  1         1  
  1         85  
13 1     1   514 use Export::Attrs;
  1         10001  
  1         5  
14 1     1   671 use Readonly;
  1         4567  
  1         691  
15              
16             # }}}
17             # {{{ variable declarations
18              
19             my Readonly::Scalar $COPY = 'Copyright (c) PetaMem, s.r.o. 2002-present';
20             our $VERSION = '0.2603300';
21              
22             # }}}
23              
24             # {{{ num2kir_cardinal convert number to text
25              
26             sub num2kir_cardinal :Export {
27 52     52 1 149809 my $positive = shift;
28              
29 52 50 33     395 croak 'You should specify a number from interval [0, 999_999_999]'
      33        
      33        
30             if !defined $positive
31             || $positive !~ m{\A\d+\z}xms
32             || $positive < 0
33             || $positive > 999_999_999;
34              
35 52         160 my @ones = ('нөл', 'бир', 'эки', 'үч', 'төрт', 'беш', 'алты', 'жети', 'сегиз', 'тогуз');
36 52         95 my @tens = ('он', 'жыйырма', 'отуз', 'кырк', 'элүү', 'алтымыш', 'жетимиш', 'сексен', 'токсон');
37              
38 52 100 66     140 return $ones[$positive] if ($positive >= 0 && $positive < 10); # 0 .. 9
39 37 100 66     118 return $tens[$positive / 10 - 1] if ($positive >= 10 && $positive < 100 && $positive % 10 == 0); # 10,20,..,90
      100        
40              
41 31         70 my $out;
42             my $remain;
43              
44 31 100 66     118 if ($positive > 9 && $positive < 100) { # 11 .. 99
    100 66        
    100 66        
    100 33        
    50          
45 11         17 my $ten_idx = int($positive / 10);
46 11         10 $remain = $positive % 10;
47              
48 11         24 $out = $tens[$ten_idx - 1] . ' ' . $ones[$remain];
49             }
50             elsif ($positive == 100) { # 100
51 2         3 $out = 'жүз';
52             }
53             elsif ($positive > 100 && $positive < 1000) { # 101 .. 999
54 9         16 my $hun_idx = int($positive / 100);
55 9         20 $remain = $positive % 100;
56              
57 9 100       20 $out = $hun_idx == 1 ? 'жүз' : $ones[$hun_idx] . ' жүз';
58 9 100       24 $out .= $remain ? ' ' . num2kir_cardinal($remain) : '';
59             }
60             elsif ($positive >= 1000 && $positive < 1_000_000) { # 1000 .. 999_999
61 7         12 my $tho_idx = int($positive / 1000);
62 7         8 $remain = $positive % 1000;
63              
64 7 100       15 $out = $tho_idx == 1 ? 'миң' : num2kir_cardinal($tho_idx) . ' миң';
65 7 100       28 $out .= $remain ? ' ' . num2kir_cardinal($remain) : '';
66             }
67             elsif ($positive >= 1_000_000 && $positive < 1_000_000_000) { # 1_000_000 .. 999_999_999
68 2         5 my $mil_idx = int($positive / 1_000_000);
69 2         3 $remain = $positive % 1_000_000;
70              
71 2         5 $out = num2kir_cardinal($mil_idx) . ' миллион';
72 2 100       7 $out .= $remain ? ' ' . num2kir_cardinal($remain) : '';
73             }
74              
75 31         79 return $out;
76 1     1   8 }
  1         1  
  1         5  
77              
78             # }}}
79              
80             # {{{ num2kir_ordinal convert number to ordinal text
81              
82             sub num2kir_ordinal :Export {
83 0     0 1 0 my $number = shift;
84              
85 0 0 0     0 croak 'You should specify a number from interval [1, 999_999_999]'
      0        
      0        
86             if !defined $number
87             || $number !~ m{\A\d+\z}xms
88             || $number < 1
89             || $number > 999_999_999;
90              
91 0         0 my $cardinal = num2kir_cardinal($number);
92              
93             # Kyrgyz ordinals: cardinal + suffix determined by vowel harmony.
94             # Cyrillic vowels: а, е, и, о, ө, у, ү, ы
95             # After consonant: -(ы)нчы / -(и)нчи / -(у)нчу / -(ү)нчү
96             # After vowel: -нчы / -нчи / -нчу / -нчү
97              
98 0         0 my $last_vowel = q{};
99 0 0       0 if ($cardinal =~ m{([аеиоөуүы])[^аеиоөуүы]*\z}xms) {
100 0         0 $last_vowel = $1;
101             }
102              
103 0         0 my $ends_in_vowel = $cardinal =~ m{[аеиоөуүы]\z}xms;
104              
105 0         0 my %suffix_v = ( # after vowel
106             'а' => 'нчы', 'ы' => 'нчы',
107             'е' => 'нчи', 'и' => 'нчи',
108             'о' => 'нчу', 'у' => 'нчу',
109             'ө' => 'нчү', 'ү' => 'нчү',
110             );
111 0         0 my %suffix_c = ( # after consonant
112             'а' => 'ынчы', 'ы' => 'ынчы',
113             'е' => 'инчи', 'и' => 'инчи',
114             'о' => 'унчу', 'у' => 'унчу',
115             'ө' => 'үнчү', 'ү' => 'үнчү',
116             );
117              
118 0 0       0 my $suffix_table = $ends_in_vowel ? \%suffix_v : \%suffix_c;
119 0   0     0 my $suffix = $suffix_table->{$last_vowel} // 'инчи';
120              
121 0         0 return $cardinal . $suffix;
122 1     1   585 }
  1         3  
  1         5  
123              
124             # }}}
125              
126             # {{{ capabilities declare supported features
127              
128             sub capabilities {
129             return {
130 1     1 1 529 cardinal => 1,
131             ordinal => 1,
132             };
133             }
134              
135             # }}}
136             1;
137              
138             __END__