Ruby Interview Questions

Implement a fancier version of attr_accessor that includes validation. Complete the attr_validated code below so that the unit tests pass.

require 'test/unit'

class Dog

    def self.attr_validated(method_name, &validation)
        # Complete this method so that the unit tests pass
    end

    attr_validated :num_legs do |v|
        v <= 4
    end


end

class TestDog < Test::Unit::TestCase

    def test_good_value
        dog = Dog.new
        dog.num_legs = 3

        assert_equal 3, dog.num_legs
    end

    def test_nil_value
        dog = Dog.new
        assert_raises ArgumentError do
            dog.num_legs = nil
        end
    end

    def test_illegal_value
        dog = Dog.new
        assert_raises ArgumentError do
            dog.num_legs = 5
        end
    end

end

Write a Math module to extend the Fixnum class. This module should provide two methods. First, a class method called pi that prints out the value of pi to two significant digits. Second, an instance method called squared that squares a number. E.g. when you are finished the following should be possible:

puts Fixnum.pi
# 3.14
puts 2.squared
# 4

Suppose you have a class that performs several expensive calculations. However, during the lifetime of an object, the result of the expensive calculation won't change. Therefore, you wish to ensure that each calculation is performed only once, and that result is cached. A simple technique for this would be as follows:

class Calculator
    def expensive_calc_one
        return @result1 unless @result1.nil?
       @result1 = # Do very expensive calculation.
    end

   def expensive_calc_two
        return @result2 unless @result2.nil?
       @result2 = # Do very expensive calculation.
    end
end

If this class contained many such expensive calculations, this memoization technique would become repetitive. Can you come up with a framework that reduces this repetition by allowing one to simply mark a method as memoized and no longer have to worry about manually handling the caching?

Bonus points: There is a flaw in the simple technique. Under one set of circumstances the caching will fail and repeated calls to expensive_calc_one will result in the expensive calculation being executed again and gain. When would this occur?

Suppose you have the following array

stuff = [:dog,:cat,:orange,:banana]
  1. How can you slice this array to create a new array [:cat,:orange]
  2. Add the element :apple on to the end of the array.
  3. Now take :apple back off again
  4. Add the element :fish to the start of the array.
  5. Now remove the element :fish.

When opening a connection to a remote service, it's typically important to make sure that the connection (or "resource") is closed - no matter what happens in the code that uses the resource. In Java this might be done as follows:

Connection conn;
try{
  conn = new Connection("some service");
  conn.doSomething();
}
catch(Exception e){}
finally{
  conn.close();
}

This pattern is tedious and repetitious, and depends on the programmer to remember to include the finally clause. In Ruby, we can do better. Suppose we wished developers to be able to safely manage connection resources using a pattern like the following...

Connection conn = new Connection("some server")
using(conn){
   conn.doSomething();
}

Define a Kernel method using that ensures that no matter what happens within the using block, the connection is always closed.

The following code will fail with NoMethodError : private method 'dream' called for Dog

Assuming that you cannot modify the source code for the Dog class and that the method
must remain private - how can you nonetheless call this method from outside of Dog class?

class Dog
    def speak
        puts "woof"
    end

    private

    def dream
        puts "chasing a rabbit"
    end
end

dog = Dog.new
dog.speak
dog.dream

Suppose you have a class Dog with two methods GetHasSpots and say_Woof. The method names do not follow your new naming conventions and you wish to rename them to has_spots? and say_woof. However, finding and correcting all references to these methods in one coding session is impractical due to a very large code base.

Thus, for some interim period of time you wish to allow both the old method names and the new methods names to work. Of course, you want to do this in the most DRY way possible, while also clearly marking the old methods as deprecated. The shell of a solution is shown below. Fill in the details of the deprecate method to make the unit tests pass.

require 'test/unit'

class Dog

    def has_spots?
        true
    end

    def woof
        "woof"
    end

    def self.deprecate(old_method, new_method)
       # Add code here that will make the unit test pass
    end

    deprecate :say_Woof, :woof
    deprecate :GetHasSpots, :has_spots?
end

class TestDog < Test::Unit::TestCase

    def test_deprecation
        dog = Dog.new
        assert_equal true, dog.GetHasSpots
        assert_equal "woof", dog.say_Woof
    end

end

