CrackedRuby logo

CrackedRuby

Method Aliases and Undef

Overview

Ruby provides method aliasing and method removal capabilities through alias, alias_method, undef, and undef_method. Method aliases create alternative names for existing methods, allowing multiple ways to invoke the same functionality. Method removal eliminates method definitions from classes and modules, preventing method calls and controlling inheritance behavior.

The alias keyword creates method aliases at parse time, while alias_method creates aliases at runtime. Both preserve the original method implementation even if the original method gets redefined later. Method removal through undef and undef_method works differently from method redefinition - undefined methods cannot be called and do not participate in method lookup chains.

class Calculator
  def add(a, b)
    a + b
  end
  
  alias plus add
  alias_method :sum, :add
end

calc = Calculator.new
calc.add(2, 3)    # => 5
calc.plus(2, 3)   # => 5
calc.sum(2, 3)    # => 5

Method aliases maintain independent references to the original method implementation. Redefining the original method does not affect existing aliases, while removing methods through undef prevents method calls entirely.

class Example
  def original_method
    "original implementation"
  end
  
  alias aliased_method original_method
  
  def original_method
    "new implementation"
  end
end

obj = Example.new
obj.original_method  # => "new implementation"
obj.aliased_method   # => "original implementation"

Basic Usage

The alias keyword creates method aliases using method names without quotes or symbols. This syntax requires the method names to be valid identifiers and works at parse time, making it suitable for static method aliasing.

class StringProcessor
  def normalize_text(text)
    text.strip.downcase
  end
  
  alias clean_text normalize_text
  alias sanitize normalize_text
end

processor = StringProcessor.new
result = processor.clean_text("  HELLO WORLD  ")
# => "hello world"

The alias_method method accepts symbols or strings as arguments and executes at runtime, making it suitable for dynamic method aliasing and metaprogramming scenarios.

class DynamicAliasing
  def self.create_alias(new_name, existing_name)
    alias_method new_name, existing_name
  end
  
  def calculate_result(x, y)
    x * y + 10
  end
  
  create_alias :compute, :calculate_result
  create_alias "process", "calculate_result"
end

obj = DynamicAliasing.new
obj.calculate_result(3, 4)  # => 22
obj.compute(3, 4)          # => 22
obj.process(3, 4)          # => 22

Method removal uses undef with method names or undef_method with symbols or strings. Unlike method redefinition, undefined methods cannot be called and raise NoMethodError exceptions.

class RestrictedCalculator
  def add(a, b); a + b; end
  def subtract(a, b); a - b; end
  def multiply(a, b); a * b; end
  def divide(a, b); a / b; end
  
  # Remove dangerous division method
  undef divide
end

calc = RestrictedCalculator.new
calc.add(10, 5)      # => 15
calc.divide(10, 5)   # NoMethodError: undefined method `divide'

Runtime method removal through undef_method allows conditional method elimination based on application state or configuration.

class ConfigurableAPI
  def read_data; "reading data"; end
  def write_data; "writing data"; end
  def delete_data; "deleting data"; end
  
  def self.disable_destructive_methods
    undef_method :write_data
    undef_method :delete_data
  end
end

api = ConfigurableAPI.new
api.read_data    # => "reading data"

ConfigurableAPI.disable_destructive_methods
api.write_data   # NoMethodError: undefined method `write_data'

Advanced Usage

Method aliases preserve method visibility and binding characteristics from the original method. Private and protected methods maintain their visibility when aliased, and aliases reference the same method object as the original definition.

class VisibilityExample
  def public_method; "public"; end
  
  private
  def private_method; "private"; end
  
  public
  alias public_alias public_method
  alias private_alias private_method
  
  def call_private_alias
    private_alias
  end
end

obj = VisibilityExample.new
obj.public_alias           # => "public"
obj.call_private_alias     # => "private"
obj.private_alias          # NoMethodError: private method called

Module inclusion and inheritance interact with method aliases in specific ways. Aliases created before module inclusion reference the original method, while aliases created after inclusion may reference overridden methods.

module Auditing
  def save_record
    log_save_attempt
    super
  end
  
  private
  def log_save_attempt
    puts "Attempting to save record"
  end
end

class DatabaseRecord
  def save_record
    "saving to database"
  end
  
  alias original_save save_record
  
  include Auditing
  
  alias audited_save save_record
end

record = DatabaseRecord.new
record.original_save  # => "saving to database"
record.audited_save   # Attempting to save record
                      # => "saving to database"

Method aliases support method chaining and decoration patterns by preserving the original implementation while allowing method enhancement.

class EnhancedCalculator
  def multiply(a, b)
    result = a * b
    puts "Multiplying #{a} × #{b} = #{result}"
    result
  end
  
  alias_method :original_multiply, :multiply
  
  def multiply(a, b)
    return 0 if a.zero? || b.zero?
    original_multiply(a, b)
  end
  
  def multiply_with_validation(a, b)
    raise ArgumentError unless a.is_a?(Numeric) && b.is_a?(Numeric)
    multiply(a, b)
  end
end

calc = EnhancedCalculator.new
calc.multiply(0, 5)        # => 0
calc.multiply(3, 4)        # Multiplying 3 × 4 = 12
                           # => 12

Metaprogramming with method aliases enables dynamic interface generation and API adaptation patterns.

