emojidex 0.0.23 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.rubocop.yml +3 -0
  4. data/.travis.yml +7 -6
  5. data/Gemfile +0 -2
  6. data/Guardfile +17 -8
  7. data/README.md +54 -17
  8. data/emojidex.gemspec +4 -1
  9. data/lib/emojidex.rb +12 -10
  10. data/lib/emojidex/{categories.rb → data/categories.rb} +3 -4
  11. data/lib/emojidex/{category.rb → data/category.rb} +1 -1
  12. data/lib/emojidex/data/collection.rb +158 -0
  13. data/lib/emojidex/data/collection/asset_information.rb +52 -0
  14. data/lib/emojidex/data/collection/cache.rb +137 -0
  15. data/lib/emojidex/{collection → data/collection}/moji_data.rb +1 -1
  16. data/lib/emojidex/data/collection/static_collection.rb +35 -0
  17. data/lib/emojidex/data/collection_checker.rb +94 -0
  18. data/lib/emojidex/{emoji.rb → data/emoji.rb} +3 -2
  19. data/lib/emojidex/data/emoji/asset_information.rb +45 -0
  20. data/lib/emojidex/data/extended.rb +18 -0
  21. data/lib/emojidex/data/utf.rb +18 -0
  22. data/lib/emojidex/defaults.rb +21 -0
  23. data/lib/emojidex/env_helper.rb +11 -0
  24. data/lib/emojidex/service/collection.rb +67 -0
  25. data/lib/emojidex/service/error.rb +9 -0
  26. data/lib/emojidex/service/indexes.rb +43 -0
  27. data/lib/emojidex/service/search.rb +82 -0
  28. data/lib/emojidex/service/transactor.rb +100 -0
  29. data/lib/emojidex/service/user.rb +233 -0
  30. data/spec/{categories_spec.rb → emojidex/data/categories_spec.rb} +4 -3
  31. data/spec/{collection_checker_spec.rb → emojidex/data/collection_checker_spec.rb} +12 -15
  32. data/spec/{collection_spec.rb → emojidex/data/collection_spec.rb} +40 -23
  33. data/spec/{emoji_spec.rb → emojidex/data/emoji_spec.rb} +2 -2
  34. data/spec/{extended_spec.rb → emojidex/data/extended_spec.rb} +21 -10
  35. data/spec/{utf_spec.rb → emojidex/data/utf_spec.rb} +22 -17
  36. data/spec/emojidex/service/collection_spec.rb +20 -0
  37. data/spec/emojidex/service/error_spec.rb +17 -0
  38. data/spec/emojidex/service/indexes_spec.rb +62 -0
  39. data/spec/emojidex/service/search_spec.rb +87 -0
  40. data/spec/emojidex/service/transactor_spec.rb +11 -0
  41. data/spec/emojidex/service/user_spec.rb +128 -0
  42. data/spec/spec_helper.rb +9 -62
  43. metadata +36 -31
  44. data/lib/emojidex/api/categories.rb +0 -16
  45. data/lib/emojidex/api/emoji.rb +0 -26
  46. data/lib/emojidex/api/search/emoji.rb +0 -16
  47. data/lib/emojidex/client.rb +0 -60
  48. data/lib/emojidex/collection.rb +0 -156
  49. data/lib/emojidex/collection/asset_information.rb +0 -49
  50. data/lib/emojidex/collection/cache.rb +0 -78
  51. data/lib/emojidex/collection_checker.rb +0 -93
  52. data/lib/emojidex/emoji/asset_information.rb +0 -20
  53. data/lib/emojidex/error.rb +0 -15
  54. data/lib/emojidex/extended.rb +0 -19
  55. data/lib/emojidex/service.rb +0 -32
  56. data/lib/emojidex/utf.rb +0 -19
  57. data/spec/api/categories_spec.rb +0 -49
  58. data/spec/api/emoji_spec.rb +0 -89
  59. data/spec/api/search/emoji_spec.rb +0 -30
  60. data/spec/client_spec.rb +0 -24
