<commit_before>require 'json'

module Volt
  class EJSON
    class NonEjsonType < Exception ; end

    OTHER_VALID_CLASSES = [String, Symbol, TrueClass, FalseClass, Numeric, NilClass]

    def self.stringify(obj)
      encode(obj).to_json
    end

    def self.parse(str)
      decode(JSON.parse(str))
    end

    private

    def self.decode(obj)
      if Array === obj
        obj.map {|v| decode(v) }
      elsif Hash === obj
        if obj.size == 1 && (escape = obj['$escape'])
          return escape.map do |key, value|
            [key, decode(value)]
          end.to_h
        elsif obj.size == 1 && (time = obj['$date'])
          if time.is_a?(Fixnum)
            return Time.at(time / 1000.0)
          end
        end

        obj.map do |key, value|
          [key, decode(value)]
        end.to_h
      else
        obj
      end
    end

    def self.encode(obj)
      if Array === obj
        obj.map {|v| encode(v) }
      elsif Hash === obj
        obj.map do |key, value|
          if key == '$date'
            key = '$escape'
            value = {'$date' => encode(value)}
          else
            value = encode(value)
          end

          [key, value]
        end.to_h
      elsif Time === obj
        {'$date' => obj.to_i * 1_000}
      elsif OTHER_VALID_CLASSES.any? {|klass| obj.is_a?(klass) }
        obj
      else
        # Not a valid class for serializing, raise an exception
        raise NonEjsonType, "Unable to serialize #{obj.inspect} to EJSON"
      end
    end
  end
end<commit_msg>EJSON support for VoltTime<commit_after>require 'json'

module Volt
  class EJSON
    class NonEjsonType < Exception ; end

    OTHER_VALID_CLASSES = [String, Symbol, TrueClass, FalseClass, Numeric, NilClass]

    def self.stringify(obj)
      encode(obj).to_json
    end

    def self.parse(str)
      decode(JSON.parse(str))
    end

    private

    def self.decode(obj)
      if Array === obj
        obj.map {|v| decode(v) }
      elsif Hash === obj
        if obj.size == 1 && (escape = obj['$escape'])
          return escape.map do |key, value|
            [key, decode(value)]
          end.to_h
        elsif obj.size == 1 && (time = obj['$date'])
          if time.is_a?(Fixnum)
            if defined?(Volt::VoltTime)
              return Volt::VoltTime.at(time / 1000.0)
            else
              return Time.at(time / 1000.0)
            end
          end
        end

        obj.map do |key, value|
          [key, decode(value)]
        end.to_h
      else
        obj
      end
    end

    def self.encode(obj)
      if Array === obj
        obj.map {|v| encode(v) }
      elsif Hash === obj
        obj.map do |key, value|
          if key == '$date'
            key = '$escape'
            value = {'$date' => encode(value)}
          else
            value = encode(value)
          end

          [key, value]
        end.to_h
      elsif Time === obj || (defined?(Volt::VoltTime) && Volt::VoltTime === obj)
        {'$date' => obj.to_i * 1_000}
      elsif OTHER_VALID_CLASSES.any? {|klass| obj.is_a?(klass) }
        obj
      else
        # Not a valid class for serializing, raise an exception
        raise NonEjsonType, "Unable to serialize #{obj.inspect} to EJSON"
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.11732186732186732, 'fraction_numerical': 0.008292383292383292, 'mean_word_length': 1.6587755102040815, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4404518', 'n_tokens_mistral': 1074, 'n_tokens_neox': 1035, 'n_words': 284}