neopoly/rubyfox-sfsobject

View on GitHub
lib/rubyfox/sfsobject/bulk.rb

Summary

Maintainability
A
25 mins
Test Coverage
require "rubyfox/sfsobject/java"

module Rubyfox
  module SFSObject
    module Bulk
      extend self

      TO_SFS = {
        NilClass => proc { |o, k, _| o.putNull(k) },
        String => :putUtfString,
        TrueClass => :putBool,
        FalseClass => :putBool,
        Integer => :putInt,
        Float => :putDouble,
        Hash => proc { |o, k, v| o.putSFSObject(k, to_sfs(v)) },
        Java::SFSObject => :putSFSObject,
        [String] => :putUtfStringArray,
        [TrueClass] => :putBoolArray,
        [FalseClass] => :putBoolArray,
        [Integer] => proc do |o, k, v|
          collection = Java::ArrayList.new
          v.each { |e| collection.add(e.to_java(:int)) }
          o.putIntArray(k, collection)
        end,
        [Float] => :putDoubleArray,
        [Hash] => proc do |o, k, v|
          ary = Java::SFSArray.new
          v.each { |e| ary.addSFSObject(to_sfs(e)) }
          o.putSFSArray(k, ary)
        end,
        [Java::SFSObject] => proc do |o, k, v|
          ary = Java::SFSArray.new
          v.each { |e| ary.addSFSObject(e) }
          o.putSFSArray(k, ary)
        end,
      }

      TO_HASH = {
        "NULL" => proc { |k, v| nil },
        "UTF_STRING" => :getUtfString,
        "BOOL" => :getBool,
        "INT" => :getInt,
        "DOUBLE" => :getDouble,
        "FLOAT" => :getFloat,
        "UTF_STRING_ARRAY" => :getUtfStringArray,
        "BOOL_ARRAY" => :getBoolArray,
        #"INT_ARRAY"         =>  :getIntArray,
        "INT_ARRAY" => proc { |k, v| v.object.to_a },
        "LONG_ARRAY" => :getLongArray,
        "DOUBLE_ARRAY" => :getDoubleArray,
        "FLOAT_ARRAY" => :getFloatArray,
        "SFS_OBJECT" => proc { |k, v| to_hash(v.object) },
        "SFS_ARRAY" => proc { |k, v| to_array(v.object) },
      }

      # hash -> object
      def to_sfs(hash = {})
        object = Java::SFSObject.new
        hash.each do |key, value|
          wrap_value!(object, key, value)
        end
        object
      end

      def wrap_value!(object, key, value)
        if wrapper_method = _wrapper(value)
          case wrapper_method
          when Symbol
            object.send(wrapper_method, key, value)
          else
            wrapper_method.call(object, key, value)
          end
        else
          raise ArgumentError, "wrapper for #{key}=#{value} (#{value.class}) not found"
        end
      end

      def _wrapper(value)
        case value
        when Array
          case value = value.first
          when Integer # This is necessary to support ruby < 2.4.
            TO_SFS[[Integer]]
          else
            TO_SFS[[value.class]]
          end
        when Integer # See above.
          TO_SFS[Integer]
        else
          TO_SFS[value.class]
        end
      end

      # object -> hash
      def to_hash(object)
        hash = {}
        object.keys.each do |key|
          hash[key.to_sym] = unwrap_value!(object, key)
        end
        hash
      end

      def to_array(object)
        object.iterator.each_with_index.map do |value, index|
          _unwrap(object, index, value)
        end
      end

      def unwrap_value!(object, key)
        value = object.get(key)
        _unwrap(object, key, value)
      end

      def _unwrap(object, key, value)
        raise ArgumentError, "nil value for #{key.inspect}" unless value

        if wrapper_method = _unwrapper(value)
          case wrapper_method
          when Symbol
            object.send(wrapper_method, key)
          else
            wrapper_method.call(key, value)
          end
        else
          raise ArgumentError, "unwrapper for #{key}=#{value.object.inspect} (#{value.type_id}) not found"
        end
      end

      def _unwrapper(value)
        TO_HASH[value.type_id.to_s]
      end
    end
  end
end