@@ -0,0 +1,137 @@
1
+ require 'json'
2
+ require 'fileutils'
3
+ require_relative 'asset_information'
4
+ require_relative '../../service/transactor'
5
+ require_relative '../../defaults'
6
+
7
+ module Emojidex
8
+ module Data
9
+ # local caching functionality for collections
10
+ module CollectionCache
11
+ include Emojidex::Data::CollectionAssetInformation
12
+ attr_reader :cache_path, :download_queue
13
+ attr_accessor :download_threads
14
+
15
+ def setup_cache(path = nil)
16
+ @download_queue = []
17
+ @download_threads = 8
18
+ # check if cache dir is already set
19
+ return @cache_path if @cache_path && path.nil?
20
+ # setup cache
21
+ @cache_path = File.expand_path((path || ENV['EMOJI_CACHE'] || "#{ENV['HOME']}/.emojidex/") + '/emoji')
22
+ # ENV['EMOJI_CACHE'] = @cache_path
23
+ FileUtils.mkdir_p(@cache_path)
24
+ Emojidex::Defaults.sizes.keys.each do |size|
25
+ FileUtils.mkdir_p(@cache_path + "/#{size}")
26
+ end
27
+ @cache_path
28
+ end
29
+
30
+ # Caches emoji to local emoji storage cache
31
+ # Options:
32
+ # cache_path: manually specify cache location
33
+ # (default is ENV['EMOJI_CACHE'] or '$HOME/.emoji_cache')
34
+ # formats: formats to cache (default is SVG only)
35
+ # sizes: sizes to cache (default is px32, but this is irrelivant for SVG)
36
+ def cache!(options = {})
37
+ setup_cache options[:cache_path]
38
+ formats = options[:formats] || Emojidex::Defaults.selected_formats
39
+ sizes = options[:sizes] || Emojidex::Defaults.selected_sizes
40
+ @emoji.values.each do |moji|
41
+ _svg_check_copy(moji) if formats.include? :svg
42
+ _raster_check_copy(moji, :png, sizes) if formats.include? :png
43
+ end
44
+ _process_download_queue
45
+ cache_index
46
+ end
47
+
48
+ # Updates an index in the specified destination (or the cache path if not specified).
49
+ # This method reads the existing index, combines the contents with this collection, and
50
+ # writes the results.
51
+ def cache_index(destination = nil)
52
+ destination ||= @cache_path
53
+ idx = Emojidex::Data::Collection.new
54
+ idx.load_local_collection(destination) if FileTest.exist? "#{destination}/emoji.json"
55
+ idx.add_emoji @emoji.values
56
+ File.open("#{destination}/emoji.json", 'w') { |f| f.write idx.emoji.values.to_json }
57
+ end
58
+
59
+ # [over]writes a sanitized index to the specified destination.
60
+ # WARNING: This method destroys any index files in the destination.
61
+ def write_index(destination)
62
+ idx = @emoji.values.to_json
63
+ idx = JSON.parse idx
64
+ idx.each { |moji| moji.delete_if{ |k, v| v.nil? }}
65
+ File.open("#{destination}/emoji.json", 'w') { |f| f.write idx.to_json }
66
+ end
67
+
68
+ private
69
+
70
+ def _svg_check_copy(moji)
71
+ @download_queue << { moji: moji, formats: :svg, sizes: [] } if @vector_source_path.nil? && @source_path.nil?
72
+ @vector_source_path = @source_path if @vector_source_path.nil?
73
+ src = "#{@vector_source_path}/#{moji.code}.svg"
74
+ if File.exist? "#{src}"
75
+ unless File.exist?("#{@cache_path}/#{moji.code}") &&
76
+ FileUtils.compare_file("#{src}", "#{@cache_path}/#{moji.code}.svg")
77
+ FileUtils.cp("#{src}", @cache_path)
78
+ end
79
+ else
80
+ _cache_svg_from_net(moji)
81
+ end
82
+ FileUtils.cp_r src, @cache_path if File.directory? src
83
+ end
84
+
85
+ def _raster_check_copy(moji, format, sizes)
86
+ @download_queue << { moji: moji, formats: [format], sizes: sizes } if @raster_source_path.nil? && @source_path.nil?
87
+ @raster_source_path = @source_path if @raster_source_path.nil?
88
+ _cache_raster_from_net(moji, format, sizes) if @raster_source_path.nil?
89
+ sizes.each do |size|
90
+ src = "#{@raster_source_path}/#{size}/#{moji.code}"
91
+ if FileTest.exist? "#{src}.#{format}"
92
+ FileUtils.cp("#{src}.#{format}", ("#{@cache_path}/#{size}"))
93
+ else
94
+ _cache_raster_from_net(moji, format, sizes)
95
+ end
96
+ FileUtils.cp_r(src, @cache_path) if File.directory? src
97
+ end
98
+ end
99
+
100
+ def _process_download_queue
101
+ thr = []
102
+ @download_queue.each do |dl|
103
+ thr << Thread.new { _cache_from_net(dl[:moji], dl[:formats], dl[:sizes]) }
104
+ thr.each { |t| t.join } if thr.length >= @download_threads
105
+ end
106
+ end
107
+
108
+ def _cache_from_net(moji, formats, sizes)
109
+ formats = *formats unless formats.class == Array
110
+ dls = []
111
+ dls << Thread.new { _cache_svg_from_net(moji) } if formats.include? :svg
112
+ dls << Thread.new { _cache_raster_from_net(moji, :png, sizes) } if formats.include? :png
113
+ dls.each { |t| t.join }
114
+ end
115
+
116
+ def _cache_svg_from_net(moji)
117
+ target = "#{@cache_path}/#{moji.code}.svg"
118
+ if File.exist? target # check for an existing copy so we don't double downlaod
119
+ return if moji.checksum?(:svg).nil? # no updates if we didn't get details
120
+ # if the checksums are the same there is no reason to update
121
+ return if moji.checksum?(:svg) == get_checksums(moji, [:svg])[:svg]
122
+ end
123
+ response = Emojidex::Service::Transactor.download("#{moji.code}.svg")
124
+ File.open(target, 'wb') { |fp|
125
+ fp.write(response.body) }
126
+ end
127
+
128
+ def _cache_raster_from_net(moji, format, sizes)
129
+ sizes.each do |size|
130
+ response = Emojidex::Service::Transactor.download("#{size}/#{moji.code}.#{format.to_s}")
131
+ File.open("#{@cache_path}/#{size}/#{moji.code}.#{format.to_s}", 'wb') { |fp|
132
+ fp.write(response.body) }
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -1,4 +1,4 @@
1
- module Emojidex
1
+ module Emojidex::Data
2
2
  # collects and condenses UTF moji codes within a collection
