从JSON动态挑选字段?

时间:2014-04-10 17:06:16

标签: ruby json

我正在编写一些东西,通过从服务器上的代理读取JSON输出来填充设备数据存储库。我遇到了一个我无法解释的障碍。

在使用nic_bonds时,我得到了:

block (2 levels) in translate': undefined method `[]' for nil:NilClass (NoMethodError)

在声明slaves =的行。当我将["#{name}"]更改为硬编码['bond0']时,我最终会找到我想要的内容:"bond0"=>"eth2,eth3"

当我使用类似模式时,使用["#{name}"]使用以太网端口似乎没问题。

是什么给出了?

代码:

class DeviceDataTranslator
  def initialize(device_data_collector, device_data_repo)
    @device_data_collector = device_data_collector
    @device_data_repo = device_data_repo
  end

  # translates data between tools
  def translate
    devices_input = @device_data_collector.get_devices_data
    devices_output = []

    # translate data for each node/device
    devices_input.each do |node|

      std_fields = {}
      custom_fields = {}

      # network
      interfaces = node['automatic']['network']['interfaces']
      ethernets = interfaces.select {|k, v| k.match(/^eth/)}
      ethernets.each do |name, data|
        eth_port = {}
        mac = node['automatic']['network'].keys.find {|k| k.include? "macaddress_#{name}"}
        eth_port["#{name}_mac"] = node['automatic']['network']["#{mac}"] unless !mac
        custom_fields.merge!(eth_port)
      end

      nic_bonds = interfaces.select {|k, v| k.match(/^bond/)}
      if nic_bonds
        nic_bonds.each do |name, data|
          bond = {}
          slaves = node['automatic']['ls']['bonding']["#{name}"]['slaves'].join(',')
          bond["#{name}"] = slaves
          custom_fields.merge!(bond)
        end
      end

      # combine fields & add to devices list
      device = [std_fields, custom_fields]
      devices_output.push(device)
    end

    # handoff to device data repo
    @device_data_repo.set_devices(devices_output)
  end
end

和(减少的)JSON:

    {
      "automatic": {
        "network": {
          "interfaces": {
            "bond0": {
              "type": "bond",
              "number": "0",
              "mtu": "1500"
            },
          "default_interface": "bond0",
          "default_gateway": "x.x.x.x",
          "ipaddress_lo": "127.0.0.1",
          "ipaddress6_lo": "::1",
          "macaddress_eth2": "x-x-x-x-x-x",
          "macaddress_eth3": "x-x-x-x-x-x",
          "macaddress_eth0": "x-x-x-x-x-x",
          "macaddress_eth1": "x-x-x-x-x-x",
          "macaddress_bond0": "x-x-x-x-x-x",
          "ipaddress_bond0": "x.x.x.x"
        },
        "ls": {
          "bonding": {
            "bond0": {
              "slaves": [
                "eth2",
                "eth3"
              ]
            }
          }
        }
      }
    }
  }

1 个答案:

答案 0 :(得分:2)

block (2 levels) in translate': undefined method `[]' for nil:NilClass (NoMethodError)

使用不存在的密钥时预期。

  

在声明slaves =的行。当我将[“#{name}”]更改为硬编码['bond0']时,我最终得到了我正在寻找的内容:“bond0”=>“eth2,eth3”。

很明显name不是bond0

  

当我使用类似的模式使用[“#{name}”]使用以太网端口时似乎没问题。

     

是什么给出了?

你某处有个bug。 :)我刚刚使用提供的JSON运行了您的示例(必须修复}),但它运行正常。也许你驱逐了一些破坏你代码的坏数据?添加如下语句:

p name

在你的循环中看看那里到底是什么。