Skip to content

Commit 70eb18c

Browse files
authored
Merge pull request #165 from github/skin-tones
Add skin tones support
2 parents d04fd77 + 744495f commit 70eb18c

File tree

4 files changed

+57
-3
lines changed

4 files changed

+57
-3
lines changed

db/emoji.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6416,7 +6416,7 @@
64166416
]
64176417
, "unicode_version": "12.0"
64186418
, "ios_version": "13.0"
6419-
, "skin_tones": true
6419+
, "skin_tones": false
64206420
}
64216421
, {
64226422
"emoji": "👭"

lib/emoji.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,12 @@ def find_by_alias(name)
5151

5252
# Public: Find an emoji by its unicode character. Return nil if missing.
5353
def find_by_unicode(unicode)
54-
unicodes_index[unicode]
54+
unicodes_index[unicode] || unicodes_index[unicode.sub(SKIN_TONE_RE, "")]
5555
end
5656

5757
private
5858
VARIATION_SELECTOR_16 = "\u{fe0f}".freeze
59+
SKIN_TONE_RE = /[\u{1F3FB}-\u{1F3FF}]/
5960

6061
# Characters which must have VARIATION_SELECTOR_16 to render as color emoji:
6162
TEXT_GLYPHS = [
@@ -70,7 +71,7 @@ def find_by_unicode(unicode)
7071
"\u{3030}", # wavy dash
7172
].freeze
7273

73-
private_constant :VARIATION_SELECTOR_16, :TEXT_GLYPHS
74+
private_constant :VARIATION_SELECTOR_16, :TEXT_GLYPHS, :SKIN_TONE_RE
7475

7576
def parse_data_file
7677
data = File.open(data_file, 'r:UTF-8') do |file|
@@ -118,6 +119,7 @@ def parse_data_file
118119
emoji.description = dedup.call(raw_emoji[:description])
119120
emoji.unicode_version = dedup.call(raw_emoji[:unicode_version])
120121
emoji.ios_version = dedup.call(raw_emoji[:ios_version])
122+
emoji.skin_tones = raw_emoji.fetch(:skin_tones, false)
121123
end
122124
end
123125
end

lib/emoji/character.rb

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ def self.hex_inspect(str)
1111
# True if the emoji is not a standard Emoji character.
1212
def custom?() !raw end
1313

14+
# True if the emoji supports Fitzpatrick scale skin tone modifiers
15+
def skin_tones?() @skin_tones end
16+
17+
attr_writer :skin_tones
18+
1419
# A list of names uniquely referring to this emoji.
1520
attr_reader :aliases
1621

@@ -38,6 +43,21 @@ def add_alias(name)
3843
# Raw Unicode string for an emoji. Nil if emoji is non-standard.
3944
def raw() unicode_aliases.first end
4045

46+
# Raw Unicode strings for each skin tone variant of this emoji.
47+
def raw_skin_tone_variants
48+
return [] if custom? || !skin_tones?
49+
raw_normalized = raw.sub("\u{fe0f}", "") # strip VARIATION_SELECTOR_16
50+
idx = raw_normalized.index("\u{200d}") # detect zero-width joiner
51+
SKIN_TONES.map do |modifier|
52+
if idx
53+
# insert modifier before zero-width joiner
54+
raw_normalized[...idx] + modifier + raw_normalized[idx..]
55+
else
56+
raw_normalized + modifier
57+
end
58+
end
59+
end
60+
4161
def add_unicode_alias(str)
4262
unicode_aliases << str
4363
end
@@ -54,6 +74,7 @@ def initialize(name)
5474
@aliases = Array(name)
5575
@unicode_aliases = []
5676
@tags = []
77+
@skin_tones = false
5778
end
5879

5980
def inspect
@@ -76,6 +97,16 @@ def image_filename
7697
end
7798

7899
private
100+
101+
SKIN_TONES = [
102+
"\u{1F3FB}", # light skin tone
103+
"\u{1F3FC}", # medium-light skin tone
104+
"\u{1F3FD}", # medium skin tone
105+
"\u{1F3FE}", # medium-dark skin tone
106+
"\u{1F3FF}", # dark skin tone
107+
]
108+
109+
private_constant :SKIN_TONES
79110

80111
def default_image_filename
81112
if custom?

test/emoji_test.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,27 @@ class EmojiTest < TestCase
157157
assert_equal '8.3', emoji.ios_version
158158
end
159159

160+
test "skin tones" do
161+
smiley = Emoji.find_by_alias("smiley")
162+
assert_equal false, smiley.skin_tones?
163+
assert_equal [], smiley.raw_skin_tone_variants
164+
165+
wave = Emoji.find_by_alias("wave")
166+
assert_equal true, wave.skin_tones?
167+
168+
wave = Emoji.find_by_unicode("\u{1f44b}\u{1f3ff}") # wave + dark skin tone
169+
assert_equal "wave", wave.name
170+
171+
woman_with_beard = Emoji.find_by_unicode("\u{1f9d4}\u{200d}\u{2640}\u{fe0f}")
172+
assert_equal [
173+
"1f9d4-1f3fb-200d-2640",
174+
"1f9d4-1f3fc-200d-2640",
175+
"1f9d4-1f3fd-200d-2640",
176+
"1f9d4-1f3fe-200d-2640",
177+
"1f9d4-1f3ff-200d-2640",
178+
], woman_with_beard.raw_skin_tone_variants.map { |u| Emoji::Character.hex_inspect(u) }
179+
end
180+
160181
test "no custom emojis" do
161182
custom = Emoji.all.select(&:custom?)
162183
assert 0, custom.size

0 commit comments

Comments
 (0)