2013-05-02 96 views
3

我想檢查一個字符串是否有效YAML。我想從我的Ruby代碼中用寶石或庫來做到這一點。我唯一有此開始/救援條款,但它並沒有得到適當的搶救:如何檢查字符串是否有效YAML?

def valid_yaml_string?(config_text) 
    require 'open-uri' 
    file = open("https://github.com/TheNotary/the_notarys_linux_mint_postinstall_configuration") 
    hard_failing_bad_yaml = file.read 
    config_text = hard_failing_bad_yaml 
    begin 
    YAML.load config_text 
    return true 
    rescue 
    return false 
    end 
end 

我遺憾的是越來越可怕的錯誤:

irb(main):089:0> valid_yaml_string?("b") 
Psych::SyntaxError: (<unknown>): mapping values are not allowed in this context at line 6 column 19 
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/lib/ruby/1.9.1/psych.rb:203:in `parse' 
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/lib/ruby/1.9.1/psych.rb:203:in `parse_stream' 
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/lib/ruby/1.9.1/psych.rb:151:in `parse' 
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/lib/ruby/1.9.1/psych.rb:127:in `load' 
from (irb):83:in `valid_yaml_string?' 
from (irb):89 
from /home/kentos/.rvm/rubies/ruby-1.9.3-p374/bin/irb:12:in `<main>' 

回答

7

使用你的代碼的清理後的版本:

require 'yaml' 
require 'open-uri' 

URL = "https://github.com/TheNotary/the_notarys_linux_mint_postinstall_configuration" 

def valid_yaml_string?(yaml) 
    !!YAML.load(yaml) 
rescue Exception => e 
    STDERR.puts e.message 
    return false 
end 

puts valid_yaml_string?(open(URL).read) 

我得到:

(<unknown>): mapping values are not allowed in this context at line 6 column 19 
false 

當我運行它。

的原因是,你是從URL獲取數據不是在所有YAML,這是HTML:

open('https://github.com/TheNotary/the_notarys_linux_mint_postinstall_configuration').read[0, 100] 
=> " \n\n\n<!DOCTYPE html>\n<html>\n <head prefix=\"og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# githubog:" 

如果你只想要一個真/假響應是否是可解析YAML,刪除此行:

STDERR.puts e.message 

不幸的是,超越這一點,並確定如果字符串是一個YAML字符串變得更加困難。你可以做一些嗅探,尋找一些線索:

yaml[/^---/m] 

將搜索YAML「文件」的標記,但YAML文件沒有使用這些,也沒有必須在開始文件。我們可以添加在收緊測試:

!!YAML.load(yaml) && !!yaml[/^---/m] 

但是,即使是留下了一些漏洞,在測試因此增加,看看有什麼解析器回報可以幫助甚至更多。 YAML可以返回一個Fixnum,String,一個數組或一個哈希,但是如果您已經知道期望什麼,您可以檢查YAML想要返回的內容。例如:

YAML.load(({}).to_yaml).class 
=> Hash 
YAML.load(({}).to_yaml).instance_of?(Hash) 
=> true 

所以,你可以找一個哈希:

parsed_yaml = YAML.load(yaml) 
!!yaml[/^---/m] && parsed_yaml.instance_of(Hash) 

更換Hash與任何類型的,你認爲你應該得到的。

有可能有更好的方法來嗅探出來,但這些都是我首先想要的。

+0

'!!'是什麼意思? – fotanus 2013-05-02 01:51:42

+0

在IRB中嘗試'!true',然後嘗試'!! true',然後嘗試'!('foo'=='foo')',後面跟着!!('foo'=='foo')'。 – 2013-05-02 01:53:02

+0

對不起,不知道我在想什麼... – fotanus 2013-05-02 01:56:19

相關問題