CrackedRuby logo

CrackedRuby

Reserved Keywords and Identifiers

Complete guide to Ruby's reserved keywords, identifier naming rules, and syntax restrictions.

Ruby Language Fundamentals Basic Syntax and Structure
1.1.5

Overview

Ruby reserves specific words that cannot be used as variable names, method names, or other identifiers. These reserved keywords form the core syntax of the language and include control structures, literals, and operators. Ruby's identifier naming system follows strict rules for variables, methods, constants, and classes, with specific conventions that affect scope and behavior.

Ruby defines 41 reserved keywords that serve different purposes: control flow (if, else, case, when), iteration (for, while, until), method definition (def, class, module), and special values (nil, true, false). The language also distinguishes between different identifier types through naming conventions - local variables start with lowercase letters, constants with uppercase letters, instance variables with @, class variables with @@, and global variables with $.

# Reserved keyword usage
def calculate_score
  return nil if invalid_data?
  case competition_type
  when 'standard'
    base_score * 1.0
  else
    base_score * 1.5
  end
end

# Identifier types
LOCAL_CONSTANT = 100
@instance_var = "data"
@@class_var = "shared"
$global_var = "system_wide"

The identifier system directly impacts variable scope, method visibility, and constant lookup. Ruby's parser uses these naming patterns to determine how identifiers behave at runtime, making the conventions more than stylistic choices.

Basic Usage

Ruby's reserved keywords cannot be redefined or used as identifiers. Attempting to use reserved words as variable names, method names, or other identifiers results in syntax errors. The complete list includes logical operators (and, or, not), control structures (if, unless, case), loop constructs (while, until, for), and special literals (nil, true, false, self, super).

# This raises SyntaxError
def class
  "invalid method name"
end
# => SyntaxError: unexpected keyword_class

# This also raises SyntaxError
if = 5
# => SyntaxError: unexpected '='

Local variables and method names follow identical naming rules: they begin with lowercase letters or underscores, followed by letters, digits, or underscores. Ruby allows method names to end with ? or ! for predicate and mutating methods respectively.

# Valid local variables and method names
user_name = "alice"
is_valid = true
total_count = 42

def user_logged_in?
  @session_active
end

def reset_password!
  @password = generate_secure_password
  save_to_database
end

Constants must start with uppercase letters and typically use SCREAMING_SNAKE_CASE for multiple words. Ruby allows constant reassignment but issues warnings. Constants defined in classes or modules are scoped to those containers.

# Module-scoped constants
module Configuration
  DATABASE_URL = "postgresql://localhost/myapp"
  MAX_CONNECTIONS = 50

  class Settings
    DEFAULT_TIMEOUT = 30
  end
end

# Accessing scoped constants
puts Configuration::DATABASE_URL
puts Configuration::Settings::DEFAULT_TIMEOUT

Instance variables begin with @ and exist within object instances. Class variables start with @@ and are shared across all instances of a class and its subclasses. Global variables use $ prefix and are accessible throughout the program.

class UserAccount
  @@total_accounts = 0

  def initialize(username)
    @username = username
    @created_at = Time.now
    @@total_accounts += 1
  end

  def self.account_count
    @@total_accounts
  end
end

$application_name = "MyApp"

Advanced Usage

Ruby's identifier scoping rules create complex interactions when combined with metaprogramming. Constants undergo lexical scoping, meaning Ruby searches for constants starting from the current lexical scope, then moving outward through nesting levels before checking the inheritance chain.

module Outer
  CONSTANT = "outer"

  module Inner
    CONSTANT = "inner"

    class Example
      def self.demonstrate_lookup
        puts CONSTANT  # Finds Inner::CONSTANT
        puts ::CONSTANT rescue "Not found at top level"
        puts Outer::CONSTANT  # Explicit scope resolution
      end
    end
  end
end

Outer::Inner::Example.demonstrate_lookup
# => inner
# => Not found at top level
# => outer

Dynamic identifier creation through metaprogramming requires careful handling of reserved keywords. Methods like define_method and const_set can create identifiers dynamically, but reserved keywords still cannot be used.

class DynamicMethodGenerator
  RESERVED_WORDS = %w[class module def if else case when]

  def self.create_method(name, &block)
    if RESERVED_WORDS.include?(name.to_s)
      raise ArgumentError, "Cannot use reserved word '#{name}' as method name"
    end

    define_method(name, &block)
  end

  def self.safe_const_set(name, value)
    if name.to_s !~ /\A[A-Z][A-Za-z0-9_]*\z/
      raise ArgumentError, "Invalid constant name: #{name}"
    end

    const_set(name, value)
  end
end

generator = Class.new(DynamicMethodGenerator)
generator.create_method(:calculate_total) { |items| items.sum }
generator.safe_const_set("MAX_ITEMS", 100)

Method aliasing and alias_method can create alternative names for methods, including potentially confusing scenarios where methods have names similar to reserved keywords but with slight variations.

class MethodAliasing
  def original_method
    "original implementation"
  end

  # Create aliases that might be confusing
  alias_method :klass, :original_method  # Similar to 'class'
  alias_method :modul, :original_method  # Similar to 'module'

  # Dynamic aliasing with validation
  def self.safe_alias(new_name, original_name)
    reserved = %w[class module def if else case when while until for]

    if reserved.include?(new_name.to_s)
      raise ArgumentError, "Cannot alias to reserved word: #{new_name}"
    end

    alias_method new_name, original_name
  end
end

Constant autoloading in Ruby creates complex scenarios where constant resolution might trigger file loading, potentially defining new constants that affect the lookup chain.

