emojidex 0.0.23 → 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 +4 -4
- data/.coveralls.yml +1 -0
- data/.rubocop.yml +3 -0
- data/.travis.yml +7 -6
- data/Gemfile +0 -2
- data/Guardfile +17 -8
- data/README.md +54 -17
- data/emojidex.gemspec +4 -1
- data/lib/emojidex.rb +12 -10
- data/lib/emojidex/{categories.rb → data/categories.rb} +3 -4
- data/lib/emojidex/{category.rb → data/category.rb} +1 -1
- data/lib/emojidex/data/collection.rb +158 -0
- data/lib/emojidex/data/collection/asset_information.rb +52 -0
- data/lib/emojidex/data/collection/cache.rb +137 -0
- data/lib/emojidex/{collection → data/collection}/moji_data.rb +1 -1
- data/lib/emojidex/data/collection/static_collection.rb +35 -0
- data/lib/emojidex/data/collection_checker.rb +94 -0
- data/lib/emojidex/{emoji.rb → data/emoji.rb} +3 -2
- data/lib/emojidex/data/emoji/asset_information.rb +45 -0
- data/lib/emojidex/data/extended.rb +18 -0
- data/lib/emojidex/data/utf.rb +18 -0
- data/lib/emojidex/defaults.rb +21 -0
- data/lib/emojidex/env_helper.rb +11 -0
- data/lib/emojidex/service/collection.rb +67 -0
- data/lib/emojidex/service/error.rb +9 -0
- data/lib/emojidex/service/indexes.rb +43 -0
- data/lib/emojidex/service/search.rb +82 -0
- data/lib/emojidex/service/transactor.rb +100 -0
- data/lib/emojidex/service/user.rb +233 -0
- data/spec/{categories_spec.rb → emojidex/data/categories_spec.rb} +4 -3
- data/spec/{collection_checker_spec.rb → emojidex/data/collection_checker_spec.rb} +12 -15
- data/spec/{collection_spec.rb → emojidex/data/collection_spec.rb} +40 -23
- data/spec/{emoji_spec.rb → emojidex/data/emoji_spec.rb} +2 -2
- data/spec/{extended_spec.rb → emojidex/data/extended_spec.rb} +21 -10
- data/spec/{utf_spec.rb → emojidex/data/utf_spec.rb} +22 -17
- data/spec/emojidex/service/collection_spec.rb +20 -0
- data/spec/emojidex/service/error_spec.rb +17 -0
- data/spec/emojidex/service/indexes_spec.rb +62 -0
- data/spec/emojidex/service/search_spec.rb +87 -0
- data/spec/emojidex/service/transactor_spec.rb +11 -0
- data/spec/emojidex/service/user_spec.rb +128 -0
- data/spec/spec_helper.rb +9 -62
- metadata +36 -31
- data/lib/emojidex/api/categories.rb +0 -16
- data/lib/emojidex/api/emoji.rb +0 -26
- data/lib/emojidex/api/search/emoji.rb +0 -16
- data/lib/emojidex/client.rb +0 -60
- data/lib/emojidex/collection.rb +0 -156
- data/lib/emojidex/collection/asset_information.rb +0 -49
- data/lib/emojidex/collection/cache.rb +0 -78
- data/lib/emojidex/collection_checker.rb +0 -93
- data/lib/emojidex/emoji/asset_information.rb +0 -20
- data/lib/emojidex/error.rb +0 -15
- data/lib/emojidex/extended.rb +0 -19
- data/lib/emojidex/service.rb +0 -32
- data/lib/emojidex/utf.rb +0 -19
- data/spec/api/categories_spec.rb +0 -49
- data/spec/api/emoji_spec.rb +0 -89
- data/spec/api/search/emoji_spec.rb +0 -30
- data/spec/client_spec.rb +0 -24
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'transactor'
|
2
|
+
require_relative 'collection'
|
3
|
+
require_relative '../defaults'
|
4
|
+
|
5
|
+
module Emojidex
|
6
|
+
module Service
|
7
|
+
# emoji indexes
|
8
|
+
class Indexes
|
9
|
+
# Obtain a service Collection of emoji indexed by score.
|
10
|
+
# This is the default index.
|
11
|
+
def self.emoji(detailed = false, limit = Emojidex::Defaults.limit, page = 1)
|
12
|
+
Emojidex::Service::Collection.new({endpoint: 'emoji', detailed: detailed, limit: limit, page: page})
|
13
|
+
end
|
14
|
+
|
15
|
+
# Obtain a service Collection of emoji indexed by date of creation (or in some cases update).
|
16
|
+
def self.newest(detailed = false, limit = Emojidex::Defaults.limit, page = 1)
|
17
|
+
Emojidex::Service::Collection.new({endpoint: 'newest', detailed: detailed, limit: limit, page: page})
|
18
|
+
end
|
19
|
+
|
20
|
+
# Obtain a service Collection of emoji indexed by popularity [how many times they have been favorited].
|
21
|
+
def self.popular(detailed = false, limit = Emojidex::Defaults.limit, page = 1)
|
22
|
+
Emojidex::Service::Collection.new({endpoint: 'popular', detailed: detailed, limit: limit, page: page})
|
23
|
+
end
|
24
|
+
|
25
|
+
# Obtains a hash with three different types of chracter [moji] code indexes:
|
26
|
+
# moji_string: a string that can be used for things like regex matches.
|
27
|
+
# Contains conglomorate codes ahead of single chracter codes.
|
28
|
+
# moji_array: an array of emoji characters.
|
29
|
+
# Contains conglomorate codes ahead of single chracter codes.
|
30
|
+
# moji_index: a hash map with the keys being emoji strings and the values being
|
31
|
+
# the emoji short codes in the locale [language] specified (defaults to english).
|
32
|
+
def self.moji_codes(locale = Emojidex::Defaults.lang)
|
33
|
+
begin
|
34
|
+
res = Emojidex::Service::Transactor.get('moji_codes', { locale: locale })
|
35
|
+
rescue
|
36
|
+
return { moji_string: "", moji_array: [], moji_index: {} }
|
37
|
+
end
|
38
|
+
res[:moji_index] = Hash[res[:moji_index].map{ |k, v| [k.to_s, v] }]
|
39
|
+
res
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require_relative '../defaults'
|
2
|
+
require_relative 'collection'
|
3
|
+
require_relative '../../emojidex'
|
4
|
+
|
5
|
+
module Emojidex
|
6
|
+
module Service
|
7
|
+
class Search
|
8
|
+
|
9
|
+
# Searches by term with the options given. Options are:
|
10
|
+
# tags: an array of tags to restrict the search to
|
11
|
+
# categories: an arry of categories to restrict the serach to
|
12
|
+
# detailed: set to true to enable detailed results (defaults to false)
|
13
|
+
# limit: sets the number of items per page (default Emojidex::Defaults.limit)
|
14
|
+
# Returns a service Collection.
|
15
|
+
def self.term(code_cont, opts = {})
|
16
|
+
opts[:code_cont] = Emojidex.escape_code(code_cont)
|
17
|
+
_do_search(opts)
|
18
|
+
end
|
19
|
+
def self.search(code_cont, opts = {})
|
20
|
+
self.term(code_cont, opts)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Searches for a code starting with the given term.
|
24
|
+
# Available options are the same as term.
|
25
|
+
# Returns a service Collection.
|
26
|
+
def self.starting(code_sw, opts = {})
|
27
|
+
opts[:code_sw] = Emojidex.escape_code(code_sw)
|
28
|
+
_do_search(opts)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Searches for a code ending with the given term.
|
32
|
+
# Available options are the same as term.
|
33
|
+
# Returns a service Collection.
|
34
|
+
def self.ending(code_ew, opts = {})
|
35
|
+
opts[:code_ew] = Emojidex.escape_code(code_ew)
|
36
|
+
_do_search(opts)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Searches an array of tags for emoji associated with all those tags.
|
40
|
+
# Available options are the same as term.
|
41
|
+
# Returns a service Collection.
|
42
|
+
def self.tags(tags, opts = {})
|
43
|
+
tags = [] << tags unless tags.class == Array
|
44
|
+
opts[:tags] = tags
|
45
|
+
_do_search(opts)
|
46
|
+
end
|
47
|
+
|
48
|
+
# An expanded version of term with categories and tags as arguments.
|
49
|
+
# Options are:
|
50
|
+
# detailed: set to true to enable detailed results (defaults to false)
|
51
|
+
# limit: sets the number of items per page (default Emojidex::Defaults.limit)
|
52
|
+
# Returns a service Collection.
|
53
|
+
def self.advanced(code_cont, categories = [], tags = [], opts = {})
|
54
|
+
opts[:code_cont] = Emojidex.escape_code(code_cont)
|
55
|
+
tags = [] << tags unless tags.class == Array
|
56
|
+
opts[:tags] = tags
|
57
|
+
categories = [] << categories unless categories.class == Array
|
58
|
+
opts[:categories] = categories
|
59
|
+
_do_search(opts)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def self._sanitize_opts(opts)
|
65
|
+
opts[:tags].map! { |tag| tag.to_s } if opts.include? :tags
|
66
|
+
opts[:categories].map! { |category| category.to_s } if opts.include? :categories
|
67
|
+
opts
|
68
|
+
end
|
69
|
+
|
70
|
+
def self._do_search(opts)
|
71
|
+
opts = _sanitize_opts(opts)
|
72
|
+
opts[:endpoint] = 'search/emoji'
|
73
|
+
begin
|
74
|
+
col = Emojidex::Service::Collection.new(opts)
|
75
|
+
rescue
|
76
|
+
return Emojidex::Service::Collection.new
|
77
|
+
end
|
78
|
+
col
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
require_relative 'error'
|
4
|
+
|
5
|
+
module Emojidex
|
6
|
+
module Service
|
7
|
+
# API transaction utility
|
8
|
+
class Transactor
|
9
|
+
@@connection = nil
|
10
|
+
|
11
|
+
@@settings = {
|
12
|
+
api: {
|
13
|
+
host: 'www.emojidex.com',
|
14
|
+
prefix: '/api/v1/',
|
15
|
+
protocol: 'https'
|
16
|
+
},
|
17
|
+
cdn: {
|
18
|
+
host: 'cdn.emojidex.com',
|
19
|
+
prefix: '/emoji/',
|
20
|
+
protocol: 'http'
|
21
|
+
},
|
22
|
+
closed_net: false
|
23
|
+
}
|
24
|
+
|
25
|
+
def self.get(endpoint, params = {})
|
26
|
+
response = self.connect.get(
|
27
|
+
"#{self.api_url}#{endpoint}", params)
|
28
|
+
|
29
|
+
self._status_raiser(response)
|
30
|
+
self._datafy_json(response.body)
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.post(endpoint, params = {})
|
34
|
+
response = self.connect.post(
|
35
|
+
"#{self.api_url}#{endpoint}", params)
|
36
|
+
|
37
|
+
self._status_raiser(response)
|
38
|
+
self._datafy_json(response.body)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.delete(endpoint, params = {})
|
42
|
+
response = self.connect.delete(
|
43
|
+
"#{self.api_url}#{endpoint}", params)
|
44
|
+
|
45
|
+
self._status_raiser(response)
|
46
|
+
self._datafy_json(response.body)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.download(file_subpath)
|
50
|
+
self.connect.get(URI.escape("#{self.cdn_url}#{file_subpath}"))
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.connect
|
54
|
+
return @@connection if @@connection
|
55
|
+
@@connection = Faraday.new do |conn|
|
56
|
+
conn.request :url_encoded
|
57
|
+
# conn.response :logger
|
58
|
+
conn.adapter Faraday.default_adapter
|
59
|
+
end
|
60
|
+
@@connection
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.api_url()
|
64
|
+
"#{@@settings[:api][:protocol]}://#{@@settings[:api][:host]}#{@@settings[:api][:prefix]}"
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.cdn_url()
|
68
|
+
"#{@@settings[:cdn][:protocol]}://#{@@settings[:cdn][:host]}#{@@settings[:cdn][:prefix]}"
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def self._status_raiser(response)
|
74
|
+
case response.status
|
75
|
+
when 200..299
|
76
|
+
return # don't raise
|
77
|
+
when 401
|
78
|
+
raise Error::Unauthorized.new(self._extract_status_line(response))
|
79
|
+
when 422
|
80
|
+
raise Error::UnprocessableEntity.new(self._extract_status_line(response))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self._extract_status_line(response)
|
85
|
+
data = self._datafy_json(response.body)
|
86
|
+
status_line = (data.key?(:status) ? data[:status] : '')
|
87
|
+
status_line
|
88
|
+
end
|
89
|
+
|
90
|
+
def self._datafy_json(body)
|
91
|
+
begin
|
92
|
+
data = JSON.parse(body, symbolize_names: true)
|
93
|
+
rescue JSON::ParserError
|
94
|
+
raise Error::InvalidJSON.new('could not parse JSON')
|
95
|
+
end
|
96
|
+
data
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,233 @@
|
|
1
|
+
require_relative '../../emojidex'
|
2
|
+
require_relative 'error'
|
3
|
+
require_relative 'transactor'
|
4
|
+
require_relative 'collection'
|
5
|
+
|
6
|
+
module Emojidex
|
7
|
+
module Service
|
8
|
+
# User auth and user details
|
9
|
+
class User
|
10
|
+
attr_reader :username, :auth_token, :premium, :pro, :premium_exp, :pro_exp, :status
|
11
|
+
attr_accessor :favorites, :history, :cache_path
|
12
|
+
|
13
|
+
@@auth_status_codes = { none: false, failure: false,
|
14
|
+
unverified: false, verified: true,
|
15
|
+
loaded: false }
|
16
|
+
def self.auth_status_codes
|
17
|
+
@@auth_status_codes
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(opts = {})
|
21
|
+
clear_auth_data
|
22
|
+
@status = :none
|
23
|
+
@history = []
|
24
|
+
@favorites = Emojidex::Data::Collection.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def login(user, password, sync_on_login = true)
|
28
|
+
begin
|
29
|
+
auth_response = Transactor.get('users/authenticate',
|
30
|
+
{ user: user, password: password })
|
31
|
+
rescue Error::Unauthorized
|
32
|
+
@status = :unverified
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
|
36
|
+
return false unless _process_auth_response(auth_response)
|
37
|
+
if sync_on_login
|
38
|
+
sync_favorites
|
39
|
+
sync_history
|
40
|
+
end
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
def authorize(username, auth_token, sync_on_auth = true)
|
45
|
+
begin
|
46
|
+
auth_response = Transactor.get('users/authenticate',
|
47
|
+
{ username: username, token: auth_token })
|
48
|
+
rescue Error::Unauthorized
|
49
|
+
@status = :unverified
|
50
|
+
return false
|
51
|
+
end
|
52
|
+
|
53
|
+
return false unless _process_auth_response(auth_response)
|
54
|
+
if sync_on_auth
|
55
|
+
sync_favorites
|
56
|
+
sync_history
|
57
|
+
end
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
61
|
+
def authorized?
|
62
|
+
@@auth_status_codes[@status]
|
63
|
+
end
|
64
|
+
|
65
|
+
def sync_favorites(limit = Emojidex::Defaults.limit, detailed = true)
|
66
|
+
return false unless authorized?
|
67
|
+
|
68
|
+
begin
|
69
|
+
res = Emojidex::Service::Collection.new(
|
70
|
+
{ endpoint: 'users/favorites', limit: limit, detailed: detailed,
|
71
|
+
username: @username, auth_token: @auth_token })
|
72
|
+
rescue Error::Unauthorized
|
73
|
+
return false
|
74
|
+
end
|
75
|
+
|
76
|
+
@favorites = res
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_favorite(code)
|
81
|
+
return false unless authorized?
|
82
|
+
|
83
|
+
begin
|
84
|
+
res = Transactor.post('users/favorites',
|
85
|
+
{ username: @username, auth_token: @auth_token,
|
86
|
+
emoji_code: Emojidex.escape_code(code) })
|
87
|
+
rescue Error::Unauthorized
|
88
|
+
return false
|
89
|
+
rescue Error::UnprocessableEntity => e
|
90
|
+
# TODO: API is currently returning this both when emoji already registered
|
91
|
+
# and when code is invalid. When already registerd it will return 202 on
|
92
|
+
# next update
|
93
|
+
return true if e.message == 'emoji already in user favorites'
|
94
|
+
return false
|
95
|
+
end
|
96
|
+
return true
|
97
|
+
end
|
98
|
+
|
99
|
+
def remove_favorite(code)
|
100
|
+
return false unless authorized?
|
101
|
+
|
102
|
+
begin
|
103
|
+
res = Transactor.delete('users/favorites',
|
104
|
+
{ username: @username, auth_token: @auth_token,
|
105
|
+
emoji_code: Emojidex.escape_code(code) })
|
106
|
+
rescue Error::Unauthorized
|
107
|
+
return false
|
108
|
+
rescue Error::UnprocessableEntity => e
|
109
|
+
# TODO: API is currently returning this both when emoji already registered
|
110
|
+
# and when code is invalid. When already registerd it will return 200 on
|
111
|
+
# next update
|
112
|
+
return true if e.message == 'emoji not in user favorites'
|
113
|
+
return false
|
114
|
+
end
|
115
|
+
true
|
116
|
+
end
|
117
|
+
|
118
|
+
def sync_history(limit = Emojidex::Defaults.limit, page = 1)
|
119
|
+
return false unless authorized?
|
120
|
+
|
121
|
+
@history = Transactor.get('users/history',
|
122
|
+
{ limit: limit, page: page, username: @username, auth_token: @auth_token })
|
123
|
+
# TODO: this is a temporary implementation of history. It will be revised after an
|
124
|
+
# API update.
|
125
|
+
true
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_history(code)
|
129
|
+
end
|
130
|
+
|
131
|
+
def clear_auth_data()
|
132
|
+
@username = @auth_token = ''
|
133
|
+
@pro = false
|
134
|
+
@premium = false
|
135
|
+
@pro_exp = nil
|
136
|
+
@premium_exp = nil
|
137
|
+
end
|
138
|
+
|
139
|
+
def sync
|
140
|
+
authorize(@username, @auth_token) &&
|
141
|
+
sync_favorites &&
|
142
|
+
sync_history
|
143
|
+
end
|
144
|
+
|
145
|
+
def save(path)
|
146
|
+
_set_cache_path(path)
|
147
|
+
_save_user
|
148
|
+
_save_favorites
|
149
|
+
_save_history
|
150
|
+
end
|
151
|
+
|
152
|
+
def load(path, auto_sync = true)
|
153
|
+
_set_cache_path(path)
|
154
|
+
_load_user
|
155
|
+
_load_favorites
|
156
|
+
_load_history
|
157
|
+
sync if auto_sync
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def _process_auth_response(auth_response)
|
163
|
+
if auth_response[:auth_status] == 'verified'
|
164
|
+
_set_verified_data(auth_response)
|
165
|
+
return true
|
166
|
+
elsif auth_response[:auth_status] == 'unverified'
|
167
|
+
@status = :unverified
|
168
|
+
else
|
169
|
+
@status = :failure
|
170
|
+
end
|
171
|
+
clear_auth_data
|
172
|
+
false
|
173
|
+
end
|
174
|
+
|
175
|
+
def _set_verified_data(auth_response)
|
176
|
+
@status = :verified
|
177
|
+
@username = auth_response[:auth_user]
|
178
|
+
@auth_token = auth_response[:auth_token]
|
179
|
+
@pro = auth_response[:pro]
|
180
|
+
@premium = auth_response[:premium]
|
181
|
+
@pro_exp = auth_response[:pro_exp]
|
182
|
+
@premium_exp = auth_response[:premium_exp]
|
183
|
+
end
|
184
|
+
|
185
|
+
def _set_cache_path(path)
|
186
|
+
@cache_path = @cache_path || File.expand_path(
|
187
|
+
path || ENV['EMOJI_CACHE'] || "#{ENV['HOME']}/.emojidex/")
|
188
|
+
FileUtils.mkdir_p(@cache_path)
|
189
|
+
@cache_path
|
190
|
+
end
|
191
|
+
|
192
|
+
def _save_user
|
193
|
+
user_info = { username: username, auth_token: auth_token,
|
194
|
+
premium: premium, pro: pro,
|
195
|
+
premium_exp: premium_exp, pro_exp: pro_exp
|
196
|
+
}
|
197
|
+
File.open("#{@cache_path}/user.json", 'w') { |f| f.write user_info.to_json }
|
198
|
+
end
|
199
|
+
|
200
|
+
def _save_favorites
|
201
|
+
File.open("#{@cache_path}/favorites.json", 'w') { |f| f.write @favorites.emoji.values.to_json }
|
202
|
+
end
|
203
|
+
|
204
|
+
def _save_history
|
205
|
+
File.open("#{@cache_path}/history.json", 'w') { |f| f.write @history.to_json }
|
206
|
+
end
|
207
|
+
|
208
|
+
def _load_user
|
209
|
+
json = IO.read("#{@cache_path}/user.json")
|
210
|
+
user_info = JSON.parse(json, symbolize_names: true)
|
211
|
+
@username = user_info[:username]
|
212
|
+
@auth_token = user_info[:auth_token]
|
213
|
+
@premium = user_info[:premium]
|
214
|
+
@pro = user_info[:pro]
|
215
|
+
@premium_exp = user_info[:premium_exp]
|
216
|
+
@pro_exp = user_info[:pro_exp]
|
217
|
+
@status = :loaded
|
218
|
+
end
|
219
|
+
|
220
|
+
def _load_favorites
|
221
|
+
json = IO.read("#{@cache_path}/favorites.json")
|
222
|
+
@favorites = Emojidex::Service::Collection.new(
|
223
|
+
emoji: JSON.parse(json, symbolize_names: true),
|
224
|
+
auto_init: false)
|
225
|
+
end
|
226
|
+
|
227
|
+
def _load_history
|
228
|
+
json = IO.read("#{@cache_path}/history.json")
|
229
|
+
@history = JSON.parse json
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|