Programatically get current version of ruby standard library - ruby

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

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

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.

Ruby hash.key error

I feel like I'm overlooking something here. When I try to use the Hash.key(keytolookfor) method, I get an error.
Is this method deprecated?
pete#Vader:~/tmp$ ruby -v
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-linux]
pete#Vader:~/tmp$ ./hashtest.rb
./hashtest.rb:8: undefined method `key' for {"firstkey"=>"firstvalue", "secondkey"=>"secondvalue"}:Hash (NoMethodError)
pete#Vader:~/tmp$
The script is as follows.
#!/usr/bin/ruby
testHash = Hash.new
testHash["firstkey"] = "firstvalue"
testHash["secondkey"] = "secondvalue"
if testHash.has_value?("secondvalue")
keyvalue = testHash.key("secondvalue")
puts "match found with key #{keyvalue}"
else
puts "no match found"
end
My wild guess is that your system ruby /usr/bin/ruby is 1.8.7 which doesn't have Hash#key method. ruby -v most probably shows rvm version which is located in ~/.rvm/..., but first line in your script calls /usr/bin/ruby.
Use the heap record for script as follows:
#/usr/bin/env ruby
This picks up the default ruby version specified by the system, rvm, or rbenv. Since Ruby 1.8.7 has no Hash#key, make sure that you're running at least Ruby 1.9.1:
$ /usr/bin/ruby -v
1.9.1p0
Alternatively, use Hash#[] instead:
keyvalue = testHash["secondvalue"]

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

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

Does Ruby 1.8 have an equivalent to 1.9's __callee__?

I need to grab the name of the lexically enclosing method in Ruby 1.8; e.g.
def foo
this_method = __callee__ # => 'foo'
end
The above code is valid in Ruby 1.9, but fails in 1.8, since __callee__ was introduced in 1.9.
Any suggestions for doing this in 1.8? Kernel#caller looked promising, but seems to give me the call stack starting with the caller of the method, not the method itself.
I guess I could throw an exception, catch it, and grab the first element in the Exception#backtrace array, but my gut tells me that will be slow.
On Ruby 1.8.7 there is the __method__, not sure about 1.8.6.
Anyway, You can monkey patch the Kernel module:
module Kernel
# Defined in ruby 1.9
unless defined?(__callee__)
def __callee__
caller[0] =~ /`([^']*)'/ and $1
end
end
end
Have you checked whether the "backports" gem has it?

Resources