File Coverage

blib/lib/Convert/Pluggable.pm
Criterion Covered Total %
statement 18 181 9.9
branch 0 56 0.0
condition 0 20 0.0
subroutine 6 15 40.0
pod 6 8 75.0
total 30 280 10.7


line stmt bran cond sub pod time code
1             package Convert::Pluggable;
2              
3 1     1   109078 use Moo;
  1         16554  
  1         6  
4              
5 1     1   2469 use File::Slurp qw/read_file/;
  1         15906  
  1         66  
6              
7 1     1   1020 use Data::Float qw/float_is_infinite float_is_nan/;
  1         9166  
  1         93  
8 1     1   7 use Scalar::Util qw/looks_like_number/;
  1         2  
  1         65  
9              
10 1     1   1000 use JSON;
  1         103392  
  1         6  
11 1     1   1569 use Switch;
  1         73883  
  1         7  
12              
13             our @EXPORT_OK = qw(convert get_units);
14              
15             our $VERSION = '0.032';
16             our $DEFAULT_PRECISION = 3;
17              
18             has data_file => ( is => 'lazy', );
19              
20             has types => ( is => 'lazy', );
21              
22             sub temperature_get_factor {
23 0     0 0   my $convert = shift;
24              
25 0           switch ( $convert->{'from_unit'} ) {
  0            
  0            
26 0 0         case /^(fahrenheit|f)$/i { return $convert->{'factor'}; }
  0            
  0            
  0            
  0            
  0            
  0            
27 0 0         case /^(celsius|c)$/i {
  0            
28 0           return ( $convert->{'factor'} * ( 9 / 5 ) ) + 32;
29 0           }
  0            
  0            
  0            
30 0 0         case /^(kelvin|k)$/i {
  0            
31 0           return ( $convert->{'factor'} * ( 9 / 5 ) ) - 459.67;
32 0           }
  0            
  0            
  0            
33 0 0         case /^(rankine|r)$/i { return ( $convert->{'factor'} - 491.67 ) + 32; }
  0            
  0            
  0            
  0            
  0            
  0            
34 0 0         case /^(reaumur|re)$/i {
  0            
35 0           return ( $convert->{'factor'} * ( 9 / 4 ) ) + 32;
36 0           }
  0            
  0            
  0            
37 0           else { return undef; }
38 0           }
39             }
40              
41             sub convert_temperatures {
42 0     0 1   my $convert = shift;
43              
44             # convert $from to fahrenheit:
45 0           my $factor = temperature_get_factor($convert);
46              
47             # convert fahrenheit $to:
48 0           switch ( $convert->{'to_unit'} ) {
  0            
  0            
49 0 0         case /^(fahrenheit|f)$/i { return $factor; }
  0            
  0            
  0            
  0            
  0            
  0            
50 0 0         case /^(celsius|c)$/i { return ( $factor - 32 ) * ( 5 / 9 ); }
  0            
  0            
  0            
  0            
  0            
  0            
51 0 0         case /^(kelvin|k)$/i { return ( $factor + 459.67 ) * ( 5 / 9 ); }
  0            
  0            
  0            
  0            
  0            
  0            
52 0 0         case /^(rankine|r)$/i { return $factor + 459.67; }
  0            
  0            
  0            
  0            
  0            
  0            
53 0 0         case /^(reaumur|re)$/i { return ( $factor - 32 ) * ( 4 / 9 ); }
  0            
  0            
  0            
  0            
  0            
  0            
54 0           else { return undef; }
55 0           }
56             }
57              
58             sub get_matches {
59 0     0 1   my $self = shift;
60 0           my $matches = shift;
61              
62 0           my @matches = @{$matches};
  0            
63              
64 0           $matches[0] =~ s/"/inches/;
65 0           $matches[0] =~ s/'/feet/;
66 0           $matches[1] =~ s/"/inches/;
67 0           $matches[1] =~ s/'/feet/;
68              
69 0           my @match_types = ();
70 0           my @factors = ();
71 0           my @units = ();
72 0           my @can_be_negative = ();
73              
74 0           my @types = @{ get_units() };
  0            
75              
76 0           foreach my $match (@matches) {
77 0           foreach my $type ( @{ $self->types } ) {
  0            
78 0 0 0       if ( lc $match eq $type->{'unit'}
79 0           || grep { $_ eq lc $match } @{ $type->{'aliases'} } )
  0            
80             {
81 0           push( @match_types, $type->{'type'} );
82 0           push( @factors, $type->{'factor'} );
83 0           push( @units, $type->{'unit'} );
84 0   0       push( @can_be_negative, $type->{'can_be_negative'} || '0' );
85             }
86             }
87             }
88              
89 0 0         return if scalar(@match_types) != 2;
90 0 0         return if scalar(@factors) != 2;
91 0 0         return if scalar(@units) != 2;
92 0 0         return if scalar(@can_be_negative) != 2;
93              
94 0           my %matches = (
95             'type_1' => $match_types[0],
96             'type_2' => $match_types[1],
97             'factor_1' => $factors[0],
98             'factor_2' => $factors[1],
99             'from_unit' => $units[0],
100             'to_unit' => $units[1],
101             'can_be_negative_1' => $can_be_negative[0],
102             'can_be_negative_2' => $can_be_negative[1],
103             );
104              
105 0           return \%matches;
106             }
107              
108             sub convert {
109 0     0 1   my $self = shift;
110              
111 0           my $conversion = shift;
112             my $matches = get_matches( $self,
113 0           [ $conversion->{'from_unit'}, $conversion->{'to_unit'} ] );
114              
115             return
116 0 0 0       if !( $matches->{'type_1'} && $matches->{'type_2'} );
117              
118 0 0         if ( looks_like_number( $conversion->{'factor'} ) ) {
119              
120             # looks_like_number thinks 'Inf' and 'NaN' are numbers:
121             return
122             if float_is_infinite( $conversion->{'factor'} )
123 0 0 0       || float_is_nan( $conversion->{'factor'} );
124              
125             # if factor is < 0 and first thing can't be negative ...
126             return
127 0 0 0       if $conversion->{'factor'} < 0 && !$matches->{'can_be_negative_1'};
128             }
129             else {
130             # if it doesn't look like a number, and it contains a number (e.g., '6^2'):
131 0           $conversion->{'factor'} = parse_number( $conversion->{'factor'} );
132             }
133              
134 0 0         return if $conversion->{'factor'} =~ /[[:alpha:]]/;
135              
136             # matches must be of the same type (e.g., can't convert mass to length):
137 0 0         return if ( $matches->{'type_1'} ne $matches->{'type_2'} );
138              
139             # run the conversion:
140             # temperatures don't have 1:1 conversions, so they get special treatment:
141 0           my $factor;
142 0 0         if ( $matches->{'type_1'} eq 'temperature' ) {
143             $factor = convert_temperatures(
144             {
145             from_unit => $matches->{'from_unit'},
146             to_unit => $matches->{'to_unit'},
147 0           factor => $conversion->{'factor'},
148             }
149             );
150             }
151             else {
152             $factor = $conversion->{'factor'} *
153 0           ( $matches->{'factor_2'} / $matches->{'factor_1'} );
154             }
155              
156 0 0 0       return if $factor < 0 && !( $matches->{'can_be_negative_2'} );
157              
158             $matches->{'result'} = precision(
159             {
160             factor => $factor,
161 0   0       precision => $conversion->{'precision'} || $DEFAULT_PRECISION,
162             }
163             );
164              
165 0           return $matches;
166             }
167              
168             # thanks, @mwmiller!
169             sub parse_number {
170 0     0 1   my $in = shift;
171              
172 0 0         my $out =
173             ( $in =~ /^(-?\d*(?:\.?\d+))\^(-?\d*(?:\.?\d+))$/ ) ? $1**$2 : $in;
174              
175 0 0         return $in if $out =~ /[^\d]/; # elo
176              
177 0           return 0 + $out;
178             }
179              
180             sub _build_types {
181 0     0     my $self = shift;
182              
183 0           return get_units( $self->{data_file} );
184             }
185              
186             sub get_units {
187 0     0 1   my $self = shift;
188              
189             #my $data_file = shift // 'NO_DATA_FILE';
190 0 0         my $data_file = defined(shift) ? shift : 'NO_DATA_FILE';
191              
192 0           my $units;
193              
194 0 0         if ( $data_file eq 'NO_DATA_FILE' ) {
195              
196 0           $units = encode_json( old_get_units() );
197              
198             }
199             else {
200 0           $units = read_file($data_file);
201             }
202              
203 0           return decode_json($units);
204             }
205              
206             # does it make sense to return X if precision is > 1?
207             # e.g., result = '0.999' with precision = '3' returns '1' atm
208             # e.g., result = '1.000' with precision = '3' returns '1' atm
209             sub precision {
210 0     0 0   my $precision = shift;
211              
212 0 0         if ( $precision->{'factor'} == 0 ) { return 0; }
  0            
213              
214 0           my $f = $precision->{'factor'} * ( 10**$precision->{'precision'} );
215              
216 0           my $r = int( $f + $f / abs( $f * 2 ) );
217              
218 0           return $r / ( 10**$precision->{'precision'} );
219             }
220              
221             sub old_get_units {
222              
223             # metric ton is base unit for mass
224             # known SI units and aliases / plurals
225 0     0 1   my @mass = (
226             {
227             'unit' => 'metric ton',
228             'factor' => '1',
229             'aliases' => [
230             'tonne', 't', 'mt', 'te',
231             'metric tons', 'tonnes', 'ts', 'mts',
232             'tes'
233             ],
234             'type' => 'mass',
235             },
236             {
237             'unit' => 'ounce',
238             'factor' => '35274',
239             'aliases' => [ 'oz', 'ounces', 'ozs' ],
240             'type' => 'mass',
241             },
242             {
243             'unit' => 'pound',
244             'factor' => '2204.62',
245             'aliases' => [
246             'lb', 'lbm', 'pound mass', 'pounds',
247             'lbs', 'lbms', 'pounds mass'
248             ],
249             'type' => 'mass',
250             },
251             {
252             'unit' => 'stone',
253             'factor' => '157.473',
254             'aliases' => [ 'st', 'stones', 'sts' ],
255             'type' => 'mass',
256             },
257             {
258             'unit' => 'long ton',
259             'factor' => '0.984207',
260             'aliases' => [
261             'weight ton',
262             'imperial ton',
263             'long tons',
264             'weight tons',
265             'imperial tons'
266             ],
267             'type' => 'mass',
268             },
269             {
270             'unit' => 'microgram',
271             'factor' => 1_000_000_000_000,
272             'aliases' => [ 'mcg', 'micrograms', 'mcgs' ],
273             'type' => 'mass',
274             },
275             {
276             'unit' => 'kilogram',
277             'factor' => 1000,
278             'aliases' => [
279             'kg', 'kilo', 'kilogramme', 'kilograms',
280             'kgs', 'kilos', 'kilogrammes'
281             ],
282             'type' => 'mass',
283             },
284             {
285             'unit' => 'gram',
286             'factor' => 1_000_000,
287             'aliases' =>
288             [ 'g', 'gm', 'gramme', 'grams', 'gs', 'gms', 'grammes' ],
289             'type' => 'mass',
290             },
291             {
292             'unit' => 'milligram',
293             'factor' => 1_000_000_000,
294             'aliases' => [ 'mg', 'milligrams', 'mgs' ],
295             'type' => 'mass',
296             },
297             {
298             'unit' => 'ton',
299             'factor' => '1.10231',
300             'aliases' => [ 'short ton', 'short tons', 'tons' ],
301             'type' => 'mass',
302             },
303             );
304              
305             # meter is the base unit for length
306             # known SI units and aliases / plurals
307 0           my @length = (
308             {
309             'unit' => 'meter',
310             'factor' => '1',
311             'aliases' => [ 'meters', 'metre', 'metres', 'm' ],
312             'type' => 'length',
313             },
314             {
315             'unit' => 'kilometer',
316             'factor' => '0.001',
317             'aliases' => [
318             'kilometers', 'kilometre', 'kilometres', 'km',
319             'kms', 'klick', 'klicks'
320             ],
321             'type' => 'length',
322             },
323             {
324             'unit' => 'centimeter',
325             'factor' => '100',
326             'aliases' =>
327             [ 'centimeters', 'centimetre', 'centimetres', 'cm', 'cms' ],
328             'type' => 'length',
329             },
330             {
331             'unit' => 'millimeter',
332             'factor' => '1000',
333             'aliases' =>
334             [ 'millimeters', 'millimetre', 'millimetres', 'mm', 'mms' ],
335             'type' => 'length',
336             },
337             {
338             'unit' => 'mile',
339             'factor' => 1 / 1609.344,
340             'aliases' => [
341             'miles',
342             'statute mile',
343             'statute miles',
344             'land mile',
345             'land miles',
346             'mi'
347             ],
348             'type' => 'length',
349             },
350             {
351             'unit' => 'yard',
352             'factor' => '1.0936133',
353             'aliases' => [ 'yards', 'yd', 'yds', 'yrds', 'yrd' ],
354             'type' => 'length',
355             },
356             {
357             'unit' => 'foot',
358             'factor' => '3.28084',
359             'aliases' => [
360             'feet',
361             'ft',
362             'international foot',
363             'international feet',
364             'survey foot',
365             'survey feet'
366             ],
367             'type' => 'length',
368             },
369             {
370             'unit' => 'inch',
371             'factor' => '39.3701',
372             'aliases' => [ 'inches', 'in', 'ins' ],
373             'type' => 'length',
374             },
375             {
376             'unit' => 'nautical mile',
377             'factor' => '0.000539957',
378             'aliases' =>
379             [ 'nautical miles', 'n', 'ns', 'nm', 'nms', 'nmi', 'nmis' ],
380             'type' => 'length',
381             },
382             {
383             'unit' => 'furlong',
384             'factor' => ( 1 / 201.168 ),
385             'aliases' => ['furlongs'],
386             'type' => 'length',
387             },
388             {
389             'unit' => 'chain',
390             'factor' => ( 1 / 20.1168 ),
391             'aliases' => [ "gunter's chains", 'chains' ],
392             'type' => 'length',
393             },
394             {
395             'unit' => 'link',
396             'factor' => ( 1 / 0.201168 ),
397             'aliases' => [ "gunter's links", 'links' ],
398             'type' => 'length',
399             },
400             {
401             'unit' => 'rod',
402             'factor' => 1 / (5.0292),
403             'aliases' => ['rods'],
404             'type' => 'length',
405             },
406             {
407             'unit' => 'fathom',
408             'factor' => 1 / (1.853184),
409             'aliases' => [ 'fathoms', 'ftm', 'ftms' ],
410             'type' => 'length',
411             },
412             {
413             'unit' => 'league',
414             'factor' => 1 / (4828.032),
415             'aliases' => ['leagues'],
416             'type' => 'length',
417             },
418             {
419             'unit' => 'cable',
420             'factor' => 1 / (185.3184),
421             'aliases' => ['cables'],
422             'type' => 'length',
423             },
424             {
425             'unit' => 'light year',
426             'factor' => ( 1 / 9460730472580800 ),
427             'aliases' => [ 'light years', 'ly', 'lys' ],
428             'type' => 'length',
429             },
430             {
431             'unit' => 'parsec',
432             'factor' => ( 1 / 30856776376340067 ),
433             'aliases' => [ 'parsecs', 'pc', 'pcs' ],
434             'type' => 'length',
435             },
436             {
437             'unit' => 'astronomical unit',
438             'factor' => ( 1 / 149597870700 ),
439             'aliases' => [ 'astronomical units', 'au', 'aus' ],
440             'type' => 'length',
441             },
442             );
443              
444             # day is base unit for time
445             # known SI units and aliases / plurals
446 0           my @time = (
447             {
448             'unit' => 'day',
449             'factor' => '1',
450             'aliases' => [ 'days', 'dy', 'dys', 'd' ],
451             'type' => 'duration',
452             },
453             {
454             'unit' => 'second',
455             'factor' => '86400',
456             'aliases' => [ 'seconds', 'sec', 's' ],
457             'type' => 'duration',
458             },
459             {
460             'unit' => 'millisecond',
461             'factor' => '86400000',
462             'aliases' => [ 'milliseconds', 'millisec', 'millisecs', 'ms' ],
463             'type' => 'duration',
464             },
465             {
466             'unit' => 'microsecond',
467             'factor' => '86400000000',
468             'aliases' => [ 'microseconds', 'microsec', 'microsecs', 'us' ],
469             'type' => 'duration',
470             },
471             {
472             'unit' => 'nanosecond',
473             'factor' => '86400000000000',
474             'aliases' => [ 'nanoseconds', 'nanosec', 'nanosecs', 'ns' ],
475             'type' => 'duration',
476             },
477             {
478             'unit' => 'minute',
479             'factor' => '1440',
480             'aliases' => [ 'minutes', 'min', 'mins' ],
481             'type' => 'duration',
482             },
483             {
484             'unit' => 'hour',
485             'factor' => '24',
486             'aliases' => [ 'hours', 'hr', 'hrs', 'h' ],
487             'type' => 'duration',
488             },
489             {
490             'unit' => 'week',
491             'factor' => 1 / 7,
492             'aliases' => [ 'weeks', 'wks', 'wk' ],
493             'type' => 'duration',
494             },
495             {
496             'unit' => 'fortnight',
497             'factor' => 1 / 14,
498             'aliases' => [],
499             'type' => 'duration',
500             },
501             {
502             'unit' => 'month',
503             'factor' => 12 / 365,
504             'aliases' => [ 'months', 'mons', 'mns', 'mn' ],
505             'type' => 'duration',
506             },
507             {
508             'unit' => 'year',
509             'factor' => 1 / 365,
510             'aliases' => [ 'years', 'yr', 'yrs' ],
511             'type' => 'duration',
512             },
513             {
514             'unit' => 'leap year',
515             'factor' => 1 / 366,
516             'aliases' => [ 'leap years', 'leapyear', 'leapyr', 'leapyrs' ],
517             'type' => 'duration',
518             },
519             );
520              
521             # pascal is base unit for pressure
522             # known SI units and aliases / plurals
523 0           my @pressure = (
524             {
525             'unit' => 'pascal',
526             'factor' => 1,
527             'aliases' => [ 'pascals', 'pa', 'pas' ],
528             'type' => 'pressure',
529             },
530             {
531             'unit' => 'kilopascal',
532             'factor' => ( 1 / 1000 ),
533             'aliases' => [ 'kilopascals', 'kpa', 'kpas' ],
534             'type' => 'pressure',
535             },
536             {
537             'unit' => 'megapascal',
538             'factor' => ( 1 / 1_000_000 ),
539             'aliases' => [ 'megapascals', 'megapa', 'megapas' ],
540             'type' => 'pressure',
541             },
542             {
543             'unit' => 'gigapascal',
544             'factor' => ( 1 / 1_000_000_000 ),
545             'aliases' => [ 'gigapascals', 'gpa', 'gpas' ],
546             'type' => 'pressure',
547             },
548             {
549             'unit' => 'bar',
550             'factor' => 1 / (100_000),
551             'aliases' => [ 'bars', 'pa', 'pas' ],
552             'type' => 'pressure',
553             },
554             {
555             'unit' => 'atmosphere',
556             'factor' => 1 / (101_325),
557             'aliases' => [ 'atmospheres', 'atm', 'atms' ],
558             'type' => 'pressure',
559             },
560             {
561             'unit' => 'pounds per square inch',
562             'factor' => 1 / 6894.8,
563             'aliases' => [ 'psis', 'psi', 'lbs/inch^2', 'p.s.i.', 'p.s.i' ],
564             'type' => 'pressure',
565             },
566             );
567              
568             # joule is base unit for energy
569             # known SI units and aliases / plurals
570 0           my @energy = (
571             {
572             'unit' => 'joule',
573             'factor' => 1,
574             'aliases' => [ 'joules', 'j', 'js' ],
575             'type' => 'energy',
576             },
577             {
578             'unit' => 'watt-second',
579             'factor' => (1),
580             'aliases' => [ 'watt second', 'watt seconds', 'ws' ],
581             'type' => 'energy',
582             },
583             {
584             'unit' => 'watt-hour',
585             'factor' => ( 1 / 3600 ),
586             'aliases' => [ 'watt hour', 'watt hours', 'wh' ],
587             'type' => 'energy',
588             },
589             {
590             'unit' => 'kilowatt-hour',
591             'factor' => ( 1 / 3_600_000 ),
592             'aliases' => [ 'kilowatt hour', 'kilowatt hours', 'kwh' ],
593             'type' => 'energy',
594             },
595             {
596             'unit' => 'erg',
597             'factor' => ( 1 / 10_000_000 ),
598             'aliases' => [ 'ergon', 'ergs', 'ergons' ],
599             'type' => 'energy',
600             },
601             {
602             'unit' => 'electron volt',
603             'factor' => (6.2415096e+18),
604             'aliases' => [ 'electronvolt', 'electron volts', 'ev', 'evs' ],
605             'type' => 'energy',
606             },
607             {
608             'unit' => 'thermochemical gram calorie',
609             'factor' => ( 1 / 4.184 ),
610             'aliases' => [
611             'small calories',
612             'thermochemical gram calories',
613             'chemical calorie',
614             'chemical calories'
615             ],
616             'type' => 'energy',
617             },
618             {
619             'unit' => 'large calorie',
620             'factor' => ( 1 / 4184 ),
621             'aliases' => [
622             'large calories',
623             'food calorie',
624             'food calories',
625             'kcals',
626             'kcal'
627             ],
628             'type' => 'energy',
629             },
630             {
631             'unit' => 'british thermal unit',
632             'factor' => ( 1 / 1054.5 ),
633             'aliases' => [ 'british thermal units', 'btu', 'btus' ],
634             'type' => 'energy',
635             },
636             {
637             'unit' => 'ton of TNT',
638             'factor' => ( 1 / 4.184e+9 ),
639             'aliases' =>
640             [ 'tnt equivilent', 'tonnes of tnt', 'tnt', 'tons of tnt' ],
641             'type' => 'energy',
642             }
643             );
644              
645             # watt is base unit for power
646             # known SI units and aliases / plurals
647 0           my @power = (
648             {
649             'unit' => 'watt',
650             'factor' => 1,
651             'aliases' => [ 'watts', 'w' ],
652             'type' => 'power',
653             },
654             {
655             'unit' => 'kilowatt',
656             'factor' => 1 / 1000,
657             'aliases' => [ 'kilowatts', 'kw' ],
658             'type' => 'power',
659             },
660             {
661             'unit' => 'megawatt',
662             'factor' => 1 / 1_000_000,
663             'aliases' => [ 'megawatts', 'mw' ],
664             'type' => 'power',
665             },
666             {
667             'unit' => 'gigawatt',
668             'factor' => 1 / 1_000_000_000,
669             'aliases' => [ 'gigawatts', 'jiggawatts', 'gw' ],
670             'type' => 'power',
671             },
672             {
673             'unit' => 'terawatt',
674             'factor' => 1 / 1_000_000_000_000,
675             'aliases' => [ 'terawatts', 'tw' ],
676             'type' => 'power',
677             },
678             {
679             'unit' => 'petawatt',
680             'factor' => 1 / 1_000_000_000_000_000,
681             'aliases' => [ 'petawatts', 'pw' ],
682             'type' => 'power',
683             },
684             {
685             'unit' => 'milliwatt',
686             'factor' => 1000,
687             'aliases' => ['milliwatts'],
688             'type' => 'power',
689             },
690             {
691             'unit' => 'microwatt',
692             'factor' => 1_000_000,
693             'aliases' => ['microwatts'],
694             'type' => 'power',
695             },
696             {
697             'unit' => 'nanowatt',
698             'factor' => 1_000_000_000,
699             'aliases' => [ 'nanowatts', 'nw' ],
700             'type' => 'power',
701             },
702             {
703             'unit' => 'picowatt',
704             'factor' => 1_000_000_000_000,
705             'aliases' => [ 'picowatts', 'pw' ],
706             'type' => 'power',
707             },
708             {
709             'unit' => 'metric horsepower',
710             'factor' => ( 1 / 735.49875 ),
711             'aliases' => [
712             'metric horsepowers',
713             'mhp', 'hp', 'ps', 'cv', 'hk', 'ks', 'ch'
714             ],
715             'type' => 'power',
716             },
717             {
718             'unit' => 'horsepower',
719             'factor' => ( 1 / 745.69987158227022 ),
720             'aliases' =>
721             [ 'mechnical horsepower', 'horsepower', 'hp', 'hp', 'bhp' ],
722             'type' => 'power',
723             },
724             {
725             'unit' => 'electical horsepower',
726             'factor' => ( 1 / 746 ),
727             'aliases' => [ 'electical horsepowers', 'hp', 'hp' ],
728             'type' => 'power',
729             },
730             );
731              
732             # degree is base unit for angles
733             # known SI units and aliases / plurals
734 0           my @angle = (
735             {
736             'unit' => 'degree',
737             'factor' => 1,
738             'aliases' => [ 'degrees', 'deg', 'degs' ],
739             'type' => 'angle',
740             },
741             {
742             'unit' => 'radian',
743             'factor' => 3.14159265358979323 / 180,
744             'aliases' => [ 'radians', 'rad', 'rads' ],
745             'type' => 'angle',
746             },
747             {
748             'unit' => 'gradian',
749             'factor' => 10 / 9,
750             'aliases' =>
751             [ 'gradians', 'grad', 'grads', 'gon', 'gons', 'grade', 'grades' ],
752             'type' => 'angle',
753             },
754             {
755             'unit' => 'quadrant',
756             'factor' => 1 / 90,
757             'aliases' => [ 'quadrants', 'quads', 'quad' ],
758             'type' => 'angle',
759             },
760             {
761             'unit' => 'semi-circle',
762             'factor' => 1 / 180,
763             'aliases' => [
764             'semi circle', 'semicircle', 'semi circles', 'semicircles',
765             'semi-circles'
766             ],
767             'type' => 'angle',
768             },
769             {
770             'unit' => 'revolution',
771             'factor' => 1 / 360,
772             'aliases' => [ 'revolutions', 'circle', 'circles', 'revs' ],
773             'type' => 'angle',
774             },
775             );
776              
777             # newton is base unit for force
778             # known SI units and aliases / plurals
779 0           my @force = (
780             {
781             'unit' => 'newton',
782             'factor' => 1,
783             'aliases' => [ 'newtons', 'n' ],
784             'type' => 'force',
785             },
786             {
787             'unit' => 'kilonewton',
788             'factor' => 1 / 1000,
789             'aliases' => [ 'kilonewtons', 'kn' ],
790             'type' => 'force',
791             },
792             {
793             'unit' => 'meganewton',
794             'factor' => 1 / 1_000_000,
795             'aliases' => [ 'meganewtons', 'mn' ],
796             'type' => 'force',
797             },
798             {
799             'unit' => 'giganewton',
800             'factor' => 1 / 1_000_000_000,
801             'aliases' => [ 'giganewtons', 'gn' ],
802             'type' => 'force',
803             },
804             {
805             'unit' => 'dyne',
806             'factor' => 1 / 100000,
807             'aliases' => ['dynes'],
808             'type' => 'force',
809             },
810             {
811             'unit' => 'kilodyne',
812             'factor' => 1 / 100,
813             'aliases' => ['kilodynes'],
814             'type' => 'force',
815             },
816             {
817             'unit' => 'megadyne',
818             'factor' => 10,
819             'aliases' => ['megadynes'],
820             'type' => 'force',
821             },
822             {
823             'unit' => 'pounds force',
824             'factor' => 1 / 4.4482216152605,
825             'aliases' => [ 'lbs force', 'pounds force' ],
826             'type' => 'force',
827             },
828             {
829             'unit' => 'poundal',
830             'factor' => 1 / 0.138254954376,
831             'aliases' => [ 'poundals', 'pdl' ],
832             'type' => 'force',
833             },
834             );
835              
836             # fahrenheit is base unit for temperature
837             # known SI units and aliases / plurals
838 0           my @temperature = (
839             {
840             'unit' => 'fahrenheit',
841             'factor' => 1, # all '1' because un-used
842             'aliases' => ['f'],
843             'type' => 'temperature',
844             'can_be_negative' => 1,
845             },
846             {
847             'unit' => 'celsius',
848             'factor' => 1,
849             'aliases' => ['c'],
850             'type' => 'temperature',
851             'can_be_negative' => 1,
852             },
853             {
854             'unit' => 'kelvin',
855             'factor' => 1,
856             'aliases' => ['k'], # be careful ... other units could use 'K'
857             'type' => 'temperature',
858             },
859             {
860             'unit' => 'rankine',
861             'factor' => 1,
862             'aliases' => ['r'],
863             'type' => 'temperature',
864             },
865             {
866             'unit' => 'reaumur',
867             'factor' => 1,
868             'aliases' => ['re']
869             , # also can be 'R', but that's being used for rankine
870             'type' => 'temperature',
871             'can_be_negative' => 1,
872             },
873             );
874              
875             # bit is base unit for digital
876             # while not absolutely correct, a byte is defined as 8 bits herein.
877             # known SI units and aliases / plurals
878 0           my @digital = (
879             {
880             'unit' => 'bit',
881             'factor' => 1,
882             'aliases' => ['bits'],
883             'type' => 'digital',
884             },
885             {
886             'unit' => 'kilobit',
887             'factor' => 1 / 1_000,
888             'aliases' => [ 'kbit', 'kbits', 'kilobits' ],
889             'type' => 'digital',
890             },
891             {
892             'unit' => 'megabit',
893             'factor' => 1 / 1_000_000,
894             'aliases' => [ 'mbit', 'mbits', 'megabits' ],
895             'type' => 'digital',
896             },
897             {
898             'unit' => 'gigabit',
899             'factor' => 1 / 1_000_000_000,
900             'aliases' => [ 'gbit', 'gigabits', 'gbits' ],
901             'type' => 'digital',
902             },
903             {
904             'unit' => 'terabit',
905             'factor' => 1 / 1_000_000_000_000,
906             'aliases' => [ 'tbit', 'tbits', 'terabits' ],
907             'type' => 'digital',
908             },
909             {
910             'unit' => 'petabit',
911             'factor' => 1 / 1_000_000_000_000_000,
912             'aliases' => [ 'pbit', 'pbits', 'petabits' ],
913             'type' => 'digital',
914             },
915             {
916             'unit' => 'exabit',
917             'factor' => 1 / 1_000_000_000_000_000_000,
918             'aliases' => [ 'ebit', 'ebits', 'exabits' ],
919             'type' => 'digital',
920             },
921             {
922             'unit' => 'zettabit',
923             'factor' => 1 / 1_000_000_000_000_000_000_000,
924             'aliases' => [ 'zbit', 'zbits', 'zettabits' ],
925             'type' => 'digital',
926             },
927             {
928             'unit' => 'yottabit',
929             'factor' => 1 / 1_000_000_000_000_000_000_000_000,
930             'aliases' => [ 'ybit', 'ybits', 'yottabits' ],
931             'type' => 'digital',
932             },
933             {
934             'unit' => 'kibibit',
935             'factor' => 1 / 1024,
936             'aliases' => [ 'kibit', 'kibits', 'kibibits' ],
937             'type' => 'digital',
938             },
939             {
940             'unit' => 'mebibit',
941             'factor' => 1 / 1024**2,
942             'aliases' => [ 'mibit', 'mibits', 'mebibits' ],
943             'type' => 'digital',
944             },
945             {
946             'unit' => 'gibibit',
947             'factor' => 1 / 1024**3,
948             'aliases' => [ 'gibit', 'gibits', 'gibibits' ],
949             'type' => 'digital',
950             },
951             {
952             'unit' => 'tebibit',
953             'factor' => 1 / 1024**4,
954             'aliases' => [ 'tibit', 'tibits', 'tebibits' ],
955             'type' => 'digital',
956             },
957             {
958             'unit' => 'pebibit',
959             'factor' => 1 / 1024**5,
960             'aliases' => [ 'pibit', 'pibits', 'pebibits' ],
961             'type' => 'digital',
962             },
963             {
964             'unit' => 'exbibit',
965             'factor' => 1 / 1024**6,
966             'aliases' => [ 'eibit', 'eibits', 'exbibits' ],
967             'type' => 'digital',
968             },
969             {
970             'unit' => 'zebibit',
971             'factor' => 1 / 1024**7,
972             'aliases' => [ 'zibit', 'zibits', 'zebibits' ],
973             'type' => 'digital',
974             },
975             {
976             'unit' => 'yobibit',
977             'factor' => 1 / 1024**8,
978             'aliases' => [ 'yibit', 'yibits', 'yobibits' ],
979             'type' => 'digital',
980             },
981             {
982             'unit' => 'byte',
983             'factor' => 1 / 8,
984             'aliases' => ['bytes'],
985             'type' => 'digital',
986             },
987             {
988             'unit' => 'kilobyte',
989             'factor' => 1 / 8_000,
990             'aliases' => [ 'kb', 'kbs', 'kilobytes' ],
991             'type' => 'digital',
992             },
993             {
994             'unit' => 'megabyte',
995             'factor' => 1 / 8_000_000,
996             'aliases' => [ 'mb', 'mbs', 'megabytes' ],
997             'type' => 'digital',
998             },
999             {
1000             'unit' => 'gigabyte',
1001             'factor' => 1 / 8_000_000_000,
1002             'aliases' => [ 'gb', 'gbs', 'gigabytes' ],
1003             'type' => 'digital',
1004             },
1005             {
1006             'unit' => 'terabyte',
1007             'factor' => 1 / 8_000_000_000_000,
1008             'aliases' => [ 'tb', 'tbs', 'terabytes' ],
1009             'type' => 'digital',
1010             },
1011             {
1012             'unit' => 'petabyte',
1013             'factor' => 1 / 8_000_000_000_000_000,
1014             'aliases' => [ 'pb', 'pbs', 'petabytes' ],
1015             'type' => 'digital',
1016             },
1017             {
1018             'unit' => 'exabyte',
1019             'factor' => 1 / 8_000_000_000_000_000_000,
1020             'aliases' => [ 'eb', 'ebs', 'exabytes' ],
1021             'type' => 'digital',
1022             },
1023             {
1024             'unit' => 'zettabyte',
1025             'factor' => 1 / 8_000_000_000_000_000_000_000,
1026             'aliases' => [ 'zb', 'zbs', 'zettabytes' ],
1027             'type' => 'digital',
1028             },
1029             {
1030             'unit' => 'yottabyte',
1031             'factor' => 1 / 8_000_000_000_000_000_000_000_000,
1032             'aliases' => [ 'yb', 'ybs', 'yottabytes' ],
1033             'type' => 'digital',
1034             },
1035             {
1036             'unit' => 'kibibyte',
1037             'factor' => 1 / 8192,
1038             'aliases' => [ 'kib', 'kibs', 'kibibytes' ], # KB
1039             'type' => 'digital',
1040             },
1041             {
1042             'unit' => 'mebibyte',
1043             'factor' => 1 / 8388608,
1044             'aliases' => [ 'mib', 'mibs', 'mebibytes' ], # MB
1045             'type' => 'digital',
1046             },
1047             {
1048             'unit' => 'gibibyte',
1049             'factor' => 1 / 8589934592, # 1/8*1024**3 ...
1050             'aliases' => [ 'gib', 'gibs', 'gibibytes' ], # GB ...
1051             'type' => 'digital',
1052             },
1053             {
1054             'unit' => 'tebibyte',
1055             'factor' => 1 / 8796093022208,
1056             'aliases' => [ 'tib', 'tibs', 'tebibytes' ],
1057             'type' => 'digital',
1058             },
1059             {
1060             'unit' => 'pebibyte',
1061             'factor' => 1 / 9007199254740992, # 1/8*1024**5 ...
1062             'aliases' => [ 'pib', 'pibs', 'pebibytes' ],
1063             'type' => 'digital',
1064             },
1065             {
1066             'unit' => 'exbibyte',
1067             'factor' => 1 / 9.22337203685478e+18,
1068             'aliases' => [ 'eib', 'eibs', 'exbibytes' ],
1069             'type' => 'digital',
1070             },
1071             {
1072             'unit' => 'zebibyte',
1073             'factor' => 1 / 9.44473296573929e+21,
1074             'aliases' => [ 'zib', 'zibs', 'zebibytes' ],
1075             'type' => 'digital',
1076             },
1077             {
1078             'unit' => 'yobibyte',
1079             'factor' => 1 / 9.67140655691703e+24,
1080             'aliases' => [ 'yib', 'yibs', 'yobibytes' ],
1081             'type' => 'digital',
1082             },
1083             );
1084              
1085             # hectare is base unit for area
1086 0           my @area = (
1087             {
1088             'unit' => 'hectare',
1089             'factor' => 1,
1090             'aliases' => [ 'hectares', 'ha' ],
1091             'type' => 'area',
1092             },
1093             {
1094             'unit' => 'acre',
1095             'factor' => 2.4710439,
1096             'aliases' => ['acres'],
1097             'type' => 'area',
1098             },
1099             {
1100             'unit' => 'square meter',
1101             'factor' => 10_000,
1102             'aliases' => [
1103             'square meters', 'metre^2',
1104             'meter^2', 'metres^2',
1105             'meters^2', 'square metre',
1106             'square metres', 'm^2'
1107             ],
1108             'type' => 'area',
1109             },
1110             {
1111             'unit' => 'square kilometer',
1112             'factor' => 0.01,
1113             'aliases' => [
1114             'square kilometers',
1115             'square kilometre',
1116             'square kilometres',
1117             'km^2'
1118             ],
1119             'type' => 'area',
1120             },
1121             {
1122             'unit' => 'square centimeter',
1123             'factor' => 100_000_000,
1124             'aliases' => [
1125             'square centimeters',
1126             'square centimetre',
1127             'square centimetres',
1128             'cm^2'
1129             ],
1130             'type' => 'area',
1131             },
1132             {
1133             'unit' => 'square millimeter',
1134             'factor' => 10_000_000_000,
1135             'aliases' => [
1136             'square millimeters',
1137             'square millimetre',
1138             'square millimetres',
1139             'mm^2'
1140             ],
1141             'type' => 'area',
1142             },
1143             {
1144             'unit' => 'square mile',
1145             'factor' => 1 / 258.99881,
1146             'aliases' => [
1147             'square miles',
1148             'square statute mile',
1149             'square statute miles',
1150             'square land mile',
1151             'square land miles',
1152             'miles^2',
1153             'sq mi'
1154             ],
1155             'type' => 'area',
1156             },
1157             {
1158             'unit' => 'square yard',
1159             'factor' => 11959.9,
1160             'aliases' =>
1161             [ 'square yards', 'yard^2', 'yards^2', 'yd^2', 'yrd^2' ],
1162             'type' => 'area',
1163             },
1164             {
1165             'unit' => 'square foot',
1166             'factor' => 107639.1,
1167             'aliases' => [ 'square feet', 'feet^2', 'foot^2', 'foot', 'ft^2' ],
1168             'type' => 'area',
1169             },
1170             {
1171             'unit' => 'square inch',
1172             'factor' => 15500031,
1173             'aliases' =>
1174             [ 'square inches', 'inch^2', 'inches^2', 'squinch', 'in^2' ],
1175             'type' => 'area',
1176             },
1177             {
1178             'unit' => 'tsubo',
1179             'factor' => 3024.9863876,
1180             'aliases' => ['tsubos'],
1181             'type' => 'area',
1182             }
1183             );
1184              
1185             # litre is the base unit for volume
1186 0           my @volume = (
1187             {
1188             'unit' => 'litre',
1189             'factor' => 1,
1190             'aliases' =>
1191             [ 'liter', 'litres', 'liters', 'l', 'litter', 'litters' ],
1192             'type' => 'volume',
1193             },
1194             {
1195             'unit' => 'millilitre',
1196             'factor' => 1000,
1197             'aliases' => [ 'milliliter', 'millilitres', 'milliliters', 'ml' ],
1198             'type' => 'volume',
1199             },
1200             {
1201             'unit' => 'cubic metre',
1202             'factor' => 1 / 1000,
1203             'aliases' =>
1204             [ 'metre^3', 'meter^3', 'metres^3', 'meters^3', 'm^3' ],
1205             'type' => 'volume',
1206             },
1207             {
1208             'unit' => 'cubic centimetre',
1209             'factor' => 1000,
1210             'aliases' => [
1211             'centimetre^3', 'centimeter^3',
1212             'centimetres^3', 'centimeters^3',
1213             'cm^3'
1214             ],
1215             'type' => 'volume',
1216             },
1217             {
1218             'unit' => 'cubic millimetre',
1219             'factor' => 1_000_000,
1220             'aliases' => [
1221             'millimetre^3', 'millimeter^3',
1222             'millimetres^3', 'millimeters^3',
1223             'mm^3'
1224             ],
1225             'type' => 'volume',
1226             },
1227             {
1228             'unit' => 'liquid pint',
1229             'factor' => 1000 / 473.176473,
1230             'aliases' => [
1231             'liquid pints',
1232             'us pints',
1233             'us liquid pint',
1234             'us liquid pints'
1235             ],
1236             'type' => 'volume',
1237             },
1238             {
1239             'unit' => 'dry pint',
1240             'factor' => 1000 / 550.6104713575,
1241             'aliases' => ['dry pints'],
1242             'type' => 'volume',
1243             },
1244             {
1245             'unit' => 'imperial pint',
1246             'factor' => 1000 / 568.26125,
1247             'aliases' => [
1248             'pints', 'pint', 'imperial pints', 'uk pint',
1249             'british pint', 'pts'
1250             ],
1251             'type' => 'volume',
1252             },
1253             {
1254             'unit' => 'imperial gallon',
1255             'factor' => 1 / 4.54609,
1256             'aliases' => [
1257             'imperial gallon',
1258             'uk gallon',
1259             'british gallon',
1260             'british gallons',
1261             'uk gallons'
1262             ],
1263             'type' => 'volume',
1264             },
1265             {
1266             'unit' => 'us gallon',
1267             'factor' => 1 / 3.78541178,
1268             'aliases' => [
1269             'fluid gallon',
1270             'us fluid gallon',
1271             'fluid gallons',
1272             'us gallons',
1273             'gallon',
1274             'gallons'
1275             ],
1276             'type' => 'volume',
1277             },
1278             {
1279             'unit' => 'quart',
1280             'factor' => 1 / 0.946352946,
1281             'aliases' => [
1282             'liquid quart',
1283             'us quart',
1284             'us quarts',
1285             'quarts',
1286             'liquid quarts'
1287             ],
1288             'type' => 'volume',
1289             },
1290             {
1291             'unit' => 'imperial quart',
1292             'factor' => 4 * 1000 / 568.26125,
1293             'aliases' =>
1294             [ 'imperial quarts', 'british quarts', 'british quart' ],
1295             'type' => 'volume',
1296             },
1297             {
1298             'unit' => 'imperial fluid ounce',
1299             'factor' => 16 * 1000 / 568.26125,
1300             'aliases' => [
1301             'imperial fluid ounces',
1302             'imperial fl oz',
1303             'imperial fluid oz',
1304             ],
1305             'type' => 'volume',
1306             },
1307             {
1308             'unit' => 'us fluid ounce',
1309             'factor' => 16 * 1000 / 473.176473,
1310             'aliases' =>
1311             [ 'us fluid ounces', 'us fl oz', 'fl oz', 'fl. oz', 'fluid oz' ],
1312             'type' => 'volume',
1313             },
1314             {
1315             'unit' => 'us cup',
1316             'factor' => 4.2267528,
1317             'aliases' => [ 'us cups', 'cups', 'cup' ],
1318             'type' => 'volume',
1319             },
1320             {
1321             'unit' => 'metric cup',
1322             'factor' => 4,
1323             'aliases' => ['metric cups'],
1324             'type' => 'volume',
1325             },
1326             );
1327              
1328             # unit types available for conversion
1329 0           my @types = (
1330             @mass, @length, @area, @volume,
1331             @time, @pressure, @energy, @power,
1332             @angle, @force, @temperature, @digital
1333             );
1334              
1335 0           return \@types;
1336             }
1337              
1338             1;
1339              
1340             __END__