name_tamer 0.6.1 → 1.0.2

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.
@@ -1,563 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class String
4
- unless respond_to? :presence
5
- def presence
6
- self unless empty?
7
- end
8
- end
9
-
10
- # Strip illegal characters out completely
11
- def strip_unwanted!(filter)
12
- substitute!(filter, '')
13
- end
14
-
15
- def strip_or_self!
16
- strip! || self
17
- end
18
-
19
- # Change any whitespace into our separator character
20
- def whitespace_to!(separator)
21
- substitute!(/[[:space:]]+/, separator)
22
- end
23
-
24
- # Ensure commas have exactly one space after them
25
- def space_around_comma!
26
- substitute!(/[[:space:]]*,[[:space:]]*/, ',
27
- ')
28
- end
29
-
30
- # Change some characters embedded in words to our separator character
31
- # e.g. example.com -> example-com
32
- def invalid_chars_to!(separator)
33
- substitute!(%r{(?<![[:space:]])[\.\/](?![[:space:]])}, separator)
34
- end
35
-
36
- # Unescape percent-encoded characters
37
- # This might introduce UTF-8 invalid byte sequence
38
- # so we take precautions
39
- def safe_unescape!
40
- string = CGI.unescape(gsub('+', '%2B'))
41
- return self if self == string
42
- replace string
43
- ensure_safe!
44
- end
45
-
46
- # Remove HTML entities
47
- def unescape_html!
48
- replace CGI.unescapeHTML self
49
- end
50
-
51
- # Make sure separators are not where they shouldn't be
52
- def fix_separators!(separator)
53
- return self if separator.nil? || separator.empty?
54
-
55
- r = Regexp.escape(separator)
56
-
57
- # No more than one of the separator in a row.
58
- substitute!(/#{r}{2,}/, separator)
59
-
60
- # Remove leading/trailing separator.
61
- substitute!(/^#{r}|#{r}$/i, '')
62
- end
63
-
64
- # Any characters that resemble latin characters might usefully be
65
- # transliterated into ones that are easy to type on an anglophone
66
- # keyboard.
67
- def approximate_latin_chars!
68
- gsub!(/[^\x00-\x7f]/u) { |char| APPROXIMATIONS[char] || char } || self
69
- end
70
-
71
- # Strings that were wrongly encoded with single-byte encodings sometimes have
72
- # tell-tale substrings that we can put back into the correct UTF-8 character
73
- def fix_encoding_errors!
74
- gsub!(BAD_ENCODING_PATTERNS) { |substring| BAD_ENCODING[substring] || substring } || self
75
- end
76
-
77
- def upcase_first_letter!
78
- gsub!(/\b\w/, &:upcase) || self
79
- end
80
-
81
- def downcase_after_apostrophe!
82
- gsub!(/\'\w\b/, &:downcase) || self # Lowercase 's
83
- end
84
-
85
- # Our list of terminal characters that indicate a non-celtic name used
86
- # to include o but we removed it because of MacMurdo.
87
- def fix_mac!
88
- if self =~ /\bMac[A-Za-z]{2,}[^acizj]\b/ || self =~ /\bMc/
89
- gsub!(/\b(Ma?c)([A-Za-z]+)/) { |_| Regexp.last_match[1] + Regexp.last_match[2].capitalize }
90
-
91
- # Fix Mac exceptions
92
- %w[
93
- MacEdo MacEvicius MacHado MacHar MacHin MacHlin MacIas MacIulis MacKie
94
- MacKle MacKlin MacKmin MacKmurdo MacQuarie MacLise MacKenzie
95
- ].each { |mac_name| substitute!(/\b#{mac_name}/, mac_name.capitalize) }
96
- end
97
-
98
- self # Allows chaining
99
- end
100
-
101
- # Fix ff wierdybonks
102
- def fix_ff!
103
- %w[
104
- Fforbes Fforde Ffinch Ffrench Ffoulkes
105
- ].each { |ff_name| substitute!(ff_name, ff_name.downcase) }
106
-
107
- self # Allows chaining
108
- end
109
-
110
- # Fixes for name modifiers followed by space
111
- # Also replaces spaces with non-breaking spaces
112
- # Fixes for name modifiers followed by an apostrophe, e.g. d'Artagnan, Commedia dell'Arte
113
- def fix_name_modifiers!
114
- NAME_MODIFIERS.each do |modifier|
115
- gsub!(/((?:[[:space:]]|^)#{modifier})([[:space:]]+|-)/) do |_|
116
- "#{Regexp.last_match[1].rstrip.downcase}#{Regexp.last_match[2].tr(ASCII_SPACE, NONBREAKING_SPACE)}"
117
- end
118
- end
119
-
120
- fix_apostrophe_modifiers!
121
- self # Allows chaining
122
- end
123
-
124
- def fix_apostrophe_modifiers!
125
- %w[Dell D].each do |modifier|
126
- gsub!(/(.#{modifier}')(\w)/) { |_| "#{Regexp.last_match[1].rstrip.downcase}#{Regexp.last_match[2]}" }
127
- end
128
-
129
- self # Allows chaining
130
- end
131
-
132
- # Upcase words with no vowels, e.g JPR Williams
133
- # Except Ng
134
- def upcase_initials!
135
- gsub!(/\b([bcdfghjklmnpqrstvwxz]+)\b/i) { |_| Regexp.last_match[1].upcase }
136
- gsub!(/\b(NG)\b/i) { |_| Regexp.last_match[1].capitalize } || self # http://en.wikipedia.org/wiki/Ng
137
- end
138
-
139
- # Fix known last names that have spaces (not hyphens!)
140
- def nbsp_in_compound_name!
141
- COMPOUND_NAMES.each do |compound_name|
142
- substitute!(compound_name, compound_name.tr(ASCII_SPACE, NONBREAKING_SPACE))
143
- end
144
-
145
- self # Allows chaining
146
- end
147
-
148
- def nbsp_in_name_modifier!
149
- NAME_MODIFIERS.each do |modifier|
150
- gsub!(/([[:space:]]#{modifier})([[:space:]])/i) { |_| "#{Regexp.last_match[1]}#{NONBREAKING_SPACE}" }
151
- end
152
-
153
- self # Allows chaining
154
- end
155
-
156
- def remove_periods_from_initials!
157
- gsub!(/\b([a-z])\./i) { |_| Regexp.last_match[1] } || self
158
- end
159
-
160
- def remove_spaces_from_initials!
161
- gsub!(/\b([a-z])(\.)* \b(?![a-z0-9'\u00C0-\u00FF]{2,})/i) do |_|
162
- "#{Regexp.last_match[1]}#{Regexp.last_match[2]}"
163
- end || self
164
- end
165
-
166
- def ensure_space_after_initials!
167
- gsub!(/\b([a-z]\.)(?=[a-z0-9]{2,})/i) { |_| "#{Regexp.last_match[1]} " } || self
168
- end
169
-
170
- def ensure_safe!
171
- encode!('UTF-8', invalid: :replace, undef: :replace, replace: '') # Doesn't fully work in Ruby 2.0
172
- end
173
-
174
- def substitute!(pattern, replacement)
175
- gsub!(pattern, replacement) || self
176
- end
177
-
178
- NONBREAKING_SPACE = "\u00a0"
179
- ASCII_SPACE = ' '
180
-
181
- COMPOUND_NAMES = [
182
- # Known families with a space in their surname
183
- 'Baron Cohen',
184
- 'Bonham Carter',
185
- 'Holmes a Court',
186
- 'Holmes à Court',
187
- 'Lane Fox',
188
- 'Lloyd Webber',
189
- 'Pitt Rivers',
190
- 'Sebag Montefiore',
191
- 'Strang Steel',
192
- 'Wedgwood Benn',
193
- 'Wingfield Digby',
194
- # Sometimes companies appear as people
195
- 'Corporation Company',
196
- 'Corporation System',
197
- 'Incorporations Limited',
198
- 'Service Company',
199
- ].freeze
200
-
201
- NAME_MODIFIERS = [
202
- 'Al',
203
- 'Ap',
204
- 'Ben',
205
- 'D[aeiou]',
206
- 'D[ao]s',
207
- 'De[lrn]',
208
- 'Dell[ae]',
209
- 'El',
210
- 'L[eo]',
211
- 'La',
212
- 'Of',
213
- 'San',
214
- 'St[\.]?',
215
- 'V[ao]n',
216
- 'Zur',
217
- ].freeze
218
-
219
- # Transliterations (like the i18n defaults)
220
- # see https://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/transliterator.rb
221
- APPROXIMATIONS = {
222
- 'İ' => 'I',
223
- '×' => 'x',
224
- 'ß' => 'ss',
225
- 'À' => 'A',
226
- 'à' => 'a',
227
- 'Á' => 'A',
228
- 'á' => 'a',
229
- 'Â' => 'A',
230
- 'â' => 'a',
231
- 'Ã' => 'A',
232
- 'ã' => 'a',
233
- 'Ä' => 'A',
234
- 'ä' => 'a',
235
- 'Å' => 'A',
236
- 'å' => 'a',
237
- 'Æ' => 'AE',
238
- 'æ' => 'ae',
239
- 'Ç' => 'C',
240
- 'ç' => 'c',
241
- 'È' => 'E',
242
- 'è' => 'e',
243
- 'É' => 'E',
244
- 'é' => 'e',
245
- 'Ê' => 'E',
246
- 'ê' => 'e',
247
- 'Ë' => 'E',
248
- 'ë' => 'e',
249
- 'Ì' => 'I',
250
- 'ì' => 'i',
251
- 'Í' => 'I',
252
- 'í' => 'i',
253
- 'Î' => 'I',
254
- 'î' => 'i',
255
- 'Ï' => 'I',
256
- 'ï' => 'i',
257
- 'Ð' => 'D',
258
- 'ð' => 'd',
259
- 'Ñ' => 'N',
260
- 'ñ' => 'n',
261
- 'Ò' => 'O',
262
- 'ò' => 'o',
263
- 'Ó' => 'O',
264
- 'ó' => 'o',
265
- 'Ô' => 'O',
266
- 'ô' => 'o',
267
- 'Õ' => 'O',
268
- 'õ' => 'o',
269
- 'Ö' => 'O',
270
- 'ö' => 'o',
271
- 'Ø' => 'O',
272
- 'ø' => 'o',
273
- 'Ù' => 'U',
274
- 'ù' => 'u',
275
- 'Ú' => 'U',
276
- 'ú' => 'u',
277
- 'Û' => 'U',
278
- 'û' => 'u',
279
- 'Ü' => 'U',
280
- 'ü' => 'u',
281
- 'Ý' => 'Y',
282
- 'ý' => 'y',
283
- 'Þ' => 'Th',
284
- 'þ' => 'th',
285
- 'ÿ' => 'y',
286
- 'Ÿ' => 'Y',
287
- 'Ā' => 'A',
288
- 'ā' => 'a',
289
- 'Ă' => 'A',
290
- 'ă' => 'a',
291
- 'Ą' => 'A',
292
- 'ą' => 'a',
293
- 'Ć' => 'C',
294
- 'ć' => 'c',
295
- 'Ĉ' => 'C',
296
- 'ĉ' => 'c',
297
- 'Ċ' => 'C',
298
- 'ċ' => 'c',
299
- 'Č' => 'C',
300
- 'č' => 'c',
301
- 'Ď' => 'D',
302
- 'ď' => 'd',
303
- 'Đ' => 'D',
304
- 'đ' => 'd',
305
- 'Ē' => 'E',
306
- 'ē' => 'e',
307
- 'Ĕ' => 'E',
308
- 'ĕ' => 'e',
309
- 'Ė' => 'E',
310
- 'ė' => 'e',
311
- 'Ę' => 'E',
312
- 'ę' => 'e',
313
- 'Ě' => 'E',
314
- 'ě' => 'e',
315
- 'Ĝ' => 'G',
316
- 'ĝ' => 'g',
317
- 'Ğ' => 'G',
318
- 'ğ' => 'g',
319
- 'Ġ' => 'G',
320
- 'ġ' => 'g',
321
- 'Ģ' => 'G',
322
- 'ģ' => 'g',
323
- 'Ĥ' => 'H',
324
- 'ĥ' => 'h',
325
- 'Ħ' => 'H',
326
- 'ħ' => 'h',
327
- 'Ĩ' => 'I',
328
- 'ĩ' => 'i',
329
- 'Ī' => 'I',
330
- 'ī' => 'i',
331
- 'Ĭ' => 'I',
332
- 'ĭ' => 'i',
333
- 'Į' => 'I',
334
- 'į' => 'i',
335
- 'ı' => 'i',
336
- 'IJ' => 'IJ',
337
- 'ij' => 'ij',
338
- 'Ĵ' => 'J',
339
- 'ĵ' => 'j',
340
- 'Ķ' => 'K',
341
- 'ķ' => 'k',
342
- 'ĸ' => 'k',
343
- 'Ĺ' => 'L',
344
- 'ĺ' => 'l',
345
- 'Ļ' => 'L',
346
- 'ļ' => 'l',
347
- 'Ľ' => 'L',
348
- 'ľ' => 'l',
349
- 'Ŀ' => 'L',
350
- 'ŀ' => 'l',
351
- 'Ł' => 'L',
352
- 'ł' => 'l',
353
- 'Ń' => 'N',
354
- 'ń' => 'n',
355
- 'Ņ' => 'N',
356
- 'ņ' => 'n',
357
- 'Ň' => 'N',
358
- 'ň' => 'n',
359
- 'ʼn' => "'n",
360
- 'Ŋ' => 'NG',
361
- 'ŋ' => 'ng',
362
- 'Ō' => 'O',
363
- 'ō' => 'o',
364
- 'Ŏ' => 'O',
365
- 'ŏ' => 'o',
366
- 'Ő' => 'O',
367
- 'ő' => 'o',
368
- 'Œ' => 'OE',
369
- 'œ' => 'oe',
370
- 'Ŕ' => 'R',
371
- 'ŕ' => 'r',
372
- 'Ŗ' => 'R',
373
- 'ŗ' => 'r',
374
- 'Ř' => 'R',
375
- 'ř' => 'r',
376
- 'Ś' => 'S',
377
- 'ś' => 's',
378
- 'Ŝ' => 'S',
379
- 'ŝ' => 's',
380
- 'Ş' => 'S',
381
- 'ş' => 's',
382
- 'Š' => 'S',
383
- 'š' => 's',
384
- 'Ţ' => 'T',
385
- 'ţ' => 't',
386
- 'Ť' => 'T',
387
- 'ť' => 't',
388
- 'Ŧ' => 'T',
389
- 'ŧ' => 't',
390
- 'Ũ' => 'U',
391
- 'ũ' => 'u',
392
- 'Ū' => 'U',
393
- 'ū' => 'u',
394
- 'Ŭ' => 'U',
395
- 'ŭ' => 'u',
396
- 'Ů' => 'U',
397
- 'ů' => 'u',
398
- 'Ű' => 'U',
399
- 'ű' => 'u',
400
- 'Ų' => 'U',
401
- 'ų' => 'u',
402
- 'Ŵ' => 'W',
403
- 'ŵ' => 'w',
404
- 'Ŷ' => 'Y',
405
- 'ŷ' => 'y',
406
- 'Ź' => 'Z',
407
- 'ź' => 'z',
408
- 'Ż' => 'Z',
409
- 'ż' => 'z',
410
- 'ž' => 'z',
411
- 'Ž' => 'Z',
412
- }.freeze
413
-
414
- # When strings are mistakenly encoded as single-byte character sets, instead
415
- # of UTF-8, there are some distinctive character combinations that we can spot
416
- # and fix
417
- # Useful table here http://www.i18nqa.com/debug/utf8-debug.html
418
- BAD_ENCODING = {
419
- "\xC3\x8D" => 'Í',
420
- "\xC3\x8F" => 'Ï',
421
- "\xC3\x90" => 'Ð',
422
- "\xC3\x9D" => 'Ý',
423
- ' ' => ' ',
424
- '¡' => '¡',
425
- '¢' => '¢',
426
- '£' => '£',
427
- '¤' => '¤',
428
- 'Â¥' => '¥',
429
- '¦' => '¦',
430
- '§' => '§',
431
- '¨' => '¨',
432
- '©' => '©',
433
- 'ª' => 'ª',
434
- '«' => '«',
435
- '¬' => '¬',
436
- '­' => '­',
437
- '®' => '®',
438
- '¯' => '¯',
439
- '°' => '°',
440
- '±' => '±',
441
- '²' => '²',
442
- '³' => '³',
443
- '´' => '´',
444
- 'µ' => 'µ',
445
- '¶' => '¶',
446
- '·' => '·',
447
- '¸' => '¸',
448
- '¹' => '¹',
449
- 'º' => 'º',
450
- '»' => '»',
451
- '¼' => '¼',
452
- '½' => '½',
453
- '¾' => '¾',
454
- '¿' => '¿',
455
- '€' => '€',
456
- 'â„¢' => '™',
457
- '”' => '”', # Note the invisible Ux009D in the key
458
- '†' => '†',
459
- '‡' => '‡',
460
- '•' => '•',
461
- '…' => '…',
462
- '‰' => '‰',
463
- '′' => '′', # Manually added. Some seem to use this instead of Ux2019
464
- '‹' => '‹',
465
- '›' => '›',
466
- '“' => '“',
467
- '‚' => '‚',
468
- '„' => '„',
469
- '‘' => '‘',
470
- '–' => '–',
471
- '—' => '—',
472
- '’' => '’',
473
- 'à' => 'à',
474
- 'á' => 'á',
475
- 'â' => 'â',
476
- 'ã' => 'ã',
477
- 'ä' => 'ä',
478
- 'Ã¥' => 'å',
479
- 'æ' => 'æ',
480
- 'ç' => 'ç',
481
- 'è' => 'è',
482
- 'é' => 'é',
483
- 'ê' => 'ê',
484
- 'ë' => 'ë',
485
- 'ì' => 'ì',
486
- 'í' => 'í',
487
- 'î' => 'î',
488
- 'ï' => 'ï',
489
- 'ð' => 'ð',
490
- 'ñ' => 'ñ',
491
- 'ò' => 'ò',
492
- 'ó' => 'ó',
493
- 'ô' => 'ô',
494
- 'õ' => 'õ',
495
- 'ö' => 'ö',
496
- '÷' => '÷',
497
- 'ø' => 'ø',
498
- 'ù' => 'ù',
499
- 'ú' => 'ú',
500
- 'û' => 'û',
501
- 'ü' => 'ü',
502
- 'ý' => 'ý',
503
- 'þ' => 'þ',
504
- 'ÿ' => 'ÿ',
505
- 'ß' => 'ß',
506
- 'ÃŒ' => 'Ì',
507
- 'Ü' => 'Ü',
508
- 'Ê' => 'Ê',
509
- 'Ú' => 'Ú',
510
- 'ÃŽ' => 'Î',
511
- 'Þ' => 'Þ',
512
- 'Ã' => 'Ã',
513
- 'È' => 'È',
514
- 'Ø' => 'Ø',
515
- 'Ö' => 'Ö',
516
- '×' => '×',
517
- 'Ñ' => 'Ñ',
518
- 'Ã’' => 'Ò',
519
- 'Â' => 'Â',
520
- 'Ó' => 'Ó',
521
- 'Ô' => 'Ô',
522
- 'Ä' => 'Ä',
523
- 'Æ' => 'Æ',
524
- 'Ç' => 'Ç',
525
- 'Õ' => 'Õ',
526
- 'Ã…' => 'Å',
527
- 'É' => 'É',
528
- 'Ë' => 'Ë',
529
- 'Û' => 'Û',
530
- 'À' => 'À',
531
- 'Ù' => 'Ù',
532
- 'Ã�' => 'Á',
533
- 'Å ' => 'Š',
534
- 'Å¡' => 'š',
535
- 'Ÿ' => 'Ÿ',
536
- 'Ž' => 'Ž',
537
- 'ž' => 'ž',
538
- 'Å’' => 'Œ',
539
- 'Å“' => 'œ',
540
- 'Æ’' => 'ƒ',
541
- 'Ëœ' => '˜',
542
- 'ˆ' => 'ˆ',
543
- "\x00" => '' # Manually added to avoid Bad Argument exception
544
- }.freeze
545
-
546
- BAD_ENCODING_PATTERNS = /(#{BAD_ENCODING.keys.join('|')})/
547
-
548
- # Colorize strings
549
- colors = %w[black red green yellow blue magenta cyan white]
550
-
551
- colors.each_with_index do |fg_color, i|
552
- fg = 30 + i
553
- define_method(fg_color) { ansi_attributes(fg) }
554
-
555
- colors.each_with_index do |bg_color, j|
556
- define_method("#{fg_color}_on_#{bg_color}") { ansi_attributes(fg, 40 + j) }
557
- end
558
- end
559
-
560
- def ansi_attributes(*args)
561
- "\e[#{args.join(';')}m#{self}\e[0m"
562
- end
563
- end
data/name_tamer.gemspec DELETED
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- lib = File.expand_path('lib', __dir__)
4
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
- require 'name_tamer/version'
6
-
7
- Gem::Specification.new do |spec|
8
- spec.name = 'name_tamer'
9
- spec.version = NameTamer::VERSION
10
- spec.authors = ['Dominic Sayers']
11
- spec.email = ['dominic@sayers.cc']
12
- spec.description = 'Useful methods for taming names'
13
- spec.summary = "Example: NameTamer['Mr. John Q. Smith III, MD'].simple_name # => John Smith"
14
- spec.homepage = 'https://github.com/dominicsayers/name_tamer'
15
- spec.license = 'MIT'
16
-
17
- spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR).reject { |file| file =~ %r{^(bin|spec)/} }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features|coverage)/})
19
- spec.require_paths = ['lib']
20
- end