Ruby和获取哈希值魔术

问题描述 投票:0回答:2

我正在尝试解析JSON数据并创建自己的字典来显示数据的子集。问题是,我注意到我的输入数据根据扫描的内容而改变(使用nmap)。一些元素可能是数组值,而有些可能不是。这些组合看起来相当广泛。

例如,这是最简单的输入,其中只找到了一个IP地址:

{
  'host' => {
    'address' => {
      'addr' => '192.168.0.1'
    },
    'status' => {...}
  }
}

但是,可能会找到IP和MAC地址:

{
  'host' => {
    'address' => [{
      'addrtype' => 'ipv4',
      'addr' => '192.168.0.1',
     },{
      'addrtype' => 'mac',
      'mac' => '00:AA:BB:CC:DD:EE',
     },
    'status' => {...}
  }]
}

这只是几个例子。我见过的其他变化:

`host.class` = Array
`address.class` = Hash
`host['status'].class` = Array
etc...

当我解析输出时,我首先检查元素是否是一个数组,如果是,我以一种方式访问​​键/值,而如果它不是数组,我基本上必须用一些数据复制我的代码调整它,这似乎不是很有说服力:

hash = {}
  if hosts.class == Array
    hosts.each do |host|
      ip = if host['address'].class == Array
             host['address'][0]['addr']
           else
             host['address']['addr']
           end
      hash[ip] = {}
    end
  else
    ip = if hosts['address'].class == Array
           hosts['address'][0]['addr']
         else
           hosts['address']['addr']
         end
    hash[ip] = {}
  end
  puts hash
end

最后,我只是想找到一种更好/更有说服力的方法来生成如下的哈希,同时考虑元素可能/可能不是数组的可能性:

{
 '192.168.0.1' => {
   'mac' => '00:aa:bb:cc:dd:ee',
   'vendor' => 'Apple',
   'ports' => {
      '80' => {
        'status' => 'open',
        'service' => 'httpd'
      }
      '443' => {
        'status' => 'filtered',
        'service' => 'httpd'
      }
    }
 },
 192.168.0.2 => {
   ...
 }
}

如果有一种我尚未遇到过的红宝石方法会让它变得更加流畅?

ruby-on-rails json ruby
2个回答
1
投票

不是真的......但你可以使它总是一个数组,例如通过做类似的事情:

hosts = [hosts] unless hosts.is_a?(Array)

或类似...然后将其传递给您现在不重复的代码。 :)


0
投票

您的问题中的20行代码可以使用Array#wrap而不是条件减少为单行,并使用Enumerable#map而不是Enumerable#each

Array.wrap(hosts).map { |host| [Array.wrap(host['address']).first['addr'], {}] }.to_h

现在这太神奇了!

© www.soinside.com 2019 - 2024. All rights reserved.