Bignum problems

The problems with Bignums in recent YAMLs have been discussed(*), but
does anyone have a patch that can be loaded in ruby code to get around
it?

This just turned into a minor disaster for me…

$ ruby -v
ruby 1.8.4 (2005-12-24) [i686-linux]
$ ruby -r yaml -e ‘y 1234567890’
— !ruby/object:Bignum 1234567890
$ ruby -r yaml -e ‘YAML.load 1234567890.to_yaml’
/usr/local/lib/ruby/1.8/yaml.rb:133:in transfer': allocator undefined for Bignum (TypeError) from /usr/local/lib/ruby/1.8/yaml.rb:133:in load’
from -e:1

(*)
http://groups.google.com/group/comp.lang.ruby/browse_frm/thread/4d62fa19fc7f4ffe/2331cd65b83bffe2?q=YAML+Bignum&rnum=1#2331cd65b83bffe2

Joel VanderWerf wrote:

/usr/local/lib/ruby/1.8/yaml.rb:133:in transfer': allocator undefined for Bignum (TypeError) from /usr/local/lib/ruby/1.8/yaml.rb:133:in load’
from -e:1

(*)
http://groups.google.com/group/comp.lang.ruby/browse_frm/thread/4d62fa19fc7f4ffe/2331cd65b83bffe2?q=YAML+Bignum&rnum=1#2331cd65b83bffe2

Answering my own question, but it’s a hack…

class Bignum
def to_yaml( opts = {} )
super.sub(/!ruby/object:Bignum /, “”)
end
end

s = 1000000000000000.to_yaml
puts s
p YAML.load(s)

OUTPUT:

— 1000000000000000
1000000000000000

Hello,

The latest ruby cvs seems to work ok?

bash-3.00# ruby -r yaml -e ‘y 1234567890000000000000’
— 1234567890000000000000
bash-3.00# ruby -r yaml -e ‘YAML.load 1234567890000000000000.to_yaml’
bash-3.00# ruby -v
ruby 1.8.4 (2006-03-04) [i386-solaris2.10]

Ville Mattila wrote:

Hello,

The latest ruby cvs seems to work ok?

bash-3.00# ruby -r yaml -e ‘y 1234567890000000000000’
— 1234567890000000000000
bash-3.00# ruby -r yaml -e ‘YAML.load 1234567890000000000000.to_yaml’
bash-3.00# ruby -v
ruby 1.8.4 (2006-03-04) [i386-solaris2.10]

That’s good to hear. I’d rather not have to install from cvs in all my
locations, but my workaround didn’t work (see below), so maybe that’s
necessary.

$ ruby
require ‘yaml’

class Bignum
def to_yaml( opts = {} )
super.sub(/!ruby/object:Bignum /, “”)
end
end

h={}
h[1] = 1000000000000000
y h

-:5:in to_yaml': private methodsub’ called for
#YAML::Syck::Scalar:0xb7b6d03c (NoMethodError)
from /usr/local/lib/ruby/1.8/yaml/rubytypes.rb:41:in to_yaml' from /usr/local/lib/ruby/1.8/yaml/rubytypes.rb:40:into_yaml’
from /usr/local/lib/ruby/1.8/yaml/rubytypes.rb:39:in to_yaml' from /usr/local/lib/ruby/1.8/yaml.rb:387:inquick_emit’
from /usr/local/lib/ruby/1.8/yaml/rubytypes.rb:38:in to_yaml' from /usr/local/lib/ruby/1.8/yaml.rb:117:indump’
from /usr/local/lib/ruby/1.8/yaml.rb:428:in `y’
from -:11

Joel VanderWerf [email protected] writes:

h={}
h[1] = 1000000000000000
y h

This works fine with CVS ruby, without your special hack.
So probably the cvs is way to go.

irb(main):001:0> require ‘yaml’
=> true
irb(main):002:0>
irb(main):003:0* h={}
=> {}
irb(main):004:0> h[1] = 1000000000000000
=> 1000000000000000
irb(main):005:0> y h

1: 1000000000000000
=> nil

Joel,

If it’s helpfuly, here’s the small patch we’ve been using in Gentoo
that I believe fixes this:

— ext/syck/rubyext.c 27 Sep 2005 22:57:52 -0000 1.30.2.15
+++ ext/syck/rubyext.c 5 Oct 2005 10:24:16 -0000
@@ -1142,6 +1142,9 @@
}
else if ( !NIL_P( target_class ) )
{

  •            if (subclass == rb_cBignum)
    
  •                obj = rb_str2inum(val, 10);
    
  •            else
                obj = rb_obj_alloc( subclass );
                if ( rb_respond_to( obj, s_yaml_initialize ) )
                {

Joel VanderWerf wrote:

/usr/local/lib/ruby/1.8/yaml.rb:133:in transfer': allocator undefined for Bignum (TypeError) from /usr/local/lib/ruby/1.8/yaml.rb:133:in load’
from -e:1

(*)
http://groups.google.com/group/comp.lang.ruby/browse_frm/thread/4d62fa19fc7f4ffe/2331cd65b83bffe2?q=YAML+Bignum&rnum=1#2331cd65b83bffe2

I think this workaround actually works:

if RUBY_VERSION == “1.8.4”
class Bignum
def to_yaml( opts = {} )
YAML::quick_emit( nil, opts ) { |out|
out.scalar( nil, to_s, :plain )
}
end
end
end

…that sure beats compiling cvs for several platforms and distributing
it to users.