Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I control which fields to serialize with YAML

Tags:

ruby

yaml

For instance,

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

I only want to serialize x and y and leave everything else as nil.

like image 529
alexloh Avatar asked May 17 '12 02:05

alexloh


4 Answers

In Ruby 1.9, to_yaml_properties is deprecated; if you're using Ruby 1.9, a more future proof method would be to use encode_with:

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

In this case that’s all you need, as the default is to set the corresponding instance variable of the new object to the appropriate value when loading from Yaml, but in more comple cases you could use init_with:

def init_with coder
  @x = coder['x']
  @y = coder['y']
end
like image 106
matt Avatar answered Nov 01 '22 17:11

matt


You should use #encode_with because #to_yaml_properties is deprecated:

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

or you might prefer this if eval is too dangerous and you only need to filter out one instance var. All other vars need to have an accessor:

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
like image 20
Simon Duncombe Avatar answered Nov 01 '22 15:11

Simon Duncombe


After an inordinate amount of searching I stumbled on this:

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

This method is used to select the properties that YAML serializes. There is a more powerful approach that involves custom emitters (in Psych) but I don't know what it is.

This solution only works in Ruby 1.8; in Ruby 1.9, to_yaml has switched to using Psych, for which Matt's answer using encode_with is the appropriate solution.

like image 43
alexloh Avatar answered Nov 01 '22 17:11

alexloh


If you want all fields but a few, you could do this

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

This stops you from manually having to manage the list. Tested on Ruby 1.9

like image 31
jessebs Avatar answered Nov 01 '22 17:11

jessebs