sexy_slug 1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: d790a4c1a75bf89ae99be5f8199f8041f6e87e16a13a72c71581585bbd6e8bba
4
+ data.tar.gz: 296d25729f0fece000ba04ee621acff32d29dcbca922882f519ee421148be741
5
+ SHA512:
6
+ metadata.gz: 82ab515d4339eb3123b100732a257732748ba2a0844fda32be4fc5c3fc34f8f80ddadb77bcf69aabb200e36f1fff569e2a4cb44086b881d0cc214b3c23dc6ef5
7
+ data.tar.gz: c42da580bb64ba495a168145bb101a4fa03c06447f27322e93da942a225a17ac80421db1f3c3d7cc9e7355d133e92327276798dc1b7ffcd59ad90fe444c97c93
@@ -0,0 +1,7 @@
1
+ module SexySlug::AbbreviationDot
2
+ def self.call(string)
3
+ string.gsub(PATTERN) { |match| match.tr('.', '') }
4
+ end
5
+
6
+ PATTERN = /(?:\s|\(|^)(?:\p{alpha}(?:\.\p{alpha})+\.?\p{alpha}*(?:\s|\)|$))/
7
+ end
@@ -0,0 +1,5 @@
1
+ module SexySlug::ActiveSupportComposableChar
2
+ def self.call(string)
3
+ ActiveSupport::Multibyte::Chars.new(string).compose.to_s
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module SexySlug::ActiveSupportParameterize
2
+ def self.call(string)
3
+ ActiveSupport::Inflector.parameterize(string)
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module SexySlug::Apostrophe
2
+ def self.call(string)
3
+ string.gsub(PATTERN, '')
4
+ end
5
+
6
+ PATTERN = /(?<=^|\p{alpha})['’`´](?=\p{alpha}|$)/
7
+ end
@@ -0,0 +1,7 @@
1
+ module SexySlug::DateTimeDelimiter
2
+ def self.call(string)
3
+ string.gsub(PATTERN, '-')
4
+ end
5
+
6
+ PATTERN = /(?<=\d)[:\/](?=\d)/
7
+ end
@@ -0,0 +1,162 @@
1
+ require 'yaml'
2
+
3
+ module SexySlug
4
+ TRANSLATIONS = YAML.load(File.read(__FILE__).split('__END__').last)
5
+ LOCALES = TRANSLATIONS.keys.map(&:to_sym)
6
+
7
+ def self.t(path)
8
+ path.split('.').inject(TRANSLATIONS[locale.to_s]) { |obj, key| obj[key] }
9
+ end
10
+
11
+ def self.locale
12
+ defined?(I18n) && LOCALES.include?(I18n.locale) ? I18n.locale : :en
13
+ end
14
+ end
15
+
16
+ __END__
17
+
18
+ de:
19
+ currency:
20
+ '$':
21
+ full:
22
+ one: Dollar
23
+ other: Dollar
24
+ part:
25
+ one: Cent
26
+ other: Cent
27
+ '€':
28
+ full:
29
+ one: Euro
30
+ other: Euro
31
+ part:
32
+ one: Cent
33
+ other: Cent
34
+ '£':
35
+ full:
36
+ one: Pfund
37
+ other: Pfund
38
+ part:
39
+ one: Pence
40
+ other: Pence
41
+
42
+ dot: Punkt
43
+
44
+ logogram:
45
+ '%': Prozent
46
+ '&': und
47
+ '+': plus
48
+ '/': oder
49
+ '=': gleich
50
+ '@': at
51
+ '°': Grad
52
+ '¼': ein Viertel
53
+ '½': halb
54
+ '¾': drei Viertel
55
+ '÷': geteilt durch
56
+ '⅓': ein Drittel
57
+ '⅔': zwei Drittel
58
+ '⅕': ein Fünftel
59
+ '⅖': zwei Fünftel
60
+ '⅗': drei Fünftel
61
+ '⅘': vier Fünftel
62
+ '⅙': ein Sechstel
63
+ '⅚': fünf Sechstel
64
+ '⅛': ein Achtel
65
+ '⅜': drei Achtel
66
+ '⅝': fünf Achtel
67
+ '⅞': sieben Achtel
68
+
69
+ number:
70
+ delimiter: '.'
71
+ separator: ','
72
+ sign:
73
+ hashtag: Hashtag
74
+ number: Nummer
75
+ word:
76
+ # only include numbers that are
77
+ # - conventionally spelled out in the locale
78
+ # - not subject to inflection
79
+ '0': null
80
+ '2': zwei
81
+ '3': drei
82
+ '4': vier
83
+ '5': fuenf
84
+ '6': sechs
85
+ '7': sieben
86
+ '8': acht
87
+ '9': neun
88
+ '10': zehn
89
+ '11': elf
90
+ '12': zwoelf
91
+
92
+ en:
93
+ currency:
94
+ '$':
95
+ full:
96
+ one: dollar
97
+ other: dollars
98
+ part:
99
+ one: cent
100
+ other: cents
101
+ '€':
102
+ full:
103
+ one: euro
104
+ other: euros
105
+ part:
106
+ one: cent
107
+ other: cents
108
+ '£':
109
+ full:
110
+ one: pound
111
+ other: pounds
112
+ part:
113
+ one: pence
114
+ other: pence
115
+
116
+ dot: dot
117
+
118
+ logogram:
119
+ '%': percent
120
+ '&': and
121
+ '+': plus
122
+ '/': or
123
+ '=': equals
124
+ '@': at
125
+ '°': degrees
126
+ '¼': one fourth
127
+ '½': half
128
+ '¾': three fourths
129
+ '÷': divided by
130
+ '⅓': one third
131
+ '⅔': two thirds
132
+ '⅕': one fifth
133
+ '⅖': two fifths
134
+ '⅗': three fifths
135
+ '⅘': four fifths
136
+ '⅙': one sixth
137
+ '⅚': five sixths
138
+ '⅛': one eighth
139
+ '⅜': three eighths
140
+ '⅝': five eighths
141
+ '⅞': seven eighths
142
+
143
+ number:
144
+ delimiter: ','
145
+ separator: '.'
146
+ sign:
147
+ hashtag: hashtag
148
+ number: number
149
+ word:
150
+ # only include numbers that are
151
+ # - conventionally spelled out in the locale
152
+ # - not subject to inflection
153
+ '0': zero
154
+ '1': one
155
+ '2': two
156
+ '3': three
157
+ '4': four
158
+ '5': five
159
+ '6': six
160
+ '7': seven
161
+ '8': eight
162
+ '9': nine
@@ -0,0 +1,7 @@
1
+ module SexySlug::Logogram
2
+ def self.call(string)
3
+ string.gsub(PATTERN) { ' ' + SexySlug.t("logogram.#{$1}") + ' ' }
4
+ end
5
+
6
+ PATTERN = /\s*(#{Regexp.union(SexySlug.t('logogram').keys)})\s*/
7
+ end
@@ -0,0 +1,30 @@
1
+ module SexySlug::MoneyAmount
2
+ def self.call(string)
3
+ result = string
4
+ separator = Regexp.escape(SexySlug.t('number.separator'))
5
+
6
+ SexySlug.t('currency').keys.each do |currency_symbol|
7
+ sym = Regexp.escape(currency_symbol)
8
+ next unless string.match?(/#{sym}/)
9
+
10
+ result = result.gsub(/
11
+ (?<=\s|^)
12
+ #{sym}\ *\d*(?:#{separator}\d+)? | \d*(?:#{separator}\d+)?\ *#{sym}
13
+ (?=\s|$)
14
+ /x) do |match|
15
+ translations = SexySlug.t("currency.#{currency_symbol}")
16
+
17
+ full, part = match.split(/#{separator}/).map { |el| el.to_s[/\d+/] }
18
+ part = nil if part.to_i == 0
19
+
20
+ [
21
+ full,
22
+ full && translations['full'][full.to_i == 1 ? 'one' : 'other'],
23
+ part,
24
+ part && translations['part'][part.to_i == 1 ? 'one' : 'other'],
25
+ ].compact.join(' ')
26
+ end
27
+ end
28
+ result
29
+ end
30
+ end
@@ -0,0 +1,6 @@
1
+ module SexySlug::NumberDelimiter
2
+ def self.call(string)
3
+ del = Regexp.escape(SexySlug.t('number.delimiter'))
4
+ string.gsub(/((?:^|[^\d#{del}])\d+)#{del}(\d+(?:[^\d#{del}]|$))/, '\1\2')
5
+ end
6
+ end
@@ -0,0 +1,10 @@
1
+ module SexySlug::NumberSign
2
+ def self.call(string)
3
+ string.gsub(PATTERN) do
4
+ word = SexySlug.t("number.sign.#{$~[:number] ? :number : :hashtag}")
5
+ " #{word} #{$~[:target]}"
6
+ end
7
+ end
8
+
9
+ PATTERN = /\s*#\s*(?<target>(?<number>\d)|\w)/
10
+ end
@@ -0,0 +1,7 @@
1
+ module SexySlug::ShortNumber
2
+ def self.call(string)
3
+ words = SexySlug.t('number.word')
4
+ pattern = /(?<=\s|^)#{Regexp.union(words.keys)}(?=\s|$)/
5
+ string.gsub(pattern) { |match| words[match] }
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module SexySlug::SignificantDot
2
+ def self.call(string)
3
+ string.gsub(PATTERN, " #{SexySlug.t('dot')} ")
4
+ end
5
+
6
+ PATTERN = /(?<=[^\s\d.]|^)\.(?=[^\s\d.])/
7
+ end
@@ -0,0 +1,5 @@
1
+ module SexySlug::Underscore
2
+ def self.call(string)
3
+ string.tr('_', '-')
4
+ end
5
+ end
@@ -0,0 +1,7 @@
1
+ module SexySlug::UnreadableChar
2
+ def self.call(string)
3
+ string.gsub(PATTERN, '')
4
+ end
5
+
6
+ PATTERN = /\p{cntrl}/
7
+ end
@@ -0,0 +1,23 @@
1
+ module SexySlug::UsuallyTransliterableChar
2
+ def self.call(string)
3
+ string.gsub(PATTERN) { |match| TRANSLITERATIONS[match] }
4
+ end
5
+
6
+ TRANSLITERATIONS = {
7
+ 'Ä' => 'AE',
8
+ 'Å' => 'AA',
9
+ 'Æ' => 'AE',
10
+ 'Ö' => 'OE',
11
+ 'Ø' => 'OE',
12
+ 'Ü' => 'UE',
13
+ 'ß' => 'ss',
14
+ 'ä' => 'ae',
15
+ 'å' => 'aa',
16
+ 'æ' => 'ae',
17
+ 'ö' => 'oe',
18
+ 'ø' => 'oe',
19
+ 'ü' => 'ue',
20
+ }
21
+
22
+ PATTERN = Regexp.union(TRANSLITERATIONS.keys)
23
+ end
@@ -0,0 +1,3 @@
1
+ module SexySlug
2
+ VERSION = '1.0.1'
3
+ end
data/lib/sexy_slug.rb ADDED
@@ -0,0 +1,27 @@
1
+ require 'active_support/inflector/transliterate'
2
+ require 'active_support/multibyte'
3
+ require 'sexy_slug/i18n'
4
+ Dir[File.join(__dir__, 'sexy_slug', '*.rb')].each { |file| require file }
5
+
6
+ module SexySlug
7
+ def self.from(string)
8
+ PROCESSORS.inject(string.to_s) { |str, processor| processor.call(str) }
9
+ end
10
+
11
+ PROCESSORS = [
12
+ ActiveSupportComposableChar,
13
+ UnreadableChar,
14
+ Apostrophe,
15
+ NumberDelimiter,
16
+ DateTimeDelimiter,
17
+ MoneyAmount,
18
+ AbbreviationDot,
19
+ Logogram,
20
+ NumberSign,
21
+ ShortNumber,
22
+ SignificantDot,
23
+ Underscore,
24
+ UsuallyTransliterableChar,
25
+ ActiveSupportParameterize,
26
+ ]
27
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sexy_slug
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Janosch Müller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-03-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '12.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '12.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Build sexy slugs for your URL paths. A lightweight, opinionated alternative
70
+ to StringEx/ActAsUrl.
71
+ email:
72
+ - janosch84@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - lib/sexy_slug.rb
78
+ - lib/sexy_slug/abbreviation_dot.rb
79
+ - lib/sexy_slug/active_support_composable_char.rb
80
+ - lib/sexy_slug/active_support_parameterize.rb
81
+ - lib/sexy_slug/apostrophe.rb
82
+ - lib/sexy_slug/date_time_delimiter.rb
83
+ - lib/sexy_slug/i18n.rb
84
+ - lib/sexy_slug/logogram.rb
85
+ - lib/sexy_slug/money_amount.rb
86
+ - lib/sexy_slug/number_delimiter.rb
87
+ - lib/sexy_slug/number_sign.rb
88
+ - lib/sexy_slug/short_number.rb
89
+ - lib/sexy_slug/significant_dot.rb
90
+ - lib/sexy_slug/underscore.rb
91
+ - lib/sexy_slug/unreadable_char.rb
92
+ - lib/sexy_slug/usually_transliterable_char.rb
93
+ - lib/sexy_slug/version.rb
94
+ homepage: https://github.com/jaynetics/sexy_slug
95
+ licenses:
96
+ - MIT
97
+ metadata: {}
98
+ post_install_message:
99
+ rdoc_options: []
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - ">="
105
+ - !ruby/object:Gem::Version
106
+ version: 2.3.0
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ requirements: []
113
+ rubygems_version: 3.0.3
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Builds slugs from Strings
117
+ test_files: []