From: daz Date: 2005-10-02T21:36:46+09:00 Subject: Re: beginners YAML question On 2005/09/06, Adam Shelly wrote: > On 2005/09/02, daz wrote: > > In short, @size is an attribute of Box ... but you're > > using the inherited Array#to_yaml to serialise your object. > > > [...] > > That's exactly what I want. A "Box" object which acts like an array, > but has other attributes too: > For example: > [...] > > What I can't figure out is how to get the extra attributes in the > YAML. Do I have to override the to_yaml method? > Hey, Adam! So sorry - I missed this post. (Just found it whilst browsing through the archives.) Yes, you'll need to override the to_yaml method that is already overridden by Array. Ideally, you'd just want to undo the override but I don't think that's advisable, even if it's possible. Either: 1) Add this to Box#initialize self.class.class_eval do ( Object.instance_methods - instance_methods(false) ).grep(/yaml/) do |meth| define_method( meth, Object.instance_method(meth) ) end end That'll copy all yaml methods from Object into Box that were concealed as a consequence of inheriting the same-named methods from Array. (Array is interposed between Box and Object). - OR - 2) The canonical way, AFAICS, is to redefine them in the Box class, which would look similat to this: (see: ruby/lib/ruby/1.8/yaml/rubytypes.rb) def to_yaml_type "!ruby/object:#{self.class}" end def to_yaml_properties instance_variables # all ... OR ... ### ['@label', '@loc'] # your selection end def to_yaml( opts = {} ) YAML.quick_emit(nil, opts) do |out| out.map(to_yaml_type) do |map| to_yaml_properties.sort.each do |iv| map.add( iv[1..-1], instance_eval(iv) ) end end end end ------------- I think the definition of 'to_yaml' above looks like it's doing something tailored to your class, so here's another alternative: def to_yaml( opts = {} ) Object.instance_method(:to_yaml).bind(self).call(opts) end ------------- You probably worked it out yourself but this is something to compare against. BTW, an alternative to Box < Array is to delegate. The top of your class would look like this: require 'delegate' class Box < DelegateClass(Array) def initialize label, location, initial_size ... super Array.new(initial_size, initial_value) Have a look here: http://www.rubycentral.com/book/lib_patterns.html#S1 Cheers, daz