Search code examples
rubyjrubyrubymine

Run a block of legacy code in compliance with an older Ruby language version


I wasn't sure what to title this question, so if you wan't to change it, be my guest.

I am wondering if there is some way to run a block of Ruby code in compliance with a previos version of the ruby language. It would essentially be some sort of 'compatability mode' but only for a block of code.

My idea was to chagne the RUBY_VERSION global variable, and see if Ruby then behaved as it would in that version, but this seems to do nothing. Here is my attempt:

puts RUBY_VERSION

an_object = Time.now

an_object.tap do |o|
  puts 'in tep function'
end # ===> an_object

RUBY_VERSION = 1.7 #potentially change ruby version to an older version to run legacy code

#attempt to run a function that was not available in version 1.7, (just an example)
an_object.tap do |o|
  puts 'in tep function'
end # ===> an_object

puts RUBY_VERSION

I realize that I could code a conditional, and test the current version of Ruby, and then execute code based on the results of that test, but that doesn't fit my needs, and it would be better to just re-factor all of our unit tests and acceptance tests if it came down to this.


Solution

  • If you have multiple rubies installed on your system, for example with rbenv:

    ls -l ~/.rbenv/versions/
    drwxr-xr-x  5 jared  staff  170 Nov  7 13:59 1.8.7-p374
    drwxr-xr-x  6 jared  staff  204 Oct 31 15:02 2.1.1
    drwxr-xr-x  6 jared  staff  204 Oct 30 12:19 2.1.2
    drwxr-xr-x  6 jared  staff  204 Oct 30 12:03 2.1.4
    

    .. then you can "shell out" from the newer ruby to the older ruby. I recommend using Open3.popen3 for this, but there are simpler methods, like Kernel#system.

    $ ruby --version
    ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]
    $ irb
    irb(main):002:0> ruby = "/Users/jared/.rbenv/versions/1.8.7-p374/bin/ruby"
    irb(main):016:0> Open3.popen3(ruby) { |stdin, stdout, stderr, wait_thr|
    irb(main):017:1*   stdin.puts "puts RUBY_VERSION"
    irb(main):018:1>   stdin.close
    irb(main):019:1>   puts stdout.read
    irb(main):020:1> }
    1.8.7
    => nil
    

    How to get your "old ruby" code as a string is left as an exercise to the reader. Maybe try Method#source_location?

    Another challenge will be how to return objects from the "old ruby". Serializing with YAML is one option.

    However, I agree with @p11y that "the only sustainable solution to this is to port the code to the newer Ruby".