immosquare-extensions 0.1.29 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1984569911ed1d2de9da6d04bbe044c867fe96f320ddf9404c14f3d31109c6c
4
- data.tar.gz: 25ee04e6d1fe8cd87b27740e5d9ff8eb7bd284b580bd67a72a665baf321961dc
3
+ metadata.gz: e9afbb3a9b644f11a9ed1991329844f00ecce1866bcde28ea55fe6264759b9ad
4
+ data.tar.gz: 7fbfa0feaa9ee228d7291749754209621a2d7064a8c922261c7362a8b460f83a
5
5
  SHA512:
6
- metadata.gz: 0a740a6bc43b6c0b2364ab7b686dd490cb0aba768dc05a6f1d0ee5cb49cb2a486b201d6d5249c5a255ef57fdc89bc3a8b40f4bafab73ce93db30dc05787e4b83
7
- data.tar.gz: 88e7380675de96e3ea6cb9bc407cd4b1c0819728e91f6b79c303594b6d792ccbf29645ef657b9597317af3fca8f07e74872ac8810798575e79b5dbb56b7a6714
6
+ metadata.gz: d640776fdcb79276cf7ea5347ea17384ededc0a804fdc97e12ab5454798f4f16dc34a049c60ed199d93621809bd8a74be053704d0cf96d6c332fd418ff9053e3
7
+ data.tar.gz: f4921568ed88a374d3ead74f9d96b5dff63d4d33204002ff84a416177066d3250c8e21710da94c135855f4f6825753ef59913060c181080c6693fdaf4180e4f1
@@ -33,7 +33,7 @@ class Array
33
33
  def to_beautiful_json(**options)
34
34
  options = {}.merge(options)
35
35
  options[:align] = true if ![true, false].include?(options[:align])
36
- options[:indent_size] = 2 if options[:indent_size].to_i == 0 || options[:indent_size].to_i > 10
36
+ options[:indent_size] = 2 if options[:indent_size].to_i <= 0 || options[:indent_size].to_i > 10
37
37
 
38
38
  dump_beautify_json(self, options[:align], options[:indent_size])
39
39
  end
@@ -89,7 +89,7 @@ class Hash
89
89
  def to_beautiful_json(**options)
90
90
  options = {}.merge(options)
91
91
  options[:align] = true if ![true, false].include?(options[:align])
92
- options[:indent_size] = 2 if options[:indent_size].to_i == 0 || options[:indent_size].to_i > 10
92
+ options[:indent_size] = 2 if options[:indent_size].to_i <= 0 || options[:indent_size].to_i > 10
93
93
 
94
94
  dump_beautify_json(self, options[:align], options[:indent_size])
95
95
  end
@@ -3,6 +3,24 @@
3
3
  ##============================================================##
4
4
  class String
5
5
 
6
+ ##============================================================##
7
+ ## Particles that stay lowercase inside a place name, unless they
8
+ ## open it. `d` and `l` cover the elided forms `d'` and `l'`.
9
+ ##============================================================##
10
+ TITLEIZE_PARTICLES_FRENCH = ["à", "au", "aux", "d", "de", "des", "du", "en", "ès", "et", "l", "la", "le", "les", "lès", "sous", "sur"].freeze
11
+
12
+ ##============================================================##
13
+ ## A capital after an apostrophe belongs to an elision or a
14
+ ## patronymic prefix (d'Orcino, O'Brien, N'Djamena), never to an
15
+ ## English clitic (King's, It's). Both sides are closed sets, so
16
+ ## the rule needs no language detection: the prefix decides and
17
+ ## the suffix vetoes.
18
+ ##============================================================##
19
+ TITLEIZE_ELISIONS = ["c", "d", "j", "l", "m", "n", "o", "qu", "s", "t"].freeze
20
+ TITLEIZE_CLITICS = ["d", "ll", "m", "re", "s", "t", "ve"].freeze
21
+
22
+ private_constant(:TITLEIZE_PARTICLES_FRENCH, :TITLEIZE_ELISIONS, :TITLEIZE_CLITICS)
23
+
6
24
  ##============================================================##
7
25
  ## Convert the string 'true' to true and 'false' to false.
8
26
  ## Any other value will return nil.
@@ -25,19 +43,95 @@ class String
25
43
  end
26
44
 
27
45
  ##============================================================##
28
- ## Provide a custom titleize method to handle strings
29
- ## especially ones with hyphens more appropriately.
30
- ## Standard titleize does not preserve hyphens in the desired manner.
46
+ ## Titleize a PLACE NAME under French typographic rules: the
47
+ ## letter after an apostrophe carries the capital, and particles
48
+ ## stay lowercase unless they open the name. Hyphenated toponyms
49
+ ## are the case standard `titleize` gets wrong.
31
50
  ##
