Need to call different Ruby method depending on what version is installed - ruby

I have a Ruby script that iterates over each line of a text file.
In Ruby 1.8.* using content.each do |line| works fine, but in Ruby 1.9.* that does not work, and I need to use content.each_line do |line|.
Since this script will be used by several different people, I need to be able to use the right method depending on their version of Ruby.
Is there a way to do this?

The global constant RUBY_VERSION contains the version of the currently running Ruby. So this script will do what you want:
if RUBY_VERSION < "1.9.2"
# code for 1.8.7
else
# code for 1.9.2+
end
If the inner code of the each_line is equal with 1.8.* and 1.9.*, the following approach is more DRY:
each_selector = RUBY_VERSION < "1.9.2" ? :each : :each_line
content.send(each_selector) do | line|
# ...
end

Related

Force .rb file running under specific ruby versions

I write a ruby script in a .rb file. It uses latest Ruby features (version 2.7). Is there any way to force this .rb file can only be executed in a specific Ruby version range? For example, the first line of a .rb file could be:
#! ruby 2.7+
# This .rb file can only be run with Ruby version 2.7 or above
Use the gem semantic to handle parsing the current Ruby version:
require 'semantic'
# Require >= 2.7 < 3
exit unless Semantic::Version.new(RUBY_VERSION).satisfies?('~> 2.7')
# Require >= 2.7, including 3 and above
exit unless Semantic::Version.new(RUBY_VERSION).satisfies?('>= 2.7')
This requires you to use bundler and a Gemfile with your app.
Other comparators are listed in the source code for the gem:
if ['<', '>', '<=', '>='].include?(comparator)
satisfies_comparator? comparator, pad_version_string(other_version_string)
elsif comparator == '~>'
pessimistic_match? other_version_string
else
tilde_matches? other_version_string
end
This will allow you to fine-tune your version requirements.
Naively,
unless RUBY_VERSION[0, 3] == "2.7"
puts "You need 2.7")
exit
end

Programatically get current version of ruby standard library

I looking for a way in my ruby program to determine the version of Ruby that is running my program as well as the version of the Standard Libary?
The version of Ruby is stored in the RUBY_VERSION global constant.
puts RUBY_VERSION
You can compare versions by using classes provided by Rubygems:
min_ruby_version = Gem::Requirement.new(">=2.2.0")
current_ruby_version = Gem::Version.new(RUBY_VERSION)
# check if ruby conforms to version req using =~ operator
if min_ruby_version =~ current_ruby_version
do_this
else
do_that
end

Why is force_encoding("BINARY") used here?

When we install Rails, we get this rails "executable":
#!/usr/bin/env ruby
#
# This file was generated by RubyGems.
#
# The application 'railties' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first
str = ARGV.first
str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding
if str =~ /\A_(.*)_\z/ and Gem::Version.correct?($1) then
version = $1
ARGV.shift
end
end
gem 'railties', version
load Gem.bin_path('railties', 'rails', version)
I'm wondering what the point of doing force_encoding("BINARY") is on that String. What possible values could it be that force_encoding is necessary? I would think that people would only specify versions using numbers and letters here.
This isn't a rails specific thing - it's a wrapper rubygems will generate for any ruby executable in a gem. The call to force_encoding was added in 6bf71914
The reason for the change is that the first argument might not be a version at all - we want to test if it is a version, but it could be anything and we don't want the regex check to blow up. For example some executables accept a list of file names as arguments, and those file names could be invalid in the default external encoding used by ruby.
There is a bit more discussion on the issue which prompted this change.

Array#to_s in Ruby 2.1 broke my code

This code broke on Ruby 2.1
class Test
def to_s()
"hi"
end
end
puts [Test.new(), Test.new()].to_s
Ruby 1.9.3:
$ ruby --version
ruby 1.9.3p484 (2013-11-22 revision 43786) [x86_64-linux]
$ /opt/chef/embedded/bin/ruby test.rb
[hi, hi]
Ruby 2.1:
$ ruby --version
ruby 2.1.4p265 (2014-10-27 revision 48166) [x86_64-linux]
$ ruby test.rb
[#<Test:0x000000022ac400>, #<Test:0x000000022ac3d8>]
Is this documented somewhere? How can the old behavior be preserved?
Your code:
puts [Test.new(), Test.new()].to_s
is a questionable use of Array.to_s. Instead I'd use:
puts [Test.new(), Test.new()].map(&:to_s)
While I can see that the first use makes sense, the second use makes more sense and should work in any version of Ruby.
On ruby 2.1.5:
class Test
def to_s
"hi"
end
alias inspect to_s # add this line
end
puts [Test.new, Test.new].to_s
#=> [hi, hi]
This seems like a bug to me. If it is intended behavior, that is really annoying.
You don't need to_s. puts does the work for you
puts [Test.new(), Test.new()]
# hi
# hi
If you want the brackets, that's what inspect is for (in which case it makes sense that you would need to define Test#inspect).

How to run code with enumerator in Ruby 1.8?

I have code like this
my_enum = [1,2].to_enum
puts my_emum.next
and it doesn't work
I understand that the enumerator is available in Ruby 1.8 as an extension. How to install it?(I'm new to ruby)
If I fix the typo it works fine. irb session follows.
>> my_enum = [1,2].to_enum
=> #<Enumerable::Enumerator:0xb79dd700>
>> puts my_enum.next
1
>> puts my_enum.next
2
Tested in
>> VERSION
=> "1.8.7"
What version of ruby 1.8 are you running? This matters significantly.
(Also note that you have a typo in "my_emum").
In Ruby 1.8.6 , there is no "next" method for enums, just "each".
Example:
my_enum = [1,2].to_enum
my_enum.each do |e|
puts e
end
In Ruby 1.8.7, "next" is supported.
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.

Resources