ultra-clean-kit 0.0.1

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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/babosa-2.1.0/Changelog.md +119 -0
  3. data/babosa-2.1.0/MIT-LICENSE +19 -0
  4. data/babosa-2.1.0/README.md +243 -0
  5. data/babosa-2.1.0/Rakefile +36 -0
  6. data/babosa-2.1.0/lib/babosa/identifier.rb +268 -0
  7. data/babosa-2.1.0/lib/babosa/transliterator/base.rb +94 -0
  8. data/babosa-2.1.0/lib/babosa/transliterator/bulgarian.rb +30 -0
  9. data/babosa-2.1.0/lib/babosa/transliterator/cyrillic.rb +108 -0
  10. data/babosa-2.1.0/lib/babosa/transliterator/danish.rb +17 -0
  11. data/babosa-2.1.0/lib/babosa/transliterator/german.rb +18 -0
  12. data/babosa-2.1.0/lib/babosa/transliterator/greek.rb +78 -0
  13. data/babosa-2.1.0/lib/babosa/transliterator/hindi.rb +138 -0
  14. data/babosa-2.1.0/lib/babosa/transliterator/latin.rb +199 -0
  15. data/babosa-2.1.0/lib/babosa/transliterator/macedonian.rb +32 -0
  16. data/babosa-2.1.0/lib/babosa/transliterator/norwegian.rb +16 -0
  17. data/babosa-2.1.0/lib/babosa/transliterator/romanian.rb +16 -0
  18. data/babosa-2.1.0/lib/babosa/transliterator/russian.rb +25 -0
  19. data/babosa-2.1.0/lib/babosa/transliterator/serbian.rb +38 -0
  20. data/babosa-2.1.0/lib/babosa/transliterator/spanish.rb +11 -0
  21. data/babosa-2.1.0/lib/babosa/transliterator/swedish.rb +18 -0
  22. data/babosa-2.1.0/lib/babosa/transliterator/turkish.rb +10 -0
  23. data/babosa-2.1.0/lib/babosa/transliterator/ukrainian.rb +33 -0
  24. data/babosa-2.1.0/lib/babosa/transliterator/vietnamese.rb +146 -0
  25. data/babosa-2.1.0/lib/babosa/version.rb +7 -0
  26. data/babosa-2.1.0/lib/babosa.rb +14 -0
  27. data/babosa-2.1.0/spec/identifier_spec.rb +161 -0
  28. data/babosa-2.1.0/spec/spec_helper.rb +45 -0
  29. data/babosa-2.1.0/spec/transliterators/base_spec.rb +15 -0
  30. data/babosa-2.1.0/spec/transliterators/bulgarian_spec.rb +19 -0
  31. data/babosa-2.1.0/spec/transliterators/danish_spec.rb +16 -0
  32. data/babosa-2.1.0/spec/transliterators/german_spec.rb +16 -0
  33. data/babosa-2.1.0/spec/transliterators/greek_spec.rb +17 -0
  34. data/babosa-2.1.0/spec/transliterators/hindi_spec.rb +17 -0
  35. data/babosa-2.1.0/spec/transliterators/latin_spec.rb +8 -0
  36. data/babosa-2.1.0/spec/transliterators/macedonian_spec.rb +8 -0
  37. data/babosa-2.1.0/spec/transliterators/norwegian_spec.rb +18 -0
  38. data/babosa-2.1.0/spec/transliterators/polish_spec.rb +12 -0
  39. data/babosa-2.1.0/spec/transliterators/romanian_spec.rb +18 -0
  40. data/babosa-2.1.0/spec/transliterators/russian_spec.rb +8 -0
  41. data/babosa-2.1.0/spec/transliterators/serbian_spec.rb +24 -0
  42. data/babosa-2.1.0/spec/transliterators/spanish_spec.rb +12 -0
  43. data/babosa-2.1.0/spec/transliterators/swedish_spec.rb +18 -0
  44. data/babosa-2.1.0/spec/transliterators/turkish_spec.rb +24 -0
  45. data/babosa-2.1.0/spec/transliterators/ukrainian_spec.rb +87 -0
  46. data/babosa-2.1.0/spec/transliterators/vietnamese_spec.rb +18 -0
  47. data/ultra-clean-kit.gemspec +12 -0
  48. metadata +87 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 197f4d14fac828fe32b54aa660baf21d2c9351fbbe793112eee9e7aa53bec536
