skipping eval is literally 10x faster

require 'benchmark/ips'

data = {
          'title'       => 'Knee Deep in JSON',
          'crazy.field' => 'CRAAAAZY!',
          '_source.artist' => {
            'name' => 'Elastiq',
            'meta' => {
              'favorited' => 1000,
              'url'       => 'http://first.fm/abc123/xyz567'
            }
          },
          '_source.track.info.duration' => {
            'minutes' => 3
          }
      }

Benchmark.ips do |x|
  x.report("eval") do |times|
    i = 0
    while i < times
      fields = data.clone
      fields.clone.each_pair do |key,value|
        next unless key.to_s =~ /_source/                 # Skip regular JSON immediately

        keys = key.to_s.split('.').reject { |n| n == '_source' }
        fields.delete(key)

        result = {}
        path = []

        keys.each do |name|
          path << name
          eval "result[:#{path.join('][:')}] ||= {}"
          eval "result[:#{path.join('][:')}] = #{value.inspect}" if keys.last == name
        end
        fields.update result
      end
      i += 1
    end
  end

  x.report("injectl") do |times|
    i = 0
    while i < times
      fields = data.clone
      fields.clone.each_pair do |key,value|
        next unless key =~ /^_source/                 # Skip regular JSON immediately

        keys = key.split('.')
        keys.shift

        fields.delete(key)

        result = {}
        path = []
        stack = result
        keys.each do |name|
          stack[name] ||= {}
          if keys.last == name
            stack[name] = value
          else
            stack = stack[name]
          end
        end
        fields.update result
      end
      i += 1
    end
  end

  x.report("inject2") do |times|
    i = 0
    while i < times
      fields = data.clone
      fields.clone.each_pair do |key,value|
        next unless key.start_with?('_source'.freeze)                 # Skip regular JSON immediately

        keys = key.split('.')
        keys.shift

        fields.delete(key)

        result = {}
        stack = result
        *keys, last_key = keys
        keys.each do |name|
          stack[name] ||= {}
          stack = stack[name]
        end
        stack[last_key] = value
        fields.update result
      end
      i += 1
    end
  end

  x.report("inject2") do |times|
    i = 0
    while i < times
      fields = data.clone
      fields.clone.each_pair do |key,value|
        next unless key.start_with?('_source'.freeze)                 # Skip regular JSON immediately

        keys = key.split('.')
        keys.shift

        fields.delete(key)

        result = {}
        stack = result
        *keys, last_key = keys
        keys.each do |name|
          stack = (stack[name] ||= {})
        end
        stack[last_key] = value
        fields.update result
      end
      i += 1
    end
  end

end
use frozen strings for the common keys in the core result processing loop
rework source/partial fields so we can have an esy transition to 1.0
allow scanners to get at the hit