Exploring Ruby's Global Constants and Variables

Exploring Ruby's Global Constants and Variables

By default, Ruby defines many constants and global variables that can be used in the code to get information about the current state of the application and the runtime. In this article we’ll go over most of them to understand what they are and what information we can set and get to simplify our scripts or to debug problems.

Global Constants

In Ruby, a constant encompasses many concepts: it can be a class, a module, or a primitive value. Global constants are actually defined as constants of the Object class, so RUBY_PLATFORM and Object::RUBY_PLATFORM are equivalent.

If we execute Object.constants we can get a list of all the global constants. This includes classes (like the Exception class), modules (like the JSON module), and others like RUBY_PLATFORM or ARGV that are primitives (a string and an array, respectively).

Useless fact: Object is a global constant, so it’s defined as a constant inside Object itself, so Object::Object::Object is equivalent to Object.

Let’s explore some of them.

RUBY_PLATFORM, RUBY_VERSION, RUBY_*

There are many constants that we can use to know which version of the engine and which version of Ruby is executing our code. We can also check the Operating System and the architecture.

These are the values when I check them in my system:

RUBY_COPYRIGHT # "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto"
RUBY_DESCRIPTION # "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]"
RUBY_ENGINE # "ruby"
RUBY_ENGINE_VERSION # "3.2.2"
RUBY_PATCHLEVEL # 53
RUBY_PLATFORM # "x86_64-linux"
RUBY_RELEASE_DATE # "2023-03-30"
RUBY_REVISION # "e51014f9c05aa65cbf203442d37fef7c12390015"
RUBY_VERSION # "3.2.2"

Here we can see that I’m running MRI 3.2.2 (RUBY_ENGINE would be jruby if using JRuby for example). In the case of MRI, RUBY_ENGINE_VERSION and RUBY_VERSION always match but, when using another implementation, the RUBY_VERSION will always show the equivalent MRI version while RUBY_ENGINE_VERSION shows the version number of that particular Ruby engine. We can also see it’s a linux OS with an x86_64 architecture for the CPU.

STDIN, STDOUT, STDERR

These constants are the defaults for the standard input, standard output, and the standard error output. These are used as the default values for the $stdin, $stdout, and $stderr global variables. Trying to change them will display a warning (it will still change it though):

STDERR = my_io_object
(irb):18: warning: already initialized constant STDERR

While trying to change the global variable is the expected method, if needed:

$stderr = my_io_object

These constants are not meant to be changed to always keep a reference to the original IO.

ARGV, ARGF

These 2 constants are related to the input passed to the process.

  • ARGV is an array of strings with all the arguments for the command.
  • ARGF behaves similar to a File object, but instead of referencing one file in the file system, it is a wrapper around all the files passed as arguments to the current process (or any file listed in the ARGV constant). Some of the File-like methods are invoked on the current file (like close, that will move the reading position to the beginning of the next file), but some are invoked for the complete list of files (like readlines that will read the lines of all the files at once). This is the documentation for the ARGF class opens a new window to see all the methods.

ENV

This constant is commonly used because of the Twelve Factor App opens a new window methodology. It lists all environment variables.

DATA

The DATA constant is only defined when executing a script (it’s not defined for IRB for example), and only if the special __END__ content is present.

This is a File object pointing to the current script file, but positioned in the line right after __END__.

From the source opens a new window :

$ cat t.rb
puts DATA.gets
__END__
hello world!

$ ruby t.rb
hello world!

In that example, DATA.gets reads the content of the file after __END__, which is the string "hello world!", and then it’s printed out.

Global Variables

Global variables always start with the $ character. New global variables can also be defined at runtime by prefixing them with $. Ruby includes many global variables by default, some of them are read-only or meant to be modified by Ruby itself.

When working with Ractors and Threads, some of these variables are “global” but only in the context of that Ractor/Thread.

These default variables are always named with the pattern of $ followed by 1 or 2 characters, but some aliased variables are defined when requiring the English module.

puts $$ # => current process id
puts $PID # => nil
require 'English' => # true
puts $PID # => current process id

Ruby Options

These variables are used to know if certain options were passed to the program.

The $-a, $-p, $-l, $-i, $-K, $-F, $-d (alias of $DEBUG), $-w/$-v (aliases of $VERBOSE) variables are all mapped to flags that can be passed to the ruby command listed when running ruby -h. Most of them are either true or false for boolean flags, except for $-i that is either a string with the extension name or nil, and $-w/$-v that can be a boolean (for warning levels 1 and 2) or nil (when warnings are disabled).

The longer-named variables $DEBUG and $VERBOSE are present by default, requiring the English module is not needed.

Regexp Options

