File Coverage

blib/lib/Lingua/EST/Num2Word.pm
Criterion Covered Total %
statement 27 102 26.4
branch 2 66 3.0
condition 4 75 5.3
subroutine 9 11 81.8
pod 3 3 100.0
total 45 257 17.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::EST::Num2Word;
4             # ABSTRACT: Number to word conversion in Estonian
5              
6 1     1   98833 use 5.16.0;
  1         5  
7 1     1   7 use utf8;
  1         3  
  1         18  
8 1     1   40 use warnings;
  1         2  
  1         78  
9              
10             # {{{ use block
11              
12 1     1   6 use Carp;
  1         3  
  1         74  
13 1     1   570 use Export::Attrs;
  1         9948  
  1         6  
14 1     1   2111 use Readonly;
  1         3913  
  1         474  
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             # {{{ num2est_cardinal convert number to text
25              
26             sub num2est_cardinal :Export {
27 2     2 1 200709 my $positive = shift;
28              
29 2 50 33     39 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 2         25 my @ones = qw(null üks kaks kolm neli viis kuus seitse kaheksa üheksa);
36              
37 2 50 33     21 return $ones[$positive] if ($positive >= 0 && $positive < 10);
38 0 0         return 'kümme' if ($positive == 10);
39              
40             # 11-19: stem + teist
41 0 0 0       if ($positive > 10 && $positive < 20) {
42 0           my @teens = qw(üksteist kaksteist kolmteist neliteist viisteist
43             kuusteist seitseteist kaheksateist üheksateist);
44 0           return $teens[$positive - 11];
45             }
46              
47 0           my $out;
48             my $remain;
49              
50 0           my @tens_prefix = qw(. . kaks kolm neli viis kuus seitse kaheksa üheksa);
51              
52 0 0 0       if ($positive > 19 && $positive < 100) { # 20 .. 99
    0 0        
    0 0        
    0 0        
    0          
53 0           my $tens_idx = int($positive / 10);
54 0           $remain = $positive % 10;
55              
56 0           $out = $tens_prefix[$tens_idx] . 'kümmend';
57 0 0         $out .= ' ' . $ones[$remain] if ($remain);
58             }
59             elsif ($positive == 100) { # 100
60 0           $out = 'sada';
61             }
62             elsif ($positive > 100 && $positive < 1000) { # 101 .. 999
63 0           my $hundreds = int($positive / 100);
64 0           $remain = $positive % 100;
65              
66 0 0         $out = $hundreds == 1 ? 'sada' : $ones[$hundreds] . 'sada';
67 0 0         $out .= ' ' . num2est_cardinal($remain) if ($remain);
68             }
69             elsif ($positive >= 1000 && $positive < 1_000_000) { # 1000 .. 999_999
70 0           my $thousands = int($positive / 1000);
71 0           $remain = $positive % 1000;
72              
73 0 0         $out = $thousands == 1 ? 'tuhat' : num2est_cardinal($thousands) . ' tuhat';
74 0 0         $out .= ' ' . num2est_cardinal($remain) if ($remain);
75             }
76             elsif ($positive >= 1_000_000 && $positive < 1_000_000_000) { # 1_000_000 .. 999_999_999
77 0           my $millions = int($positive / 1_000_000);
78 0           $remain = $positive % 1_000_000;
79              
80 0 0         if ($millions == 1) {
81 0           $out = 'miljon';
82             }
83             else {
84 0           $out = num2est_cardinal($millions) . ' miljonit';
85             }
86 0 0         $out .= ' ' . num2est_cardinal($remain) if ($remain);
87             }
88              
89 0           return $out;
90 1     1   15 }
  1         4  
  1         12  
