tl;dr Yes, this is documented in Assignment.
Whether a thing is defined,and what it is defined as, can be had with the defined?
keyword.
2.6.5 :003 > defined?(fnord)
=> nil
2.6.5 :004 > fnord = 42
=> 42
2.6.5 :005 > defined?(fnord)
=> "local-variable"
2.6.5 :006 > defined?($fnord)
=> nil
2.6.5 :007 > $fnord = 42
=> 42
2.6.5 :008 > defined?($fnord)
=> "global-variable"
2.6.5 :009 > defined?(@fnord)
=> nil
2.6.5 :010 > @fnord = 42
=> 42
2.6.5 :011 > defined?(@fnord)
=> "instance-variable"
2.6.5 :012 > defined?(FNORD)
=> nil
2.6.5 :013 > FNORD = 42
=> 42
2.6.5 :014 > defined?(FNORD)
=> "constant"
This is useful for debugging, but I'd discourage "exploiting" it in application code.
First, let's clear up your example. test
is a method of main
. It is inherited from Kernel#test.
2.6.5 :004 > defined?(test)
=> "method"
2.6.5 :005 > method(:test)
=> #<Method: main.test>
A proper example looks like this.
2.6.5 :008 > puts @fnord
=> nil
2.6.5 :009 > puts fnord
Traceback (most recent call last):
4: from /Users/schwern/.rvm/rubies/ruby-2.6.5/bin/irb:23:in `<main>'
3: from /Users/schwern/.rvm/rubies/ruby-2.6.5/bin/irb:23:in `load'
2: from /Users/schwern/.rvm/rubies/ruby-2.6.5/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
1: from (irb):9
NameError (undefined local variable or method `fnord' for main:Object)
Local variables
The error hints at what's happening: ambiguity. fnord
could be the local variable fnord
or self.fnord
. Neither have been declared, Ruby won't guess at what you meant, so you get a NameError.
In Ruby local variable names and method names are nearly identical. If you have not assigned to one of these ambiguous names ruby will assume you wish to call a method. Once you have assigned to the name ruby will assume you wish to reference a local variable.
Declared local variables can be discovered with local_variables.
2.6.5 :012 > foo = 42
=> 42
2.6.5 :013 > Kernel.local_variables
=> [:foo, :_]
Instance variables
An uninitialized instance variable has a value of nil. If you run Ruby with warnings enabled, you will get a warning when accessing an uninitialized instance variable.
There are various methods for introspecting instance variables like instance_variables
and instance_variables_defined?
. While there are some instances this might be necessary when writing libraries, I strongly discourage exploiting the distinction between nil
and "undefined" in application code; it makes things fragile.
Class variables
Accessing an uninitialized class variable will raise a NameError exception.
Global variables
An uninitialized global variable has a value of nil.