Ruby is a dynamic, open-source programming language that focuses on simplicity and productivity. Exceptionally user-friendly, it is widely used to develop web applications and systems scripting. This blog post comprises various Ruby interview questions and answers, focusing on the language’s concepts, capabilities, and data structures. Practical for potential job applicants, it provides useful insight into how well a candidate understands Ruby and its applications, including object-oriented programming, error handling, and testing techniques. In technical interviews, proficiency in Ruby allows for a broad examination of an applicant’s programming acumen.
Ruby Fundamentals
- 1.
What is Ruby, and why is it popular for web development?
Answer:Ruby is a dynamic, object-oriented programming language known for its simplicity and focus on developer productivity. Its main claim to fame in web development is the web application framework, Ruby on Rails (RoR), which transformed the way web applications are built by promoting convention over configuration.
Key Features & Contributions to Web Development
-
Language Syntax: Ruby’s syntax has an appeasing natural language style. This, paired with its dynamic typing, powerful metaprogramming features, and absence of semicolons, results in clean and expressive code.
-
Gems: Ruby’s package manager, RubyGems, simplifies library management, making it easy to integrate numerous third-party extensions.
-
Database Integration: ActiveRecord, a popular object-relational mapping system, aids in managing database records via a natural, object-oriented interface.
-
MVC Pattern: Rails, in particular, is famed for its adherence to the Model-View-Controller pattern, offering a clear separation of concerns.
-
Code Rearrangement: The auto-loading mechanism allows for seamless navigation between related files and classes while coding.
-
Ecosystem Consistency: RoR brought about a
many
-to
-many
relationship with databases, streamlining and simplifying existing development patterns. -
Strong Community: The language’s supportive community and its commitment to clean, readable code are evident in guiding principles like “Mediterranean” quality and “Matz’s kindness.”
-
Test-Driven Development: RoR promotes best-testing practices from the project’s inception, ensuring reliability.
-
Giant Corporations’ Indulgence: Prominent organizations such as GitHub, Shopify, and Airbnb have successfully tapped into the potential of Ruby on Rails.
Code Example: Ruby on Rails (RoR) Routing
Here is the Ruby code:
# config/routes.rb Rails.application.routes.draw do root 'welcome#index' get 'products/:id', to: 'products#show' resources :articles end
This file configures routes for different URLs, specifying which controllers and actions to invoke. For instance, upon receiving a
GET
request forproducts/5
, RoR would route it to theshow
action in theProductsController
with the ID parameter set to5
. Such straightforward setups contribute to RoR’s appeal. -
- 2.
How do you create a Ruby script file and execute it on a command line?
Answer:First, you create a
Ruby
script file with a.rb
extension that contains your Ruby code. You can then execute this script using theruby
command in your command line.Basic Steps for Creating and Running a Ruby Script in a File
-
Create a File: Use any text editor to write your Ruby code, and save the file with a
.rb
extension, e.g.,my_ruby_script.rb
. -
Write Ruby Code: Here is a simple example.
# Filename: my_ruby_script.rb puts "Hello, Ruby Script!"
-
Run the Ruby Script: Go to your command line and navigate to the folder where the Ruby file is saved. Then, type the following command:
ruby my_ruby_script.rb
After pressing enter, you will see the output:
Hello, Ruby Script!
Getting More Advanced
Command-Line Arguments
You can access command-line arguments using special variables called
ARGV
.Here is the code:
# Filename: script_with_args.rb puts "Arguments: #{ARGV.join(', ')}"
In the command line, you would run this script as:
ruby script_with_args.rb arg1 arg2 arg3
The output would be:
Arguments: arg1, arg2, arg3
Interactive Scripts
Ruby scripts can engage with users using the
gets
method.Here is an example:
# Filename: interactive_script.rb puts "What is your name?" name = gets.chomp puts "Hello, #{name}!"
When you run this script using
ruby interactive_script.rb
, it will prompt you for your name, and after you provide it, it will greet you.Background Processing
If you want a script to run in the background without blocking your command line, you can use the
&
character.For instance, to run a script called
background_script.rb
in the background, you can use:ruby background_script.rb &
Ruby Shell
For more complex shell operations,
Ruby
offers theshell
library.Here is the sample code:
require 'shell' # Use 'open' to open a URL in your default browser. sh = Shell.new sh.open "https://example.com"
-
- 3.
What are the basic data types in Ruby?
Answer:Ruby is claimed to treat “everything as an object”. But like many languages, Ruby has both primitive and abstract data types.
Primitive Types
- Numbers:
- Integers can be of any size (limited by system memory).
- Floating-Point numbers follow the IEEE 754 standard.
- Booleans: Represented by
true
andfalse
. - Symbols: Unique, immutable identifiers represented with a
:
followed by a name.
Abstract Types
- Strings: Unicode with multiple encodings.
- Arrays: Ordered, indexed collections.
- Hashes: Key-value pairs, also known as dictionaries or maps in other languages.
Others assimilated Primitive Types
Ruby, despite its philosophy of being completely object-oriented, has some underlying primitive paradigms due to its performance concerns and efficiency considerations.
-
nil: Represents ‘nothing’ or ‘empty’. It’s the only instance of
NilClass
. -
Booleans: While
true
andfalse
are themselves keywords, any other value in Ruby is considered truthy in a conditional context.
Advanced Types
- Rational Numbers: Represented as a fraction (e.g.,
1/3r
). - Complex Numbers: Have real and imaginary parts (e.g.,
2 + 3i
). - Dates and Times: Provide various built-in classes like
Time
for dealing with date and time values.
Ruby Uniqueness
Ruby shuns a “strictly-typed” system. Variables need not be declared upfront and can be reassigned to different types during execution. This freedom, although liberating, can lead to unexpected behavior, especially in larger codebases.
- Numbers:
- 4.
Explain the difference between symbols and strings in Ruby.
Answer:Ruby features both strings and symbols, each with distinct use cases.
Key Distinctions
- Type: Strings are of class
String
, while symbols are instances ofSymbol
. - Mutability: Strings are mutable, symbols are not.
- Memory: Symbols are stored as a single, unique object in memory, while each string is unique.
- Performance: As symbols are immutable, lookups are faster than for equivalent strings.
Primary Usages
- Strings: For text and dynamic data that may change or be unique across different objects or occurrences.
- Symbols: Typically used as keys for hashes or unique identifiers in the program. They’re advantageous for lookup efficiency and when the actual content of the identifier is less relevant than its unique identity.
Memory Considerations
- As symbols are stored only once in memory, they are memory-efficient in certain scenarios, like using the same symbol across different objects or operations. Be cautious, though, as unnecessarily creating a large number of symbols can lead to memory bloat.
- Strings may be more memory-intensive, especially when there are numerous unique strings. However, they are the right choice when dealing with data that genuinely varies or where mutability is required.
Code Example: String vs Symbol
Here is the Ruby code:
# Strings str_1 = "Hello" str_2 = "Hello" puts str_1.object_id == str_2.object_id # Output: false # Symbols sym_1 = :hello sym_2 = :hello puts sym_1.object_id == sym_2.object_id # Output: true
- Type: Strings are of class
- 5.
How are constants declared and what is their scope in Ruby?
Answer:In Ruby, you declare a constant by using all uppercase letters. Constants are subject to lexical scoping. While reassignment is technically possible (spawning a warning), it should be avoided as a practice.
Constant Declaration
You can declare a Ruby constant using
Object::CONSTANT
notation or by assigning a value directly to an identifier.Code Example: Constant Declaration
# Using Object::CONSTANT notation Math::PI # Direct assignment RADIUS = 5.0
Constant Scope
Constants have a global scope, but their visibility can be restricted within classes and modules.
Global VS. Local Scope
-
Global Scope: Constants are accessible throughout the entire application.
A = 1 # Top level module M puts A # Outputs: 1 end
-
Local Scope: Constants are defined within a module or a class.
module M A = 2 A = 3 puts A # Outputs: 3 end
Best Practices
- Avoid re-assigning constants. Although this generates a warning, the reassignment can still take place, which can lead to unintended behavior.
- For areas where you want to have a constant’s value remain unchanged, use
.freeze
on the constant or variable storing the constant’s value.
Code Example: Avoiding Reassignment
require "warning" # Generates a warning: already initialized constant A = 1 A = 2 warning 'constant reassignment' puts A # Outputs: 2
Object#freeze
CIRCLE_AREA = Math::PI * (RADIUS ** 2) CIRCLE_AREA.freeze # Any reassignment will generate an error # CIRCLE_AREA = 100 puts CIRCLE_AREA
-
- 6.
Explain the use of ‘require’ and ‘include’ in Ruby.
Answer:Ruby uses both Require and Include to manage dependencies and to mix modules into classes.
Require
-
Purpose: Loads external libraries, enabling access to their defined classes and modules.
-
Execution: Done at the top of the file or script.
-
Trigger: A
LoadError
is raised if the required file is not found. -
State Management: Tracks loaded libraries, subsequently ignoring further
require
calls for the same library.
Example: Using Require
Here is the Ruby code:
# In file application.rb require 'my_library' # In file my_library.rb class MyLibrary # ... end
Include
-
Purpose: Integrates a module’s methods within a class, giving the class access to those methods.
-
Execution: On the specific class that necessitates the module’s functionality.
-
State: Not applicable for classes, as they can include multiple modules.
Why is it Used?
- Require: Ensures the presence of the external library before continuing, a basic necessity for external code.
- Include: Mixes in module functionality only when needed, aligning with Rails’ convention of using it in the classes contextually.
-
- 7.
What are Ruby iterators and how do they work?
Answer:When it comes to Ruby, iterators allow for easy, streamlined data manipulation. Whether you’re working with arrays, ranges, or other data structures, iterators help you efficiently apply operations to each element without needing to manage loop counters.
Most Common Ruby Iterators
- Each: The most basic iterator, it goes through each element.
- Each with index: Similar to each, but it also gives the index of the current element.
Code Example: Each & Each with Index
Here is the Ruby code:
arr = [5, 4, 3, 2, 1] # Iterating with Each arr.each { |num| puts num } # Output: # 5 # 4 # 3 # 2 # 1 # Iterating with Each with Index arr.each_with_index { |num, index| puts "#{index}: #{num}" } # Output: # 0: 5 # 1: 4 # 2: 3 # 3: 2 # 4: 1
Common Usage
- Each Char: Often used with strings, this iterator loops through each character.
- Each Line: Handy for reading files, it processes lines one at a time.
Code Example: Each Char & Each Line
Here is the Ruby code:
str = "Hello, World!" # Iterating Each Character str.each_char { |char| puts char } # Output: # H # e # l # l # o # , # ...
File.open('example.txt').each_line do |line| puts line end
Predicative Iterators
These iterators select elements from a collection that match specific conditions. They are typically used in combination with blocks.
Examples include
select
,reject
, andgrep
. Each is designed to achieve specific selection goals:select
returns elements that yield true in the block.reject
returns elements that yield false in the block.grep
returns elements that match a specified pattern.
Code Example:
select
,reject
, andgrep
Here is the Ruby code:
# Select even numbers numbers.select { |num| num.even? } # Reject short names names.reject { |name| name.length < 5 } # Grep to find email addresses text = "Email me at user@example.com" text.grep(/\b\w+@\w+\.\w+\b/)
Chase & Transform
These iterators process the elements and return a result. They include
map
,collect
, andpartition
.map
: Transforms each input and returns a new array.collect
: Identical to map, but ops include the return value.partition
: Separates elements into two groups based on whether the block returns true or false.
Code Example:
map
,collect
, andpartition
Here is the Ruby code:
# Double each number numbers.map { |num| num * 2 } # Names all uppercase names.collect { |name| name.upcase } # Split numbers based on even or odd numbers.partition { |num| num.even? }
Execute Operations
These iterators modify their elements or perform side effects. Examples include
each
andeach_with_index
.Often used for their simplicity, do exercise caution as these functions can have unexpected results, especially when combined with unintended side effects.
each
: Processes each element but does not return anything.each_with_index
: Similar to each, but also gives the index of the current element.
Sort-Related Operations
When working with ordered collections like arrays or ranges, Ruby provides various sorting options. Common sorting iterators include
sort
,sort_by
, andreverse_each
. They all work with blocks to customize the sorting or iteration behavior.Repetition-Based Iterators
These Ruby constructs are particularly useful in the context of text manipulation, allowing you to repeat characters (such as hyphens for formatting headers) for a specified number of times.
each_line
: Useful when processing multi-line strings or files.each_char
: Ideal for character-level processing in strings or enumerations.downto
: Iterates downwards to a specified value.upto
: Iterates upwards to a specified value.times
: Repeats the associated block a predetermined number of times.step
: Indents a set number of times, confined by a range.cycle
: Used primarily with blocks, it repeatedly moves through the specified range.
Code Example: Repetition-Based Iterators
Here is the Ruby code:
# Print a line of stars '*'.upto('*****') { |s| puts s } # Output: # * # ** # *** # **** # ***** # Print numbers from 5 to 10, then their squares 5.upto(10) { |num| puts num } 5.upto(10).each { |num| puts num**2 }
- 8.
How are errors handled in Ruby?
Answer:Ruby’s exception hierarchy enables developers to manage different kinds of errors. The two main exception types cater to a multitude of issues:
- StandardError: For generic problems that occur during code execution.
- SystemCallError: Specifically deals with errors originating from system calls.
Ways to Handle Exceptions in Ruby
Top-Level Exception Handling
Ruby leverages the
at_exit
method for centralized error handling. This approach is mainly useful for logging errors before program exit or for cleaning up resources.at_exit do puts $!.message if $! end
Single Statement Unwind
Utilize inline rescue, marked by the
begin
andend
block. If an exception arises during the evaluation of the enclosed expression, it’s caught.result = begin raise StandardError, "This is an error" rescue StandardError => e "Rescued: #{e.message}" end puts result # Output: Rescued: This is an error
Custom Exception Handling
Developers benefit from creating their custom exception classes or identifying specific exception types to tailor their error management strategies.
Defining Custom Exception Classes
The
Exception
class or, more preferably, its subclass,StandardError
, are parents to all user-defined exceptions. This inheritance ensures that all custom exceptions are catchable viarescue
.class MyCustomError < StandardError # Additional behavior or settings end raise MyCustomError, "Something went wrong!"
Identifying the Right Exception
An error’s distinct nature often demands a corresponding exception. For instance, consider a method handling file operations:
def read_file(file_path) raise ArgumentError, "File path is empty" if file_path.to_s.empty? raise IOError, "File not found" unless File.exist?(file_path) File.read(file_path) end
Upon calling
read_file
, any exception correlated to an invalid file path can be reliably caught and addressed with a targetedrescue
block.Error Handling Best Practices
-
Keep it Precise: Make use of granular
rescue
blocks orcase
statements to align the corrective measures with the specific error. -
Maintain a Balance: Overuse of exceptions can convolute code and hinder its readability. Carefully select the exceptions likely to surface and necessitate special attention.
-
Locale Transparency: Choose either a local exception resolver that terminates in the current method or a global one that percolates up the call stack, but aim for consistency.
Performance Considerations
While exceptions can be invaluable for isolated and unexpected mishaps, triggering and managing them incurs a performance cost. It’s typically wiser to leverage them predominantly in such scenarios and not as part of conventional program flow.
- 9.
Describe the difference between local, instance, and class variables.
Answer:Let’s set the record straight on the differences between local, instance, and class variables in Ruby.
Common Features
All three variable types support:
- naming: 
- assignment:
variable_name = value
- access control:
public
,private
, andprotected
- immediacy: their scope begins from where they are initialized and exists until the scope ends.
Local Variables
- Scope: Limited to the block where they are defined.
- Life Cycle: Created when the program reaches their definition and destroyed when the block is exited.
Example: Local Variable
Here is the Ruby code:
def hello name = "Ruby" puts "Hello, #{name}!" # Output: Hello, Ruby! end # Accessing name outside its defined block will cause an error. # puts name # Will raise an error
Instance Variables
Naming Convention
An instance variable is prefixed with a single ‘@’ symbol.
- Scope: Primarily within the class, but is accessible from outside the class if the class is instantiated.
- Life Cycle: Created when an object is instantiated and remains available until that particular object is destroyed.
Example: Instance Variable
Here is the Ruby code:
class Greeting def set_name(name) @name = name end def display_greeting puts "Hello, #{@name}!" # Output: Hello, Ruby! end end greeting_instance = Greeting.new greeting_instance.set_name("Ruby") greeting_instance.display_greeting
Class Variables
Naming Convention
A class variable is prefixed with two ‘@’ symbols.
- Scope: Within the class and its inheritors but not accessible from outside.
- Life Cycle: Created when assigned within the class or its inheritors and accessible as long as the class or one of its inheritors is in memory.
Example: Class Variable
Here is the Ruby code:
class Employee @@company_name = "ABC Corporation" def self.company_name=(name) @@company_name = name end def display_company_name puts @@company_name end end employee1 = Employee.new employee2 = Employee.new # Output: "ABC Corporation" for both employee1 and employee2. employee1.display_company_name employee2.display_company_name Employee.company_name = "New Company" # changes the class variable # After changing, outputs for both employee1 and employee2 will be "New Company". employee1.display_company_name employee2.display_company_name
- 10.
What are Ruby’s accessor methods?
Answer:In Ruby, accessor methods allow you to manipulate object attributes. There are three types of accessor methods:
attr_reader
,attr_writer
, andattr_accessor
, each serving a specific role in the attribute’s lifecycleAttribute Methods
attr_reader
: Generates a simple getter method for an attribute. It can be accessed but not modified externally.attr_writer
: Generates a basic setter method. The attribute can be modified but not read externally.attr_accessor
: Combines both getter and writer methods in one. This creates a full-fledged getter and setter for the attribute.
Code Example: Accessor Methods
Here is the Ruby code:
class Person attr_reader :name, :age attr_writer :name, :age def initialize(name, age) @name = name @age = age end end person = Person.new("Alice", 30) person.name # Returns "Alice" person.name = "Bob" # Error: undefined method 'name=' person.age # Returns 30 person.age = 35 # Error: undefined method 'age=' person.instance_variables # Returns [:@name, :@age]
- 11.
How does garbage collection work in Ruby?
Answer:Ruby employs automatic memory management, which is primarily influenced by garbage collection techniques. Let’s understand the specifics.
Mark-and-Sweep Algorithm
-
Step 1 - Mark: The process starts from the root of object references. The GC traverses memory, marking referenced objects.
-
Step 2 - Sweep: It scans for unmarked objects and reclaims their memory, making it available for future use.
Generational Garbage Collection
To optimize the Mark-and-Sweep approach, Ruby introduces generational garbage collection.
-
Focused on Object Age: Objects are classified based on their age.
-
Young vs. Old Objects:
- New objects start in the Young Generation.
- Objects that persist multiple GC cycles move to the Old Generation.
-
Collection Frequency: The Young Generation is collected more frequently.
-
Short- and Long-Lived Object Management: It’s easier to collect younger objects, reducing the scope and overhead of a complete garbage collection cycle.
Reference-Counting and
ObjectSpace
Although CPython uses reference-counting to track object lifespans, Ruby typically does not.
-
ObjectSpace: It’s a module that allows retrieval of all objects.
However, note that modern Ruby versions represent a hybrid system, sensitive to object types and context.
Code Example: Garbage Collection in Ruby
Here is the Ruby code:
# Enable trashcan (Ruby 2.6 onwards) ObjectSpace::count_objects[:FREE] > 100_000 && GC.start # Ruby versions before 2.6 GC.start
-
- 12.
Explain the difference between ‘gets.chomp’ and ‘gets.strip’.
Answer:Let me go through the major difference.
Key Distinctions
-
Input Requirement:
gets.chomp
removes all trailing whitespace and the newline character.gets.strip
eliminates all leading and trailing whitespace, including the newline character.
-
Use Cases:
gets.chomp
: Suited when you anticipate or require specific trailing characters to be preserved.gets.strip
: Ideal for scenarios where you need to sanitize or validate user input by removing any extra leading or trailing spaces.
Code Sample:
gets.chomp
&gets.strip
Here is the Ruby code:
# Using the gets.chomp method puts "Enter your name (including a trailing space): " name_chomp = gets.chomp puts "Name with trailing space: #{name_chomp}" # Using the gets.strip method puts "Enter your name: " name_strip = gets.strip puts "Name without trailing space: #{name_strip}"
-
- 13.
What is the role of ‘self’ in Ruby?
Answer:In Ruby,
self
serves as a “mirror” that reflects the current context. Depending on where it’s used,self
can represent different objects.Here’s the breakdown:
Self
in Different Contexts1. Instance Methods
In this context,
self
refers to the instance of the object on which the method is called.Consider the following code:
class MyClass def instance_method puts self end end object = MyClass.new object.instance_method
The output would be the object reference
#<MyClass:0x007fb4fa869358>
.2. Class Methods
Within a class definition,
self
refers to the class itself. This is why you useself.method_name
to define class methods.For instance:
class MyClass def self.class_method puts self end end MyClass.class_method
The output will be the class
MyClass
.3. Method Invocation
When a method is missing due to a typo or other reason, Ruby executes
method_missing
which can help handle such cases.Consider this example:
class MyClass def method_missing(m, *args) puts "There's no method called #{m}" end def test_method method_thaat_doesnt_exist end end
Calling
test_method
will invokemethod_missing
with the method name"method_thaat_doesnt_exist"
. - 14.
Explain the principle of ‘Convention over Configuration’ in the context of Ruby.
Answer:Convention over Configuration (CoC) is a software design principle that simplifies development by reducing the number of decisions developers need to make.
In its essence, CoC means that frameworks come with best practice defaults or “conventions” that are automatically applied unless explicitly configured to behave differently.
Practical Application
- Code-Base Structures: Many Ruby web frameworks, like Ruby on Rails or Sinatra, expect a certain directory structure that groups related files.
- Naming Conventions: Specially designed rules for naming classes, methods, and databases to help in identification and automatic linking.
- API Endpoints: Through consistent naming, it’s possible to infer routing information in web applications.
- Database Schemas: Named fields and tables allow the ORM to deduce relationships and configurations.
Example: CRUD Actions in RoR
In Ruby on Rails, the “conventions” for a resourceful route automatically map HTTP verbs to CRUD actions:
# config/routes.rb resources :articles # Routes: # HTTP Path Controller#Action Used For # ------------------------------------------------------------ # GET /articles articles#index Display a list # GET /articles/:id articles#show Display a specific article # GET /articles/new articles#new Display a form to create a new article # POST /articles articles#create Add a new article to the database # GET /articles/:id/edit articles#edit Display a form to edit an existing article # PATCH /articles/:id articles#update Update an existing article in the database # PUT /articles/:id articles#update (Alternate for update) # DELETE /articles/:id articles#destroy Remove a specific article from the database
Here, the convention to map action names to routes frees the developer from configuring each route manually.
Benefits
- Speed: It streamlines development and reduces boilerplate.
- Interoperability: CoC enables consistency across different projects and teams.
Risks and Challenges
- Over-optimization: While it’s efficient for simple, well-understood requirements, it can make advanced configurations and customizations cumbersome.
- Learning Curve: Newcomers might find it challenging to adapt to these standard conventions.
- Magic: Over-reliance on CoC can make the system seem like it has hidden, unexplained behaviors.
- 15.
How does Ruby support metaprogramming?
Answer:Ruby offers powerful metaprogramming capabilities, enabling developers to write flexible, dynamic code. Key to Ruby’s metaprogramming are
class
methods such asdefine_method
and language features likeOpen Classes
leading to advanced techniques likeDynamic Dispatch
.Dynamic Dispatch Mechanism
- Dynamic Dispatch: Methods can be called at runtime, based on the object’s context, using
send
. This makes it easier to manage method invocations in metaprogrammed code.
class MathOperations def do_operation(operator, x, y) send(operator, x, y) # Dynamic dispatch end private def add(x, y) x + y end def subtract(x, y) x - y end end result = MathOperations.new.do_operation(:add, 10, 5) # 15
Class Modifications with
Open Classes
-
Open Classes: Ruby allows changing a class’s definition dynamically, even after its initial declaration.
This example adds a
reverse
method to theString
class.class String def reverse chars.reverse.join end end
Code Evaluation and Execution
-
Code Evaluation: Code strings can be executed within a bound context, enabling runtime code execution and evaluation.
This is an example using
eval
to define a method at runtime, equivalent todef double(x) x * 2; end
, but the method signature is constructed dynamically.method_signature = 'double(x)' method_body = 'x * 2' eval("def #{method_signature}; #{method_body}; end")
-
Binding Tasks:
proc
objects capture both the method (or block) and its associated context. They can be transferred across lexical scopes, allowing delayed execution of code.context = binding task = Proc.new { eval 'some_method', context }
-
Context Toggling: By toggling a method’s visibility, you can control its access scope.
class MyClass def some_method "Public method" end private def toggle_method_visibility(visibility) # `send` here is being used for dynamic dispatch send(visibility, :some_method) end end instance = MyClass.new instance.toggle_method_visibility(:private)
Internationalization: Advanced Use of
send
andeval
-
Localizing Method Calls: In internationalization tasks where method calls need to be localized,
send
,public_send
, or even the more generaleval
can be suitable.def greeting(language) eval("#{language}_greeting") end def spanish_greeting "Hola Mundo" end
Method Missing and Missing Method Feature
-
Method Missing: This feature is the heart of Ruby’s duck typing. It allows classes and objects to respond to method calls even when their definitions are absent, rather than resorting to method-not-found errors.
This example cleans up a method call, removing spaces or underscores.
def method_missing(name, *args, &block) cleaned_name = name.to_s.delete(' ').delete('_') send(cleaned_name, *args, &block) end
-
respond_to_missing?
: This method is often used in conjunction withmethod_missing
, providing a way for a class to communicate whether it handles a method call beyond what is statically defined.
- Dynamic Dispatch: Methods can be called at runtime, based on the object’s context, using