91              
92             # }}}
93              
94              
95             # {{{ num2est_ordinal convert number to ordinal text
96              
97             sub num2est_ordinal :Export {
98 0     0 1   my $number = shift;
99              
100 0 0 0       croak 'You should specify a number from interval [1, 999_999_999]'
      0        
      0        
101             if !defined $number
102             || $number !~ m{\A\d+\z}xms
103             || $number < 1
104             || $number > 999_999_999;
105              
106             # 1-10: unique ordinal forms
107 0           my %base_ordinals = (
108             1 => 'esimene',
109             2 => 'teine',
110             3 => 'kolmas',
111             4 => 'neljas',
112             5 => 'viies',
113             6 => 'kuues',
114             7 => 'seitsmes',
115             8 => 'kaheksas',
116             9 => 'üheksas',
117             10 => 'kümnes',
118             );
119              
120 0 0         return $base_ordinals{$number} if exists $base_ordinals{$number};
121              
122             # 11-19: stem + "teistkümnes"
123 0 0 0       if ($number >= 11 && $number <= 19) {
124 0           my @teen_stems = qw(. ühe kahe kolme nelja viie kuue seitse kaheksa üheksa);
125 0           return $teen_stems[$number - 10] . 'teistkümnes';
126             }
127              
128             # Round tens 20-90: stem + "kümnes"
129 0 0 0       if ($number >= 20 && $number < 100 && $number % 10 == 0) {
      0        
130 0           my @tens_stems = qw(. . kahe kolme nelja viie kuue seitse kaheksa üheksa);
131 0           my $tens_idx = int($number / 10);
132 0           return $tens_stems[$tens_idx] . 'kümnes';
133             }
134              
135             # Compound 21-99: cardinal tens prefix + ordinal unit
136 0 0 0       if ($number > 20 && $number < 100) {
137 0           my @tens_prefix = qw(. . kaks kolm neli viis kuus seitse kaheksa üheksa);
138 0           my $tens_idx = int($number / 10);
139 0           my $remain = $number % 10;
140 0           return $tens_prefix[$tens_idx] . 'kümmend ' . num2est_ordinal($remain);
141             }
142              
143             # Round hundreds
144 0 0 0       if ($number >= 100 && $number < 1000 && $number % 100 == 0) {
      0        
145 0           my $h = int($number / 100);
146 0           my @ones = qw(. üks kaks kolm neli viis kuus seitse kaheksa üheksa);
147 0 0         my $prefix = $h == 1 ? 'sajas' : $ones[$h] . 'sajas';
148 0           return $prefix;
149             }
150              
151             # Compound hundreds
152 0 0 0       if ($number >= 100 && $number < 1000) {
153 0           my $h = int($number / 100);
154 0           my $remain = $number % 100;
155 0           my @ones = qw(. üks kaks kolm neli viis kuus seitse kaheksa üheksa);
156 0 0         my $prefix = $h == 1 ? 'sada' : $ones[$h] . 'sada';
157 0           return $prefix . ' ' . num2est_ordinal($remain);
158             }
159              
160             # Round thousands
161 0 0 0       if ($number >= 1000 && $number < 1_000_000 && $number % 1000 == 0) {
      0        
162 0           my $t = int($number / 1000);
163 0 0         my $prefix = $t == 1 ? 'tuhandes' : num2est_cardinal($t) . ' tuhandes';
164 0           return $prefix;
165             }
166              
167             # Compound thousands
168 0 0 0       if ($number >= 1000 && $number < 1_000_000) {
169 0           my $t = int($number / 1000);
170 0           my $remain = $number % 1000;
171 0 0         my $prefix = $t == 1 ? 'tuhat' : num2est_cardinal($t) . ' tuhat';
172 0           return $prefix . ' ' . num2est_ordinal($remain);
173             }
174              
175             # Round millions
176 0 0 0       if ($number >= 1_000_000 && $number < 1_000_000_000 && $number % 1_000_000 == 0) {
      0        
177 0           my $m = int($number / 1_000_000);
178 0 0         if ($m == 1) {
179 0           return 'miljones';
180             }
181 0           return num2est_cardinal($m) . ' miljones';
182             }
183              
184             # Compound millions
185 0 0 0       if ($number >= 1_000_000 && $number < 1_000_000_000) {
186 0           my $m = int($number / 1_000_000);
187 0           my $remain = $number % 1_000_000;
188 0 0         my $prefix = $m == 1 ? 'miljon' : num2est_cardinal($m) . ' miljonit';
189 0           return $prefix . ' ' . num2est_ordinal($remain);
190             }
191              
192 0           return;
193 1     1   853 }
  1         3  
  1         6  
194              
195             # }}}
196              
197             # {{{ capabilities declare supported features
198              
199             sub capabilities {
200             return {
201 0     0 1   cardinal => 1,
202             ordinal => 1,
203             };
204             }
205              
206             # }}}
207             1;
208              
209             __END__