3
3
  module CollectionMojiData
4
4
  attr_reader :moji_code_string, :moji_code_index
@@ -0,0 +1,35 @@
1
+ require_relative '../../service/transactor'
2
+ require_relative '../../env_helper'
3
+
4
+ module Emojidex
5
+ module Data
6
+ # mixin module to enable static collections
7
+ module StaticCollection
8
+ def load_from_server(detailed = true, locale = '??')
9
+ locale = Emojidex::EnvHelper.lang? if locale == '??'
10
+ begin
11
+ res = Emojidex::Service::Transactor.get(@endpoint, {detailed: detailed, locale: locale})
12
+ rescue
13
+ return false
14
+ end
15
+ add_emoji(res)
16
+ return true
17
+ end
18
+
19
+ def check_and_load_static(collection)
20
+ loaded = false
21
+ if defined? Emojidex::Vectors
22
+ @vector_source_path = Emojidex::Vectors.path + "/#{collection}/"
23
+ load_local_collection @vector_source_path
24
+ loaded = true
25
+ end
26
+ if defined? Emojidex::Rasters
27
+ @raster_source_path = Emojidex::Rasters.path + "/#{collection}/"
28
+ load_local_collection @raster_source_path
29
+ loaded = true
30
+ end
31
+ loaded
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,94 @@
1
+ require 'find'
2
+ require_relative '../defaults.rb'
3
+
4
+ module Emojidex
5
+ module Data
6
+ # Check collections for presence of image assets and discrepencies in emoji indexes.
7
+ class CollectionChecker
8
+ attr_reader :index_only, :asset_only
9
+
10
+ def initialize(collections, options = {})
11
+ collections = *collections
12
+ @index_only = {}
13
+ @asset_only = {}
14
+ asset_path = options[:asset_path] || collections.first.source_path
15
+ sizes = options[:sizes] || Emojidex::Defaults.sizes.keys
16
+ formats = options[:formats] || Emojidex::Defaults.formats
17
+
18
+ asset_files = create_asset_file_list(asset_path, sizes, formats)
19
+ check_for_index_only(collections, asset_files, sizes, formats)
20
+ check_for_asset_only(collections, asset_files)
21
+ end
22
+
23
+ private
24
+
25
+ def create_asset_file_list(dir, sizes, formats)
26
+ result = {}
27
+ result.merge!(create_file_list(dir, '.svg', '')) if formats.include?(:svg)
28
+ if formats.include?(:png)
29
+ sizes.each do |size|
30
+ result.merge!(create_file_list("#{dir}/#{size}", '.png', "#{size}/"))
31
+ end
32
+ end
33
+ result
34
+ end
35
+
36
+ def create_file_list(dir, ext, prefix)
37
+ result = {}
38
+ return result unless Dir.exists?(dir)
39
+ Dir.foreach(dir) do |file|
40
+ result["#{prefix}#{File.basename(file, '.*')}".to_sym] =
41
+ "#{prefix}#{file}" if File.extname(file) == ext
42
+ end
43
+ result
44
+ end
45
+
46
+ def check_for_index_only(collections, asset_files, sizes, formats)
47
+ collections.each do |collection|
48
+ collection.emoji.values.each do |emoji|
49
+ tmp = []
50
+ tmp += create_svg_array(emoji, asset_files) if formats.include?(:svg)
51
+ tmp += create_png_array(emoji, asset_files, sizes) if formats.include?(:png)
52
+ @index_only[emoji.code.to_sym] = tmp unless tmp.empty?
53
+ end
54
+ end
55
+ end
56
+
57
+ def create_svg_array(emoji, asset_files)
58
+ result = []
59
+ asset_file = asset_files[emoji.code.to_sym]
60
+ result << "#{emoji.code}.svg" if asset_files[emoji.code.to_sym].nil?
61
+ result
62
+ end
63
+
64
+ def create_png_array(emoji, asset_files, sizes)
65
+ result = []
66
+ sizes.each do |size|
67
+ name = "#{size}/#{emoji.code}"
68
+ result << "#{name}.png" if asset_files[name.to_sym].nil?
69
+ end
70
+ result
71
+ end
72
+
73
+ def check_for_asset_only(collections, asset_files)
74
+ asset_files.each do |_key, value|
75
+ code = File.basename(value, '.*')
76
+
77
+ next if find_emoji_from_collections(collections, code)
78
+
79
+ symbol = code.to_sym
80
+ @asset_only[symbol] = [] if @asset_only[symbol].nil?
81
+ @asset_only[symbol] << value
82
+ end
83
+ end
84
+
85
+ def find_emoji_from_collections(collections, code)
86
+ symbol = code.to_sym
87
+ collections.each do |collection|
88
+ return true unless collection.emoji[symbol].nil?
89
+ end
90
+ false
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,14 +1,15 @@
1
1
  require_relative 'emoji/asset_information'
