用Ruby读取YAML,意外返回类型

时间:2016-07-07 18:13:21

标签: arrays ruby count yaml

我有一个YAML文件,其中包含一些具有多个值的键和一对具有一个值的键:

inbox:
  paul: 'PHILADELPHIA-RO-ADMIN'
  tanny: 'PA-C-INDIANA-ADMIN'
  mary:
          - 'MD-C-LAUREL-ADMIN'
          - 'MD-E-BALTIMORE-ADMIN'
          - 'MD-R1-CAMBRIDGE-ADMIN'
          - 'MD-R2-BELAIR-ADMIN'
          - 'MD-R4-LAUREL-ADMIN'
          - 'MD-R5-HAGERSTWN-ADMIN'
  mike:
          - 'VA-E-Richmond-Admin'
          - 'VA-Richmond-Admin'
          - 'VA-Manassas-Admin'
          - 'VA-Norfolk-Admin'
          - 'VA-Roanoke-Admin'
          - 'VA-Verona-Admin'

我正在尝试做的是,如果键有多个值输出,则键具有多个值,但是如果键只有一个值,则只输出该值。我正在尝试使用Array.count函数来执行此操作,我遇到了一个问题,即如果Array只有一个值,则会计算键内部的字符数,例如:

require 'yaml'

POC = YAML.load_file('test.yml')

def get_poc(name)

  data = POC['inbox'][name.downcase]
  puts data.count
  if data.count == 1
    POC['inbox'][name]
  else
    puts "Multiple inboxes found for #{name.capitalize.chomp}"
    data.each.with_index(1) do |str, i|
      puts "#{i}. #{str}"
    end
    puts 'One of the above inboxes is the correct inbox for this ticket.'
  end
end

在IRB中运行时:

irb(main):020:0> get_poc('mary')
6
Multiple inboxes found for Mary
1. MD-C-LAUREL-ADMIN
2. MD-E-BALTIMORE-ADMIN
3. MD-R1-CAMBRIDGE-ADMIN
4. MD-R2-BELAIR-ADMIN
5. MD-R4-LAUREL-ADMIN
6. MD-R5-HAGERSTWN-ADMIN
One of the above inboxes is the correct inbox for this ticket.
=> nil
irb(main):021:0> get_poc('paul')
21
ArgumentError: wrong number of arguments (given 0, expected 1+)
        from (irb):10:in `count'
        from (irb):10:in `get_poc'
        from (irb):21
        from C:/Ruby23/bin/irb.cmd:19:in `<main>'
irb(main):022:0>

它似乎适用于多个值,但是当只有一个给定的值时,它似乎实际上按字符计算值的全长。

我也尝试使用Array.length方法:

require 'yaml'

    POC = YAML.load_file('test.yml')

    def get_poc(name)

      data = POC['inbox'][name.downcase]
      puts data.length
      if data.length == 1
        POC['inbox'][name]
      else
        puts "Multiple inboxes found for #{name.capitalize.chomp}"
        data.each.with_index(1) do |str, i|
          puts "#{i}. #{str}"
        end
        puts 'One of the above inboxes is the correct inbox for this ticket.'
      end
    end

同样的问题不同的错误:

irb(main):040:0> get_poc('mary')
6
Multiple inboxes found for Mary
1. MD-C-LAUREL-ADMIN
2. MD-E-BALTIMORE-ADMIN
3. MD-R1-CAMBRIDGE-ADMIN
4. MD-R2-BELAIR-ADMIN
5. MD-R4-LAUREL-ADMIN
6. MD-R5-HAGERSTWN-ADMIN
One of the above inboxes is the correct inbox for this ticket.
=> nil
irb(main):041:0> get_poc('paul')
21
Multiple inboxes found for Paul
NoMethodError: undefined method `each' for "PHILADELPHIA-RO-ADMIN":String
        from (irb):34:in `get_poc'
        from (irb):41
        from C:/Ruby23/bin/irb.cmd:19:in `<main>'
irb(main):042:0>

如何让方法只将值计为一个元素?

2 个答案:

答案 0 :(得分:2)

问题的根源是POC['inbox'][name.downcase]将返回不同的对象:

  1. 当单个项目时,返回String
  2. 列表时,会返回Array
  3. 换句话说:

    POC['inbox']['mary'].class
    #=> Array
    POC['inbox']['paul'].class
    #=> String
    
    对于这两个类,

    count的定义不同。

    要检查是否有一个项目,您可以:

    1. 检查数据是String
    2. 如果不是String,请检查count是否为1(即如果使用了列表,但只有1项)
    3. 更新后的if条件为:

      def get_poc(name)
        data = POC['inbox'][name.downcase]
      
        if data.kind_of?(String) || data.count == 1
          POC['inbox'][name]
        else
          puts "Multiple inboxes found for #{name.capitalize.chomp}"
          data.each.with_index(1) do |str, i|
            puts "#{i}. #{str}"
          end
          puts 'One of the above inboxes is the correct inbox for this ticket.'
        end
      end
      

答案 1 :(得分:2)

您没有始终如一地使用yml文件,因此您无法获得一致的结果。如果您希望Paul成为您需要的单元素数组...

inbox:
  paul: 
    - 'PHILADELPHIA-RO-ADMIN'
 ...

或者您可以通过更改一行来修复代码:

  data = [POC['inbox'][name.downcase]].flatten

这样你总是得到一个数组,即使该键只有一个元素,返回值是String。