What Are the Magic $-Prefixed Variables in Ruby

What are the magic $-prefixed variables in Ruby?

Their name is global variables. There are several different references.

You can get a full list by calling the method Kernel#global_variables

puts global_variables

Ruby also includes a file called "English.rb" in the standard library which provides an in-depth explanation of several global variables.

Also, there's (an archived version of) "Cryptic Ruby Global Variables and Their Meanings".

Finally, the Ruby Programming wikibook has a "Predefined Variables" reference.

What do $&, $', $1 etc. mean in Ruby code?

Those hold parts of the last regex match. $&: the matched substring, $': the substring that follows the match, $1: the first captured substring of the match.

What does *$ mean in Ruby?

$< is ARGF. From ruby's standard docummentation:

ARGF is a stream designed for use in scripts that process files given as command-line arguments or passed in via STDIN.

A super good explanation here

* is splat operator.

You are assigning to a and n what's inside ARGF/STDIN at that point.

Example:

raducroitoru@dotix ~$ cat a.txt                                         
a
b
c

raducroitoru@dotix ~$ cat a.rb
a, n = *$<
puts "a is: #{a}"
puts "n is: #{n}"

raducroitoru@dotix ~$ ruby a.rb a.txt
a is: a
n is: b

What does @@variable mean in Ruby?

A variable prefixed with @ is an instance variable, while one prefixed with @@ is a class variable. Check out the following example; its output is in the comments at the end of the puts lines:

class Test
@@shared = 1

def value
@@shared
end

def value=(value)
@@shared = value
end
end

class AnotherTest < Test; end

t = Test.new
puts "t.value is #{t.value}" # 1
t.value = 2
puts "t.value is #{t.value}" # 2

x = Test.new
puts "x.value is #{x.value}" # 2

a = AnotherTest.new
puts "a.value is #{a.value}" # 2
a.value = 3
puts "a.value is #{a.value}" # 3
puts "t.value is #{t.value}" # 3
puts "x.value is #{x.value}" # 3

You can see that @@shared is shared between the classes; setting the value in an instance of one changes the value for all other instances of that class and even child classes, where a variable named @shared, with one @, would not be.

[Update]

As Phrogz mentions in the comments, it's a common idiom in Ruby to track class-level data with an instance variable on the class itself. This can be a tricky subject to wrap your mind around, and there is plenty of additional reading on the subject, but think about it as modifying the Class class, but only the instance of the Class class you're working with. An example:

class Polygon
class << self
attr_accessor :sides
end
end

class Triangle < Polygon
@sides = 3
end

class Rectangle < Polygon
@sides = 4
end

class Square < Rectangle
end

class Hexagon < Polygon
@sides = 6
end

puts "Triangle.sides: #{Triangle.sides.inspect}" # 3
puts "Rectangle.sides: #{Rectangle.sides.inspect}" # 4
puts "Square.sides: #{Square.sides.inspect}" # nil
puts "Hexagon.sides: #{Hexagon.sides.inspect}" # 6

I included the Square example (which outputs nil) to demonstrate that this may not behave 100% as you expect; the article I linked above has plenty of additional information on the subject.

Also keep in mind that, as with most data, you should be extremely careful with class variables in a multithreaded environment, as per dmarkow's comment.

Is it good practice having local variables starting with underscore?

Nothing wrong with your idea. But if I was having trouble distinguishing local vars from method calls, I would probably just force myself to always use ()'s on methods. (My team at work has discussed making this part of our coding standards).

a = thing # var
b = thing() # method

The possible advantage to this is readability to others. Someone may wonder at your leading _'s, but using ()'s on all method calls should be clear to everyone.

Reasoning for Language-Required Variable Name Prefixes

Two part answer, StudyTRAX is almost certainly using a preprocessor to do some magic. JavaScript makes this relativity easy, but not as easy as a Lisp would. You still need to parse the code. By prefixing, the parser can ignore a lot of the complicated syntax of JavaScript and get to the good part without needing a "picture perfect" compiler. Actually, a lot of templeting systems do this. It is an implementation of Lisp's quasi-quote (see Greenspun's Tenth Rule).

As for prefixes in general, the best way to understand them is to try to write a parser for a language without them. For very dynamic and pure languages like Lisp and JavaScript where everything is a List / object it is not too bad. When you get languages where methods are distinct from objects, or functions are not first class the parser begins having to ask itself what type of thing doe "foo" refer to? An annoying example from Ruby: an unprefixed identifier is either a local variable or a method implicitly on self. In Rails there are a few functions that are implemented with method_missing. Person.find_first_by_rank works fine, but

Class Person < ActiveRecord::Base
def promotion(name)
p = find_first_by_rank
[...]
end
end

gives an error because find_first_by_rank looks like it might be a local variable and Ruby is scared to call method_missing on something that might just be a misspelled local variable.

Now imagine trying to distinguish between instance variables (prefix-@), class-variables (prefix-@@), global variables (prefix-$), Constants (first letter Capitol), method names and local variables (no prefix small case) by context alone.

Behaviours of a Ruby local variable shadowing an instance method

What looks like inconsistent return values for name during runtime and while debugging doesn't seem to related to Pry, but more about binding itself encapsulating the entire execution context of a method, versus the progressive change in what shadowed variables reference at runtime. To build on the example method with some more debugging code:

def say_name
puts "--- Before assignment of name: ---"
puts "defined?(name) : #{defined?(name).inspect}"
puts "binding.local_variable_defined?(:name) : #{binding.local_variable_defined?(:name).inspect}"

puts "local_variables : #{local_variables.inspect}"
puts "binding.local_variables : #{binding.local_variables.inspect}"

puts "name : #{name.inspect}"
puts "binding.eval('name') : #{binding.eval('name').inspect}"

if name.nil?
name = "Unknown"
end

puts "--- After assignment of name: ---"
puts "defined?(name) : #{defined?(name).inspect}"
puts "binding.local_variable_defined?(:name) : #{binding.local_variable_defined?(:name).inspect}"

puts "local_variables : #{local_variables.inspect}"
puts "binding.local_variables : #{binding.local_variables.inspect}"

puts "name : #{name.inspect}"
puts "binding.eval('name') : #{binding.eval('name').inspect}"

puts "My name is #{name.inspect}"
end

Now, running Person.new("Paul").say_name outputs:

--- Before assignment of name: ---
defined?(name) : "method"
binding.local_variable_defined?(:name) : true
local_variables : [:name]
binding.local_variables : [:name]
name : "Paul"
binding.eval('name') : nil
--- After assignment of name: ---
defined?(name) : "local-variable"
binding.local_variable_defined?(:name) : true
local_variables : [:name]
binding.local_variables : [:name]
name : nil
binding.eval('name') : nil
My name is nil

which shows that binding never references the method call of name and only ever the eventually-assigned name variable.

What is current $, in Ruby's Array#join?

$, is another name for $OUTPUT_FIELD_SEPARATOR, the output field separator for the print and Array#join. By default, it is nil. Confer here.



Related Topics



Leave a reply



Submit