「アンダースタンディング コンピュテーション」演習環境を整える

この本は、情報系の大学の、オートマトンと計算理論にあたる部分を自習できる教材である。具体的にはRubyのREPL環境で、コンピュータを作っていくことになる。ただ、Ruby標準のREPLであるirbはコーディングには貧弱なので、少し準備してみた。

irbの代わりにpryを使おう

pryはirbと比べて以下の点で有利だった。

  • シンタックスハイライト
  • 入力補完
  • 途中、vimで編集可能
  • コードのインポート、エクスポート

Home · pry/pry Wiki · GitHub

$ gem install pry

pryコマンドで開始できる。

pryの出力方法を変更する

pryでそのまま実行しても、本と同じ出力を得られない。本では構文木構築の結果をirbの実行結果として

<<1 * 2 + 3 * 4>>

のように表示させるのだが、pryだと各オブジェクトの詳細まで出力してしまって、

=> #<struct Add
 left=
  #<struct Multiply
   left=#<struct Number value=1>,
   right=#<struct Number value=2>>,
 right=
  #<struct Multiply
   left=#<struct Number value=3>,
   right=#<struct Number value=4>>>

となってしまう。

元のirbと同じように出力するには、~/.pryrcに以下を記述する。

Pry.config.print = proc { |output, value| output.puts "=> #{value.inspect}" }

元ネタ: IRB Like Output in Pry

途中で中断したり、再開したりしたい

この本では、最初は空のクラスを作って、徐々に
モンキーパッチングで機能を追加->確認、追加->確認というふうに繰り返す。だから、クラスの全体像がわかるコードは登場しない。また、一旦REPL環境を閉じてしまうと、また最初から書き直しになってしまう。

方法A. モンキーパッチングによる追記はvimで、確認はpryで行うようにする。

いくつかやりかたがあるが、この方法の場合、クラスの書き間違いを修正しやすい。

1. vimを呼び出せるようにする

~/.pryrcに追記

Pry.config.editor = "vim"
2. 先にファイルを作る
$ touch simple.rb
3. 読み込む
pry(main)> require './simple'

または、pry起動時のオプションで渡す:

$ pry -r './simple'
4. クラスの追記
pry(main)> edit simple.rb

これでvimが開く。本のように、モンキーパッチング的にclass Numberを何回も書いていってもいいだろうし、class Number 〜〜 endの中に追記していってもいい。

(元から別ウィンドウで編集しててもOKな気がする。)

この時、ファイルを上書きするたびに読み込み直されてしまうので、クラス二重定義エラーが出る。

class Number < Struct.new(:value)
end

class Add < Struct.new(:left, :right)
end

class Multiply < Struct.new(:left, :right)
end
pry(main)> edit simple.rb
TypeError: superclass mismatch for class Number

仕方ないので、最初のスーパークラスを持たせる部分だけはInclude guard的なことをしておく。23ページのコードだったらこんな感じ。

unless defined? Number
  class Number < Struct.new(:value)
  end
end

unless defined? Add
  class Add < Struct.new(:left, :right)
  end
end

unless defined? Multiply
  class Multiply < Struct.new(:left, :right)
  end
end

class Number
  def to_s
    value.to_s
  end

  def inspect
    "<<#{self}>>"
  end
end

class Add
  def to_s
    "#{left} + #{right}"
  end

  def inspect
    "<<#{self}>>"
  end
end

class Multiply
  def to_s
    "#{left} * #{right}"
  end

  def inspect
    "<<#{self}>>"
  end
end

こうしておけば、editコマンドによる編集後の自動再読みでエラーは出なくなり、

pry(main) > edit simple.rb

さらに、クラス名を指定して編集できるようになっている。

pry(main) > edit Number       #vim起動時に自動でclass Numberの行まで移動
5. エディタを閉じて、実行してみる

リロード操作は不要

pry(main)> Add.new(
                         Multiply.new(Number.new(1), Number.new(2)),
                         Multiply.new(Number.new(3), Number.new(4))
                       )
=> ...(出力)...

4, 5の工程の繰り返しで作業していく。

参考: Ruby - Pry上でreload!要らずのファイル編集 - Qiita

方法B. 実行履歴を保存、リロードする

この方法の場合、書いたクラスの完全版がわかるコードは得られないので注意。REPLの臨場感は損なわないのでサクっと進みたい人はいいかも。

デフォルトでpryは~/.pry_historyに履歴を溜め込んでいる。

History · pry/pry Wiki · GitHub

historyを眺め、hist --replay [m..n]というコマンドで再生できる。別ファイルに保存したい場合はhist --save [m..n] FILENAME で保存できる。