negarmoji 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +6 -0
- data/.travis.yml +12 -0
- data/CONTRIBUTING.md +31 -0
- data/Gemfile +6 -0
- data/Rakefile +24 -0
- data/db/dump.rb +69 -0
- data/db/emoji-test-parser.rb +121 -0
- data/db/index.html +113 -0
- data/db/{emoji.json → negarmoji.json} +0 -0
- data/lib/negarmoji.rb +1 -1
- data/lib/{emoji → negarmoji}/character.rb +7 -7
- data/lib/{emoji.rb → negarmoji/emoji.rb} +11 -11
- data/lib/negarmoji/version.rb +5 -0
- data/negarmoji.gemspec +24 -0
- data/script/bootstrap +10 -0
- data/script/console +16 -0
- data/script/release +31 -0
- data/script/test +14 -0
- data/test/documentation_test.rb +46 -0
- data/test/emoji_test.rb +243 -0
- data/test/test_helper.rb +8 -0
- data/vendor/unicode-negarmoji-test.txt +4119 -0
- metadata +31 -10
@@ -1,14 +1,14 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require "negarmoji/character"
|
5
|
+
require "json"
|
6
6
|
|
7
7
|
module Emoji
|
8
8
|
extend self
|
9
9
|
|
10
10
|
def data_file
|
11
|
-
File.expand_path(
|
11
|
+
File.expand_path("../../../db/negarmoji.json", __FILE__)
|
12
12
|
end
|
13
13
|
|
14
14
|
def all
|
@@ -26,7 +26,7 @@ module Emoji
|
|
26
26
|
emoji
|
27
27
|
end
|
28
28
|
|
29
|
-
# Public: Yield an
|
29
|
+
# Public: Yield an negarmoji to the block and update the indices in case its
|
30
30
|
# aliases or unicode_aliases lists changed.
|
31
31
|
def edit_emoji(emoji)
|
32
32
|
@names_index ||= Hash.new
|
@@ -44,12 +44,12 @@ module Emoji
|
|
44
44
|
emoji
|
45
45
|
end
|
46
46
|
|
47
|
-
# Public: Find an
|
47
|
+
# Public: Find an negarmoji by its aliased name. Return nil if missing.
|
48
48
|
def find_by_alias(name)
|
49
49
|
names_index[name]
|
50
50
|
end
|
51
51
|
|
52
|
-
# Public: Find an
|
52
|
+
# Public: Find an negarmoji by its unicode character. Return nil if missing.
|
53
53
|
def find_by_unicode(unicode)
|
54
54
|
unicodes_index[unicode]
|
55
55
|
end
|
@@ -57,7 +57,7 @@ module Emoji
|
|
57
57
|
private
|
58
58
|
VARIATION_SELECTOR_16 = "\u{fe0f}".freeze
|
59
59
|
|
60
|
-
|
60
|
+
# Characters which must have VARIATION_SELECTOR_16 to render as color negarmoji:
|
61
61
|
TEXT_GLYPHS = [
|
62
62
|
"\u{1f237}", # Japanese “monthly amount” button
|
63
63
|
"\u{1f202}", # Japanese “service charge” button
|
@@ -149,7 +149,7 @@ module Emoji
|
|
149
149
|
private_constant :VARIATION_SELECTOR_16, :TEXT_GLYPHS
|
150
150
|
|
151
151
|
def parse_data_file
|
152
|
-
data = File.open(data_file,
|
152
|
+
data = File.open(data_file, "r:UTF-8") do |file|
|
153
153
|
JSON.parse(file.read, symbolize_names: true)
|
154
154
|
end
|
155
155
|
|
@@ -170,10 +170,10 @@ module Emoji
|
|
170
170
|
data.each do |raw_emoji|
|
171
171
|
self.create(nil) do |emoji|
|
172
172
|
raw_emoji.fetch(:aliases).each { |name| emoji.add_alias(dedup.call(name)) }
|
173
|
-
if raw = raw_emoji[:emoji]
|
173
|
+
if (raw = raw_emoji[:emoji])
|
174
174
|
append_unicode.call(emoji, raw)
|
175
175
|
start_pos = 0
|
176
|
-
while found_index = raw.index(VARIATION_SELECTOR_16, start_pos)
|
176
|
+
while (found_index = raw.index(VARIATION_SELECTOR_16, start_pos))
|
177
177
|
# register every variant where one VARIATION_SELECTOR_16 is removed
|
178
178
|
raw_alternate = raw.dup
|
179
179
|
raw_alternate[found_index] = ""
|
@@ -209,5 +209,5 @@ module Emoji
|
|
209
209
|
end
|
210
210
|
end
|
211
211
|
|
212
|
-
# Preload
|
212
|
+
# Preload negarmoji into memory
|
213
213
|
Emoji.all
|
data/negarmoji.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path("lib", __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require "negarmoji/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "negarmoji"
|
9
|
+
spec.version = Emoji::VERSION
|
10
|
+
spec.platform = Gem::Platform::RUBY
|
11
|
+
spec.authors = ["Mohammad Mahdi Baghbani Pourvahid"]
|
12
|
+
spec.email = "MahdiBaghbani@protonmail.com"
|
13
|
+
spec.homepage = "https://gitlab.com/Azadeh-Afzar/Web-Development/Negareh-Emoji-Library"
|
14
|
+
spec.description = "%(Character information and metadata for Unicode emoji)"
|
15
|
+
spec.summary = "Unicode emoji library"
|
16
|
+
spec.licenses = "GPL-3.0"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0")
|
19
|
+
spec.executables = spec.files.grep(%r!^bin/!) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r!^test/!)
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.required_ruby_version = ">= 2.3.0"
|
24
|
+
end
|
data/script/bootstrap
ADDED
data/script/console
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -e
|
3
|
+
|
4
|
+
public_methods() {
|
5
|
+
sed '/^ *private/,$d' "$1" | grep -w def | sed -E 's/^ *def / /; s/).+/)/'
|
6
|
+
}
|
7
|
+
|
8
|
+
echo "Emoji methods:"
|
9
|
+
public_methods lib/negarmoji.rb
|
10
|
+
echo
|
11
|
+
echo "Emoji::Character methods:"
|
12
|
+
public_methods lib/negarmoji/character.rb
|
13
|
+
echo
|
14
|
+
|
15
|
+
exec irb -I lib -r negarmoji
|
16
|
+
zz
|
data/script/release
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
# Usage: script/release
|
3
|
+
#
|
4
|
+
# 1. Checks if tests pass,
|
5
|
+
# 2. commits gemspec,
|
6
|
+
# 3. tags the release with the version in the gemspec,
|
7
|
+
# 4. pushes "negarmoji" gem to RubyGems.org.
|
8
|
+
|
9
|
+
set -e
|
10
|
+
|
11
|
+
case "$1" in
|
12
|
+
-h | --help )
|
13
|
+
sed -ne '/^#/!q;s/.\{1,2\}//;1d;p' < "$0"
|
14
|
+
exit 0
|
15
|
+
;;
|
16
|
+
esac
|
17
|
+
|
18
|
+
if git diff --quiet negarmoji.gemspec; then
|
19
|
+
echo "You must bump the version in the gemspec first." >&2
|
20
|
+
exit 1
|
21
|
+
fi
|
22
|
+
|
23
|
+
script/test
|
24
|
+
|
25
|
+
trap 'rm *.gem' EXIT
|
26
|
+
|
27
|
+
version="$(gem build negarmoji.gemspec | awk '/Version:/ { print $2 }')"
|
28
|
+
git commit negarmoji.gemspec -m "negarmoji $version"
|
29
|
+
git tag "v${version}"
|
30
|
+
git push origin HEAD "v${version}"
|
31
|
+
|
data/script/test
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# Pull the EmojiHelper example from the docs
|
4
|
+
readme = File.expand_path('../../README.md', __FILE__)
|
5
|
+
docs = File.open(readme, 'r:UTF-8') { |f| f.read }
|
6
|
+
eval docs.match(/^module.+?^end/m)[0]
|
7
|
+
|
8
|
+
String.class_eval do
|
9
|
+
def html_safe() self end
|
10
|
+
def present?() !empty? end
|
11
|
+
end
|
12
|
+
|
13
|
+
class DocumentationTest < TestCase
|
14
|
+
module Helper
|
15
|
+
extend EmojiHelper
|
16
|
+
|
17
|
+
def self.h(str)
|
18
|
+
str.gsub('<', '<').gsub('>', '>')
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.image_path(img)
|
22
|
+
"/images/#{img}?123"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
test "replaces emoji syntax with images" do
|
27
|
+
assert_equal "It's raining " \
|
28
|
+
'<img alt="cat" src="/images/emoji/1f431.svg?123" style="vertical-align:middle" width="20" height="20" />s and ' \
|
29
|
+
'<img alt="dog" src="/images/emoji/1f436.svg?123" style="vertical-align:middle" width="20" height="20" />s!',
|
30
|
+
Helper.emojify("It's raining :cat:s and :dog:s!")
|
31
|
+
end
|
32
|
+
|
33
|
+
test "doesn't replace unknown emoji" do
|
34
|
+
content = ":jupiter: is in :space:"
|
35
|
+
assert_equal content, Helper.emojify(content)
|
36
|
+
end
|
37
|
+
|
38
|
+
test "escapes other HTML" do
|
39
|
+
assert_equal "You have been <script>alert('pwned!')</script>",
|
40
|
+
Helper.emojify("You have been <script>alert('pwned!')</script>")
|
41
|
+
end
|
42
|
+
|
43
|
+
test "returns nil for blank content" do
|
44
|
+
assert_nil Helper.emojify('')
|
45
|
+
end
|
46
|
+
end
|
data/test/emoji_test.rb
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require_relative '../db/emoji-test-parser'
|
3
|
+
|
4
|
+
class EmojiTest < TestCase
|
5
|
+
test "fetching all negarmoji" do
|
6
|
+
count = Emoji.all.size
|
7
|
+
assert count > 845, "there were too few emojis: #{count}"
|
8
|
+
end
|
9
|
+
|
10
|
+
test "unicodes set contains the unicodes" do
|
11
|
+
min_size = Emoji.all.size
|
12
|
+
count = Emoji.all.map(&:unicode_aliases).flatten.size
|
13
|
+
assert count > min_size, "there were too few unicode mappings: #{count}"
|
14
|
+
end
|
15
|
+
|
16
|
+
test "finding negarmoji by alias" do
|
17
|
+
assert_equal 'smile', Emoji.find_by_alias('smile').name
|
18
|
+
end
|
19
|
+
|
20
|
+
test "finding nonexistent negarmoji by alias returns nil" do
|
21
|
+
assert_nil Emoji.find_by_alias('$$$')
|
22
|
+
end
|
23
|
+
|
24
|
+
test "finding negarmoji by unicode" do
|
25
|
+
emoji = Emoji.find_by_unicode("\u{1f604}") # grinning face with smiling eyes
|
26
|
+
assert_equal "\u{1f604}", emoji.raw
|
27
|
+
end
|
28
|
+
|
29
|
+
test "finding nonexistent negarmoji by unicode returns nil" do
|
30
|
+
assert_nil Emoji.find_by_unicode("\u{1234}")
|
31
|
+
end
|
32
|
+
|
33
|
+
test "unicode_aliases" do
|
34
|
+
emoji = Emoji.find_by_unicode("\u{2728}") # sparkles
|
35
|
+
assert_equal ["2728", "2728-fe0f"], emoji.unicode_aliases.map { |u| Emoji::Character.hex_inspect(u) }
|
36
|
+
end
|
37
|
+
|
38
|
+
test "unicode_aliases doesn't necessarily include form without VARIATION_SELECTOR_16" do
|
39
|
+
emoji = Emoji.find_by_unicode("\u{00a9}\u{fe0f}") # copyright symbol
|
40
|
+
assert_equal ["00a9-fe0f"], emoji.unicode_aliases.map { |u| Emoji::Character.hex_inspect(u) }
|
41
|
+
end
|
42
|
+
|
43
|
+
test "emojis have tags" do
|
44
|
+
emoji = Emoji.find_by_alias('smile')
|
45
|
+
assert emoji.tags.include?('happy')
|
46
|
+
assert emoji.tags.include?('joy')
|
47
|
+
assert emoji.tags.include?('pleased')
|
48
|
+
end
|
49
|
+
|
50
|
+
GENDER_EXCEPTIONS = [
|
51
|
+
"man_with_gua_pi_mao",
|
52
|
+
"woman_with_headscarf",
|
53
|
+
"man_in_tuxedo",
|
54
|
+
"pregnant_woman",
|
55
|
+
"isle_of_man",
|
56
|
+
"blonde_woman",
|
57
|
+
/^couple(kiss)?_/,
|
58
|
+
/^family_/,
|
59
|
+
]
|
60
|
+
|
61
|
+
test "emojis have valid names" do
|
62
|
+
aliases = Emoji.all.flat_map(&:aliases)
|
63
|
+
|
64
|
+
gender_mismatch = []
|
65
|
+
to_another_gender = lambda do |name|
|
66
|
+
case name
|
67
|
+
when *GENDER_EXCEPTIONS then name
|
68
|
+
else
|
69
|
+
name.sub(/(?<=^|_)(?:wo)?man(?=_|$)/) do |match|
|
70
|
+
match == "woman" ? "man" : "woman"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
invalid = []
|
76
|
+
alias_count = Hash.new(0)
|
77
|
+
aliases.each do |name|
|
78
|
+
alias_count[name] += 1
|
79
|
+
invalid << name if name !~ /\A[\w+-]+\Z/
|
80
|
+
another_gender = to_another_gender.call(name)
|
81
|
+
gender_mismatch << another_gender unless aliases.include?(another_gender)
|
82
|
+
end
|
83
|
+
|
84
|
+
duplicates = alias_count.select { |_, count| count > 1 }.keys
|
85
|
+
|
86
|
+
assert_equal [], invalid, "some negarmoji have invalid names"
|
87
|
+
assert_equal [], duplicates, "some negarmoji aliases have duplicates"
|
88
|
+
assert_equal [], gender_mismatch, "missing gender variants"
|
89
|
+
end
|
90
|
+
|
91
|
+
test "missing or incorrect unicodes" do
|
92
|
+
emoji_map, _ = EmojiTestParser.parse(File.expand_path("../../vendor/unicode-negarmoji-test.txt", __FILE__))
|
93
|
+
source_unicode_emoji = emoji_map.values
|
94
|
+
text_glyphs = Emoji.const_get(:TEXT_GLYPHS)
|
95
|
+
|
96
|
+
missing = 0
|
97
|
+
message = "Missing or incorrect unicodes:\n"
|
98
|
+
source_unicode_emoji.each do |emoji|
|
99
|
+
emoji[:sequences].each do |raw|
|
100
|
+
found = Emoji.find_by_unicode(raw)
|
101
|
+
if text_glyphs.include?(raw)
|
102
|
+
assert_nil found, Emoji::Character.hex_inspect(raw)
|
103
|
+
next
|
104
|
+
end
|
105
|
+
next if found
|
106
|
+
message << "%s (%s)" % [Emoji::Character.hex_inspect(raw), emoji[:description]]
|
107
|
+
if found = Emoji.find_by_unicode(raw.gsub("\u{fe0f}", ""))
|
108
|
+
message << " - could be %s (:%s:)" % [found.hex_inspect, found.name]
|
109
|
+
end
|
110
|
+
message << "\n"
|
111
|
+
missing += 1
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
assert_equal 0, missing, message
|
116
|
+
end
|
117
|
+
|
118
|
+
test "raw representation does not include VARIATION SELECTOR 16 unless necessary" do
|
119
|
+
emoji = Emoji.all.select do |emoji|
|
120
|
+
!emoji.custom? && emoji.raw.end_with?("\u{fe0f}") && emoji.unicode_aliases.size == 2
|
121
|
+
end
|
122
|
+
assert_equal [], emoji
|
123
|
+
end
|
124
|
+
|
125
|
+
test "negarmoji have category" do
|
126
|
+
missing = Emoji.all.select { |e| e.category.to_s.empty? }
|
127
|
+
assert_equal [], missing.map(&:name), "some negarmoji don't have a category"
|
128
|
+
|
129
|
+
emoji = Emoji.find_by_alias('family_man_woman_girl')
|
130
|
+
assert_equal 'People & Body', emoji.category
|
131
|
+
|
132
|
+
categories = Emoji.all.map(&:category).uniq.compact
|
133
|
+
assert_equal [
|
134
|
+
"Smileys & Emotion",
|
135
|
+
"People & Body",
|
136
|
+
"Animals & Nature",
|
137
|
+
"Food & Drink",
|
138
|
+
"Travel & Places",
|
139
|
+
"Activities",
|
140
|
+
"Objects",
|
141
|
+
"Symbols",
|
142
|
+
"Flags",
|
143
|
+
], categories
|
144
|
+
end
|
145
|
+
|
146
|
+
test "negarmoji have description" do
|
147
|
+
missing = Emoji.all.select { |e| e.description.to_s.empty? }
|
148
|
+
assert_equal [], missing.map(&:name), "some negarmoji don't have a description"
|
149
|
+
|
150
|
+
emoji = Emoji.find_by_alias('family_man_woman_girl')
|
151
|
+
assert_equal 'family: man, woman, girl', emoji.description
|
152
|
+
end
|
153
|
+
|
154
|
+
test "negarmoji have Unicode version" do
|
155
|
+
emoji = Emoji.find_by_alias('family_man_woman_girl')
|
156
|
+
assert_equal '6.0', emoji.unicode_version
|
157
|
+
end
|
158
|
+
|
159
|
+
test "negarmoji have iOS version" do
|
160
|
+
missing = Emoji.all.select { |e| e.ios_version.to_s.empty? }
|
161
|
+
assert_equal [], missing.map(&:name), "some negarmoji don't have an iOS version"
|
162
|
+
|
163
|
+
emoji = Emoji.find_by_alias('family_man_woman_girl')
|
164
|
+
assert_equal '8.3', emoji.ios_version
|
165
|
+
end
|
166
|
+
|
167
|
+
test "no custom emojis" do
|
168
|
+
custom = Emoji.all.select(&:custom?)
|
169
|
+
assert 0, custom.size
|
170
|
+
end
|
171
|
+
|
172
|
+
test "create" do
|
173
|
+
emoji = Emoji.create("music") do |char|
|
174
|
+
char.add_unicode_alias "\u{266b}"
|
175
|
+
char.add_unicode_alias "\u{266a}"
|
176
|
+
char.add_tag "notes"
|
177
|
+
char.add_tag "eighth"
|
178
|
+
end
|
179
|
+
|
180
|
+
begin
|
181
|
+
assert_equal emoji, Emoji.all.last
|
182
|
+
assert_equal emoji, Emoji.find_by_alias("music")
|
183
|
+
assert_equal emoji, Emoji.find_by_unicode("\u{266a}")
|
184
|
+
assert_equal emoji, Emoji.find_by_unicode("\u{266b}")
|
185
|
+
|
186
|
+
assert_equal "\u{266b}", emoji.raw
|
187
|
+
assert_equal "266b.svg", emoji.image_filename
|
188
|
+
assert_equal %w[music], emoji.aliases
|
189
|
+
assert_equal %w[notes eighth], emoji.tags
|
190
|
+
ensure
|
191
|
+
Emoji.all.pop
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
test "create with custom filename" do
|
196
|
+
emoji = Emoji.create("music") do |char|
|
197
|
+
char.image_filename = "some_path/my_emoji.gif"
|
198
|
+
end
|
199
|
+
|
200
|
+
begin
|
201
|
+
assert_equal "some_path/my_emoji.gif", emoji.image_filename
|
202
|
+
ensure
|
203
|
+
Emoji.all.pop
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
test "create without block" do
|
208
|
+
emoji = Emoji.create("music")
|
209
|
+
|
210
|
+
begin
|
211
|
+
assert_equal emoji, Emoji.find_by_alias("music")
|
212
|
+
assert_equal [], emoji.unicode_aliases
|
213
|
+
assert_equal [], emoji.tags
|
214
|
+
assert_equal "music.svg", emoji.image_filename
|
215
|
+
ensure
|
216
|
+
Emoji.all.pop
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
test "edit" do
|
221
|
+
emoji = Emoji.find_by_alias("weary")
|
222
|
+
|
223
|
+
emoji = Emoji.edit_emoji(emoji) do |char|
|
224
|
+
char.add_alias "whining"
|
225
|
+
char.add_unicode_alias "\u{1f629}\u{266a}"
|
226
|
+
char.add_tag "complaining"
|
227
|
+
end
|
228
|
+
|
229
|
+
begin
|
230
|
+
assert_equal emoji, Emoji.find_by_alias("weary")
|
231
|
+
assert_equal emoji, Emoji.find_by_alias("whining")
|
232
|
+
assert_equal emoji, Emoji.find_by_unicode("\u{1f629}")
|
233
|
+
assert_equal emoji, Emoji.find_by_unicode("\u{1f629}\u{266a}")
|
234
|
+
|
235
|
+
assert_equal %w[weary whining], emoji.aliases
|
236
|
+
assert_includes emoji.tags, "complaining"
|
237
|
+
ensure
|
238
|
+
emoji.aliases.pop
|
239
|
+
emoji.unicode_aliases.pop
|
240
|
+
emoji.tags.pop
|
241
|
+
end
|
242
|
+
end
|
243
|
+
end
|