ecoji 0.1.0
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 +7 -0
- data/.gitignore +8 -0
- data/.gitmodules +3 -0
- data/.rubocop.yml +34 -0
- data/.rubocop_todo.yml +59 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +21 -0
- data/LICENSE.ecoji +201 -0
- data/README.md +58 -0
- data/Rakefile +34 -0
- data/bin/console +14 -0
- data/bin/rubocop +27 -0
- data/bin/setup +8 -0
- data/ecoji.gemspec +43 -0
- data/lib/ecoji/emojis.rb +2057 -0
- data/lib/ecoji/version.rb +5 -0
- data/lib/ecoji.rb +192 -0
- metadata +150 -0
data/lib/ecoji.rb
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ecoji
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'ecoji/emojis'
|
7
|
+
require 'ecoji/version'
|
8
|
+
|
9
|
+
module Ecoji
|
10
|
+
class Error < StandardError; end
|
11
|
+
|
12
|
+
PADDING = 0x2615
|
13
|
+
PADDING_LAST_V1 = [0x269C, 0x1F3CD, 0x1F4D1, 0x1F64B].freeze
|
14
|
+
PADDING_LAST_V2 = [0x1F977, 0x1F6FC, 0x1F4D1, 0x1F64B].freeze
|
15
|
+
|
16
|
+
REV_EMOJIS = begin
|
17
|
+
map = {}
|
18
|
+
|
19
|
+
Emojis::V1.each_with_index do |n, ordinal|
|
20
|
+
map[n] = { ordinal:, version: 1, padding: :none }
|
21
|
+
end
|
22
|
+
|
23
|
+
Emojis::V2.each_with_index do |n, ordinal|
|
24
|
+
if map[n]
|
25
|
+
map[n][:version] = 3
|
26
|
+
else
|
27
|
+
map[n] = { ordinal:, version: 2, padding: :none }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
map[PADDING] = { ordinal: 0, version: 3, padding: :fill }
|
32
|
+
map[PADDING_LAST_V1[0]] = { ordinal: 0, version: 1, padding: :last }
|
33
|
+
map[PADDING_LAST_V1[1]] = { ordinal: 1 << 8, version: 1, padding: :last }
|
34
|
+
map[PADDING_LAST_V1[2]] = { ordinal: 2 << 8, version: 3, padding: :last }
|
35
|
+
map[PADDING_LAST_V1[3]] = { ordinal: 3 << 8, version: 3, padding: :last }
|
36
|
+
map[PADDING_LAST_V2[0]] = { ordinal: 0, version: 2, padding: :last }
|
37
|
+
map[PADDING_LAST_V2[1]] = { ordinal: 1 << 8, version: 2, padding: :last }
|
38
|
+
|
39
|
+
map
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.encode(data, version: 2)
|
43
|
+
case version
|
44
|
+
when 1
|
45
|
+
emojis = Emojis::V1
|
46
|
+
padding_last = PADDING_LAST_V1
|
47
|
+
trim = false
|
48
|
+
when 2
|
49
|
+
emojis = Emojis::V2
|
50
|
+
padding_last = PADDING_LAST_V2
|
51
|
+
trim = true
|
52
|
+
else
|
53
|
+
raise Error, 'Version must be either 1 or 2'
|
54
|
+
end
|
55
|
+
|
56
|
+
result = []
|
57
|
+
data.bytes.each_slice(5) do |s|
|
58
|
+
encode_five(s, emojis, padding_last, trim) { |n| result << n }
|
59
|
+
end
|
60
|
+
result.pack('U*')
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.decode(data, encoding: Encoding::UTF_8)
|
64
|
+
expected_version = 3
|
65
|
+
chars = data.chars
|
66
|
+
result = []
|
67
|
+
|
68
|
+
loop do
|
69
|
+
emojis, expected_version = read_four(chars, expected_version)
|
70
|
+
break if emojis.empty?
|
71
|
+
|
72
|
+
bits = (emojis[0][:ordinal] << 30) |
|
73
|
+
(emojis[1][:ordinal] << 20) |
|
74
|
+
(emojis[2][:ordinal] << 10) |
|
75
|
+
emojis[3][:ordinal]
|
76
|
+
out = [
|
77
|
+
bits >> 32,
|
78
|
+
0xff & (bits >> 24),
|
79
|
+
0xff & (bits >> 16),
|
80
|
+
0xff & (bits >> 8),
|
81
|
+
0xff & bits
|
82
|
+
]
|
83
|
+
|
84
|
+
if emojis[1][:padding] == :fill
|
85
|
+
out = out[0...1]
|
86
|
+
elsif emojis[2][:padding] == :fill
|
87
|
+
out = out[0...2]
|
88
|
+
elsif emojis[3][:padding] == :fill
|
89
|
+
out = out[0...3]
|
90
|
+
elsif emojis[3][:padding] == :last
|
91
|
+
out = out[0...4]
|
92
|
+
end
|
93
|
+
|
94
|
+
result.concat(out)
|
95
|
+
end
|
96
|
+
|
97
|
+
result.pack('C*').force_encoding(encoding)
|
98
|
+
end
|
99
|
+
|
100
|
+
private_class_method def self.encode_five(s, emojis, padding_last, trim)
|
101
|
+
case s.size
|
102
|
+
when 1
|
103
|
+
yield emojis[s[0] << 2]
|
104
|
+
yield PADDING
|
105
|
+
unless trim
|
106
|
+
yield PADDING
|
107
|
+
yield PADDING
|
108
|
+
end
|
109
|
+
when 2
|
110
|
+
bits = (s[0] << 32) | (s[1] << 24)
|
111
|
+
yield emojis[bits >> 30]
|
112
|
+
yield emojis[0x3ff & (bits >> 20)]
|
113
|
+
yield PADDING
|
114
|
+
yield PADDING unless trim
|
115
|
+
when 3
|
116
|
+
bits = (s[0] << 32) | (s[1] << 24) | (s[2] << 16)
|
117
|
+
yield emojis[bits >> 30]
|
118
|
+
yield emojis[0x3ff & (bits >> 20)]
|
119
|
+
yield emojis[0x3ff & (bits >> 10)]
|
120
|
+
yield PADDING
|
121
|
+
when 4
|
122
|
+
bits = (s[0] << 32) | (s[1] << 24) | (s[2] << 16) | (s[3] << 8)
|
123
|
+
yield emojis[bits >> 30]
|
124
|
+
yield emojis[0x3ff & (bits >> 20)]
|
125
|
+
yield emojis[0x3ff & (bits >> 10)]
|
126
|
+
yield padding_last[0x3 & (bits >> 8)]
|
127
|
+
when 5
|
128
|
+
bits = (s[0] << 32) | (s[1] << 24) | (s[2] << 16) | (s[3] << 8) | s[4]
|
129
|
+
yield emojis[bits >> 30]
|
130
|
+
yield emojis[0x3ff & (bits >> 20)]
|
131
|
+
yield emojis[0x3ff & (bits >> 10)]
|
132
|
+
yield emojis[0x3ff & bits]
|
133
|
+
else
|
134
|
+
raise "BUG: unexpected length: #{s.size}"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private_class_method def self.read_four(chars, expected_version)
|
139
|
+
index = 0
|
140
|
+
saw_padding = false
|
141
|
+
emojis = [REV_EMOJIS[PADDING], REV_EMOJIS[PADDING], REV_EMOJIS[PADDING], REV_EMOJIS[PADDING]]
|
142
|
+
|
143
|
+
while index < 4
|
144
|
+
if chars.empty?
|
145
|
+
return [], expected_version if index.zero?
|
146
|
+
return emojis, expected_version if saw_padding && [3, 2].include?(expected_version)
|
147
|
+
|
148
|
+
raise Error, 'Unexpected end of data, input data size not multiple of 4'
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
c = chars.shift
|
153
|
+
next if ["\n", "\r"].include?(c)
|
154
|
+
|
155
|
+
einfo = REV_EMOJIS[c.ord]
|
156
|
+
raise Error, "Non Ecoji character seen: #{c.inspect}" unless einfo
|
157
|
+
|
158
|
+
if einfo[:version] != 3
|
159
|
+
if expected_version == 3
|
160
|
+
expected_version = einfo[:version]
|
161
|
+
elsif expected_version != einfo[:version]
|
162
|
+
raise Error, "Emojis from different ecoji versions seen: #{c.inspect}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
case einfo[:padding]
|
167
|
+
when :none
|
168
|
+
if saw_padding
|
169
|
+
raise Error, 'Unexpectedly saw non-padding after padding' unless [3, 2].include?(expected_version)
|
170
|
+
|
171
|
+
chars.unshift(c)
|
172
|
+
# NOTE(makenowjust): I think here we should set `expected_version` to `2`,
|
173
|
+
# but the original implementation does not.
|
174
|
+
# For the compatibility, `expected_version` is kept.
|
175
|
+
return emojis, expected_version
|
176
|
+
|
177
|
+
end
|
178
|
+
when :fill
|
179
|
+
raise Error, 'Padding unexpectedly seen in first position' if index.zero?
|
180
|
+
|
181
|
+
saw_padding = true
|
182
|
+
when :last
|
183
|
+
raise Error, 'Last padding seen in unexpected position' if index != 3
|
184
|
+
end
|
185
|
+
|
186
|
+
emojis[index] = einfo
|
187
|
+
index += 1
|
188
|
+
end
|
189
|
+
|
190
|
+
[emojis, expected_version]
|
191
|
+
end
|
192
|
+
end
|
metadata
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ecoji
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TSUYUSATO Kitsune
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-01-13 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.4'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '5.17'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '5.17'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '13.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '13.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.43'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.43'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop-minitest
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0.25'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0.25'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop-rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.6'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.6'
|
97
|
+
description: Ecoji is a data-to-emoji encoding scheme. This library provides the implementation
|
98
|
+
of Ecoji in Ruby.
|
99
|
+
email:
|
100
|
+
- make.just.on@gmail.com
|
101
|
+
executables: []
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- ".gitignore"
|
106
|
+
- ".gitmodules"
|
107
|
+
- ".rubocop.yml"
|
108
|
+
- ".rubocop_todo.yml"
|
109
|
+
- CODE_OF_CONDUCT.md
|
110
|
+
- Gemfile
|
111
|
+
- Gemfile.lock
|
112
|
+
- LICENSE
|
113
|
+
- LICENSE.ecoji
|
114
|
+
- README.md
|
115
|
+
- Rakefile
|
116
|
+
- bin/console
|
117
|
+
- bin/rubocop
|
118
|
+
- bin/setup
|
119
|
+
- ecoji.gemspec
|
120
|
+
- lib/ecoji.rb
|
121
|
+
- lib/ecoji/emojis.rb
|
122
|
+
- lib/ecoji/version.rb
|
123
|
+
homepage: https://github.com/makenowjust/ecoji.rb/
|
124
|
+
licenses:
|
125
|
+
- MIT
|
126
|
+
metadata:
|
127
|
+
homepage_uri: https://github.com/makenowjust/ecoji.rb/
|
128
|
+
source_code_uri: https://github.com/makenowjust/ecoji.rb/
|
129
|
+
changelog_uri: https://github.com/makenowjust/ecoji.rb/blob/main/CHANGELOG.md
|
130
|
+
rubygems_mfa_required: 'true'
|
131
|
+
post_install_message:
|
132
|
+
rdoc_options: []
|
133
|
+
require_paths:
|
134
|
+
- lib
|
135
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - '='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '3.2'
|
140
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubygems_version: 3.4.1
|
147
|
+
signing_key:
|
148
|
+
specification_version: 4
|
149
|
+
summary: Ecoji implementation in Ruby
|
150
|
+
test_files: []
|