Примеры задач с собеседования на позицию Middle Ruby разработчика

Несколько задачек по основам Ruby и часто используемым функциям языка для собеседования на позицию middle разработчика.

7К открытий9К показов

Позиции Junior, Middle и Senior в СНГ различаются не только от компаний к компаниям, но и в принципе отсутствуют в некоторых странах. Для проведения интервью у кого-то есть заранее подготовленный набор тестовых заданий, кто-то предпочитает беседу за жизнь вперемешку с конкретными техническими вопросами. Есть компании, которым важны преимущественно soft skills. И все-таки выявить подходящего кандидата — дорогостоящий процесс.

После прохождения интервью во множество компаний есть понимание, что кандидат должен знать и уметь применять основные принципы, на которых строятся современные приложения. И хотя в моей практике не было такого, чтобы интервью закончилось после первого неправильного ответа или вопроса, — есть основы, в которых надо разобраться заранее.

В этом материале создана подборка по основам Ruby, часто используемым функциям языка. И если Junior разработчик никак не привязан к языку программирования, а Senior может писать более сложный код, то если вы сможете решить эти задачи без подсказок — бо́льшая часть практической подготовки на позицию Middle пройдена и можно сфокусироваться на других темах при подготовке к собеседованию.

Реализуйте метод Array#map

Вариант ответа
			class Array
  def map
    return unless block_given?

    result = []
    i = 0

    while self[i] do
      result << yield(self[i])
      i += 1
    end

    result
  end
end
		

Проверка использования: [1,2,3,4].map { |x| x * 10 }

Реализуйте метод attr_accessor

Вариант ответа
			module AttrAccessor
  def self.included(klass)
    klass.extend(ClassMethods)
  end

  module ClassMethods
    def custom_attr_accessor(*args)
      args.each do |arg|
        define_method(arg) do
          self.instance_variable_get("@#{arg}")
        end

        define_method("#{arg}=") do |value|
          self.instance_variable_set("@#{arg}", value)
        end
      end
    end
  end
end
		

Проверка использования:

			class Car
  include AttrAccessor
  custom_attr_accessor :wheels_count, :driver_name
end

car = Car.new
car.wheels_count = 4
p car.wheels_count

car.driver_name = 'Kevin'
p car.driver_name
		

Перепишите код без использования if

			class HtmlFormatter
  def initialize(body)
    @body = body
  end

  def to_s
    "#{@body}"
  end
end

class JsonFormatter
  def initialize(body)
    @body = body
  end

  def to_s
    "{ body: #{@body} }"
  end
end

class Text
  def initialize(body)
    @body = body
  end

  def formatted(type=nil)
    if type == :json
      JsonFormatter.new(@body)
    elsif type == :html
      HtmlFormatter.new(@body)
    else
      raise 'an unknown format type'
    end
  end
end
		

Проверка использования:

			text = Text.new('New text')
puts text.formatted(:json)
		
Вариант ответа
			class Text
  def initialize(body, formatter)
    @body = body
    @formatter = formatter
  end

  def formatted
    @formatter.render(@body)
  end
end

class BaseFormatter
  def render(text)
    raise 'Not implemented :render method'
  end
end

class HtmlFormatter < BaseFormatter
  def render(text)
    "#{text}"
  end
end

class JsonFormatter < BaseFormatter
  def render(text)
    "{ body: #{text} }"
  end
end

class XmlFormatter < BaseFormatter
end
		

Проверка использования:

			text = Text.new('Text', JsonFormatter.new)
puts text.formatted
		

Напишите код, чтобы строка (1..10).select(&3) возвращала результат [3, 6, 9]

Вариант ответа
			class Fixnum
  def to_proc
    Proc.new { |item| item % self == 0 }
  end
end
		

Добавьте функциональность объекта post, изменяющую значение любого параметра объекта на требуемое и логирующую это изменение

Класс Post:

			class Post
  attr_reader :state, :title, :body

  def initialize(title, body)
    @title = title
    @body = body
    @state = :draft
  end

  def publish!
    @state = :published if @state == :draft
  end

  def delete!
    @state = :deleted if @state == :published
  end
end
		
Вариант ответа
			require 'logger'

module Forceable
  def method_missing(method, *args, &block)
    if method =~ /force_(\w+)/ && previous_value = self.instance_variable_get("@#{$1}")
      self.instance_variable_set("@#{$1}", args.first)

      puts "Post changes #{$1} value from #{previous_value} to #{args.first}"
    else
      super
    end
  end
end

Post.include(Forceable)
		

Проверка использования:

			post = Post.new('Title', 'Body')
post.publish!
p post.state
post.publish!
p post.state
post.force_state(:draft)
p post.state
		
Следите за новыми постами
Следите за новыми постами по любимым темам
7К открытий9К показов