Почему YAML выдает плавающие ArgumentErrors на строках?
У меня есть несколько вложенных строк в сложном хеше, который вызывает исключения "ArgumentError". Как лучше всего справляться с этим?
require 'yaml'
{
a: 'hello',
b: [{f:'hello',g:Hash.new,i:{a:'hello'}}],
c: {e:"+."}
}.to_yaml #=> `Float': invalid value for Float(): "+" (ArgumentError)
Полный дамп ошибок:
/Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/scalar_scanner.rb:99:in `Float': invalid value for Float(): "+" (ArgumentError)
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/scalar_scanner.rb:99:in `tokenize'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:272:in `visit_String'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:128:in `accept'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:324:in `block in visit_Hash'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:322:in `each'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:322:in `visit_Hash'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:128:in `accept'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:324:in `block in visit_Hash'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:322:in `each'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:322:in `visit_Hash'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:128:in `accept'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/visitors/yaml_tree.rb:92:in `push'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych.rb:244:in `dump'
from /Users/XXX/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/core_ext.rb:14:in `psych_to_yaml'
2 ответа
Это похоже на ошибку в комплекте психики. Заделка ~/.rvm/rubies/ruby-2.0.0-p0/lib/ruby/2.0.0/psych/scalar_scanner.rb
в строке 99 из:
Float(string.gsub(/[,_]|\.$/, ''))
чтобы:
Float(string.gsub(/[,_]|\.$/, '')) rescue ArgumentError
устраняет проблему По сути, это то, что находится в самоцвете психики, а также в комплектной версии Ruby 1.9.
Если вы не хотите вносить исправления в свой Ruby, используйте гем psych-1.3.4; просто обязательно require 'psych'
скорее, чем 'yaml'
:
gem 'psych', '=1.3.4'
require 'psych'
{a: 'hello', b: [{f:'hello',g:Hash.new,i:{a:'hello'}}], c: {e:"0+."}}.to_yaml
# => "---\n:a: hello\n:b:\n- :f: hello\n :g: {}\n :i:\n :a: hello\n:c:\n :e: 0+.\n"
Это может быть воспроизведено на более простом примере:
"+.".to_yaml
Похоже, что это ошибка в версии psych в комплекте с ruby 2.0.0 (я уверен, что в других версиях):
when FLOAT
if string == '.'
@string_cache[string] = true
string
else
Float(string.gsub(/[,_]|\.$/, ''))
end
Проблема в том что "+". выглядит как действительное число с плавающей запятой, как +.5.
Это исправлено в Ruby 2.2.1 (или, возможно, более ранней версии), которая специально проверяет случай, когда может присутствовать начальный знак (+ или -):
when FLOAT
if string =~ /\A[-+]?\.\Z/
@string_cache[string] = true
string
else
Float(string.gsub(/[,_]|\.$/, ''))
end