searls/emoruby

View on GitHub
lib/emoruby/converts_emoji_to_ruby.rb

Summary

Maintainability
A
0 mins
Test Coverage
require "emoji_data"
require "emoruby/util/string"

require "yaml"
require "pathname"

module Emoruby
  class ConvertsEmojiToRuby
    TRANSLATIONS = YAML.safe_load(File.read(Pathname.new(File.dirname(__FILE__)).join("..", "..", "config", "translations.yml")))

    GARBAGE = [
      [239, 184, 143] # evil problematic whitespace where is it from where am i what even
    ]

    def initialize(source)
      @source = source
    end

    def call
      translate_lines(@source.lines).join("")
    end

    private

    def translate_lines(lines)
      lines.map do |line|
        chars = clean_chars(scan_and_translate_doublebyte(scan_and_translate_constants(line)).chars)
        comments = false

        translate_chars(chars) do |char|
          next if comments
          emo_char = emoji_name_for(char)
          comments ||= (emo_char == "#")
          emo_char
        end
      end
    end

    def scan_and_translate_constants(source)
      find_and_replace(source, constant_map.keys, constant_map)
    end

    def scan_and_translate_doublebyte(source)
      find_and_replace(source, EmojiData.scan(source).select(&:doublebyte?).map(&:to_s), TRANSLATIONS)
    end

    def find_and_replace(source, search, replacements)
      source.gsub(Regexp.new(search.map { |x| Regexp.escape(x) }.join("|")), replacements)
    end

    def constant_map
      @constant_map ||= @source.split(/\s+/).each_cons(2).map do |operator, emo_constant|
        next unless ["class", "module"].include?(emoji_name_for(operator))
        [
          emo_constant,
          Util::String.classify(emo_constant.chars.map { |c| emoji_name_for(c) }.join)
        ]
      end.compact.to_h
    end

    def clean_chars(source)
      source.reject { |c| GARBAGE.include?(c.bytes) }
    end

    def translate_chars(chars)
      chars.each_with_index.map do |char, index|
        yield(char, index) || char
      end.join
    end

    def emoji_name_for(char)
      return unless (emoji = EmojiData.find_by_str(char).first)
      TRANSLATIONS[emoji.to_s] || emoji.short_name
    end
  end
end