forked from norman/friendly_id
/
slug.rb
98 lines (80 loc) · 2.43 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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# A Slug is a unique, human-friendly identifier for an ActiveRecord.
class Slug < ActiveRecord::Base
belongs_to :sluggable, :polymorphic => true
before_save :check_for_blank_name, :set_sequence
ASCII_APPROXIMATIONS = {
198 => "AE",
208 => "D",
216 => "O",
222 => "Th",
223 => "ss",
230 => "ae",
240 => "d",
248 => "o",
254 => "th"
}.freeze
class << self
# Sanitizes and dasherizes string to make it safe for URL's.
#
# Example:
#
# slug.normalize('This... is an example!') # => "this-is-an-example"
#
# Note that the Unicode handling in ActiveSupport may fail to process some
# characters from Polish, Icelandic and other languages.
def normalize(slug_text)
return "" if slug_text.nil? || slug_text == ""
ActiveSupport::Multibyte.proxy_class.new(slug_text.to_s).normalize(:kc).
gsub(/[\W]/u, ' ').
strip.
gsub(/\s+/u, '-').
gsub(/-\z/u, '').
downcase.
to_s
end
def parse(friendly_id)
name, sequence = friendly_id.split('--')
sequence ||= "1"
return name, sequence
end
# Remove diacritics (accents, umlauts, etc.) from the string. Borrowed
# from "The Ruby Way."
def strip_diacritics(string)
a = ActiveSupport::Multibyte.proxy_class.new(string || "").normalize(:kd)
a.unpack('U*').inject([]) { |a, u|
if ASCII_APPROXIMATIONS[u]
a += ASCII_APPROXIMATIONS[u].unpack('U*')
elsif (u < 0x300 || u > 0x036F)
a << u
end
a
}.pack('U*')
end
# Remove non-ascii characters from the string.
def strip_non_ascii(string)
strip_diacritics(string).gsub(/[^a-z0-9]+/i, ' ')
end
private
end
# Whether or not this slug is the most recent of its owner's slugs.
def is_most_recent?
sluggable.slug == self
end
def to_friendly_id
sequence > 1 ? "#{name}--#{sequence}" : name
end
protected
# Raise a FriendlyId::SlugGenerationError if the slug name is blank.
def check_for_blank_name #:nodoc:#
if name.blank?
raise FriendlyId::SlugGenerationError.new("The slug text is blank.")
end
end
def set_sequence
return unless new_record?
last = Slug.find(:first, :conditions => { :name => name, :scope => scope,
:sluggable_type => sluggable_type}, :order => "sequence DESC",
:select => 'sequence')
self.sequence = last.sequence + 1 if last
end
end