Ruby Interview Questions for Developers

Use our engineer-created questions to interview and hire the most qualified Ruby developers for your organization.

Ruby

Ruby demands a respectable following due to its super-clean syntax, large open-source library of RubyGems, and because it forms the basis of the extremely popular Ruby-on-Rails front-end framework.

Ruby is unique for its Principle of Least Astonishment (POLA), which dictates that the language’s behavior should minimize surprises for its users to make it a more intuitive language to learn and use.

We have crafted practical coding exercises and interview questions designed to assess developers’ Ruby expertise during coding interviews. Additionally, we have put together a collection of best practices to guarantee that your interview questions effectively measure the candidates’ proficiency in Ruby.

Ruby example question

Help us design a parking lot

Hey candidate! Welcome to your interview. Boilerplate is provided. Feel free to change the code as you see fit. To run the code at any time, please hit the run button located in the top left corner.

Goals: Design a parking lot using object-oriented principles

Here are a few methods that you should be able to run:

  • Tell us how many spots are remaining
  • Tell us how many total spots are in the parking lot
  • Tell us when the parking lot is full
  • Tell us when the parking lot is empty
  • Tell us when certain spots are full e.g. when all motorcycle spots are taken
  • Tell us how many spots vans are taking up

Assumptions:

  • The parking lot can hold motorcycles, cars and vans
  • The parking lot has motorcycle spots, car spots and large spots
  • A motorcycle can park in any spot
  • A car can park in a single compact spot, or a regular spot
  • A van can park, but it will take up 3 regular spots
  • These are just a few assumptions. Feel free to ask your interviewer about more assumptions as needed

Junior Ruby interview questions

Question:
Explain the difference between a Ruby class and an instance of a class.

Answer:
In Ruby, a class is a blueprint or a template that defines the properties (attributes) and behaviors (methods) of objects. It acts as a blueprint for creating objects with similar characteristics. An instance of a class, on the other hand, is a specific object created based on the class definition. It represents a unique occurrence of the class with its own set of attribute values.

For example, consider a Car class. The class may define attributes like make, model, and year, as well as methods like start_engine and drive. An instance of the Car class would be a specific car object with its unique make, model, year, and other attribute values.

Question:
Create a Ruby function that takes an array of numbers as input and returns a new array containing only the even numbers.

Answer:

def even_numbers(input_array)
  input_array.select { |num| num.even? }
end

# Example usage:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = even_numbers(numbers)
puts result
# Output: [2, 4, 6, 8, 10]Code language: PHP (php)

In this code, the even_numbers function uses the select method to filter the array and only keep elements for which the block (num.even?) returns true, i.e., even numbers.

Question:
What is a gem in Ruby, and how is it useful in the development process?

Answer:
In Ruby, a gem is a packaged library or extension that contains reusable code or functionalities. Gems allow developers to distribute and share their code with others, making it easier to incorporate pre-built solutions into Ruby applications. Gems can range from simple utility libraries to complex frameworks and tools.

Gems are useful in the development process because they provide a modular and efficient way to manage dependencies and reuse code. By using gems, developers can avoid reinventing the wheel and focus on higher-level application logic. Gems can be installed and managed using the gem command-line tool, and popular gems are hosted on the RubyGems website.

Question:
Write a Ruby class representing a basic bank account. It should have methods to deposit, withdraw, and check the balance.

Answer:

class BankAccount
  def initialize
    @balance = 0
  end

  def deposit(amount)
    @balance += amount
  end

  def withdraw(amount)
    if amount <= @balance
      @balance -= amount
    else
      puts "Insufficient balance."
    end
  end

  def balance
    @balance
  end
end

# Example usage:
account = BankAccount.new
account.deposit(1000)
account.withdraw(300)
puts account.balance
# Output: 700Code language: CSS (css)

In this code, we define a BankAccount class with an initialize method to set the initial balance to 0. The deposit method increases the balance by the specified amount, the withdraw method deducts the amount from the balance if sufficient funds are available, and the balance method returns the current balance.

