Advanced Ruby: Scope Gates, Top Level Context

Question Click to View Answer

When does the scope change in a Ruby program.

The scope changes whenever the program encounters the def, class, and module keywords. There are other techniques for changing the scope of a Ruby program (i.e. instance_eval and class_eval), but the vast majority of scope changes are related to the def, class, and module keywords, which are collectively referred to as 'scope gates'.

What does the following code print? Explain.

p "***"
p self
class SnoopDogg; end
"***"
main

main is an instance of Object that's created whenever a Ruby program is run. main is the 'top level scope' or 'top level context' of a Ruby program.

What does the following code print? Explain.

p self
p "***"
class LessThanJake
  p self
end
main
"***"
LessThanJake

A program starts in the top level scope. When the program encounters the class keyword, the scope changes to the class. When the context changes (the terms context and scope are synonymous), the self keyword is reassigned to a different object.

What does the following code print? Explain.

class Hockey
  p self
  p "***"
  def legend
    "Brian Leetch"
    p self
  end
end

Hockey.new.legend
Hockey
"***"
#<Hockey:0x007f9458a80ec8>

When the program encounters the class keyword, it changes from the top level scope to the scope of the Hockey class. The program changes scope to an instance of the Hockey class when it encounters the def keyword. When a Ruby program runs, the scope is constantly changing, thus reassigning the self keyword to new objects, taking old local variables out of scope, and brining new local variables in scope.

What does the following code print? Explain.

x = "happy, happy, joy, joy"
class Stimpy
  p x
end

This code raises the following error:

NameError: undefined local variable or methodx' for Stimpy:Class`

x is a local variable in the top level scope. When the program hits the class keyword, the context is changed to the Stimpy class and no local variables from other contexts are available.

What does the following code print? Explain.

bieber = 'person'
class Weird
  y = 'boo'
  def hi
    z = 'sleepy generation'
  end
end
fever = 'sickness'

p local_variables
[:bieber, :fever]

The program starts in the top level scope where the bieber local variable is defined. When the program encounters the class keyword, it exits the top level scope and does not return to the top level scope until the class definition is ended. The fever local variable is defined in the top level scope when it is reopened.

Refactor the following code to bypass the class scope gate and access the kicks local variable in the Nike class method.

kicks = 'air max'
class Nike
  p kicks
end
kicks = 'air max'
Nike = Class.new do
  p kicks
end

Class.new can be used to bypass the class scope gate. Class.new captures local variable bindings at the time it's defined and makes these bindings available in the class definition.

Refactor the following code to bypass the method scope gate and access the greeting variable

greeting = 'hey'
def speak
  "#{greeting} Arnold!"
end
speak()
greeting = 'hey'
define_method(:speak) do
  "#{greeting} Arnold!"
end
speak()

define_method() can be used to bypass the method scope gate. define_method captures the local variable bindings and makes these bindings available in the method.

What does the following code print? Explain.

class DaddyYankee
  class << self
    p self
    p self == DaddyYankee.singleton_class
  end
end
#<Class:DaddyYankee>
true

When the program encounters the 'class << self' line, the context changes to the DaddyYankee singleton class.

Ruby does not have 'floating' functions that are not bound to any object. All methods in Ruby are bound to an object. What object is the following method bound to? Explain.

def geek; end

The geek method is a private instance method of the Object class. All methods defined in the top level scope are private instance methods of the Object class.