I recently switched to ruby 1.9.3 as my deafult ruby verison, and suddenly some of my scripts started to fail in some funny ways.
One of the latest ones was the script that was supposed to change ‘updated’ timestamp in a YAML formatted file. Instead of the current date it started to spit out binary strings.
The problem is quite complext but the fix is simple…
I recently switched to ruby 1.9.3 as my deafult ruby verison, and suddenly some of my scripts started to fail in funny ways.
One of the latest ones was the script that was supposed to change ‘updated’ timestamp in a YAML formatted file. Instead of the current date it started to spit out binary strings.
The problem is quite complext but the fix is simple…
First lets see what happens:
In ruby 1.9.2p320
:
> require 'yaml'
=> true
> Time.now.to_s.to_yaml
=> "--- 2012-09-03 22:20:15 +0300\n"
In ruby 1.9.3p194
:
> require 'yaml'
=> true
> Time.now.to_s.to_yaml
=> "--- !binary |-\n MjAxMi0wOS0wMyAyMjoyMDozMCArMDMwMA==\n"
Why did that happen?
This happens because Time.now.to_s
returns a non-ascii string
> Time.now.to_s.encoding
=> #<Encoding:ASCII-8BIT>
To remind you, UTF-8
is backwards compatible with the standard 7bit
ASCII
, as the ASCII is just the subset of UTF8 where the 8th bit is 0;
So to output an 8bit ASCII
in UTF-8
a conversion might be required
(for example when time format contains regional characters from the upper part
of the 8bit ASCII
).
It is the same in 1.9.2 but apparently YAML over there knows how to handle it in the case when the string doesn’t actually contain any 8bit characters.
In 1.9.3, instead of performing conversions YAML seems to just opting for the ‘lets treat it as a binary’ handling.
The problem of encodings is complex and “hairy”, so we wont go into details here, but in the case when you just need a quick fix like I did you do this:
> YAML::ENGINE.yamler='syck'
=> "syck"
> Time.now.to_s.to_yaml
=> "--- 2012-09-03 22:24:22 +0300\n"
And the problem solved.