Question:
Explain the concept of inheritance in Ruby and how it facilitates code reuse.

Answer:
Inheritance is a fundamental object-oriented programming concept in Ruby (and many other languages). It allows a class to inherit properties and behaviors from another class, referred to as the parent or base class. The class inheriting the properties is called the child or derived class. The child class can add new methods or override existing ones but automatically inherits all the attributes and methods from the parent class.

Inheritance facilitates code reuse by allowing developers to create specialized classes based on existing ones. Instead of rewriting common functionalities in each class, developers can define them once in the parent class and have them inherited by all child classes. This leads to more maintainable and modular code.

Question:
Create a Ruby module called Helper with a method that calculates the square of a number. Then, implement a class Calculator that includes the Helper module and uses the square method to calculate the square of a given number.

module Helper
  def square(num)
    num * num
  end
end

class Calculator
  include Helper
end

# Example usage:
calculator = Calculator.new
result = calculator.square(5)
puts result
# Output: 25

In this code, we define a Helper module with a square method that calculates the square of a number. The Calculator class includes the Helper module, which allows instances of the Calculator class to use the square method to perform calculations.

Question:
Explain the concept of a block in Ruby and provide an example of its usage.

Answer:
In Ruby, a block is a chunk of code enclosed in either curly braces {} or do...end. Blocks are used to group statements together and pass them as an argument to a method. They provide a way to execute a set of statements within the context of a method call.

Here’s an example of using a block in Ruby:

def do_something
  puts "Start of method"
  yield
  puts "End of method"
end

do_something do
  puts "Inside the block"
end

# Output:
# Start of method
# Inside the block
# End of methodCode language: PHP (php)

In this example, the do_something method yields control to the block enclosed by do...end. The statements inside the block are executed, and then control returns to the method to continue execution.

Question:
Write a Ruby method that takes an array of strings and returns a new array containing only the strings that are of even length.’

Answer:

def even_length_strings(input_array)
  input_array.select { |str| str.length.even? }
end

# Example usage:
strings = ["apple", "banana", "orange", "grapes", "kiwi"]
result = even_length_strings(strings)
puts result
# Output: ["banana", "grapes"]Code language: PHP (php)

In this code, the even_length_strings method uses the select method to filter the array and only keep elements for which the block (str.length.even?) returns true, i.e., strings with even lengths.

Question:
Explain the concept of a symbol in Ruby and why it is useful compared to strings.

Answer:
In Ruby, a symbol is a lightweight and immutable data type represented by a name preceded by a colon (:). Symbols are used to identify names or labels within a Ruby program. Unlike strings, symbols are stored in memory only once, making them more memory-efficient. This feature makes symbols particularly useful when we need a unique identifier or label for an object, method, or key in a hash.

For example, when using symbols as keys in a hash, the retrieval is faster because Ruby doesn’t have to create new objects to represent each key.

person = {

 name: "John", age: 30, occupation: "Engineer" }Code language: JavaScript (javascript)

In this example, the keys :name, :age, and :occupation are symbols. Using symbols as keys is more efficient than using strings because symbols have the same object id throughout the program’s execution, while strings create different objects each time they are used.

Question:
Write a Ruby method that takes a string as input and returns a new string with the words reversed.

def reverse_words(input_string)
  words = input_string.split(" ")
  reversed_words = words.reverse
  reversed_string = reversed_words.join(" ")
  reversed_string
end

# Example usage:
sentence = "Hello, this is a sample sentence."
result = reverse_words(sentence)
puts result
# Output: "sentence. sample a is this Hello,"Code language: PHP (php)

In this code, the reverse_words method splits the input string into an array of words using the split method, then reverses the order of words using the reverse method, and finally joins the reversed words back into a string using the join method. The resulting string contains the words in reverse order.

Intermediate Ruby interview questions

Question:
Explain the concept of duck typing in Ruby and how it differs from static typing in other programming languages.

