negarmoji 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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