整数范围的Rails序列化被打破

时间:2012-07-09 17:16:29

标签: ruby-on-rails ruby serialization range yaml

我需要在rails上下文中使用YAML序列化ruby Range。 我想检查整数范围和字符串范围是否正确序列化。

这是我的测试:

# classic irb
require 'yaml'         # => true
YAML::VERSION          # => "0.60"
YAML.dump(1..2)        # => "--- !ruby/range \nbegin: 1\nend: 2\nexcl: false\n"
YAML.dump("1".."2")    # => "--- !ruby/range \nbegin: \"1\"\nend: \"2\"\nexcl: false\n"

两个输出是完全不同的,所以我前进并在我的rails应用程序中编码。

然而,似乎在rails上下文中,ruby忘记了如何正确序列化一系列整数!

# ./script/rails console
Rails::VERSION::STRING # => "3.0.15"
RUBY_VERSION           # => "1.8.7"
YAML::VERSION          # => "0.60"
YAML.dump(1..2)        # => "--- !ruby/range\n  begin: 1\n  end: 2\n  excl: false"
YAML.dump("1".."2")    # => "--- !ruby/range\n  begin: 1\n  end: 2\n  excl: false"
# The two outputs are identical, the distinction between integers and strings is lost!

rails上的ruby和ruby似乎都使用相同版本的YAML库。 如果我没有弄错,我的ruby版本不支持在多个编码器引擎之间切换。

我有几个问题:

  1. 造成这种差异的原因是什么?
  2. 新版本的 ruby​​ / rails 是否会出现此问题?
  3. 我怎样才能以兼容的方式正确修复?
  4. 感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

范围是Ruby内部,而不是像整数或字符串的YAML基类型。而不是按原样编码范围,使用其起点和终点并重建接收端的范围。

我用的是:

[1] (pry) main: 0> range = 0..1
=> 0..1
[2] (pry) main: 0> require 'yaml'
=> true
[3] (pry) main: 0> YAML.dump(range)
=> "--- !ruby/range\nbegin: 0\nend: 1\nexcl: false\n"
[4] (pry) main: 0> YAML.dump({'min' => range.min, 'max' => range.max})
=> "---\nmin: 0\nmax: 1\n"

然后我可以使用类似的东西在接收端重新创建范围:

Range.new(*YAML.load(YAML.dump({'min' => range.min, 'max' => range.max})).values)
=> 0..1

或如果您不确定'min''max'的顺序是否正确,请执行以下操作:

[19] (pry) main: 0> Range.new(*YAML.load(YAML.dump({'min' => range.min, 'max' => range.max})).values_at('min', 'max'))
=> 0..1

添加有关Ruby 1.9.3+序列化字符范围的一些信息:

[2] (pry) main: 0> range = '0'..'1'
=> "0".."1"
[3] (pry) main: 0> YAML.dump(range)
=> "--- !ruby/range\nbegin: '0'\nend: '1'\nexcl: false\n"

[5] (pry) main: 0> RUBY_VERSION
=> "1.9.3"

再次使用1.9.2 +:

[2] (pry) main: 0> range = '0'..'1'
=> "0".."1"
[3] (pry) main: 0> YAML.dump(range)
=> "--- !ruby/range \nbegin: \"0\"\nend: \"1\"\nexcl: false\n"
[4] (pry) main: 0> RUBY_VERSION
=> "1.9.2"

并且,变通方法维护范围开始/结束类型:

[6] (pry) main: 0> Range.new(*YAML.load(YAML.dump({'min' => range.min, 'max' => range.max})).values_at('min', 'max'))
=> "0".."1"

在这两种情况下,YAML_VERSION都是0.60