NerdyBoy Is Cool

100以下の素数を取得するクエリをActiveRecordで書く

エンジニア面接の際にコードテストを実践しているところが多い中、 quipperはいわゆるFizzBuzz問題じゃなくて、業務に近いコードを出題しているそう。

こんな問題らしい

このテストは 100 以下の素数を回答にもつ Question を DB から取得し列挙するメソッド Question.with_prime_answers_under_100 を実装してもらうテストです。

quipper.hatenablog.com

解いてみる

公式ブログに書いていた問題なので、書いたコードを載せても大丈夫だと思ったので備忘録的に解いてみた。かかった時間は20分くらい。(Intergerクラスにprime?メソッドあるもんだと思っていたらなかった・・。そこで10minロス)

コードの指針

  1. with_prime_answers_under_100 というメソッドは「100以下の整数を取得」, 「素数の取得」という二つのことをしているので それぞれ一つのことだけをするメソッドに分割
  2. 意図的にscopeを使う。(Relationオブジェクトを返すscopeに記述Railsのクラスメソッドに書く時は、rubyのオブジェクト(ArrayとかHashとか)を返す時に限定して使うようにしている。)

under_100っていうメソッド名はビミョい笑

require "bundler/inline"

gemfile do
  source "https://rubygems.org"
  gem "activerecord"
  gem "sqlite3"
  gem "minitest"
  gem "prime"
end


require "active_record"
require "minitest/autorun"

class Question < ActiveRecord::Base
  validates :content, presence: true
  validates :answer, numericality: { only_integer: true, greater_than: 0 }

  scope :under_100, -> {
    where(answer: 1..100)
  }

  def self.prime_number_answers
    select{ |question| question.answer.prime? }
  end

  def self.with_prime_answers_under_100
    under_100.order(:answer).prime_number_answers
  end
end


class QuestionTest < Minitest::Test
  def setup
    ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
    ActiveRecord::Schema.define do
      create_table :questions do |t|
        t.string  :content, null: false
        t.integer :answer,  null: false
      end
    end

    101.downto(1) do |i|
      Question.create!(content: "Question #{i}", answer: i)
    end
  end

  def test_with_prime_answers_under_100
    questions = Question.with_prime_answers_under_100
    primes = Set[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
    assert_equal primes, questions.map(&:answer).to_set
  end
end