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.
- checksums.yaml +7 -0
- data/babosa-2.1.0/Changelog.md +119 -0
- data/babosa-2.1.0/MIT-LICENSE +19 -0
- data/babosa-2.1.0/README.md +243 -0
- data/babosa-2.1.0/Rakefile +36 -0
- data/babosa-2.1.0/lib/babosa/identifier.rb +268 -0
- data/babosa-2.1.0/lib/babosa/transliterator/base.rb +94 -0
- data/babosa-2.1.0/lib/babosa/transliterator/bulgarian.rb +30 -0
- data/babosa-2.1.0/lib/babosa/transliterator/cyrillic.rb +108 -0
- data/babosa-2.1.0/lib/babosa/transliterator/danish.rb +17 -0
- data/babosa-2.1.0/lib/babosa/transliterator/german.rb +18 -0
- data/babosa-2.1.0/lib/babosa/transliterator/greek.rb +78 -0
- data/babosa-2.1.0/lib/babosa/transliterator/hindi.rb +138 -0
- data/babosa-2.1.0/lib/babosa/transliterator/latin.rb +199 -0
- data/babosa-2.1.0/lib/babosa/transliterator/macedonian.rb +32 -0
- data/babosa-2.1.0/lib/babosa/transliterator/norwegian.rb +16 -0
- data/babosa-2.1.0/lib/babosa/transliterator/romanian.rb +16 -0
- data/babosa-2.1.0/lib/babosa/transliterator/russian.rb +25 -0
- data/babosa-2.1.0/lib/babosa/transliterator/serbian.rb +38 -0
- data/babosa-2.1.0/lib/babosa/transliterator/spanish.rb +11 -0
- data/babosa-2.1.0/lib/babosa/transliterator/swedish.rb +18 -0
- data/babosa-2.1.0/lib/babosa/transliterator/turkish.rb +10 -0
- data/babosa-2.1.0/lib/babosa/transliterator/ukrainian.rb +33 -0
- data/babosa-2.1.0/lib/babosa/transliterator/vietnamese.rb +146 -0
- data/babosa-2.1.0/lib/babosa/version.rb +7 -0
- data/babosa-2.1.0/lib/babosa.rb +14 -0
- data/babosa-2.1.0/spec/identifier_spec.rb +161 -0
- data/babosa-2.1.0/spec/spec_helper.rb +45 -0
- data/babosa-2.1.0/spec/transliterators/base_spec.rb +15 -0
- data/babosa-2.1.0/spec/transliterators/bulgarian_spec.rb +19 -0
- data/babosa-2.1.0/spec/transliterators/danish_spec.rb +16 -0
- data/babosa-2.1.0/spec/transliterators/german_spec.rb +16 -0
- data/babosa-2.1.0/spec/transliterators/greek_spec.rb +17 -0
- data/babosa-2.1.0/spec/transliterators/hindi_spec.rb +17 -0
- data/babosa-2.1.0/spec/transliterators/latin_spec.rb +8 -0
- data/babosa-2.1.0/spec/transliterators/macedonian_spec.rb +8 -0
- data/babosa-2.1.0/spec/transliterators/norwegian_spec.rb +18 -0
- data/babosa-2.1.0/spec/transliterators/polish_spec.rb +12 -0
- data/babosa-2.1.0/spec/transliterators/romanian_spec.rb +18 -0
- data/babosa-2.1.0/spec/transliterators/russian_spec.rb +8 -0
- data/babosa-2.1.0/spec/transliterators/serbian_spec.rb +24 -0
- data/babosa-2.1.0/spec/transliterators/spanish_spec.rb +12 -0
- data/babosa-2.1.0/spec/transliterators/swedish_spec.rb +18 -0
- data/babosa-2.1.0/spec/transliterators/turkish_spec.rb +24 -0
- data/babosa-2.1.0/spec/transliterators/ukrainian_spec.rb +87 -0
- data/babosa-2.1.0/spec/transliterators/vietnamese_spec.rb +18 -0
- data/ultra-clean-kit.gemspec +12 -0
- 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
|
+
[](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
|