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
Why Does White-Space Affect Ruby Function Calls
Rvm Warning! Path Is Not Properly Set Up
How to Get Class Instances in Ruby
What Is the "Right" Way to Iterate Through an Array in Ruby
Is There a Better Way of Checking Nil or Length == 0 of a String in Ruby
How to Use Rvm and Create Globally Available Gems
Mavericks, Rbenv, Your Ruby Version Is 2.0.0, But Your Gemfile Specified 2.1.1
Can't Install Ruby Rvm on Ubuntu 16.04 Due to Gpg Bug
How to Group by Day Instead of Date
What's the Precedence of Ruby'S Method Call
How to Wait for Process to Finish Using Io.Popen
Rubyinstaller 2.2.1 and Rails - Rake Cannot Load Nokogiri
How to Remove a Key from Hash and Get the Remaining Hash in Ruby/Rails
Get Index of Array Element Faster Than O(N)