Answer:
In Ruby, duck typing is a concept that determines the type or class of an object based on its behavior (methods and properties) rather than its explicit type. The phrase “If it walks like a duck and quacks like a duck, then it must be a duck” captures the essence of duck typing.

When using duck typing, Ruby objects are allowed to respond to methods they understand, regardless of their class or inheritance hierarchy. This flexibility enables polymorphism, as different objects can respond to the same method calls in a way that makes sense for each object.

In contrast, static typing in other programming languages requires explicit declaration of variable types, and objects must belong to specific classes to perform certain operations. This leads to a more rigid and verbose code structure compared to the dynamic and flexible nature of duck typing in Ruby.

Question:
Implement a Ruby class that represents a geometric shape. The class should have a method to calculate the area of the shape.

Answer:

class GeometricShape
  def calculate_area
    raise NotImplementedError, "Subclasses must implement calculate_area method."
  end
end

class Rectangle < GeometricShape
  def initialize(length, width)
    @length = length
    @width = width
  end

  def calculate_area
    @length * @width
  end
end

class Circle < GeometricShape
  def initialize(radius)
    @radius = radius
  end

  def calculate_area
    Math::PI * @radius**2
  end
end

# Example usage:
rectangle = Rectangle.new(5, 3)
circle = Circle.new(4)

puts rectangle.calculate_area
puts circle.calculate_areaCode language: CSS (css)

In this code, we define an abstract GeometricShape class with a method calculate_area, which raises a NotImplementedError. This makes it an abstract method, requiring subclasses to implement it. The Rectangle and Circle classes are subclasses that inherit from GeometricShape and implement the calculate_area method accordingly.

Question:
Explain the purpose of modules in Ruby and how they facilitate code organization and reusability.

Answer:
In Ruby, modules are containers for methods, constants, and other module or class definitions. They serve two main purposes: code organization and code reusability.

  1. Code Organization: Modules help organize related methods and constants into cohesive units, allowing developers to group functionality based on common themes or responsibilities. This improves code readability, maintainability, and scalability. For example, modules can be used to group utility methods, mathematical functions, or file manipulation functions.
  2. Code Reusability: Modules enable code reusability by acting as a mixin. A module’s methods can be included in multiple classes, allowing those classes to inherit the module’s functionality without being part of the same inheritance hierarchy. This allows developers to share functionality across different classes without duplicating code.

Question:
Create a Ruby module called MathHelper that provides methods for calculating the factorial and the square root of a number. Implement a class Calculator that includes the MathHelper module and uses its methods to perform calculations.

Answer:

module MathHelper
  def factorial(n)
    n <= 1 ? 1 : n * factorial(n - 1)
  end

  def square_root(x)
    Math.sqrt(x)
  end
end

class Calculator
  include MathHelper
end

# Example usage:
calculator = Calculator.new
puts calculator.factorial(5)    # Output: 120
puts calculator.square_root(25) # Output: 5.0Code language: HTML, XML (xml)

In this code, we define a MathHelper module with methods factorial and square_root. The Calculator class includes the MathHelper module, gaining access to these methods for performing calculations.

Question:
Theoretical: Explain the concept of metaprogramming in Ruby and provide an example of how it can be used.

Answer:
Metaprogramming in Ruby refers to the ability of a program to modify or generate code at runtime. It allows developers to write code that writes code. Ruby’s dynamic nature, including features like introspection and open classes, makes metaprogramming powerful and flexible.

An example of metaprogramming in Ruby is using the define_method method to dynamically create methods in a class:

class MyClass
  define_method(:dynamic_method) do |arg|
    "Dynamic method called with argument: #{arg}"
  end
end

# Example usage:
obj = MyClass.new
puts obj.dynamic_method("Hello!") # Output: "Dynamic method called with argument: Hello!"

In this example, the define_method method is used to create a method named dynamic_method in the MyClass class at runtime. This allows us to create methods dynamically based on certain conditions or input.

Question:

Write a Ruby method that takes a string as input and returns the number of words in the string.

Answer:

def count_words(input_string)
  words = input_string.split(" ")
  words.count
end

# Example usage:
sentence = "Ruby is a powerful programming language"
result = count_words(sentence)
puts result # Output: 6Code language: PHP (php)

In this code, the count_words method splits the input string into an array of words using the split method, and then returns the count of elements in the array using the count method.

Question:

Explain the purpose of exceptions in Ruby and how they help handle errors and unexpected situations.

Answer:
Exceptions in Ruby are a way to handle errors and unexpected situations gracefully. When an error or exceptional condition occurs during program execution, Ruby raises an exception, which disrupts the normal flow of the program and jumps to the nearest exception handler.

Exceptions allow developers to identify and handle errors explicitly, preventing the program from crashing or producing incorrect results. By catching exceptions using rescue blocks, developers can take appropriate actions, such as logging the error, retrying the operation, or providing a fallback value.

For example:

begin
  # Code that may raise an exception
  result = 10 / 0
rescue ZeroDivisionError => e
  puts "Error: #{e.message}"
end

# Output: Error: divided by 0Code language: PHP (php)

In this example, a ZeroDivisionError exception is raised when trying to divide by zero. The rescue block catches the exception, and the program continues to execute without terminating abruptly.

Question:

Create a Ruby class called Person with attributes name and age. Implement a custom setter method for the age attribute that restricts the age to be within a specific range (e.g., 0 to 120).

class Person
  attr_reader :name
  attr_accessor :age

  def initialize(name, age)
    @name = name
    self.age = age
  end

  def age=(new_age)
    @age = new_age.clamp(0, 120)
  end
end

# Example usage:
person = Person.new("John", 150)


puts person.age # Output: 120 (Age is restricted to the range 0 to 120)Code language: CSS (css)

In this code, the Person class has attributes name (read-only) and age (read-write). We define a custom setter method age= for the age attribute, using the clamp method to restrict the age within the range of 0 to 120.

Question:
Explain the concept of closures in Ruby and how they capture their surrounding context.

Answer:
In Ruby, a closure is a block of code (lambda, proc, or block) that captures its surrounding context, including local variables, bindings, and methods. Closures allow developers to create functions that remember the environment in which they were created, even if they are executed in a different context later.

When a closure is defined, it captures the variables and methods available at the time of its definition. The closure can then access and manipulate these variables and methods when it is executed, even if they are no longer in scope.

Here’s an example of a closure using a block:

def outer_method
  x = 10
  inner_closure = proc { x }
  x = 20
  inner_closure.call
end

puts outer_method # Output: 20Code language: PHP (php)

In this example, the inner_closure proc captures the variable x from its surrounding context when it is defined. Even though x is modified to 20 later in the outer_method, the closure retains the original value of x (10) when it is called.

Question:
Code-related: Implement a Ruby method that takes an array of integers as input and returns a new array containing only the unique elements, removing any duplicates.

def unique_elements(input_array)
  input_array.uniq
end

# Example usage:
numbers = [1, 2, 3, 4, 3, 2, 5]
result = unique_elements(numbers)
puts result # Output: [1, 2, 3, 4, 5]Code language: PHP (php)

In this code, the unique_elements method uses the uniq method to remove duplicates from the input array and return a new array containing only the unique elements.

Senior Ruby interview questions

Question:

Explain the concept of metaprogramming in Ruby and how it is utilized in real-world applications.

Answer:
Metaprogramming is a powerful concept in Ruby that allows programs to treat code as data and manipulate it during runtime. Ruby provides several metaprogramming features, such as dynamic method definitions, opening classes at runtime, and using reflection to access methods and modify behavior.

In real-world applications, metaprogramming is extensively used in frameworks, libraries, and DSLs (Domain-Specific Languages). For example, Rails, a popular web framework, uses metaprogramming to generate accessor methods, define relationships between models, and provide database abstractions. Metaprogramming allows Rails to offer a user-friendly syntax and simplify repetitive tasks for developers.

