Ví dụ,Làm thế nào tôi có thể kiểm soát các lĩnh vực để serialize với YAML
class Point
attr_accessor :x, :y, :pointer_to_something_huge
end
Tôi chỉ muốn serialize x và y và để lại mọi thứ khác như con số không.
Ví dụ,Làm thế nào tôi có thể kiểm soát các lĩnh vực để serialize với YAML
class Point
attr_accessor :x, :y, :pointer_to_something_huge
end
Tôi chỉ muốn serialize x và y và để lại mọi thứ khác như con số không.
Tôi khuyên bạn nên thêm phương thức tùy chỉnh to_yaml
vào lớp học của bạn để xây dựng định dạng yaml cụ thể mà bạn muốn.
Tôi biết rằng to_json
chấp nhận tham số để cho biết thuộc tính nào cần tuần tự hóa, nhưng tôi không thể tìm thấy các thuộc tính cho to_yaml
.
Đây là nguồn thực tế cho 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
Vì vậy, có vẻ như có thể là một cơ hội để thiết opts
để nó bao gồm cặp khóa/giá trị cụ thể trong yaml.
Sau khi một số tiền inordinate tìm kiếm tôi loạng choạng về điều này:
class Point
def to_yaml_properties
["@x", "@y"]
end
end
Phương pháp này được sử dụng để chọn các thuộc tính mà YAML serializes. Có một cách tiếp cận mạnh mẽ hơn liên quan đến các trình phát tùy chỉnh (trong Psych) nhưng tôi không biết nó là gì.
Giải pháp này chỉ hoạt động trong Ruby 1.8; trong Ruby 1.9, to_yaml
đã chuyển sang sử dụng Psych, mà câu trả lời của Matt sử dụng encode_with
là giải pháp thích hợp.
Trong Ruby 1.9, to_yaml_properties
is deprecated; nếu bạn đang sử dụng của Ruby 1.9, một phương pháp chứng minh trong tương lai hơn là nên sử dụng encode_with
:
class Point
def encode_with coder
coder['x'] = @x
coder['y'] = @y
end
end
Trong trường hợp này đó là tất cả bạn cần, vì mặc định là để thiết lập các biến dụ tương ứng của đối tượng mới đến giá trị thích hợp khi tải từ YAML, nhưng trong trường hợp comple hơn bạn có thể sử dụng init_with
:
def init_with coder
@x = coder['x']
@y = coder['y']
end
Nếu bạn muốn tất cả các lĩnh vực nhưng một số ít, bạn có thể làm điều này
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
Điều này ngăn bạn khỏi phải tự quản lý danh sách. Thử nghiệm trên Ruby 1,9
Nếu bạn có một nhiều của các biến Ví dụ, bạn có thể sử dụng một phiên bản ngắn như thế này một
def encode_with(coder)
%w[ x y a b c d e f g ].each { |v| coder[ v ] = instance_variable_get "@#{v}" }
end
Bạn nên sử dụng #encode_with vì #to_yaml_properties bị phản đối:
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
hoặc bạn có thể thích điều này nếu eval quá nguy hiểm và bạn chỉ cần lọc ra một biến thể hiện. Tất cả vars khác cần phải có một 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
Thêm một số nhận xét vào câu trả lời của bạn. – HDJEMAI
FYI: Nếu bạn ghi đè lên '# init_with' cho một 'ActiveRecord :: Base' lớp con, hãy nhớ quay trở lại' self', nếu không bất cứ lúc nào bạn khởi tạo một mô hình nó sẽ trở lại nil. – siannopollo