🦬

Emacs + Ruby での AtCoder 環境が良すぎる

2024/01/29に公開

まず Emacs と xmpfilter の組み合わせが最高

v = "hello"                                # => "hello"
v = v.chars.collect { |e| e.ord.to_s(2) }  # => ["1101000", "1100101", "1101100", "1101100", "1101111"]
v = v.join                                 # => "11010001100101110110011011001101111"
v = v.count("1")                           # => 21

るびきち氏の開発した xmpfilter (rcodetools) は、各行の評価結果をコメントに入れてくれる。

入力例は __END__ の下にコピペするだけ

S = gets.strip  # => "hello"
p S.length      # => 5

上のコードを xmpfilter に通すと gets に __END__ の下のテキストが入ってくる。$stdin = DATADATA.gets などと書く必要はない。そしてそのまま提出できる。AtCoder 側で実行される際には gets に標準入力が入る。

プログラムが標準入力からの受け取りになっているからといって、わざわざコマンドラインで実行する必要もないし、入力例をソースコードに含めたまま提出できるので、xmpfilter と __END__ の組み合わせも最高。

標準入力を StringIO に置き換える方法もある

if $0 == "-"
  require "stringio"
  $stdin = StringIO.new(<<~EOS)
hello
EOS
end

S = gets.strip  # => "hello"
p S.length      # => 5

たまに __END__ のあとにコードを書きたいときがあるので、その場合は、$0 == "-" のとき、すなわち xmpfilter で実行したときだけ標準入力を置き換えればいい。このような柔軟性も最高。

もちろん、これもソースコードまるごと提出できる。

テストを書きたい場合

if ENV["ATCODER"] != "1"
  require "rspec/autorun"
  RSpec.configure do |config|
    config.expect_with :test_unit
  end

  describe do
    it "works" do
      assert { 1 + 2 == 3 }
    end
  end
end

これも $0 == "-" の条件下に入れてしまえばいいのだけど「コピペ用ライブラリファイル単体は xmpfilter で実行するとは限らないけど、AtCoder 側では実行されたくない」という、ようするに、ちょっとややこしい状況があったりする。

この場合、AtCoder の実行環境では環境変数 ATCODER"1" で定義されているから、ENV["ATCODER"] != "1" の条件下に入れておけば提出先で実行される心配がない。

したがって、競プロで TDD したっていい。提出するコードに思う存分テストを書けばいい。

関連

こちらではセットアップや一瞬で提出する手順を紹介している。

https://zenn.dev/megeton/articles/72d8bf71da39cb

Discussion