1

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

这是我的测试:

# 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!

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

我有几个问题:

  1. 造成这种差异的原因是什么?
  2. 新版本的ruby​​ / rails是否会出现此问题?
  3. 我怎样才能以兼容的方式正确解决这个问题?

谢谢您的帮助。

4

1 回答 1

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.

于 2012-07-09T19:30:13.273 回答