N=1

主にコンピュータ技術関連のことを投稿。 / 投稿は個人の意見であり所属団体の立場を代表するものではありません。

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

この本は、情報系の大学の、オートマトンと計算理論にあたる部分を自習できる教材である。具体的には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 で保存できる。