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