forked from discourse/discourse
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslug.rb
62 lines (49 loc) · 1.84 KB
/
slug.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# encoding: utf-8
# frozen_string_literal: true
module Slug
CHAR_FILTER_REGEXP = /[:\/\?#\[\]@!\$&'\(\)\*\+,;=_\.~%\\`^\s|\{\}"<>]+/ # :/?#[]@!$&'()*+,;=_.~%\`^|{}"<>
MAX_LENGTH = 255
def self.for(string, default = "topic", max_length = MAX_LENGTH, method: nil)
string = string.gsub(/:([\w\-+]+(?::t\d)?):/, "") if string.present? # strip emoji strings
method = (method || SiteSetting.slug_generation_method || :ascii).to_sym
max_length = 9999 if method == :encoded # do not truncate encoded slugs
slug =
case method
when :ascii
self.ascii_generator(string)
when :encoded
self.encoded_generator(string)
when :none
self.none_generator(string)
end
slug = self.prettify_slug(slug, max_length: max_length)
(slug.blank? || slug_is_only_numbers?(slug)) ? default : slug
end
private
def self.slug_is_only_numbers?(slug)
(slug =~ /[^\d]/).blank?
end
def self.prettify_slug(slug, max_length:)
# Reject slugs that only contain numbers, because they would be indistinguishable from id's.
slug = (slug_is_only_numbers?(slug) ? "" : slug)
slug
.tr("_", "-")
.truncate(max_length, omission: "")
.squeeze("-") # squeeze continuous dashes to prettify slug
.gsub(/\A-+|-+\z/, "") # remove possible trailing and preceding dashes
end
def self.ascii_generator(string)
I18n.with_locale(SiteSetting.default_locale) { string.tr("'", "").parameterize }
end
def self.encoded_generator(string, downcase: true)
# This generator will sanitize almost all special characters,
# including reserved characters from RFC3986.
# See also URI::REGEXP::PATTERN.
string = string.strip.gsub(/\s+/, "-").gsub(CHAR_FILTER_REGEXP, "")
string = string.downcase if downcase
CGI.escape(string)
end
def self.none_generator(string)
""
end
end