【问题标题】:Extracting data from yml files with ruby使用 ruby​​ 从 yml 文件中提取数据
【发布时间】:2015-06-09 15:42:18
【问题描述】:

我阅读了一些有关 Yaml 或 yml 文件格式的快速教程。我制作了一个 yaml 文档来表示我的数据。我看到了一些 ruby​​ 教程,它们告诉你如何用 ruby​​ 提取 yaml。不幸的是,他们只打印整个数据或只打印键和值。它不符合我的需求。请帮忙。

yaml 文件 -

dev:
  game1:
    server1:
        url: 'dev-game1-a-srv01.gamer.com'
        log-path: '/srv/logs'
    server2:
        url: 'dev-game1-a-srv02.gamer.com'
        log-path: '/srv/logs'

  game2:
    server1:
        url: 'dev-game2-a-srv01.gamer.com'
        log-path: '/srv/logs'
    server2:
        url: 'dev-game2-b-srv02.gamer.com'
        log-path: '/srv/logs'
    server3:
        url: 'dev-game2-b-srv01.gamer.com'
        log-path: '/srv/logs'
prod: 
etc....

如何使用 ruby​​ 代码选择 dev、game2、server 3、url?

使用下面的代码,我得到一个异常 -

require 'yaml'

def server_info
    path = 'C:\Code\demo-srv.yml'
    yml = YAML::load(File.open(path))
    game2 = yml['dev']['game2'] 
    game2.each{|server|
        if server['server3']
            puts server['server3']['url']
        end
    }
end

server_info

错误 -

server.rb:8:in `[]': can't convert String into Integer (TypeError)
        from server.rb:8:in `server_info'
        from server.rb:7:in `each'
        from server.rb:7:in `server_info'
        from server.rb:14

【问题讨论】:

    标签: ruby parsing yaml


    【解决方案1】:

    您是定义了 yaml 数据还是只是现有 yaml 文件的使用者?

    如果你定义了它,我会用哈希替换服务器数组(请参阅服务器名称前缺少的-):

    dev:
      game1:
        server1:
            url: 'dev-game1-a-srv01.gamer.com'
            log-path: '/srv/logs'
        server2:
            url: 'dev-game1-a-srv02.gamer.com'
            log-path: '/srv/logs'
    
      game2:
        server1:
            url: 'dev-game2-a-srv01.gamer.com'
            log-path: '/srv/logs'
        server2:
            url: 'dev-game2-b-srv02.gamer.com'
            log-path: '/srv/logs'
        server3:
            url: 'dev-game2-b-srv01.gamer.com'
            log-path: '/srv/logs'
    

    那你可以试试yml['dev']['game2']['server3']['url']

    注意:没有检查缺失/错误的数据。如果game2 的条目丢失,此代码将引发异常。

    所以,也许你应该做一些类似的事情

    if yml['dev'] and yml['dev'].kind_of?(Hash)
      if yml['dev']['game2'] and ....
      ...
    else
      puts "No dev-branch defined"
    end
    

    你也可以试试这样的:

    def server_info
        yml = YAML::load(DATA)
        yml['dev']['game2'].each{|server|
          if server['server3']
            p server['server3']['url']
          end
        }
    end
    

    注意(两种解决方案):

    没有检查缺失/错误数据。此处检查server['server3'] 的存在。对于真实代码,您还应该检查devgame2 数据是否存在。


    编辑后继续回答:

    如果您有一个数组但期望一个哈希值并且您尝试使用字符串访问数组元素,则通常会引发错误 convert String into Integer

    你可以试试下面的代码。有两个变化:

    • 第 8 行包含 server 的输出 - 你会看到它是一个数组,没有散列。
    • 第 9+10 行:数组被它的两个元素检查和使用(通过#first 和#last)

      require 'yaml'
      
      def server_info
          path = 'C:\Code\demo-srv.yml'
          #~ yml = YAML::load(File.open(path))
          yml = YAML::load(DATA)
          game2 = yml['dev']['game2'] 
          game2.each{|server|
              p server    #-> you get an array
              if server.first == 'server3'
                  puts server.last['url']
              end
          }
      end
      
      server_info
      

    文件 -

    dev:
      game1:
        server1:
            url: 'dev-game1-a-srv01.gamer.com'
            log-path: '/srv/logs'
        server2:
            url: 'dev-game1-a-srv02.gamer.com'
            log-path: '/srv/logs'
    
      game2:
        server1:
            url: 'dev-game2-a-srv01.gamer.com'
            log-path: '/srv/logs'
        server2:
            url: 'dev-game2-b-srv02.gamer.com'
            log-path: '/srv/logs'
        server3:
            url: 'dev-game2-b-srv01.gamer.com'
            log-path: '/srv/logs'
    

    【讨论】:

    • 有没有通用的方法来迭代这个文件?例如。对于每个“像 dev 和 prod 这样的顶级密钥”,获取游戏密钥,然后获取每个游戏密钥的服务器信息?示例 - dev = yml['dev']; dev.each_top_key do |game| puts "#{game}\n" end 谢谢。
    • 从这里得到它 - juixe.com/techknow/index.php/2009/10/08/jamming-with-ruby-yaml yml.each_key{|key| puts key} 这只能让您将环境打印为字符串,但不能迭代它们的键。我想做这个yml.each_key{|env| puts env env.each_key{|game| puts game app.each {|srv| puts srv } } }
    【解决方案2】:

    我不知道为什么,但yml['dev']['game2']=>

    [{"server1"=>{"url"=>"dev-game2-a-srv01.gamer.com", "log-path"=>"/srv/logs"}},
    {"server2"=>{"url"=>"dev-game2-b-srv02.gamer.com", "log-path"=>"/srv/logs"}},
     {"server3"=>{"url"=>"dev-game2-b-srv01.gamer.com", "log-path"=>"/srv/logs"}}]
    

    所以你必须在这个数组上使用 find 来获得密钥。

    require 'yaml'
    # require 'pry'
    
    def server3_url
        yml = YAML::load(File.read('yaml.yml'))
        # binding.pry
        begin
          yml['dev']['game2'].find{|x| x['server3']}['server3']['url']
        rescue
        end
    end
    
    
    puts server3_url
    

    server3_url 如果找不到密钥,将返回 nil

    【讨论】:

      【解决方案3】:

      更改您的代码如下应该可以解决问题。

      # ...
      game2.each{ |server, data|
        if server == 'server3'
          puts data['url']
        end
      }
      # ...
      

      您遇到类型错误是因为生成的值 server 是一个数组,而不是一个哈希。发生这种情况是因为您在 game2 变量上调用 each,这是一个哈希,并且只产生一个变量。

      示例

      hash = { one: 1, two: 2, three: 3 }
      

      屈服于单个变量

      当仅使用一个变量调用 Hash#each 时,当前键和值作为数组按顺序分配给该变量[key, value]

      hash.each do |number|
        puts number.inspect
      end
      
      # Prints
      #   [:one, 1]
      #   [:two, 2]
      #   [:three, 3]
      

      屈服于多个变量

      当使用两个变量调用Hash#each时,当前键将分配给第一个变量,当前值将分配给第二个。

      hash.each do |key, value|
        puts "Key: #{key}; Value: #{value}"
      end
      
      # Prints:
      #  Key: one; Value: 1
      #  Key: two; Value: 2
      #  Key: three; Value: 3
      

      【讨论】:

        猜你喜欢
        • 2018-04-06
        • 2014-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多