I'm trying to dump duration objects (from the ruby-duration gem) to yaml with a custom type, so they are represented in the form hh:mm:ss
. I've tried to modify the answer from this question, but when parsing the yaml with YAML.load, a Fixnum is returned instead of a Duration. Interestingly, the Fixnum is the total number of seconds in the duration, so the parsing seems to work, but convert to Fixnum after that.
My code so far:
class Duration
def to_yaml_type
"!example.com,2012-06-28/duration"
end
def to_yaml(opts = {})
YAML.quick_emit( nil, opts ) { |out|
out.scalar( to_yaml_type, to_string_representation, :plain )
}
end
def to_string_representation
format("%h:%m:%s")
end
def Duration.from_string_representation(string_representation)
split = string_representation.split(":")
Duration.new(:hours => split[0], :minutes => split[1], :seconds => split[2])
end
end
YAML::add_domain_type("example.com,2012-06-28", "duration") do |type, val|
Duration.from_string_representation(val)
end
To clarify, what results I get:
irb> Duration.new(27500).to_yaml
=> "--- !example.com,2012-06-28/duration 7:38:20\n...\n"
irb> YAML.load(Duration.new(27500).to_yaml)
=> 27500
# should be <Duration:0xxxxxxx @seconds=20, @total=27500, @weeks=0, @days=0, @hours=7, @minutes=38>
It look like you’re using the older Syck interface, rather that the newer Psych. Rather than using to_yaml
and YAML.quick_emit
, you can use encode_with
, and instead of add_domain_type
use add_tag
and init_with
. (The documentation for this is pretty poor, the best I can offer is a link to the source).
class Duration
def to_yaml_type
"tag:example.com,2012-06-28/duration"
end
def encode_with coder
coder.represent_scalar to_yaml_type, to_string_representation
end
def init_with coder
split = coder.scalar.split ":"
initialize(:hours => split[0], :minutes => split[1], :seconds => split[2])
end
def to_string_representation
format("%h:%m:%s")
end
def Duration.from_string_representation(string_representation)
split = string_representation.split(":")
Duration.new(:hours => split[0], :minutes => split[1], :seconds => split[2])
end
end
YAML.add_tag "tag:example.com,2012-06-28/duration", Duration
p s = YAML.dump(Duration.new(27500))
p YAML.load s
The output from this is:
"--- !<tag:example.com,2012-06-28/duration> 7:38:20\n...\n"
#<Duration:0x00000100e0e0d8 @seconds=20, @total=27500, @weeks=0, @days=0, @hours=7, @minutes=38>
(The reason the result you’re seeing is the total number of seconds in the Duration is because it is being parsed as sexagesimal integer.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With