When working with regular expressions, after a successful match many global variables are populated with information about it.

  • $~ ($LAST_MATCH_INFO) The information about the last match in the current scope (thread-local and frame-local).
  • $& ($MATCH) The string matched by the last successful match.
  • $` ( $PREMATCH) The string to the left of the last successful match.
  • $' ($POSTMATCH) The string to the right of the last successful match.
  • $+ ($LAST_PAREN_MATCH) The highest group matched by the last successful match.
  • $N The Nth group of the last successful match, with N being an integer greater than 1.

The longer-named variable aliases are added when requiring the English module.

So, given this regexp match "Hello World!" =~ /e(llo) (\w+)rl/, the variables are populated with this values:

puts $~ # => #<MatchData "ello Worl" 1:"llo" 2:"Wo"> (the match and each group)
puts $& # => "ello Worl" (the match)
puts $` # => "H" (the string to the left of the match)
puts $' # => "d!" (the string to the right of the match)
puts $+ # => "Wo" (the last group)
puts $1 # => "llo"
puts $2 # => "Wo
puts $3 # => nil

Process Information

These variables are useful to find information about the current process or child processes.

  • $$ (or $PID, or $PROCESS_ID) shows the current process id.
  • $? (or $CHILD_STATUS) shows the exit code of the last child process.
  • $0 shows the name of the current script.

The longer-named variable aliases are added when requiring the English module.

Input and Output

There are many variables related to the input and output of the process. These should be used carefully because some of this variables affect methods like Kernel#print or String#split.

  • $< (or DEFAULT_INPUT) is the same as the ARGF constant.
  • $FILENAME is equivalent to ARGF.filename and shows the file name of the current file being read by ARGF.
  • $* (or $ARGV) is the same as the ARGV constant.
  • $stdin references the current standard input IO object.
  • $stdout references the current standard output IO object.
  • $stderr references the current standard error output IO object.
  • $> references the standard input IO object used specifically for the Kernel#print and Kernel#printf methods.
  • $;/$-F (or $FS, or $FIELD_SEPARATOR) specifies the default separator for String#split, it can be changed at runtime but also defined using the -F flag when running Ruby.
  • $, (or $OFS, or $OUTPUT_FIELD_SEPARATOR) specifies the default separator used by String#join and when printing an array with Kernel#print. Note that this should not be used in new code since it will be deprecated.
  • $//$-0 (or $RS, or $INPUT_RECORD_SEPARATOR) specifies the default separator that is used to determine when a record ends in the input. This is the newline character by default since the most common case is to read lines from a file and can be configured with the -0 Ruby flag. This can be used to change how methods like Kernel#gets work for different input formats.
  • $\ (or $ORS, or $OUTPUT_RECORD_SEPARATOR), similar to the $/ variable but specifies the separator used when outputting data with methods like Kernel#print or IO#write instead of when reading input.
  • $_ (or $LAST_READ_LINE) holds the last string that was read using the Kernel.gets or Kernel#readline methods.
  • $F is the array resulting of applying String#split to the value of $_ when the $-a flag is true.
  • $. (or $NR, or $INPUT_LINE_NUMBER) holds the line number of the line that was last read in $_.

The longer-named variable aliases are added when requiring the English module.

Exceptions

When dealing with exceptions, there’s no need to store them in a local variable or pass them around as arguments. Ruby will populate two variables with the information of the last exception that was raised:

  • $! (or $ERROR_INFO) is a reference to the last Exception that was raised.
  • $@ (or $ERROR_POSITION) is the stack trace of the last exception (so it’s equivalent to $!.backtrace).

These variables are thread-local, so an exception inside a thread will not modify the same variables in a different thread.

The longer-named variable aliases are added when requiring the English module.

$LOAD_PATH

This variable is really important. It specifies an array with the different paths where Ruby will look for files when using the Kernel#load and Kernel#require methods.

It can be modified to point Ruby in the right direction when we want to be sure it will load the script we want to. This can be also modified to add custom non-standard directories where we have important scripts.

Bundler uses this variable opens a new window to ensure that we always use the same gem versions.

The variable is aliased as $: and $-I, and the value can me changed at runtime but also with the -I Ruby flag.

The long-name version is defined by Ruby by default, there’s no need to include the English module.

$LOADED_FEATURES

Last but not least, the $LOADED_FEATURES is an array that lists all the paths for rb and so files that were already loaded by Ruby.

This variable can be inspected to debug problems to check if a file we expect to be loaded is actually loaded or not, and to find out if files we don’t expect to be loaded actually are.

It’s aliased as $".

The long-name version is defined by Ruby by default, there’s no need to include the English module.

Conclusion

Ruby’s global constants and variables provide a lot of information about the process and the current state of the app. They can come in handy when creating new scripts and working with inputs, also when dealing with exceptions, and for debugging problems. The Ruby and OS information is also important when dealing with code that should work cross-platform.

Finally, the $LOADED_FEATURES variable can help you find code that is loaded that you don’t need, to optimize the performance of the app.

Do you need help with your Ruby app? Let’s see how we can help! opens a new window !

Resources:

Get the book