4
+ data.tar.gz: 88433d57d59c808ead4e43743697d856724a279309628165ede5591db796010f
5
+ SHA512:
6
+ metadata.gz: 4f6d825d871da8311972bef4656a2ecc78a393f1be97eab5dc51789ba743f5fd2d9f3ac349e755b6862cddd4bb7b0ebaa9e96b6fb70809a751091dbe5d4055bf
7
+ data.tar.gz: 02054dd30069f876a510672bc6f90c6f1aed855f9a11936ca1164bcdcb860360cc770fe33200c6459e74a644ca51a112f8b3e0bf0554154a83aef0077f483820
@@ -0,0 +1,119 @@
1
+ # Babosa Changelog
2
+
3
+ ## 2.0.0
4
+
5
+ This release contains no important changes. I had a week off from work and
6
+ decided to refactor the code. However there are some small breaking changes so
7
+ I have released it as 2.0.0.
8
+
9
+ * Refactor internals for simplicity
10
+ * Use built-in Ruby UTF-8 support in places of other gems.
11
+ * Drop support for Ruby < 2.5.0.
12
+ * `Babosa::Identifier#word_chars` no longer removes dashes
13
+ * `Babosa::Identifier#to_ruby_method` default argument `allow_bangs` is now a keyword argument
14
+
15
+ ## 1.0.4
16
+
17
+ * Fix nil being cast to frozen string (https://github.com/norman/babosa/pull/52)
18
+
19
+ ## 1.0.3
20
+
21
+ * Fix Active Support 6 deprecations (https://github.com/norman/babosa/pull/50)
22
+
23
+ ## 1.0.2
24
+
25
+ * Fix regression in ActiveSupport UTF8 proxy.
26
+
27
+ ## 1.0.1
28
+
29
+ * Fix error with tidy_bytes on Rubinius.
30
+ * Simplify Active Support UTF8 proxy.
31
+ * Fix `allow_bangs` argument to to_ruby_method being silently ignored.
32
+ * Raise error when generating an impossible Ruby method name.
33
+
34
+ ## 1.0.0
35
+
36
+ * Adopt semantic versioning.
37
+ * When using Active Support, require 3.2 or greater.
38
+ * Require Ruby 2.0 or greater.
39
+ * Fix Ruby warnings.
40
+ * Improve support for Ukrainian.
41
+ * Support some additional punctuation characters used by Chinese and others.
42
+ * Add Polish spec.
43
+ * Use native Unicode normalization on Ruby 2.2 in UTF8::DumbProxy.
44
+ * Invoke Ruby-native upcase/downcase in UTF8::DumbProxy.
45
+ * Proxy `tidy_bytes` method to Active Support when possible.
46
+ * Remove SlugString constant.
47
+
48
+ ## 0.3.11
49
+
50
+ * Add support for Vietnamese.
51
+
52
+ ## 0.3.10
53
+
54
+ * Fix Macedonian "S/S". Don't `include JRuby` unnecessarily.
55
+
56
+ ## 0.3.9
57
+
58
+ * Add missing Greek vowels with diaeresis.
59
+
60
+ ## 0.3.8
61
+
62
+ * Correct and improve Macedonian support.
63
+
64
+ ## 0.3.7
65
+
66
+ * Fix compatibility with Ruby 1.8.7.
67
+ * Add Swedish support.
68
+
69
+ ## 0.3.6
70
+
71
+ * Allow multiple transliterators.
72
+ * Add Greek support.
73
+
74
+ ## 0.3.5
75
+
76
+ * Don't strip underscores from identifiers.
77
+
78
+ ## 0.3.4
79
+
80
+ * Add Romanian support.
81
+
82
+ ## 0.3.3
83
+
84
+ * Add Norwegian support.
85
+
86
+ ## 0.3.2
87
+
88
+ * Improve Macedonian support.
89
+
90
+ ## 0.3.1
91
+
92
+ * Small fixes to Cyrillic.
93
+
94
+ ## 0.3.0
95
+
96
+ * Cyrillic support.
97
+ * Improve support for various Unicode spaces and dashes.
98
+
99
+ ## 0.2.2
100
+
101
+ * Fix for "smart" quote handling.
102
+
103
+ ## 0.2.1
104
+
105
+ * Implement #empty? for compatiblity with Active Support's #blank?.
106
+
107
+ ## 0.2.0
108
+
109
+ * Add support for Danish.
110
+ * Add method to generate Ruby identifiers.
111
+ * Improve performance.
112
+
113
+ ## 0.1.1
114
+
115
+ * Add support for Serbian.
116
+
117
+ ## 0.1.0
118
+
119
+ * Initial extraction from FriendlyId.
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2010 Norman Clarke
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
@@ -0,0 +1,243 @@
1
+ # Babosa
2
+
3
+ [![Build Status](https://github.com/norman/babosa/actions/workflows/main.yml/badge.svg)](https://github.com/norman/babosa/actions)
4
+
5
+ Babosa is a library for creating human-friendly identifiers, aka "slugs". It can
6
+ also be useful for normalizing and sanitizing data.
7
+
8
+ It is an extraction and improvement of the string code from
9
+ [FriendlyId](http://github.com/norman/friendly_id). I have released this as a
10
+ separate library to help developers who want to create libraries similar to
11
+ FriendlyId.
12
+
13
+ ## Features / Usage
14
+
15
+ ### Transliterate UTF-8 characters to ASCII
16
+
17
+ ```ruby
18
+ "Gölcük, Turkey".to_slug.transliterate.to_s #=> "Golcuk, Turkey"
19
+ ```
20
+
21
+ ### Locale sensitive transliteration, with support for many languages
22
+
23
+ ```ruby
24
+ "Jürgen Müller".to_slug.transliterate.to_s #=> "Jurgen Muller"
25
+ "Jürgen Müller".to_slug.transliterate(:german).to_s #=> "Juergen Mueller"
26
+ ```
27
+
28
+ Currently supported languages include:
29
+
30
+ * Bulgarian
31
+ * Danish
32
+ * German
33
+ * Greek
34
+ * Hindi
35
+ * Macedonian
36
+ * Norwegian
37
+ * Romanian
38
+ * Russian
39
+ * Serbian
40
+ * Spanish
41
+ * Swedish
42
+ * Turkish
43
+ * Ukrainian
44
+ * Vietnamese
45
+
46
+ Additionally there are generic transliterators for transliterating from the
47
+ Cyrillic alphabet and Latin alphabet with diacritics. The Latin transliterator
48
+ can be used, for example, with Czech. There is also a transliterator named
49
+ "Hindi" which may be sufficient for other Indic languages using Devanagari, but
50
+ I do not know enough to say whether the transliterations would make sense.
51
+
52
+ I'll gladly accept contributions from fluent speakers to support more languages.
53
+
54
+ ### Strip non-ASCII characters
55
+
56
+ ```ruby
57
+ "Gölcük, Turkey".to_slug.to_ascii.to_s #=> "Glck, Turkey"
58
+ ```
59
+
60
+ ### Truncate by characters
61
+
62
+ ```ruby
63
+ "üüü".to_slug.truncate(2).to_s #=> "üü"
64
+ ```
65
+
66
+ ### Truncate by bytes
67
+
68
+ This can be useful to ensure the generated slug will fit in a database column
69
+ whose length is limited by bytes rather than UTF-8 characters.
70
+
71
+ ```ruby
72
+ "üüü".to_slug.truncate_bytes(2).to_s #=> "ü"
73
+ ```
74
+
75
+ ### Remove punctuation chars
76
+
77
+ ```ruby
78
+ "this is, um, **really** cool, huh?".to_slug.word_chars.to_s #=> "this is um really cool huh"
79
+ ```
80
+
81
+ ### All-in-one
82
+
83
+ ```ruby
84
+ "Gölcük, Turkey".to_slug.normalize.to_s #=> "golcuk-turkey"
85
+ ```
86
+
87
+ ### Other stuff
88
+
89
+ #### Using Babosa With FriendlyId 4+
90
+
91
+ ```ruby
92
+ require "babosa"
93
+
94
+ class Person < ActiveRecord::Base
95
+ friendly_id :name, use: :slugged
96
+
97
+ def normalize_friendly_id(input)
98
+ input.to_slug.transliterate(:ukrainian).normalize.to_s
99
+ end
100
+ end
101
+ ```
102
+
103
+ #### UTF-8 support
104
+
105
+ Babosa normalizes all input strings [to NFC](https://en.wikipedia.org/wiki/Unicode_equivalence#Normal_forms).
106
+
107
+ #### Ruby Method Names
108
+
109
+ Babosa can generate strings for Ruby method names. (Yes, Ruby 1.9+ can use
110
+ UTF-8 chars in method names, but you may not want to):
111
+
112
+
113
+ ```ruby
114
+ "this is a method".to_slug.to_ruby_method! #=> this_is_a_method
115
+ "über cool stuff!".to_slug.to_ruby_method! #=> uber_cool_stuff!
116
+
117
+ # You can also disallow trailing punctuation chars
118
+ "über cool stuff!".to_slug.to_ruby_method(allow_bangs: false) #=> uber_cool_stuff
119
+ ```
120
+
121
+ #### Easy to Extend
122
+
123
+ You can add custom transliterators for your language with very little code. For
124
+ example here's the transliterator for German:
125
+
126
+ ```ruby
127
+ module Babosa
128
+ module Transliterator
129
+ class German < Latin
130
+ APPROXIMATIONS = {
131
+ "ä" => "ae",
132
+ "ö" => "oe",
133
+ "ü" => "ue",
134
+ "Ä" => "Ae",
135
+ "Ö" => "Oe",
136
+ "Ü" => "Ue"
137
+ }
138
+ end
139
+ end
140
+ end
141
+ ```
142
+
143
+ And a spec (you can use this as a template):
144
+
145
+ ```ruby
146
+ require "spec_helper"
147
+
148
+ describe Babosa::Transliterator::German do
149
+ let(:t) { described_class.instance }
150
+ it_behaves_like "a latin transliterator"
151
+
152
+ it "should transliterate Eszett" do
153
+ t.transliterate("ß").should eql("ss")
154
+ end
155
+
156
+ it "should transliterate vowels with umlauts" do
157
+ t.transliterate("üöä").should eql("ueoeae")
158
+ end
159
+ end
160
+ ```
161
+
162
+ ### Rails 3.x and higher
163
+
164
+ Some of Babosa's functionality was added to Active Support 3.0.0.
165
+
166
+ Babosa now differs from ActiveSupport primarily in that it supports non-Latin
167
+ strings by default, and has per-locale ASCII transliterations already baked-in.
168
+ If you are considering using Babosa with Rails, you may want to first take a
169
+ look at Active Support's
170
+ [transliterate](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-transliterate)
171
+ and
172
+ [parameterize](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html#method-i-parameterize)
173
+ to see if they suit your needs.
174
+
175
+ Please see the [API docs](http://rubydoc.info/github/norman/babosa/master/frames) and source code for
176
+ more info.
177
+
178
+ ## Getting it
179
+
180
+ Babosa can be installed via Rubygems:
181
+
182
+ gem install babosa
183
+
184
+ You can get the source code from its [Github repository](http://github.com/norman/babosa).
185
+
186
+ ## Reporting bugs
187
+
188
+ Please use Babosa's [Github issue
189
+ tracker](http://github.com/norman/babosa/issues).
190
+
191
+
192
+ ## Misc
193
+
194
+ "Babosa" means "slug" in Spanish.
195
+
196
+ ## Maintainers
197
+
198
+ * [Philip Arndt](https://github.com/parndt)
199
+ * [Norman Clarke](https://github.com/norman/)
200
+
201
+ ## Contributors
202
+
203
+ Many thanks to the following people for their help:
204
+
205
+ * [Dmitry A. Ilyashevich](https://github.com/dmitry-ilyashevich) - Deprecation fixes
206
+ * [anhkind](https://github.com/anhkind) - Vietnamese support
207
+ * [Martins Zakis](https://github.com/martins) - Bug fixes
208
+ * [Vassilis Rodokanakis](https://github.com/vrodokanakis) - Greek support
209
+ * [Peco Danajlovski](https://github.com/Vortex) - Macedonian support
210
+ * [Philip Arndt](https://github.com/parndt) - Bug fixes
211
+ * [Jonas Forsberg](https://github.com/himynameisjonas) - Swedish support
212
+ * [Jaroslav Kalistsuk](https://github.com/jarosan) - Greek support
213
+ * [Steven Heidel](https://github.com/stevenheidel) - Bug fixes
214
+ * [Edgars Beigarts](https://github.com/ebeigarts) - Support for multiple transliterators
215
+ * [Tiberiu C. Turbureanu](https://gitorious.org/~tct) - Romanian support
216
+ * [Kim Joar Bekkelund](https://github.com/kjbekkelund) - Norwegian support
217
+ * [Alexey Shkolnikov](https://github.com/grlm) - Russian support
218
+ * [Martin Petrov](https://github.com/martin-petrov) - Bulgarian support
219
+ * [Molte Emil Strange Andersen](https://github.com/molte) - Danish support
220
+ * [Milan Dobrota](https://github.com/milandobrota) - Serbian support
221
+ * [Norman Clarke](https://github.com/norman) - Original author
222
+
223
+ ## Copyright
224
+
225
+ Copyright (c) 2010-2021 Norman Clarke and contributors
226
+
227
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
228
+ this software and associated documentation files (the "Software"), to deal in
229
+ the Software without restriction, including without limitation the rights to
230
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
231
+ of the Software, and to permit persons to whom the Software is furnished to do
232
+ so, subject to the following conditions:
233
+
234
+ The above copyright notice and this permission notice shall be included in all
235
+ copies or substantial portions of the Software.
236
+
237
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
238
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
239
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
240
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
241
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
242
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
243
+ SOFTWARE.
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubygems"
4
+ require "bundler/gem_helper"
5
+ require "rake/testtask"
6
+ require "rake/clean"
7
+ require "rubygems/package_task"
8
+
9
+ task default: [:spec]
10
+ task test: :spec
11
+
12
+ CLEAN << "pkg" << "doc" << "coverage" << ".yardoc"
13
+
14
+ begin
15
+ require "yard"
16
+ YARD::Rake::YardocTask.new do |t|
17
+ t.options = ["--output-dir=doc"]
18
+ end
19
+ rescue LoadError
20
+ puts "Yard not present"
21
+ end
22
+
23
+ begin
24
+ desc "Run SimpleCov"
25
+ task :coverage do
26
+ ENV["COV"] = "true"
27
+ Rake::Task["spec"].execute
28
+ end
29
+ rescue LoadError
30
+ puts "SimpleCov not present"
31
+ end
32
+
33
+ require "rspec/core/rake_task"
34
+ RSpec::Core::RakeTask.new(:spec)
35
+
36
+ Bundler::GemHelper.install_tasks(name: "babosa")
@@ -0,0 +1,268 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Babosa
4
+ # This class provides some string-manipulation methods specific to slugs.
5
+ #
6
+ # Note that this class includes many "bang methods" such as {#clean!} and
7
+ # {#normalize!} that perform actions on the string in-place. Each of these
8
+ # methods has a corresponding "bangless" method (i.e., +Identifier#clean!+
9
+ # and +Identifier#clean+) which does not appear in the documentation because
10
+ # it is generated dynamically.
11
+ #
12
+ # All of the bang methods return an instance of String, while the bangless
13
+ # versions return an instance of {Babosa::Identifier}, so that calls to methods
14
+ # specific to this class can be chained:
15
+ #
16
+ # string = Identifier.new("hello world")
17
+ # string.with_separators! # => "hello-world"
18
+ # string.with_separators # => <Babosa::Identifier:0x000001013e1590 @wrapped_string="hello-world">
19
+ #
20
+ # @see http://www.utf8-chartable.de/unicode-utf8-table.pl?utf8=dec Unicode character table
21
+ class Identifier
22
+ Error = Class.new(StandardError)
23
+
24
+ attr_reader :wrapped_string
25
+ alias_method :to_s, :wrapped_string
26
+
27
+ def method_missing(symbol, *args, &block)
28
+ @wrapped_string.__send__(symbol, *args, &block)
29
+ end
30
+
31
+ def respond_to_missing?(name, include_all)
32
+ @wrapped_string.respond_to?(name, include_all)
33
+ end
34
+
35
+ # @param string [#to_s] The string to use as the basis of the Identifier.
36
+ def initialize(string)
37
+ @wrapped_string = string.to_s.dup
38
+ tidy_bytes!
39
+ normalize_utf8!
40
+ end
41
+
42
+ def ==(other)
43
+ to_s == other.to_s
44
+ end
45
+
46
+ def eql?(other)
47
+ self == other
48
+ end
49
+
50
+ # Approximate an ASCII string. This works only for strings using characters
51
+ # that are Roman-alphabet characters + diacritics. Non-letter characters
52
+ # are left unmodified.
53
+ #
54
+ # string = Identifier.new "Łódź, Poland"
55
+ # string.transliterate # => "Lodz, Poland"
56
+ # string = Identifier.new "日本"
57
+ # string.transliterate # => "日本"
58
+ #
59
+ # You can pass the names of any transliterator class as arguments. This
60
+ # allows for contextual approximations. Various languages are supported,
61
+ # you can see which ones by looking at the source of
62
+ # {Babosa::Transliterator::Base}.
63
+ #
64
+ # string = Identifier.new "Jürgen Müller"
65
+ # string.transliterate # => "Jurgen Muller"
66
+ # string.transliterate :german # => "Juergen Mueller"
67
+ # string = Identifier.new "¡Feliz año!"
68
+ # string.transliterate # => "¡Feliz ano!"
69
+ # string.transliterate :spanish # => "¡Feliz anio!"
70
+ #
71
+ # The approximations are an array, which you can modify if you choose:
72
+ #
73
+ # # Make Spanish use "nh" rather than "nn"
74
+ # Babosa::Transliterator::Spanish::APPROXIMATIONS["ñ"] = "nh"
75
+ #
76
+ # Notice that this method does not simply convert to ASCII; if you want
77
+ # to remove non-ASCII characters such as "¡" and "¿", use {#to_ascii!}:
78
+ #
79
+ # string.transliterate!(:spanish) # => "¡Feliz anio!"
80
+ # string.to_ascii! # => "Feliz anio!"
81
+ #
82
+ # @param *args <Symbol>
83
+ # @return String
84
+ def transliterate!(*kinds)
85
+ kinds.compact!
86
+ kinds = [:latin] if kinds.empty?
87
+ kinds.each do |kind|
88
+ transliterator = Transliterator.get(kind).instance
89
+ @wrapped_string = transliterator.transliterate(@wrapped_string)
90
+ end
91
+ to_s
92
+ end
93
+
94
+ # Converts dashes to spaces, removes leading and trailing spaces, and
95
+ # replaces multiple whitespace characters with a single space.
96
+ #
97
+ # @return String
98
+ def clean!
99
+ gsub!(/[- ]+/, " ")
100
+ strip!
101
+ to_s
102
+ end
103
+
104
+ # Remove any non-word characters. For this library's purposes, this means
105
+ # anything other than letters, numbers, spaces, underscores, dashes,
106
+ # newlines, and linefeeds.
107
+ #
108
+ # @return String
109
+ def word_chars!
110
+ # `^\p{letter}` = Any non-Unicode letter
111
+ # `&&` = add the following character class
112
+ # `[^ _\n\r\p{Extended_Pictographic}]` = Anything other than space, underscore, newline, linefeed or emojis
113
+ gsub!(/[[^\p{letter}]&&[^ \d_\-\n\r\p{Extended_Pictographic}]]/, "")
114
+ to_s
115
+ end
116
+
117
+ # Normalize the string for use as a URL slug. Note that in this context,
118
+ # +normalize+ means, strip, remove non-letters/numbers, downcasing,
119
+ # truncating to 255 bytes and converting whitespace to dashes.
120
+ #
121
+ # @param options [Hash]
122
+ # @return String
123
+ def normalize!(options = {})
124
+ options = default_normalize_options.merge(options)
125
+
126
+ if options[:transliterate]
127
+ option = options[:transliterate]
128
+ if option == true
129
+ transliterate!(*options[:transliterations])
130
+ else
131
+ transliterate!(*option)
132
+ end
133
+ end
134
+ to_ascii! if options[:to_ascii]
135
+ word_chars!
136
+ clean!
137
+ downcase!
138
+ truncate_bytes!(options[:max_length])
139
+ with_separators!(options[:separator])
140
+ end
141
+
142
+ # Normalize a string so that it can safely be used as a Ruby method name.
143
+ #
144
+ # @param allow_bangs [Boolean]
145
+ # @return String
146
+ def to_ruby_method!(allow_bangs: true)
147
+ last_char = self[-1]
148
+ transliterate!
149
+ to_ascii!
150
+ word_chars!
151
+ strip_leading_digits!
152
+ clean!
153
+ @wrapped_string += last_char if allow_bangs && ["!", "?"].include?(last_char)
154
+ raise Error, "Input generates impossible Ruby method name" if self == ""
155
+
156
+ with_separators!("_")
157
+ end
158
+
159
+ # Delete any non-ascii characters.
160
+ #
161
+ # @return String
162
+ def to_ascii!
163
+ gsub!(/[^\x00-\x7f]/u, "")
164
+ to_s
165
+ end
166
+
167
+ # Truncate the string to +max+ characters.
168
+ #
169
+ # @example
170
+ # "üéøá".to_identifier.truncate(3) #=> "üéø"
171
+ #
172
+ # @param max [Integer] The maximum number of characters.
173
+ # @return String
174
+ def truncate!(max)
175
+ @wrapped_string = slice(0, max)
176
+ end
177
+
178
+ # Truncate the string to +max+ bytes. This can be useful for ensuring that
179
+ # a UTF-8 string will always fit into a database column with a certain max
180
+ # byte length. The resulting string may be less than +max+ if the string must
181
+ # be truncated at a multibyte character boundary.
182
+ #
183
+ # @example
184
+ # "üéøá".to_identifier.truncate_bytes(3) #=> "ü"
185
+ #
186
+ # @param max [Integer] The maximum number of bytes.
187
+ # @return String
188
+ def truncate_bytes!(max)
189
+ truncate!(max)
190
+ chop! until bytesize <= max
191
+ end
192
+
193
+ # Replaces whitespace with dashes ("-").
194
+ #
195
+ # @param char [String] the separator character to use.
196
+ # @return String
197
+ def with_separators!(char = "-")
198
+ gsub!(/\s/u, char)
199
+ to_s
200
+ end
201
+
202
+ # Perform Unicode composition on the wrapped string.
203
+ #
204
+ # @return String
205
+ def normalize_utf8!
206
+ unicode_normalize!(:nfc)
207
+ to_s
208
+ end
209
+
210
+ # Strip any leading digits.
211
+ #
212
+ # @return String
213
+ def strip_leading_digits!
214
+ gsub!(/^\d+/, "")
215
+ to_s
216
+ end
217
+
218
+ # Attempt to convert characters encoded using CP1252 and IS0-8859-1 to
219
+ # UTF-8.
220
+ # @return String
221
+ def tidy_bytes!
222
+ scrub! do |bad|
223
+ bad.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
224
+ end
225
+ to_s
226
+ end
227
+
228
+ %w[clean downcase normalize normalize_utf8 strip_leading_digits
229
+ tidy_bytes to_ascii transliterate truncate truncate_bytes upcase
230
+ with_separators word_chars].each do |method|
231
+ class_eval(<<-METHOD, __FILE__, __LINE__ + 1)
232
+ def #{method}(*args)
233
+ with_new_instance { |id| id.send(:#{method}!, *args) }
234
+ end
235
+ METHOD
236
+ end
237
+
238
+ def to_ruby_method(allow_bangs: true)
239
+ with_new_instance { |id| id.to_ruby_method!(allow_bangs: allow_bangs) }
240
+ end
241
+
242
+ def to_identifier
243
+ self
244
+ end
245
+
246
+ # The default options for {#normalize!}. Override to set your own defaults.
247
+ def default_normalize_options
248
+ {transliterate: :latin, max_length: 255, separator: "-"}
249
+ end
250
+
251
+ alias_method :approximate_ascii, :transliterate
252
+ alias_method :approximate_ascii!, :transliterate!
253
+ alias_method :with_dashes, :with_separators
254
+ alias_method :with_dashes!, :with_separators!
255
+ alias_method :to_slug, :to_identifier
256
+
257
+ private
258
+
259
+ # Used as the basis of the non-mutating (bangless) methods.
260
+ def with_new_instance
261
+ Identifier.allocate.tap do |id|
262
+ id.instance_variable_set :@wrapped_string, to_s
263
+
264
+ yield id
265
+ end
266
+ end
267
+ end
268
+ end