Why Does 6.Times.Map Work in Ruby 1.8.7 But Not 1.8.6

Why does 6.times.map work in ruby 1.8.7 but not 1.8.6

In 1.8.7+ iterator methods like times return an enumerator if they are called without a block. In 1.8.6 you have to do

require 'enumerator'
6.enum_for(:times).map {...}

Or for this specific use case you could simply do (0...6).map {...}

Upgrade ruby projects from 1.8.6 to 1.8.7

It should be mostly seamless, since it was mostly compatible changes to the api.

Still, check out the list of incompatibilities

If you start using the new methods offered by 1.8.7 (or newer!) but would like to remain compatible with 1.8.6, checkout my backports gem.

How to update to Ruby 1.8.7

The simplest answer is "don't". Ruby 1.8.7 was an attempt to create bridging release between 1.8 and 1.9, and the consensus of the community was that this was not necessary, so there was little support for it before 1.9 was finalized. The general recommendation is either to stick with 1.8 (the version is supplied with OS X 10.5), or use Ruby 1.9.

MacPorts has packages for Ruby 1.8.7 and Ruby 1.9, so that is probably the easiest way to get newer versions of Ruby without any risk of modifying OS X itself.

UPDATE: As ajhit406 noted, RVM is now the best option, rather than MacPorts.

Why doesn't each_slice work?

In ruby 1.8.6 you have to require 'enumerator' (which is part of stdlib and has been merged into core in 1.8.7+) before using each_slice.

Sadly the ruby-doc lists methods that are added to core classes by stdlib without mentioning where the methods are from.

RVM doesn't work for 1.9.1 but works for 1.8.6 and 1.8.7

SOLUTION!!!!
I was able to get rvm to function by doing 3 things:

  1. Navigate to usr/local/lib/
  2. sudo rm -rf libsqlite3.dylib (Caution this could be a really bad thing to do; but it worked to solve this problem)
  3. sudo port upgrade --force sqlite3 +universal and got sqlite3 and all its dependencies to build x86_64/i386 universal libraries

How to map/collect with index in Ruby?

If you're using ruby 1.8.7 or 1.9, you can use the fact that iterator methods like each_with_index, when called without a block, return an Enumerator object, which you can call Enumerable methods like map on. So you can do:

arr.each_with_index.map { |x,i| [x, i+2] }

In 1.8.6 you can do:

require 'enumerator'
arr.enum_for(:each_with_index).map { |x,i| [x, i+2] }

Is there a reason Ruby 1.8.7 is still so widely used?

My understanding was that the 1.8.7 to 1.9.x transition broke rails and thus broke a lot of web sites.

As a result of this, many of those web sites stayed with Ruby 1.8.7 and (I'm less sure about this) Rails 3.x

This traumatic transition has been referenced by Matz and many others at various Ruby conferences over the years. It is used to underline the commitment of the Ruby development team to avoid ever doing that again.

Sorry, I don't have a reference for any of these videos.

Exponentiation in Ruby 1.8.7 Returns Wrong Answers

When calculating, Ruby is supposed to convert from Fixnum to Bignum when the numbers go beyond the bounds of Fixnum. For older versions of Ruby, this fails with the ** operator:

$ ruby --version
ruby 1.8.7 (2012-02-08 patchlevel 358) [universal-darwin12.0]
$ irb
>> 2 ** 62
=> 4611686018427387904
>> 2 ** 63
=> -9223372036854775808
>> 2 ** 64
=> 0

Where it fails depends on the word size of the architecture. 64-bit words on the iMac in this example. Internally, the Fixnum is cast to a long integer, and the operator is handled with longs. The longs overflow at word size, and Ruby is ungracefully handling this by returning 0.

Note that the * operator works correctly (converting to Bignum), where the ** fails:

>> a = 2 ** 62
=> 4611686018427387904
>> 2 ** 63
=> -9223372036854775808
>> a * 2
=> 9223372036854775808
>> 2 ** 64
=> 0
>> a * 4
=> 18446744073709551616

Moving to a newer version of Ruby will fix this. If you can't move to a newer version, then avoid using Fixnum and ** with large powers.

How to run code with enumerator in Ruby 1.8?

As mentioned in this answer to a different question, in Ruby 1.8.6, you can do

require 'enumerator'
6.enum_for(:times).map {...}

But I don't know if it'll allow you to do my_enum.next.

I think the documentation is at http://ruby-doc.org/stdlib/libdoc/enumerator/rdoc/ , but it seems to be down right now.



Related Topics



Leave a reply



Submit