Modify the + operator in Ruby so that it always adds an extra (i.e1+1=3`). When you are done the unit test below should pass.

Hint: remember that the + operator is really a method with signature def +(value) on the Fixnum class.

require 'test/unit/'

class BackToKindergartenTest < Test::Unit::TestCase
    def test_plus_one
        assert_equal 3, 1 + 1
        assert_equal 5, 2 + 2
        assert_equal 1, -1 + 1
    end
end

Print out the prime numbers between 1 and 100. As a first pass, don't worry about writing an efficient algorithm. Just write clear code that is easy to follow. Once you've done that, consider different possible optimizations.

What will original and copy evaluate to in each of the following examples? Explain why there is a difference.

original = "hello"
copy = original
copy << " there"
puts copy
puts original
original = "hello"
copy = original
copy += " there"
puts copy
puts original

In each example below indicate whether or not we should be asserting true or false. (E.g. what should the ? be?).

Explain the difference between ==, eql and equal?

str1 = "chitter"
str2 = "chitter"

assert_equal ?, str1 == str2
assert_equal ?, str1.eql?(str2)
assert_equal ?, str1.equal?(str2)
assert_equal ?, str1.object_id == str2.object_id
sym1 = :chatter
sym2 = :chatter

assert_equal ?, sym1 == sym2
assert_equal ?, sym1.eql?(sym2)
assert_equal ?, sym1.equal?(sym2)
assert_equal ?, sym1.object_id == sym2.object_id

Suppose you have a web form that allows users to upload JPG, GIF or PNG images. Before you store the images in your system, you want to convert them all to the JPG format. Design an image converter API. Sketch out all classes and interfaces that are involved.

Note: the actual code necessary to convert a JPG image to a GIF image is not the point. Just place a comment at the appropriate location where the actual conversion should occur.

Assume that you have access to an employee's email Inbox, and that you can parse the content of their emails, including the email headers.

  1. How can you use this to deduce their first-degree connections?
  2. What kind of heuristics can you come up with to quantify the strength of these first-degree connections?
  3. How can you use this to deduce their second-degree connections?
  4. How can you use this to deduce their third-degree connections?

Suppose you have an array of 99 numbers. The array contains the digits 1 to 100 with one digit missing. Describe four different algorithms to compute the missing number. Two of these should optimize for low storage and two of these should optimize for fast processing.

  1. Describe how you would store a social graph in a relational database.
  2. Describe an efficient algorithm to determine whether or not person X is a 2nd degree connection of person Y.
  3. Describe an efficient algorithm to determine whether or not person X is a 3rd degree connection of person Y.
  4. How can you make #3 very quick. E.g. how does Linked In compute 3rd degree connections quickly?

Write a program to print out a multiplication table, from 1x1 to 12x12. This should look like:

   1   2   3   4   5   6   7   8   9  10  11  12
   2   4   6   8  10  12  14  16  18  20  22  24
   3   6   9  12  15  18  21  24  27  30  33  36
   4   8  12  16  20  24  28  32  36  40  44  48
   5  10  15  20  25  30  35  40  45  50  55  60
   6  12  18  24  30  36  42  48  54  60  66  72
   7  14  21  28  35  42  49  56  63  70  77  84
   8  16  24  32  40  48  56  64  72  80  88  96
   9  18  27  36  45  54  63  72  81  90  99 108
  10  20  30  40  50  60  70  80  90 100 110 120
  11  22  33  44  55  66  77  88  99 110 121 132
  12  24  36  48  60  72  84  96 108 120 132 144

Define the following object oriented concepts:

  • Class, object (and the difference between the two)
  • Instantiation
  • Method (as opposed to, say, a C function)
  • Static methods and classes
  • Destructor/finalizer
  • Inheritance
  • Encapsulation
  • Multiple inheritance (and give an example)
  • Abstract class
  • Interface/protocol (and different from abstract class)
  • Method overriding
  • Method overloading (and difference from overriding)
  • Polymorphism (without resorting to examples)
  • Method visibility (e.g. public/private/other)

Describe the difference between a class instance variable and a class variable in Ruby. Which bears more resemblance to a static field in Java?

Explain big o notation and how it is useful in computer science to classify algorithms.

  • What order is a hash table lookup?
  • What order is determining if a number is even or odd?
  • What order is finding an item in an unsorted list?
  • What order is a binary search?

In Ruby, there are three methods for converting a block into a Proc object (see below). Discuss the differences between these three choices.

b1 = Proc.new{|x| x + 1}
b2 = lamba{|x| x + 1}
b3 = proc{|x| x + 1 }

A user types the following URL into their browser: http://www.foo.com/bar.php

Explain in detail how this would cause a page to appear in their browser, with images, interactive elements (Ajax), styled paragraphs of text etc.

Write a function to efficiently determine the result of a game of Tic Tac Toe.

The function takes as input the game and the sign (x or o) of the player. The function returns if this player has won the game or not.

Carefully consider both the data structure and the algorithm for your answer.

Express the following table as a static structure, and write a function, find_routes(source, destination) that efficiently outputs all possible routes.

Source  | Dest
~~~~~~    ~~~~
Seattle | LA
LA      | Florida
LA      | Maine
Florida | Seattle
Seattle | Florida

The solution for find_routes('Seattle', 'Florida') should be [Seattle -> Florida, Seattle -> LA -> Florida]