10

例如,

class Point
  attr_accessor :x, :y, :pointer_to_something_huge
end

我只想序列化 x 和 y 并将其他所有内容都保留为 nil。

4

6 回答 6

24

在 Ruby 1.9 中,to_yaml_properties已弃用;如果您使用的是 Ruby 1.9,一个更面向未来的方法是使用encode_with

class Point
  def encode_with coder
    coder['x'] = @x
    coder['y'] = @y
  end
end

在这种情况下,这就是您所需要的,因为默认设置是在从 Yaml 加载时将新对象的相应实例变量设置为适当的值,但在更复杂的情况下,您可以使用init_with

def init_with coder
  @x = coder['x']
  @y = coder['y']
end
于 2012-05-17T22:17:54.127 回答
8

经过大量搜索后,我偶然发现了这一点:

class Point
  def to_yaml_properties
    ["@x", "@y"]
  end
end

此方法用于选择 YAML 序列化的属性。有一种更强大的方法涉及自定义发射器(在 Psych 中),但我不知道它是什么。

此解决方案仅适用于 Ruby 1.8;在 Ruby 1.9 中,to_yaml已切换到使用 Psych,Matt 的回答 usingencode_with是合适的解决方案。

于 2012-05-17T12:37:56.787 回答
1

如果您有大量实例变量,则可以使用像这样的简短版本

def encode_with( coder )
  %w[ x y a b c d e f g ].each { |v| coder[ v ] = instance_variable_get "@#{v}" }
end
于 2014-05-14T19:47:57.727 回答
1

如果你想要除少数几个以外的所有字段,你可以这样做

def encode_with(coder)
  vars = instance_variables.map{|x| x.to_s}
  vars = vars - ['@unwanted_field1', '@unwanted_field2']

  vars.each do |var|
    var_val = eval(var)
    coder[var.gsub('@', '')] = var_val
  end
end

这使您不必手动管理列表。在 Ruby 1.9 上测试

于 2014-05-13T19:54:12.890 回答
1

您应该使用#encode_with,因为不推荐使用#to_yaml_properties:

def encode_with(coder)
  # remove @unwanted and @other_unwanted variable from the dump
  (instance_variables - [:@unwanted, :@other_unwanted]).each do |var|
    var = var.to_s                       # convert symbol to string
    coder[var.gsub('@', '')] = eval(var) # set key and value in coder hash
  end
end

或者,如果 eval 太危险并且您只需要过滤掉一个实例 var,您可能更喜欢这个。所有其他变量都需要有一个访问器:

attr_accessor :keep_this, :unwanted

def encode_with(coder)
  # reject @unwanted var, all others need to have an accessor
  instance_variables.reject{|x|x==:@unwanted}.map(&:to_s).each do |var|
    coder[var[1..-1]] = send(var[1..-1])
  end
end
于 2017-03-31T14:24:45.707 回答
-2

我建议to_yaml在您的类中添加一个自定义方法,以构建您想要的特定 yaml 格式。

我知道to_json接受参数来告诉它要序列化哪些属性,但我找不到相同的to_yaml.

这是 的实际来源to_yaml

# File activerecord/lib/active_record/base.rb, line 653

  def to_yaml(opts = {}) #:nodoc:
    if YAML.const_defined?(:ENGINE) && !YAML::ENGINE.syck?
      super
    else
      coder = {}
      encode_with(coder)
      YAML.quick_emit(self, opts) do |out|
        out.map(taguri, to_yaml_style) do |map|
          coder.each { |k, v| map.add(k, v) }
        end
      end
    end
  end

所以看起来可能有机会进行设置opts,以便在 yaml 中包含特定的键/值对。

于 2012-05-17T03:01:56.137 回答