2
2
 
3
- module Emojidex
3
+ module Emojidex::Data
4
4
  # emoji base class
5
5
  class Emoji
6
6
  attr_accessor :moji, :category, :code, :code_ja,
7
7
  :unicode, :tags, :emoticon, :variants, :base
8
8
 
9
- include Emojidex::EmojiAssetInformation
9
+ include Emojidex::Data::EmojiAssetInformation
10
10
 
11
11
  def initialize(details = {})
12
+ init_asset_info(details)
12
13
  @moji = details[:moji]
13
14
  @code, @code_ja = details[:code], details[:code_ja]
14
15
  @unicode, @full_name = details[:unicode], details[:full_name]
@@ -0,0 +1,45 @@
1
+ require_relative '../../defaults'
2
+
3
+ module Emojidex
4
+ module Data
5
+ # Asset information for emoji
6
+ module EmojiAssetInformation
7
+ attr_accessor :checksums, :paths
8
+
9
+ def init_asset_info(details)
10
+ blank_checksums
11
+ fill_checksums(details[:checksums]) if details.include? :checksums
12
+ end
13
+
14
+ # returns asset checksum
15
+ def checksum?(format, size = nil)
16
+ puts @checksums
17
+ return @checksums[format][size] unless size.nil?
18
+ @checksums[format]
19
+ end
20
+
21
+ def blank_checksums
22
+ @checksums = {}
23
+ @checksums[:svg] = nil
24
+ @checksums[:png] = {}
25
+ Emojidex::Defaults.sizes.keys.each do |size|
26
+ @checksums[:png][size] = nil
27
+ end
28
+ end
29
+
30
+ def fill_checksums(checksums)
31
+ @checksums[:svg] = checksums[:svg] if checksums.include? :svg
32
+ return unless checksums.include? :png
33
+ Emojidex::Defaults.sizes.keys.each do |size|
34
+ @checksums[:png][size] = checksums[:png][size] if checksums[:png].include? size
35
+ end
36
+ end
37
+
38
+ # returns asset path
39
+ def path?(format, size = nil)
40
+ return @paths[format][size] unless size.nil?
41
+ @paths[format]
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'collection'
2
+ require_relative 'collection/static_collection'
3
+
4
+ module Emojidex
5
+ module Data
6
+ # listing and search of extended emoji from the emojidex set
7
+ class Extended < Collection
8
+ include Emojidex::Data::StaticCollection
9
+
10
+ def initialize
11
+ super
12
+ @endpoint = 'extended_emoji'
13
+ load_from_server unless check_and_load_static('extended')
14
+ @emoji
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'collection'
2
+ require_relative 'collection/static_collection'
3
+
4
+ module Emojidex
5
+ module Data
6
+ # listing and search of standard UTF emoji
7
+ class UTF < Collection
8
+ include Emojidex::Data::StaticCollection
9
+
10
+ def initialize
11
+ super
12
+ @endpoint = 'utf_emoji'
13
+ load_from_server unless check_and_load_static('utf')
14
+ @emoji
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,14 +1,35 @@
1
1
  module Emojidex