module AutoloadExample
  # Simulate autoloading behavior
  def self.const_missing(name)
    case name
    when :DatabaseConfig
      const_set(name, Class.new do
        TIMEOUT = 30
        HOST = "localhost"
      end)
    when :CacheConfig
      const_set(name, Module.new do
        TTL = 3600
        SIZE_LIMIT = 1000
      end)
    else
      super
    end
  end
end

# These constants are created on first access
puts AutoloadExample::DatabaseConfig::TIMEOUT  # => 30
puts AutoloadExample::CacheConfig::TTL         # => 3600

Common Pitfalls

One of the most frequent mistakes involves using reserved keywords as hash keys without proper quoting. While symbols and strings can represent reserved words, they require careful syntax to avoid parser confusion.

# Problematic hash syntax
hash = { class: "User", module: "Authentication" }  # Syntax error

# Correct approaches
hash = { "class" => "User", "module" => "Authentication" }
hash = { :class => "User", :module => "Authentication" }
hash = { "class": "User", "module": "Authentication" }  # Symbol keys

Constant reassignment warnings are often ignored but can indicate serious design problems. Ruby allows constant modification but warns about it, and the behavior can be surprising in inheritance scenarios.

class Parent
  SHARED_CONFIG = { timeout: 30, retries: 3 }
end

class Child < Parent
  # This modifies the parent's constant
  SHARED_CONFIG[:timeout] = 60  # No warning, but dangerous

  # This creates a new constant with warning
  SHARED_CONFIG = { timeout: 60, retries: 5 }  # Warning issued
end

puts Parent::SHARED_CONFIG  # May not be what you expect

Variable shadowing occurs when local variables hide method calls of the same name, leading to unexpected behavior that's difficult to debug.

class ShadowingExample
  def name
    "instance method"
  end

  def demonstrate_shadowing
    puts name  # Calls method: "instance method"

    name = "local variable"
    puts name  # Local variable shadows method: "local variable"

    # To call method when local variable exists
    puts self.name  # Explicit receiver: "instance method"
  end
end

Global variable pollution represents a serious pitfall where libraries or application code accidentally creates global variables, leading to conflicts and unpredictable behavior.

# Dangerous: accidental global variable creation
def process_data(items)
  $processed_count = 0  # Accidentally global

  items.each do |item|
    # Process item
    $processed_count += 1
  end

  $processed_count
end

# Better: explicit local scope
def process_data_safely(items)
  processed_count = 0

  items.each do |item|
    # Process item
    processed_count += 1
  end

  processed_count
end

Class variable inheritance creates unexpected sharing between parent and child classes, where modifications in child classes affect parent classes and siblings.

class Vehicle
  @@count = 0

  def initialize
    @@count += 1
  end

  def self.count
    @@count
  end
end

class Car < Vehicle
end

class Truck < Vehicle
end

# All classes share the same @@count variable
Vehicle.new
Car.new
Truck.new

puts Vehicle.count  # => 3 (shared across all classes)
puts Car.count      # => 3 (same variable)
puts Truck.count    # => 3 (same variable)

Reference

Reserved Keywords

Category Keywords Purpose
Control Flow if, unless, else, elsif, case, when, then Conditional execution
Loops while, until, for, break, next, redo Iteration control
Method Definition def, undef, alias, return, yield Method creation and control
Class/Module class, module, super, self Object-oriented constructs
Exception Handling begin, rescue, ensure, raise, retry Error management
Logical Operators and, or, not Boolean logic
Literals nil, true, false Special values
Variable Scope defined?, END, BEGIN Runtime introspection

Identifier Naming Rules

Type Pattern Example Scope
Local Variable [a-z_][a-zA-Z0-9_]* user_name, _temp Method/block local
Constant [A-Z][A-Z0-9_]* MAX_SIZE, CONFIG Class/module scoped
Instance Variable @[a-zA-Z_][a-zA-Z0-9_]* @name, @user_id Object instance
Class Variable @@[a-zA-Z_][a-zA-Z0-9_]* @@count, @@total Class hierarchy
Global Variable $[a-zA-Z_][a-zA-Z0-9_]* $debug, $app_name Program global
Method Name [a-z_][a-zA-Z0-9_]*[?!]? valid?, save! Object scope

Special Global Variables

Variable Purpose Example
$! Current exception rescue; puts $!.message; end
$$ Process ID puts "PID: #{$$}"
$? Child process status system('ls'); puts $?.exitstatus
$0 Script name puts "Running: #{$0}"
$* Command line arguments puts "Args: #{$*}"
$/ Input record separator $/ = "\n\n"
$\ Output record separator $\ = "\n"

Constant Lookup Order

  1. Lexical scope - Current class/module nesting
  2. Inheritance chain - Superclasses of current class
  3. Included modules - Mixed-in modules
  4. Top-level constants - Main object constants
  5. Object class - Ruby's root object class

Method Naming Conventions

Suffix Purpose Example Behavior
? Predicate method empty?, valid? Returns boolean
! Mutating method sort!, upcase! Modifies receiver
= Setter method name=, value= Assignment syntax
No suffix Standard method size, first Returns value

Scope Resolution Operators

Operator Purpose Example
:: Absolute scope ::Math::PI
:: Relative scope Module::CONSTANT
:: Method call object::method (rare)

Reserved Word Alternatives

Reserved Alternative Usage
class klass, type Hash keys, method parameters
module mod, namespace Configuration, APIs
def define, definition Metaprogramming contexts
if condition, when_true Configuration keys
else otherwise, default Conditional logic