DSLs, such as Rake and Capistrano, are built using metaprogramming to define domain-specific tasks and configurations concisely. This enables developers to express complex tasks with simple and readable code.

Question:
Write a Ruby method that takes a block and executes it only if the block is given.

Answer:

def execute_block_if_given
  if block_given?
    yield
  else
    puts "No block given."
  end
end

# Example usage:
execute_block_if_given { puts "Block is executed!" }
# Output: "Block is executed!"

execute_block_if_given
# Output: "No block given."Code language: PHP (php)

In this code, the execute_block_if_given method uses the block_given? method to check if a block is provided. If a block is given, the method uses yield to execute the block.

Question:
Explain the difference between modules and classes in Ruby and when to use each.

Answer:
In Ruby, both modules and classes serve as containers for methods and constants, but they serve different purposes:

  1. Classes: Classes define objects with attributes (instance variables) and behaviors (methods). They support inheritance, encapsulation, and object instantiation. Classes are used when you want to create objects with specific attributes and behaviors and group related functionality.
  2. Modules: Modules are similar to classes, but they cannot be instantiated or serve as a blueprint for objects. Instead, they act as containers for methods and constants that can be included in classes or other modules using the include or extend keyword. Modules are used when you want to share functionality across multiple classes without creating a full-blown class hierarchy.

Use classes when you want to create objects and define their behavior. Use modules when you want to share methods and constants across multiple classes or define mixins that can be included in various classes.

Question:
Implement a Ruby method that finds the most frequent element in an array.

Answer:

def most_frequent_element(array)
  frequency = Hash.new(0)

  array.each do |element|
    frequency[element] += 1
  end

  max_frequency = frequency.values.max
  most_frequent_elements = frequency.select { |_element, freq| freq == max_frequency }.keys
  most_frequent_elements
end

# Example usage:
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
result = most_frequent_element(numbers)
puts result
# Output: [4]Code language: PHP (php)

In this code, we use a hash to store the frequency of each element in the array. The most_frequent_element method iterates through the array and updates the frequency count for each element. After that, it finds the maximum frequency and selects the elements with that frequency to return as the most frequent elements.

Question:
Explain the concept of refinements in Ruby and their intended use.

Answer:
Refinements in Ruby allow developers to modify the behavior of classes or methods locally within a specific scope. Unlike monkey-patching, which modifies the behavior globally, refinements are only active within the block in which they are used. Refinements are primarily intended to address issues related to monkey-patching, where unintended side effects can occur when modifying core classes or methods.

Refinements are defined using the refine keyword and applied to a specific class or module using the using keyword within a block. When the block exits, the modifications from the refinement are no longer in effect.

Here’s an example of using refinements:

module MyRefinement
  refine String do
    def shout
      upcase + "!!!"
    end
  end
end

class MyClass
  using MyRefinement

  def greet(name)
    "Hello, #{name.shout}"
  end
end

# Example usage:
obj = MyClass.new
puts obj.greet("Alice") # Output: "Hello, ALICE!!!"
puts "Hi, Ruby".shout   # Output: NoMethodError (undefined method `shout' for "Hi, Ruby":String)

In this example, the MyRefinement module defines a refinement for the String class, adding a shout method. The refinement is applied to the String class within the MyClass using block. Inside the block, the shout method is available, but outside the block, it is not, preventing unintended side effects.

Question:
Write a Ruby method that takes an array of integers as input and returns a new array containing only the prime numbers.

Answer:

def prime_numbers(input_array)
  input_array.select { |num| is_prime?(num) }
end

def is_prime?(num)
  return false if num <= 1

  (2..Math.sqrt(num)).none? { |i| num % i == 0 }
end

# Example usage:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
result = prime_numbers(numbers)
puts result
# Output: [2, 3, 5, 7]Code language: PHP (php)

In this code, we define the prime_numbers method, which uses the select method to filter the array and only keep elements for which the is_prime? method returns true. The is_prime? method checks whether a number is prime using a simple primality test.

Question:
Explain the concept of garbage collection in Ruby and how it helps manage memory.