2
2
  # Global defines for emojidex
3
3
  class Defaults
4
+ @@selected_sizes = [:mdpi, :px32]
5
+ @@selected_formats = [:png]
6
+
4
7
  def self.sizes
5
8
  { ldpi: 13, mdpi: 18, hdpi: 27, xhdpi: 36, xxhdpi: 54, xxxhdpi: 72,
6
9
  px8: 8, px16: 16, px32: 32, px64: 64, px128: 128, px256: 256, px512: 512,
7
10
  hanko: 90, seal: 320 }
8
11
  end
9
12
 
13
+ def self.selected_sizes(sizes = nil)
14
+ @@selected_sizes = sizes unless sizes.nil?
15
+ @@selected_sizes
16
+ end
17
+
10
18
  def self.formats
11
19
  [:svg, :png]
12
20
  end
21
+
22
+ def self.selected_formats(formats = nil)
23
+ @@selected_formats = formats unless formats.nil?
24
+ @@selected_formats
25
+ end
26
+
27
+ def self.limit
28
+ 50
29
+ end
30
+
31
+ def self.lang
32
+ 'en'
33
+ end
13
34
  end
14
35
  end
@@ -0,0 +1,11 @@
1
+ module Emojidex
2
+ # Obtains and parses local environment variables
3
+ module EnvHelper
4
+
5
+ def self.lang?
6
+ lang = ENV['LANG'].match('^..')
7
+ lang = 'en' unless lang.to_s == 'ja'
8
+ lang
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,67 @@
1
+ require_relative '../data/collection'
2
+ require_relative 'transactor'
3
+ require_relative '../defaults'
4
+
5
+ module Emojidex
6
+ module Service
7
+ # A modified collection class for collections tied to the emojidex service
8
+ class Collection < Emojidex::Data::Collection
9
+ attr_reader :endpoint, :page, :limit, :detailed, :auto_cache
10
+
11
+ def initialize(opts = {})
12
+ @emoji = {}
13
+ add_emoji(opts[:emoji]) && opts.delete(:emoji) if opts.include? :emoji
14
+
15
+ @username = opts[:username] || nil
16
+ opts.delete(:username)
17
+ @auth_token = opts[:auth_token] || nil
18
+ opts.delete(:auth_token)
19
+
20
+ @endpoint = opts[:endpoint] || 'emoji'
21
+ opts.delete(:endpoint)
22
+ @page = opts[:page] || 0
23
+ opts.delete(:page)
24
+ @limit = opts[:limit] || Emojidex::Defaults.limit
25
+ opts.delete(:limit)
26
+ @detailed = opts[:detailed] || false
27
+ opts.delete(:detailed)
28
+
29
+ @auto_cache = opts[:auto_cache] || true
30
+ opts.delete(:auto_cache)
31
+
32
+ auto_init = opts[:auto_init] || true
33
+ opts.delete(:auto_init)
34
+
35
+ @opts = opts
36
+
37
+ more if auto_init
38
+ @emoji
39
+ end
40
+
41
+ # Get the next page worth of emoji and add them to the collection
42
+ def more()
43
+ @page += 1
44
+
45
+ opts = { page: @page, limit: @limit, detailed: @detailed }
46
+ opts[:username] = @username unless @username.nil?
47
+ opts[:auth_token] = @auth_token unless @auth_token.nil?
48
+ opts.merge! @opts
49
+
50
+ page_moji = Emojidex::Service::Transactor.get(@endpoint, opts)
51
+
52
+ if page_moji.is_a? Hash
53
+ unless page_moji.key? :emoji
54
+ @page -= 1 # reset page beacuse we failed
55
+ return {}
56
+ end
57
+
58
+ add_emoji(page_moji[:emoji])
59
+ return page_moji[:emoji]
60
+ end
61
+ add_emoji(page_moji)
62
+ cache! if @auto_cache
63
+ page_moji
64
+ end
65
+ end
66
+ end
67
+ end