dictable 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -1
- data/README.md +45 -19
- data/dictable.gemspec +5 -3
- data/dictionaries/en/address_abbreviations_exploded.yml +206 -0
- data/dictionaries/en/numbers_to_words.yml +32 -0
- data/lib/dictable/street_name.rb +14 -0
- data/lib/dictable/street_number.rb +60 -0
- data/lib/dictable/version.rb +1 -1
- data/lib/dictable.rb +23 -35
- metadata +11 -8
- data/lib/dictable/dictable_number.rb +0 -114
- data/lib/dictable/exceptions.rb +0 -11
- data/lib/dictable/extend_primitives.rb +0 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5bce84832eecc44c3b43987ab5a20d95fad7b135f5b14febd2e0cccccb414654
|
|
4
|
+
data.tar.gz: f02c799cf5ee3928c6d26adac75f9c84bbc02a335cb8d89579e90cbd605152fb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1c8d79925d5b9495fb525c0d5d0c141aca3667c73ef37ae0f203a434f93e151fa30577e963463edf6b2b44572af712182c3acd0d78d44943b996764713acd275
|
|
7
|
+
data.tar.gz: f98accf83447ec44cd1162a5bd5b07b2ecd0b1bca26d4d1f957a47cab0285805b47ab097cce742f565a79595b3890163eaf2bc6155b0d456c7d129e4ef8e3a7d
|
data/CHANGELOG.md
CHANGED
|
@@ -24,4 +24,14 @@
|
|
|
24
24
|
## [0.1.4] - 2024-01-14
|
|
25
25
|
|
|
26
26
|
- Refactor to use instance methods to avoid exposing so many
|
|
27
|
-
- Added rubocop and fixed all errors
|
|
27
|
+
- Added rubocop and fixed all errors
|
|
28
|
+
|
|
29
|
+
## [0.1.5] - 2024-03-01
|
|
30
|
+
|
|
31
|
+
- Refactor to simplify
|
|
32
|
+
- Supporting leading zeroes is out of scope
|
|
33
|
+
- Added dictionaries to explode address abbreviations
|
|
34
|
+
|
|
35
|
+
## [0.1.6] - 2024-03-01
|
|
36
|
+
|
|
37
|
+
- Fix issue with dictionaries not loading when importing the gem in another project
|
data/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Dictable
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Ever encountered the challenge of ensuring your text-to-speech applications pronounce addresses just the way most people in the U.S. do? Dictable is here to bridge that gap. This Ruby Gem transforms addresses like `1234 N Lasalle Ave` into their spoken-word equivalents, such as `twelve thirty four north lasalle avenue`, optimizing them for clear and natural dictation.
|
|
4
|
+
|
|
5
|
+
Our approach to converting numbers into words is opinionated and intentionally avoids frequent use of "hundred" and "thousand" unless common usage dictates otherwise. The goal? To closely replicate the nuanced way addresses are articulated in everyday conversation across the U.S. Dive into the examples from our tests to see the difference in action.
|
|
6
|
+
|
|
7
|
+
In a landscape where text-to-voice platforms each have their unique way of pronouncing numbers, as of March 2024, Dictable hands you the reins for more consistent and predictable address dictation.
|
|
4
8
|
|
|
5
9
|
## Installation
|
|
6
10
|
|
|
@@ -29,27 +33,49 @@ To use Dictable, simply call the `to_dictable` method on any `Integer`, this con
|
|
|
29
33
|
```ruby
|
|
30
34
|
require 'dictable'
|
|
31
35
|
|
|
32
|
-
puts
|
|
33
|
-
#
|
|
36
|
+
puts Dictable.address('2300 N Lincoln Park St')
|
|
37
|
+
# > 'twenthy three hundred North Lincoln Park Street'
|
|
34
38
|
|
|
35
|
-
puts "1243".to_dictable_number
|
|
36
|
-
# Output: "twelve forty three"
|
|
37
39
|
```
|
|
38
40
|
|
|
39
41
|
## Example
|
|
40
|
-
List of samples from specs:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
42
|
+
List of samples from specs for addresses:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
Dictable::StreetName
|
|
46
|
+
converts 1234 N Lasalle Ave to 1234 north lasalle avenue
|
|
47
|
+
converts 1234 E Chelsea Rd to 1234 east chelsea road
|
|
48
|
+
converts 1234 s Chelsea st to 1234 south chelsea street
|
|
49
|
+
converts 1234 w Chelsea Blvd to 1234 west chelsea boulevard
|
|
50
|
+
converts 1234 N Clifford Dr to 1234 north clifford drive
|
|
51
|
+
converts 1234 E Chelsea Ct to 1234 east chelsea court
|
|
52
|
+
converts 1234 S Chelsea pl to 1234 south chelsea place
|
|
53
|
+
converts 1234 S Chelsea Pl Gandalf to 1234 south chelsea place gandalf
|
|
54
|
+
converts 1234 W Chelsea Ter to 1234 west chelsea terrace
|
|
55
|
+
|
|
56
|
+
Dictable::StreetNumber
|
|
57
|
+
converts 0 to zero
|
|
58
|
+
converts 5 to five
|
|
59
|
+
converts 10 to ten
|
|
60
|
+
converts 21 to twenty one
|
|
61
|
+
converts 100 to one hundred
|
|
62
|
+
converts 103 to one hundred three
|
|
63
|
+
converts 303 to three hundred three
|
|
64
|
+
converts 123 to one twenty three
|
|
65
|
+
converts 323 to three twenty three
|
|
66
|
+
converts 1000 to one thousand
|
|
67
|
+
converts 4321 to forty three twenty one
|
|
68
|
+
converts 4300 to forty three hundred
|
|
69
|
+
converts 1900 to nineteen hundred
|
|
70
|
+
converts 32323 to thirty two three twenty three
|
|
71
|
+
|
|
72
|
+
Dictable
|
|
73
|
+
#address
|
|
74
|
+
converts 1234 N Lasalle Ave to twelve thirty four north lasalle avenue
|
|
75
|
+
converts 123 S Lasalle rd to one twenty three south lasalle road
|
|
76
|
+
converts 1500 s Lasalle Rd to fifteen hundred south lasalle road
|
|
77
|
+
|
|
78
|
+
```
|
|
53
79
|
|
|
54
80
|
Please note that the numbers in quotes are treated as strings, which allows leading zeroes to be preserved.
|
|
55
81
|
|
|
@@ -63,4 +89,4 @@ Bug reports and pull requests are welcome on GitHub. This project aims to be a s
|
|
|
63
89
|
|
|
64
90
|
## License
|
|
65
91
|
|
|
66
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
92
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/dictable.gemspec
CHANGED
|
@@ -8,9 +8,11 @@ Gem::Specification.new do |spec|
|
|
|
8
8
|
spec.authors = ['Matias Verges']
|
|
9
9
|
spec.email = ['matis@matis.io']
|
|
10
10
|
|
|
11
|
-
spec.summary = 'Transform numbers into words to dictate them easily.'
|
|
12
|
-
spec.description =
|
|
13
|
-
|
|
11
|
+
spec.summary = 'Transform street numbers into words to dictate them easily, and explodes street names abbreviations.'
|
|
12
|
+
spec.description =
|
|
13
|
+
'Transform street numbers into words to dictate them easily, and explodes street names abbreviations.' \
|
|
14
|
+
"For example 1234 becomes twelve thirty four and 123456 becomes 'one two three, four five six'"
|
|
15
|
+
|
|
14
16
|
spec.homepage = 'https://github.com/matismasters/dictable'
|
|
15
17
|
spec.required_ruby_version = '>= 2.6.0'
|
|
16
18
|
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
---
|
|
2
|
+
n: north
|
|
3
|
+
s: south
|
|
4
|
+
e: east
|
|
5
|
+
w: west
|
|
6
|
+
aly: alley
|
|
7
|
+
anx: anex
|
|
8
|
+
arc: arcade
|
|
9
|
+
ave: avenue
|
|
10
|
+
byu: bayou
|
|
11
|
+
bch: beach
|
|
12
|
+
bnd: bend
|
|
13
|
+
blf: bluff
|
|
14
|
+
blfs: bluffs
|
|
15
|
+
btm: bottom
|
|
16
|
+
blvd: boulevard
|
|
17
|
+
br: branch
|
|
18
|
+
brg: bridge
|
|
19
|
+
brk: brook
|
|
20
|
+
brks: brooks
|
|
21
|
+
bg: burg
|
|
22
|
+
bgs: burgs
|
|
23
|
+
byp: bypass
|
|
24
|
+
cp: camp
|
|
25
|
+
cyn: canyon
|
|
26
|
+
cpe: cape
|
|
27
|
+
cswy: causeway
|
|
28
|
+
ctr: center
|
|
29
|
+
ctrs: centers
|
|
30
|
+
cir: circle
|
|
31
|
+
cirs: circles
|
|
32
|
+
clf: cliff
|
|
33
|
+
clfs: cliffs
|
|
34
|
+
clb: club
|
|
35
|
+
cmn: common
|
|
36
|
+
cmns: commons
|
|
37
|
+
cor: corner
|
|
38
|
+
cors: corners
|
|
39
|
+
crse: course
|
|
40
|
+
ct: court
|
|
41
|
+
cts: courts
|
|
42
|
+
cv: cove
|
|
43
|
+
cvs: coves
|
|
44
|
+
crk: creek
|
|
45
|
+
cres: crescent
|
|
46
|
+
crst: crest
|
|
47
|
+
xing: crossing
|
|
48
|
+
xrd: crossroad
|
|
49
|
+
xrds: crossroads
|
|
50
|
+
curv: curve
|
|
51
|
+
dl: dale
|
|
52
|
+
dm: dam
|
|
53
|
+
dv: divide
|
|
54
|
+
dr: drive
|
|
55
|
+
drs: drives
|
|
56
|
+
est: estate
|
|
57
|
+
ests: estates
|
|
58
|
+
expy: expressway
|
|
59
|
+
ext: extension
|
|
60
|
+
exts: extensions
|
|
61
|
+
fls: falls
|
|
62
|
+
fry: ferry
|
|
63
|
+
fld: field
|
|
64
|
+
flds: fields
|
|
65
|
+
flt: flat
|
|
66
|
+
flts: flats
|
|
67
|
+
frd: ford
|
|
68
|
+
frds: fords
|
|
69
|
+
frst: forest
|
|
70
|
+
frg: forge
|
|
71
|
+
frgs: forges
|
|
72
|
+
frk: fork
|
|
73
|
+
frks: forks
|
|
74
|
+
ft: fort
|
|
75
|
+
fwy: freeway
|
|
76
|
+
gdn: garden
|
|
77
|
+
gdns: gardens
|
|
78
|
+
gtwy: gateway
|
|
79
|
+
gln: glen
|
|
80
|
+
glns: glens
|
|
81
|
+
grn: green
|
|
82
|
+
grns: greens
|
|
83
|
+
grv: grove
|
|
84
|
+
grvs: groves
|
|
85
|
+
hbr: harbor
|
|
86
|
+
hbrs: harbors
|
|
87
|
+
hvn: haven
|
|
88
|
+
hts: heights
|
|
89
|
+
hwy: highway
|
|
90
|
+
hl: hill
|
|
91
|
+
hls: hills
|
|
92
|
+
holw: hollow
|
|
93
|
+
inlt: inlet
|
|
94
|
+
is: island
|
|
95
|
+
iss: islands
|
|
96
|
+
isle: isles
|
|
97
|
+
jct: junction
|
|
98
|
+
jcts: junctions
|
|
99
|
+
ky: key
|
|
100
|
+
kys: keys
|
|
101
|
+
knl: knoll
|
|
102
|
+
knls: knolls
|
|
103
|
+
lk: lake
|
|
104
|
+
lks: lakes
|
|
105
|
+
land: land
|
|
106
|
+
lndg: landing
|
|
107
|
+
ln: lane
|
|
108
|
+
lgt: light
|
|
109
|
+
lgts: lights
|
|
110
|
+
lf: loaf
|
|
111
|
+
lck: lock
|
|
112
|
+
lcks: locks
|
|
113
|
+
ldg: lodge
|
|
114
|
+
loop: loops
|
|
115
|
+
mall: mall
|
|
116
|
+
mnr: manor
|
|
117
|
+
mnrs: manors
|
|
118
|
+
mdw: meadow
|
|
119
|
+
mdws: meadows
|
|
120
|
+
mews: mews
|
|
121
|
+
ml: mill
|
|
122
|
+
mls: mills
|
|
123
|
+
msn: mission
|
|
124
|
+
mtwy: motorway
|
|
125
|
+
mt: mount
|
|
126
|
+
mtn: mountain
|
|
127
|
+
mtns: mountains
|
|
128
|
+
nck: neck
|
|
129
|
+
orch: orchard
|
|
130
|
+
oval: ovl
|
|
131
|
+
opas: overpass
|
|
132
|
+
park: parks
|
|
133
|
+
pkwy: parkway
|
|
134
|
+
pass: pass
|
|
135
|
+
psge: passage
|
|
136
|
+
path: paths
|
|
137
|
+
pike: pikes
|
|
138
|
+
pne: pine
|
|
139
|
+
pnes: pines
|
|
140
|
+
pl: place
|
|
141
|
+
pln: plain
|
|
142
|
+
plns: plains
|
|
143
|
+
plz: plaza
|
|
144
|
+
pt: point
|
|
145
|
+
pts: points
|
|
146
|
+
prt: port
|
|
147
|
+
prts: ports
|
|
148
|
+
pr: prairie
|
|
149
|
+
radl: radial
|
|
150
|
+
ramp: ramp
|
|
151
|
+
rnch: ranch
|
|
152
|
+
rpd: rapid
|
|
153
|
+
rpds: rapids
|
|
154
|
+
rst: rest
|
|
155
|
+
rdg: ridge
|
|
156
|
+
rdgs: ridges
|
|
157
|
+
riv: river
|
|
158
|
+
rd: road
|
|
159
|
+
rds: roads
|
|
160
|
+
rte: route
|
|
161
|
+
row: row
|
|
162
|
+
rue: rue
|
|
163
|
+
run: run
|
|
164
|
+
shl: shoal
|
|
165
|
+
shls: shoals
|
|
166
|
+
shr: shore
|
|
167
|
+
shrs: shores
|
|
168
|
+
skwy: skyway
|
|
169
|
+
spg: spring
|
|
170
|
+
spgs: springs
|
|
171
|
+
spur: spurs
|
|
172
|
+
sq: square
|
|
173
|
+
sqs: squares
|
|
174
|
+
sta: station
|
|
175
|
+
stra: stravenue
|
|
176
|
+
strm: stream
|
|
177
|
+
st: street
|
|
178
|
+
sts: streets
|
|
179
|
+
smt: summit
|
|
180
|
+
ter: terrace
|
|
181
|
+
trwy: throughway
|
|
182
|
+
trce: trace
|
|
183
|
+
trak: track
|
|
184
|
+
trfy: trafficway
|
|
185
|
+
trl: trail
|
|
186
|
+
trlr: trailer
|
|
187
|
+
tunl: tunnel
|
|
188
|
+
tpke: turnpike
|
|
189
|
+
upas: underpass
|
|
190
|
+
un: union
|
|
191
|
+
uns: unions
|
|
192
|
+
vly: valley
|
|
193
|
+
vlys: valleys
|
|
194
|
+
via: viaduct
|
|
195
|
+
vw: view
|
|
196
|
+
vws: views
|
|
197
|
+
vlg: village
|
|
198
|
+
vlgs: villages
|
|
199
|
+
vl: ville
|
|
200
|
+
vis: vista
|
|
201
|
+
walk: walks
|
|
202
|
+
wall: wall
|
|
203
|
+
way: wy
|
|
204
|
+
ways: ways
|
|
205
|
+
wl: well
|
|
206
|
+
wls: wells
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
"0": zero
|
|
3
|
+
"00": hundred # this enables the hundreds but also 15 hundred 36 hundred etc
|
|
4
|
+
"000": thousand
|
|
5
|
+
"1": one
|
|
6
|
+
"2": two
|
|
7
|
+
"3": three
|
|
8
|
+
"4": four
|
|
9
|
+
"5": five
|
|
10
|
+
"6": six
|
|
11
|
+
"7": seven
|
|
12
|
+
"8": eight
|
|
13
|
+
"9": nine
|
|
14
|
+
"10": ten
|
|
15
|
+
"11": eleven
|
|
16
|
+
"12": twelve
|
|
17
|
+
"13": thirteen
|
|
18
|
+
"14": fourteen
|
|
19
|
+
"15": fifteen
|
|
20
|
+
"16": sixteen
|
|
21
|
+
"17": seventeen
|
|
22
|
+
"18": eighteen
|
|
23
|
+
"19": nineteen
|
|
24
|
+
"20": twenty
|
|
25
|
+
"30": thirty
|
|
26
|
+
"40": forty
|
|
27
|
+
"50": fifty
|
|
28
|
+
"60": sixty
|
|
29
|
+
"70": seventy
|
|
30
|
+
"80": eighty
|
|
31
|
+
"90": ninety
|
|
32
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dictable
|
|
4
|
+
class StreetName
|
|
5
|
+
def initialize(street_number, lang: :en)
|
|
6
|
+
@street_number = street_number.downcase
|
|
7
|
+
@dictionary = Dictable.load_dictionary(:address_abbreviations_exploded, lang: lang)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_dictable
|
|
11
|
+
@street_number.split.map { |word| @dictionary[word.downcase] || word }.join(' ')
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Dictable
|
|
4
|
+
class StreetNumber
|
|
5
|
+
def initialize(street_number, lang: :en)
|
|
6
|
+
@street_number = street_number
|
|
7
|
+
@dictionary = Dictable.load_dictionary(:numbers_to_words, lang: lang)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def to_dictable
|
|
11
|
+
# less than 20 or multiples of 10
|
|
12
|
+
@dictionary.key?(@street_number)
|
|
13
|
+
return @dictionary[@street_number] if @dictionary.key?(@street_number)
|
|
14
|
+
|
|
15
|
+
# 100, 200, ... 900 and 1000, 2000, ... 9000
|
|
16
|
+
return plain_hundreds_or_thousands_to_words(@street_number) if hundreds_or_thousands?(@street_number)
|
|
17
|
+
|
|
18
|
+
# 20 or more and less than 100
|
|
19
|
+
return two_digit_number_to_words(@street_number) if @street_number.length == 2
|
|
20
|
+
|
|
21
|
+
# 5 digit addresses are rare, and we'll be opinionated and pronounce them as two digits, one digit, and two digits
|
|
22
|
+
return five_digit_number_to_words(@street_number) if @street_number.length == 5
|
|
23
|
+
|
|
24
|
+
# now everythinge else
|
|
25
|
+
parse_in_pairs(@street_number)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def hundreds_or_thousands?(number)
|
|
31
|
+
number[1..].to_i.zero? && (number.length == 3 || number.length == 4)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def plain_hundreds_or_thousands_to_words(number)
|
|
35
|
+
"#{@dictionary[number[0]]} #{@dictionary[number[1..]]}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def five_digit_number_to_words(number)
|
|
39
|
+
[two_digit_number_to_words(number[0..1]), @dictionary[number[2]],
|
|
40
|
+
two_digit_number_to_words(number[3..])].join(' ')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def two_digit_number_to_words(number)
|
|
44
|
+
@dictionary[number] || "#{@dictionary["#{number[0]}0"]} #{@dictionary[number[1]]}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def parse_in_pairs(number)
|
|
48
|
+
parts = []
|
|
49
|
+
|
|
50
|
+
# for 3 digit numbers, we extract the first digit and pronounce it as a single digit number
|
|
51
|
+
if number.length == 3
|
|
52
|
+
parts << @dictionary[number[0]]
|
|
53
|
+
number = number[1..]
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
parts += number.scan(/../).map { |pair| two_digit_number_to_words(pair) }
|
|
57
|
+
parts.join(' ')
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/dictable/version.rb
CHANGED
data/lib/dictable.rb
CHANGED
|
@@ -2,45 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
# lib/dictable.rb
|
|
4
4
|
require_relative 'dictable/version'
|
|
5
|
-
require_relative 'dictable/
|
|
6
|
-
require_relative 'dictable/
|
|
7
|
-
|
|
5
|
+
require_relative 'dictable/street_name'
|
|
6
|
+
require_relative 'dictable/street_number'
|
|
7
|
+
require 'yaml'
|
|
8
8
|
|
|
9
9
|
# We are going to change the design of the gem to make it more flexible.
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
10
|
+
module Dictable
|
|
11
|
+
def self.address(address, lang: :en)
|
|
12
|
+
address_parts = address.split
|
|
13
|
+
street_number = address_parts.shift
|
|
14
|
+
street_address = address_parts.join(' ')
|
|
15
|
+
|
|
16
|
+
[
|
|
17
|
+
number_to_words(street_number, lang: lang),
|
|
18
|
+
explode_abberviations(street_address, lang: lang)
|
|
19
|
+
].join(' ')
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
=begin
|
|
28
|
-
|
|
29
|
-
module DictableNumber; end
|
|
30
|
-
class DictableNumber::Base; end
|
|
31
|
-
|
|
32
|
-
# Each language will have a dictionary
|
|
33
|
-
module DictableNumber::English; end
|
|
34
|
-
module DictableNumber::Spanish; end
|
|
35
|
-
|
|
36
|
-
# this is the explanation of the adapter pattern
|
|
37
|
-
# https://refactoring.guru/design-patterns/adapter/ruby/example
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
22
|
+
def self.number_to_words(street_number, lang:)
|
|
23
|
+
StreetNumber.new(street_number, lang: lang).to_dictable
|
|
24
|
+
end
|
|
43
25
|
|
|
26
|
+
def self.explode_abberviations(address, lang:)
|
|
27
|
+
StreetName.new(address, lang: lang).to_dictable
|
|
28
|
+
end
|
|
44
29
|
|
|
30
|
+
def self.load_dictionary(name, lang: :en)
|
|
31
|
+
dictionary_path = File.join(__dir__, '../dictionaries', lang.to_s, "#{name}.yml")
|
|
32
|
+
YAML.load_file(dictionary_path)
|
|
33
|
+
end
|
|
45
34
|
end
|
|
46
|
-
|
metadata
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dictable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Matias Verges
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-03-
|
|
11
|
+
date: 2024-03-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
|
-
description: Transform numbers into words to dictate them easily
|
|
14
|
-
|
|
13
|
+
description: Transform street numbers into words to dictate them easily, and explodes
|
|
14
|
+
street names abbreviations.For example 1234 becomes twelve thirty four and 123456
|
|
15
|
+
becomes 'one two three, four five six'
|
|
15
16
|
email:
|
|
16
17
|
- matis@matis.io
|
|
17
18
|
executables: []
|
|
@@ -25,10 +26,11 @@ files:
|
|
|
25
26
|
- README.md
|
|
26
27
|
- Rakefile
|
|
27
28
|
- dictable.gemspec
|
|
29
|
+
- dictionaries/en/address_abbreviations_exploded.yml
|
|
30
|
+
- dictionaries/en/numbers_to_words.yml
|
|
28
31
|
- lib/dictable.rb
|
|
29
|
-
- lib/dictable/
|
|
30
|
-
- lib/dictable/
|
|
31
|
-
- lib/dictable/extend_primitives.rb
|
|
32
|
+
- lib/dictable/street_name.rb
|
|
33
|
+
- lib/dictable/street_number.rb
|
|
32
34
|
- lib/dictable/version.rb
|
|
33
35
|
- sig/dictable.rbs
|
|
34
36
|
homepage: https://github.com/matismasters/dictable
|
|
@@ -57,5 +59,6 @@ requirements: []
|
|
|
57
59
|
rubygems_version: 3.4.22
|
|
58
60
|
signing_key:
|
|
59
61
|
specification_version: 4
|
|
60
|
-
summary: Transform numbers into words to dictate them easily
|
|
62
|
+
summary: Transform street numbers into words to dictate them easily, and explodes
|
|
63
|
+
street names abbreviations.
|
|
61
64
|
test_files: []
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Dictable
|
|
4
|
-
class DictableNumber
|
|
5
|
-
attr_reader :number_to_dictate, :dictable_number_in_words
|
|
6
|
-
|
|
7
|
-
ONES = %w[zero one two three four five six seven eight nine].freeze
|
|
8
|
-
TEENS = %w[ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen].freeze
|
|
9
|
-
TENS = %w[twenty thirty forty fifty sixty seventy eighty ninety].freeze
|
|
10
|
-
|
|
11
|
-
def initialize(number_to_dictate)
|
|
12
|
-
@number_to_dictate = number_to_dictate.to_s
|
|
13
|
-
validate_number(@number_to_dictate)
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def to_dictable
|
|
17
|
-
@to_dictable ||= number_to_words
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
def number_to_words
|
|
23
|
-
number_as_string = @number_to_dictate
|
|
24
|
-
|
|
25
|
-
leading_zeroes_words = leading_zeroes_to_words(number_as_string)
|
|
26
|
-
|
|
27
|
-
number_without_leading_zeroes = number_without_leading_zeroes(number_as_string)
|
|
28
|
-
number_without_leading_zeroes_words = number_without_leading_zeroes_to_words(number_without_leading_zeroes)
|
|
29
|
-
|
|
30
|
-
[leading_zeroes_words, number_without_leading_zeroes_words].reject(&:empty?).join(' ')
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
def validate_number(number_as_string)
|
|
34
|
-
raise NonNumberCharactersPresent if number_as_string.match?(/[^0-9]/)
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def number_without_leading_zeroes_to_words(number_as_string)
|
|
38
|
-
case number_as_string.length
|
|
39
|
-
when 1 then one_digit_number_to_words(number_as_string)
|
|
40
|
-
when 2 then two_digit_number_to_words(number_as_string)
|
|
41
|
-
when 3 then three_digit_number_to_words(number_as_string)
|
|
42
|
-
when 4 then four_digit_number_to_words(number_as_string)
|
|
43
|
-
else large_number_to_words(number_as_string)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def repeat_zeroes(number_of_zeroes)
|
|
48
|
-
Array.new(number_of_zeroes) { ONES[0] }.join(' ')
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def leading_zeroes_to_words(number_as_string)
|
|
52
|
-
leading_zeroes = number_as_string.match(/^0+/).to_s
|
|
53
|
-
return '' if leading_zeroes.empty?
|
|
54
|
-
|
|
55
|
-
repeat_zeroes(leading_zeroes.length)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def number_without_leading_zeroes(number_as_string)
|
|
59
|
-
number_as_string.sub(/^0+/, '')
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def single_thousands_to_words(number_as_string)
|
|
63
|
-
number = number_as_string.to_i / 1000
|
|
64
|
-
|
|
65
|
-
[one_digit_number_to_words(number), 'thousand'].join(' ')
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def one_digit_number_to_words(number_as_string)
|
|
69
|
-
number = number_as_string.to_i
|
|
70
|
-
return repeat_zeroes(1) if number.zero?
|
|
71
|
-
|
|
72
|
-
ONES[number]
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def two_digit_number_to_words(number_as_string)
|
|
76
|
-
number = number_as_string.to_i
|
|
77
|
-
|
|
78
|
-
return repeat_zeroes(2) if number.zero?
|
|
79
|
-
return TEENS[number - 10] if number < 20
|
|
80
|
-
|
|
81
|
-
div, mod = number.divmod(10)
|
|
82
|
-
TENS[div - 2] + (mod.zero? ? '' : " #{ONES[mod]}")
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
def three_digit_number_to_words(number_as_string)
|
|
86
|
-
number = number_as_string.to_i
|
|
87
|
-
return repeat_zeroes(3) if number.zero?
|
|
88
|
-
|
|
89
|
-
first_digit, remainder = number.divmod(100)
|
|
90
|
-
words = [ONES[first_digit]]
|
|
91
|
-
words << (remainder.zero? ? 'hundred' : two_digit_number_to_words(remainder))
|
|
92
|
-
words.join(' ')
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
def four_digit_number_to_words(number_as_string)
|
|
96
|
-
number = number_as_string.to_i
|
|
97
|
-
|
|
98
|
-
return repeat_zeroes(4) if number.zero?
|
|
99
|
-
return single_thousands_to_words(number_as_string) if (number % 1000).zero?
|
|
100
|
-
|
|
101
|
-
high_pair = number_as_string[0..1]
|
|
102
|
-
low_pair = number_as_string[2..3]
|
|
103
|
-
|
|
104
|
-
[
|
|
105
|
-
two_digit_number_to_words(high_pair),
|
|
106
|
-
low_pair.to_i.zero? ? 'hundred' : two_digit_number_to_words(low_pair)
|
|
107
|
-
].join(' ')
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def large_number_to_words(number_as_string)
|
|
111
|
-
number_as_string.chars.map { |digit| ONES[digit.to_i] }.each_slice(3).map { |digit| digit.join(' ') }.join(', ')
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
data/lib/dictable/exceptions.rb
DELETED