Answer:
Garbage collection is a memory management mechanism in Ruby (and many other programming languages) that automatically reclaims memory that is no longer in use or referenced by any part of the program. It helps prevent memory leaks and efficiently manages memory resources.

Ruby uses a mark-and-sweep garbage collector. When the garbage collector runs, it marks all objects that are still in use by the program (reachable) and then sweeps through the memory to free up the memory occupied by objects that are not marked (unreachable).

The garbage collector in Ruby is transparent to the developer, as it runs automatically at specific intervals or when the memory threshold is reached. This automatic memory management ensures that developers don’t have to explicitly deallocate memory, making Ruby more convenient and less prone to memory-related bugs.

Question:
Implement a Ruby method that converts a given sentence to title case.

Answer:

def title_case(sentence)
  words = sentence.split(" ")
  capitalized_words = words.map(&:capitalize)
  capitalized_sentence = capitalized_words.join(" ")
  capitalized_sentence
end

# Example usage:
text = "this is a sample sentence in title case."
result = title_case(text)
puts result
# Output: "This Is A Sample Sentence In Title Case."Code language: PHP (php)

In this code, the title_case method splits the input sentence into an array of words using the split method, capitalizes each word using the map method and capitalize method, and then joins the capitalized words back into a sentence using the join method.

Question:
Explain the concept of concurrency and parallelism in Ruby, and how they are achieved.

Answer:
Concurrency and parallelism are related but distinct concepts in Ruby (and other languages):

  1. Concurrency: Concurrency is the ability of a program to handle multiple tasks at the same time, making progress on each of them. In Ruby, concurrency is typically achieved using threads. Ruby’s threads allow the program to switch between tasks (context switching) so that it appears that multiple tasks are being executed simultaneously.
  2. Parallelism: Parallelism is the actual simultaneous execution of multiple tasks on multiple cores or processors. In Ruby, parallelism can be achieved using multiple processes or threads. Ruby threads are not true OS-level threads, so parallelism on multiple cores is generally limited. However, parallelism can be achieved using the Process class to create multiple processes, which can run in parallel on multicore systems.

It’s essential to note that Ruby’s Global Interpreter Lock (GIL) restricts true parallelism with threads, but concurrency can still be effectively achieved for I/O-bound tasks.

Question:
Write a Ruby method that takes a string as input and returns the number of occurrences of each word in the string.

Answer:

def word_occurrences(input_string)
  words = input_string.split(" ")
  frequency = Hash.new(0)

  words.each do |word|
    frequency[word.downcase] += 1
  end

  frequency
end

# Example usage:
sentence = "This is a sample sentence. This is another sample sentence."
result = word_occurrences(sentence)
puts result
# Output: {"this"=>2, "is"=>2, "a"=>1, "sample"=>2, "sentence."=>1, "another"=>1}Code language: PHP (php)

In this code, the word_occurrences method uses the split method to split the input string into an array of words, and then it iterates through the array, counting the occurrences of each word using a hash. The downcase method is used to ensure case-insensitive counting of word occurrences. The resulting hash contains each word as a key and its frequency as the value.

1,000 Companies use CoderPad to Screen and Interview Developers

Best interview practices for Ruby roles

In order to conduct successful Ruby interviews, it is essential to take into account various factors, such as the candidate’s background and the specific engineering role. To guarantee a productive interview experience, we suggest implementing the following best practices:

  • Formulate technical questions that represent real-world business situations within your organization. This method will effectively engage the candidate and help assess their fit with your team.
  • Foster a collaborative atmosphere by encouraging the candidate to ask questions during the interview.
  • If you’re employing Ruby in a full-stack capacity, ensure that the candidate possess a fundamental understanding of HTML & CSS.

Furthermore, adhering to established interview procedures is crucial when conducting Ruby interviews. This includes adjusting the difficulty of the questions to align with the candidate’s abilities, promptly updating them on the status of their application, and offering them the chance to inquire about the evaluation process and collaborating with you and your team.