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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd26758c30c54939beaf4e76085d9387a67643ead74c1cbcd5d2dab836488dd6
4
- data.tar.gz: 6a3cf4a22e18f043a610fd4491566044bad0e40f4401fafca59fb45d64597c33
3
+ metadata.gz: 9e2e1d815a0ef7dd8148b4b72d2ec5e4f20e78a75cd650b769193793bb9a142d
4
+ data.tar.gz: 49d687a4853b687614cc6f3f9829cefcaa76447f6703fdb6c8c624af390dd319
5
5
  SHA512:
6
- metadata.gz: 636cc57a22185f7db90ab9e593106cdfb88c60cca68848507e8d527c6e1907bcc112a952f9af377cb43d13504314b1e6d330d94a11aa26469b6b16a8df6f7282
7
- data.tar.gz: 0bcddc0efcea4556dbfafb931efd1256a29d3561ca993a3c2e0ea4e575b05f98ba3002c0a8467ccee10358159308ea93fde2abe1c47a5ec5e8aaae8d75d5e452
6
+ metadata.gz: a78d55cf033e29c0cd95a8a22d40f3b91f90f5525e8944ee69137dc4f347c2364094351f63a90dbc5fc08fa4370d2066281d786aaefbf284d13fb30fb9c93c49
7
+ data.tar.gz: 2b064af840975fe10d14c8190def116540da1bddcba0abd0e3a7c8e2cba8d78a9590eb8c65d91c898304973f626410f78ddbdb72174fa49971803dd732589381
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ /bin/*
2
+ .bundle
3
+ .ruby-version
4
+ Gemfile.lock
5
+ vendor/*
6
+ !vendor/unicode-negarmoji-test.txt
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ sudo: false
2
+ script: script/test
3
+ rvm:
4
+ - 1.9.3
5
+ - '2.1'
6
+ - '2.2'
7
+ - '2.3'
8
+ - '2.4'
9
+ - '2.5'
10
+ - '2.6'
11
+ notifications:
12
+ email: false
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,31 @@
1
+ Contributions to this project are released to the public under the [project's open source license](LICENSE).
2
+
3
+ Some useful tools in development are:
4
+
5
+ ```
6
+ script/bootstrap
7
+ ```
8
+
9
+ Sets up the development environment. The prerequisites are:
10
+
11
+ * Ruby 1.9+
12
+ * Bundler
13
+
14
+ ```
15
+ script/test
16
+ ```
17
+
18
+ Runs the test suite.
19
+
20
+ ```
21
+ script/console
22
+ ```
23
+
24
+ Opens `irb` console with negarmoji library preloded for experimentation.
25
+
26
+ ```
27
+ script/release
28
+ ```
29
+
30
+ For maintainers only: after the gemspec has been edited, this commits the
31
+ change, tags a release, and pushes it to both GitHub and RubyGems.org.
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rake", "~> 10.3.2"
4
+ gem "minitest", "~> 5.3.5"
5
+
6
+ gemspec
data/Rakefile ADDED
@@ -0,0 +1,24 @@
1
+ require 'rake/testtask'
2
+
3
+ task :default => :test
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << "test"
7
+ t.test_files = FileList["test/*_test.rb"]
8
+ end
9
+
10
+ namespace :db do
11
+ desc %(Generate Emoji data files needed for development)
12
+ task :generate => [
13
+ 'vendor/unicode-negarmoji-test.txt',
14
+ ]
15
+
16
+ desc %(Dump a list of supported Emoji with Unicode descriptions and aliases)
17
+ task :dump => :generate do
18
+ system 'ruby', '-Ilib', 'db/dump.rb'
19
+ end
20
+ end
21
+
22
+ file 'vendor/unicode-negarmoji-test.txt' do |t|
23
+ system 'curl', '-fsSL', 'http://unicode.org/Public/negarmoji/12.0/negarmoji-test.txt', '-o', t.name
24
+ end
data/db/dump.rb ADDED
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'emoji'
4
+ require 'json'
5
+ require_relative './emoji-test-parser'
6
+
7
+ items = []
8
+
9
+ _, categories = EmojiTestParser.parse(File.expand_path("../../vendor/unicode-negarmoji-test.txt", __FILE__))
10
+ seen_existing = {}
11
+
12
+ categories.each { |category|
13
+ category[:emoji].each { |sub_category|
14
+ sub_category[:emoji].each { |emoji_item|
15
+ unicodes = emoji_item[:sequences].sort_by(&:bytesize)
16
+ existing_emoji = nil
17
+ unicodes.detect do |raw|
18
+ existing_emoji = Emoji.find_by_unicode(raw)
19
+ end
20
+ existing_emoji = nil if seen_existing.key?(existing_emoji)
21
+ output_item = {
22
+ emoji: unicodes[0],
23
+ description: emoji_item[:description],
24
+ category: category[:name],
25
+ }
26
+ if existing_emoji
27
+ eu = existing_emoji.unicode_aliases
28
+ preferred_raw = eu.size == 2 && eu[0] == "#{eu[1]}\u{fe0f}" ? eu[1] : eu[0]
29
+ output_item.update(
30
+ emoji: preferred_raw,
31
+ aliases: existing_emoji.aliases,
32
+ tags: existing_emoji.tags,
33
+ unicode_version: existing_emoji.unicode_version,
34
+ ios_version: existing_emoji.ios_version,
35
+ )
36
+ seen_existing[existing_emoji] = true
37
+ else
38
+ output_item.update(
39
+ aliases: [emoji_item[:description].gsub(/\W+/, '_').downcase],
40
+ tags: [],
41
+ unicode_version: "12.0",
42
+ ios_version: "13.0",
43
+ )
44
+ end
45
+ output_item[:skin_tones] = true if emoji_item[:skin_tones]
46
+ items << output_item
47
+ }
48
+ }
49
+ }
50
+
51
+ missing_emoji = Emoji.all.reject { |e| e.custom? || seen_existing.key?(e) }
52
+ if missing_emoji.any?
53
+ $stderr.puts "Error: these `negarmoji.json` entries were not matched:"
54
+ $stderr.puts missing_emoji.map { |e| "%s (%s)" % [e.hex_inspect, e.name] }
55
+ exit 1
56
+ end
57
+
58
+ Emoji.all.select(&:custom?).each { |emoji|
59
+ items << {
60
+ aliases: emoji.aliases,
61
+ tags: emoji.tags,
62
+ }
63
+ }
64
+
65
+ trap(:PIPE) { abort }
66
+
67
+ puts JSON.pretty_generate(items)
68
+ .gsub("\n\n", "\n")
69
+ .gsub(/,\n( +)/) { "\n%s, " % $1[2..-1] }
@@ -0,0 +1,121 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EmojiTestParser
4
+ VARIATION_SELECTOR_16 = "\u{fe0f}"
5
+ SKIN_TONES = [
6
+ "\u{1F3FB}", # light skin tone
7
+ "\u{1F3FC}", # medium-light skin tone
8
+ "\u{1F3FD}", # medium skin tone
9
+ "\u{1F3FE}", # medium-dark skin tone
10
+ "\u{1F3FF}", # dark skin tone
11
+ ]
12
+ HAIR_MODIFIERS = [
13
+ "\u{1F9B0}", # red-haired
14
+ "\u{1F9B1}", # curly-haired
15
+ "\u{1F9B2}", # bald
16
+ "\u{1F9B3}", # white-haired
17
+ ]
18
+
19
+ module_function
20
+
21
+ def parse(filename)
22
+ File.open(filename, "r:UTF-8") do |file|
23
+ parse_file(file)
24
+ end
25
+ end
26
+
27
+ def parse_file(io)
28
+ data = []
29
+ emoji_map = {}
30
+ category = nil
31
+ sub_category = nil
32
+
33
+ io.each do |line|
34
+ begin
35
+ if line.start_with?("# group: ")
36
+ _, group_name = line.split(":", 2)
37
+ category = {
38
+ name: group_name.strip,
39
+ emoji: [],
40
+ }
41
+ data << category
42
+ sub_category = nil
43
+ elsif line.start_with?("# subgroup: ")
44
+ _, group_name = line.split(":", 2)
45
+ sub_category = {
46
+ name: group_name.strip,
47
+ emoji: [],
48
+ }
49
+ category[:emoji] << sub_category
50
+ elsif line.start_with?("#") || line.strip.empty?
51
+ next
52
+ else
53
+ row, desc = line.split("#", 2)
54
+ desc = desc.strip.split(" ", 2)[1]
55
+ codepoints, _ = row.split(";", 2)
56
+ emoji_raw = codepoints.strip.split.map { |c| c.hex }.pack("U*")
57
+ next if HAIR_MODIFIERS.include?(emoji_raw)
58
+ emoji_normalized = emoji_raw
59
+ .gsub(VARIATION_SELECTOR_16, "")
60
+ .gsub(/(#{SKIN_TONES.join("|")})/o, "")
61
+ emoji_item = emoji_map[emoji_normalized]
62
+ if SKIN_TONES.any? { |s| emoji_raw.include?(s) }
63
+ emoji_item[:skin_tones] = true if emoji_item
64
+ next
65
+ end
66
+ if emoji_item
67
+ emoji_item[:sequences] << emoji_raw
68
+ else
69
+ emoji_item = {
70
+ sequences: [emoji_raw],
71
+ description: desc,
72
+ }
73
+ emoji_map[emoji_normalized] = emoji_item
74
+ sub_category[:emoji] << emoji_item
75
+ end
76
+ end
77
+ rescue
78
+ warn "line: %p" % line
79
+ raise
80
+ end
81
+ end
82
+
83
+ [emoji_map, data]
84
+ end
85
+ end
86
+
87
+ if $0 == __FILE__
88
+ html_output = false
89
+ if ARGV[0] == "--html"
90
+ ARGV.shift
91
+ html_output = true
92
+ end
93
+
94
+ _, categories = EmojiTestParser.parse
95
+
96
+ trap(:PIPE) { abort }
97
+
98
+ if html_output
99
+ puts "<!doctype html>"
100
+ puts "<meta charset=utf-8>"
101
+ for category in categories
102
+ puts "<h2>#{category[:name]}</h2>"
103
+ for sub_category in category[:emoji]
104
+ puts "<h3>#{sub_category[:name]}</h3>"
105
+ puts "<ol>"
106
+ for char in sub_category[:emoji]
107
+ puts "<li>"
108
+ for sequence in char[:sequences]
109
+ codepoints = sequence.unpack("U*").map { |c| c.to_s(16).upcase }.join(" ")
110
+ printf '<span class=emoji title="%s">%s</span> ', codepoints, sequence
111
+ end
112
+ puts "#{char[:description]}</li>"
113
+ end
114
+ puts "</ol>"
115
+ end
116
+ end
117
+ else
118
+ require "json"
119
+ puts JSON.pretty_generate(categories)
120
+ end
121
+ end
data/db/index.html ADDED
@@ -0,0 +1,113 @@
1
+ <!doctype html>
2
+ <title>Emoji preview</title>
3
+
4
+ <style type="text/css">
5
+ body {
6
+ font: 14px/18px Verdana, Arial, sans-serif;
7
+ padding: 2em;
8
+ }
9
+ ol {
10
+ list-style: none;
11
+ padding-left: 0;
12
+ }
13
+ li {
14
+ margin-left: 0;
15
+ margin-top: 5px;
16
+ clear: left;
17
+ }
18
+ li:first-child { display: none; }
19
+ li > span {
20
+ display: block;
21
+ }
22
+ .emoji {
23
+ font-size: 50px;
24
+ line-height: 50px;
25
+ float: left;
26
+ margin-right: 20px;
27
+ }
28
+ .description {
29
+ font-style: italic;
30
+ color: gray;
31
+ }
32
+ .aliases span:before, .aliases span:after {
33
+ content: ":";
34
+ color: gray;
35
+ }
36
+ .tags {
37
+ font-size: 11px;
38
+ }
39
+ .tags span {
40
+ display: inline-block;
41
+ padding: 1px 5px 2px;
42
+ border-radius: 3px;
43
+ background: #dadada;
44
+ line-height: 11px;
45
+ }
46
+ </style>
47
+
48
+ <p><input type=search placeholder="Search..."></p>
49
+
50
+ <ol>
51
+ <li>
52
+ <span class="emoji"></span>
53
+ <span class="description"></span>
54
+ <span class="aliases"></span>
55
+ <span class="tags"></span>
56
+ </li>
57
+ </ol>
58
+
59
+ <script>
60
+ function renderEmoji(emojis) {
61
+ var item, els, template = document.querySelector('li')
62
+ for (var emoji, i=0; i < emojis.length; i++) {
63
+ emoji = emojis[i]
64
+ item = template.cloneNode(true)
65
+ els = item.querySelectorAll('span')
66
+ if (emoji.emoji) els[0].textContent = emoji.emoji
67
+ else {
68
+ var img = document.createElement('img')
69
+ img.src = "../images/" + emoji.aliases[0] + ".png"
70
+ els[0].appendChild(img)
71
+ }
72
+ els[1].textContent = emoji.description || ''
73
+ els[2].innerHTML = emoji.aliases.map(function(n){ return '<span>'+n+'</span>' }).join(' ')
74
+ els[3].innerHTML = emoji.tags.map(function(n){ return '<span>'+n+'</span>' }).join(' ')
75
+ template.parentNode.appendChild(item)
76
+
77
+ item._emojiText = (els[2].textContent + ' ' + els[3].textContent).replace(/_/g, '-')
78
+ }
79
+ }
80
+
81
+ xhr = new XMLHttpRequest
82
+ xhr.onreadystatechange = function() {
83
+ if (this.readyState == 4) {
84
+ json = JSON.parse(this.responseText)
85
+ renderEmoji(json)
86
+ }
87
+ }
88
+ xhr.open('GET', 'emoji.json', false)
89
+ xhr.send(null)
90
+
91
+ function searchEmoji(query) {
92
+ var el,
93
+ re = new RegExp('\\b' + query),
94
+ els = document.querySelectorAll('li')
95
+
96
+ for (var i=1; i < els.length; i++) {
97
+ el = els[i]
98
+ if ( !query || re.test(el._emojiText) ) {
99
+ el.style.display = 'list-item'
100
+ } else {
101
+ el.style.display = 'none'
102
+ }
103
+ }
104
+ }
105
+
106
+ var timeout, search = document.querySelector('input[type=search]')
107
+ search.addEventListener('input', function() {
108
+ var $this = this
109
+ if (timeout) clearTimeout(timeout)
110
+ timeout = setTimeout(function(){ searchEmoji($this.value) }, 200)
111
+ }, false)
112
+ search.focus()
113
+ </script>
File without changes
data/lib/negarmoji.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'emoji'
3
+ require "negarmoji/emoji"
@@ -5,7 +5,7 @@ module Emoji
5
5
  # Inspect individual Unicode characters in a string by dumping its
6
6
  # codepoints in hexadecimal format.
7
7
  def self.hex_inspect(str)
8
- str.codepoints.map { |c| c.to_s(16).rjust(4, '0') }.join('-')
8
+ str.codepoints.map { |c| c.to_s(16).rjust(4, "0") }.join("-")
9
9
  end
10
10
 
11
11
  # True if the emoji is not a standard Emoji character.
@@ -57,7 +57,7 @@ module Emoji
57
57
  end
58
58
 
59
59
  def inspect
60
- hex = '(%s)' % hex_inspect unless custom?
60
+ hex = "(#{hex_inspect unless custom?})"
61
61
  %(#<#{self.class.name}:#{name}#{hex}>)
62
62
  end
63
63
 
@@ -67,22 +67,22 @@ module Emoji
67
67
 
68
68
  attr_writer :image_filename
69
69
 
70
- def image_filename
70
+ def image_filename(extension = "svg")
71
71
  if defined? @image_filename
72
72
  @image_filename
73
73
  else
74
- default_image_filename
74
+ default_image_filename(extension)
75
75
  end
76
76
  end
77
77
 
78
78
  private
79
79
 
80
- def default_image_filename
80
+ def default_image_filename(extension)
81
81
  if custom?
82
- '%s.svg' % name
82
+ "#{name}.#{extension}"
83
83
  else
84
84
  hex_name = hex_inspect.gsub(/-(fe0f|200d)\b/, '')
85
- 'unicode/%s.svg' % hex_name
85
+ "#{hex_name}.#{extension}"
86
86
  end
87
87
  end
88
88
  end