class APIAdapter
  OPERATIONS = {
    create: :post_request,
    read: :get_request,
    update: :put_request,
    destroy: :delete_request
  }
  
  OPERATIONS.each do |crud_name, http_name|
    define_method(http_name) do |endpoint, data = nil|
      "#{http_name.to_s.upcase} #{endpoint} #{data}"
    end
    
    alias_method crud_name, http_name
  end
  
  def self.add_alias(new_name, existing_name)
    alias_method new_name, existing_name
  end
end

adapter = APIAdapter.new
adapter.create('/users', {name: 'John'})  # => "POST_REQUEST /users {:name=>\"John\"}"
adapter.read('/users/1')                  # => "GET_REQUEST /users/1 "

APIAdapter.add_alias :fetch, :read
adapter.fetch('/users/1')                 # => "GET_REQUEST /users/1 "

Common Pitfalls

Method aliases capture the method implementation at the time of aliasing, not at the time of calling. This behavior can lead to unexpected results when original methods get redefined after alias creation.

class ProblematicAliasing
  def greet(name)
    "Hello, #{name}!"
  end
  
  alias say_hello greet
  
  def greet(name)
    "Hi there, #{name}!"
  end
end

obj = ProblematicAliasing.new
obj.greet(name)      # => "Hi there, John!"
obj.say_hello("John") # => "Hello, John!" (old implementation)

Method aliases do not automatically update when the original method changes, which can create inconsistent behavior in applications that rely on method redefinition for customization.

class ConfigurableGreeting
  def greeting_message
    @custom_message || "Welcome"
  end
  
  alias default_greeting greeting_message
  
  def customize_greeting(message)
    @custom_message = message
  end
  
  def greeting_message
    "[CUSTOM] #{@custom_message || 'Welcome'}"
  end
end

greeter = ConfigurableGreeting.new
greeter.customize_greeting("Hello")
greeter.greeting_message    # => "[CUSTOM] Hello"
greeter.default_greeting    # => "Welcome" (unexpected)

The undef keyword and undef_method have different scoping rules that can cause confusion in inheritance hierarchies. Undefined methods in parent classes prevent method calls in child classes even if the child defines the same method.

class Parent
  def restricted_method
    "parent implementation"
  end
  
  undef restricted_method
end

class Child < Parent
  def restricted_method
    "child implementation"
  end
end

child = Child.new
child.restricted_method  # NoMethodError: undefined method `restricted_method'

Private method aliasing can accidentally expose private methods as public methods if not handled carefully with visibility modifiers.

class SecurityVulnerability
  private
  def sensitive_operation
    "accessing sensitive data"
  end
  
  public
  alias exposed_operation sensitive_operation  # Accidentally public!
end

obj = SecurityVulnerability.new
obj.exposed_operation  # => "accessing sensitive data" (security issue)

Method removal during class definition can prevent expected method inheritance and cause subtle bugs in complex inheritance hierarchies.

module Mixin
  def shared_method
    "from mixin"
  end
end

class Base
  include Mixin
  
  def shared_method
    "from base class"
  end
  
  undef shared_method  # Removes both versions!
end

class Derived < Base
end

derived = Derived.new
derived.shared_method  # NoMethodError: undefined method `shared_method'

Reference

Method Aliasing Methods

Method Parameters Returns Description
alias new_name existing_name Method names (identifiers) nil Creates method alias at parse time
alias_method(new_name, existing_name) Symbol or String Symbol Creates method alias at runtime

Method Removal Methods

Method Parameters Returns Description
undef method_name Method name (identifier) nil Removes method definition at parse time
undef_method(method_name) Symbol or String self Removes method definition at runtime

Visibility and Access Control

Scenario Alias Visibility Original Method Access
Public method aliased Inherits original visibility Both accessible
Private method aliased Remains private Private method rules apply
Protected method aliased Remains protected Protected method rules apply
Method redefined after alias Alias unchanged New implementation used

Method Lookup Behavior

Operation Method Lookup Inheritance Chain
alias created Captures current implementation Unaffected
Method redefined Uses new implementation Aliases use old implementation
undef called Method removed from lookup Prevents inheritance
Module included before alias Alias references original Normal inheritance
Module included after alias Alias unchanged Module method used

Error Conditions

Condition Exception Description
Alias nonexistent method NameError Original method must exist
Undef nonexistent method NameError Cannot remove undefined method
Call undefined method NoMethodError Method removed from lookup
Alias with invalid name SyntaxError Method names must be valid identifiers

Best Practice Patterns

Pattern Implementation Use Case
Method decoration alias_method :original_method, :method; def method; ...; original_method; ...; end Adding behavior to existing methods
API versioning alias_method :method_v1, :method; def method; ...; end Maintaining backward compatibility
Method delegation alias_method :delegated_method, :target_method Forwarding method calls
Conditional removal undef_method :method_name if condition Feature-based method availability

Metaprogramming Integration

# Dynamic alias creation
%w[create read update delete].each do |operation|
  alias_method "#{operation}_record", "#{operation}_data"
end

# Conditional method removal
[:delete, :destroy].each do |dangerous_method|
  undef_method dangerous_method if SAFE_MODE
end

# Bulk alias creation
ALIAS_MAP = {
  'new_name' => 'original_name',
  'another_name' => 'another_original'
}

ALIAS_MAP.each do |new_name, original_name|
  alias_method new_name.to_sym, original_name.to_sym
end