32
- ## Reference:
33
- ## https://stackoverflow.com/questions/29784873/titleize-a-hyphenated-name
51
+ ## Use `titleize_name` for anything that is not a place — there,
52
+ ## no particle is lowered.
34
53
  ##
35
54
  ## Examples:
36
- ## "SANT-ANDREA-D'ORCINO".titleize_custom => Sant-Andrea-D'orcino
37
- ## "SANT-ANDREA-D'ORCINO".titleize => Sant Andrea D'orcino
55
+ ## "SANT-ANDREA-D'ORCINO".titleize_place => Sant-Andrea-d'Orcino
56
+ ## "saint-jean-sur-richelieu".titleize_place => Saint-Jean-sur-Richelieu
57
+ ## "st john's".titleize_place => St John's
58
+ ## "SANT-ANDREA-D'ORCINO".titleize => Sant Andrea D'orcino
59
+ ##============================================================##
60
+ def titleize_place
61
+ titleize_words(:lower_particles => true)
62
+ end
63
+
64
+ ##============================================================##
65
+ ## Titleize a proper name or a label — a person, an agency, a
66
+ ## building, an enumeration value. Same apostrophe and accent
67
+ ## handling as `titleize_place`, but every word is capitalized.
68
+ ##
69
+ ## Examples:
70
+ ## "o'brien".titleize_name => O'Brien
71
+ ## "MAISON DE VILLE".titleize_name => Maison De Ville
72
+ ##============================================================##
73
+ def titleize_name
74
+ titleize_words(:lower_particles => false)
75
+ end
76
+
77
+ ##============================================================##
78
+ ## The helpers below are private on every String in the process:
79
+ ## a new public extension must be added ABOVE this line.
38
80
  ##============================================================##
39
- def titleize_custom
40
- humanize.gsub(/\b('?[a-z])/) { ::Regexp.last_match(1).capitalize }
81
+ private
82
+
83
+ ##============================================================##
84
+ ## `humanize` normalizes first: it folds underscores into spaces
85
+ ## and downcases the tail, so an all-caps source comes back
86
+ ## readable.
87
+ ##
88
+ ## The scan keeps letters, digits and apostrophes in a single
89
+ ## match, so `d'howard` arrives as ONE word and its two halves
90
+ ## can be ruled on separately. Hyphens and spaces stay untouched
91
+ ## between the matches, which is how the shape of the original
92
+ ## string survives.
93
+ ##
94
+ ## Known limits of that pair, each frozen by a characterization
95
+ ## test: internal capitals are flattened (MacDonald → Macdonald),
96
+ ## a dotted abbreviation reads as a particle (`n.-d.-de-grâce` →
97
+ ## `N.-d.-de-Grâce`) and roman numerals are recapitalized (Louis
98
+ ## XIV → Louis Xiv).
99
+ ##============================================================##
100
+ def titleize_words(lower_particles:)
101
+ first = true
102
+
103
+ humanize.gsub(/[\p{L}\p{N}'’]+/) do |word|
104
+ titleized = titleize_single_word(word, :first => first, :lower_particles => lower_particles)
105
+ first = false
106
+ titleized
107
+ end
108
+ end
109
+
110
+ def titleize_single_word(word, first:, lower_particles:)
111
+ ##============================================================##
112
+ ## Split on the FIRST apostrophe only — a second one belongs to
113
+ ## the name itself. The prefix follows the particle rule; the
114
+ ## suffix takes a capital only after an elision, so a
115
+ ## possessive stays intact: "King's", never "King'S".
116
+ ##============================================================##
117
+ if word =~ /['’]/
118
+ separator = word[/['’]/]
119
+ prefix, suffix = word.split(/['’]/, 2)
120
+ suffix = suffix.capitalize if elision?(prefix, suffix)
121
+ return "#{titleize_particle(prefix, :first => first, :lower_particles => lower_particles)}#{separator}#{suffix}"
122
+ end
123
+
124
+ titleize_particle(word, :first => first, :lower_particles => lower_particles)
125
+ end
126
+
127
+ def elision?(prefix, suffix)
128
+ TITLEIZE_ELISIONS.include?(prefix.downcase) && !TITLEIZE_CLITICS.include?(suffix.downcase)
129
+ end
130
+
131
+ def titleize_particle(word, first:, lower_particles:)
132
+ return word.downcase if lower_particles && !first && TITLEIZE_PARTICLES_FRENCH.include?(word.downcase)
133
+
134
+ word.capitalize
41
135
  end
42
136
 
43
137
  end
@@ -1,3 +1,3 @@
1
1
  module ImmosquareExtensions
2
- VERSION = "0.1.29".freeze
2
+ VERSION = "0.2.0".freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: immosquare-extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.29
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - immosquare
@@ -46,7 +46,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
48
  requirements: []
49
- rubygems_version: 4.0.10
49
+ rubygems_version: 4.0.19
50
50
  specification_version: 4
51
51
  summary: Utility extensions for Ruby core classes
52
52
  test_files: []