Ruby技術者認定試験(シルバー)のような試験を生成するアプリを公開しました

Rubyに関する選択式の試験が作れるCUIアプリrcertをgithubに公開しました。資格試験に興味がなくても、間違いやすいメソッドなどの問題を作っておいて、一日のはじめにやれば、ミスが減って開発が早くなるかもしれません。と言っておきたいと思います。

デモ動画

2種ある範囲演算子の暗記方法

範囲演算子は'0..10'と'0...10'があります。どっちかが10を含んで、どちらかが10を含まないんですが、さぁこれをどう暗記しようかなという話です。使用頻度が高い方をおぼえたら、消去法でどちらの意味も分かるのですが、なんとなく範囲演算子ってあまり書いた記憶がありません。たまに書くという感じ。

ということで方針を変更。記号の意味をこじつけてみましょう。まず、'a..b'がbを含む方なのですが、こちらを基本形とします。すると、bを含まない方は'a..(bの前)'と書くことになるでしょう。bの前を出す関数をリテラルで表しているのが'.b'を考えれば辻褄があいます。

更にa=0, b=100としてaからbの数字を並べて書くとa1...99b。更に関係ない部分を除くと99bって感じに書ける。でも実際にはb=100とは限らないので'.b'と書くと考えると割とグラフィカルな記号です。どうでも良い話ですが、除算の記号÷も上の.に左の数を下の.に右の数をというように(例えば3÷6は3/6)、グラフィカルな記号なんだと勝手に納得してます。

静的ページのミドルウェア(Rack)

Rack::FileのラッパーStaticが静的ページを扱うミドルウェアになっています。railsもpublicディレクトリの表示は同様の方法をとっています。なので、静的なページをpublicに置くとそちらが優先されます。

動作デモ

Engine, Applicationはクラスメソッドの呼び出しに失敗した場合は、インスタンスメソッドを実行する

railsアプリのconfig.ruを見ると"run XXX::Application"となっていて、でもRails::Applicationにはcall(env)がなくてってので、どうして動くのか理解できませんでしたが、ソースコードを見ると

 class Railtie
    autoload :Configurable,  "rails/railtie/configurable"
    ...
    class << self
      def inherited(base)
        unless base.abstract_railtie?
          base.send(:include, Railtie::Configurable)
          ...
        end
      end
     ...

となっていて、ようするにXXX::ApplicationはConfigurableをincludeしています。Configurableはだいたい次のコードのConfigurableをextendしたような効果があります。それで、rackがXXX::Application.call(env)しても動いてくれるのです。

最後にちょっと言語の知識をメモを。「rubyはメソッドが見つからないとき、method_missingを呼ぶきまりになっている」ようです。

ctrl+cでrackサーバーをシャットダウンする

Rack.version == 1.1で、

require 'rack'
Rack::Handler::WEBrick.run HelloRack.new, :Port => 9292

とするとctrl+cでサーバーがシャットダウンできないので、次のように書き換えてシャットダウンできるようにしています。

rackアプリは設定ファイル(hello.ru)のなかで指定しています。設定ファイルには"run HelloRack.new"が書かれていますが、このrunはRack::Builderのメソッドです。
Rack::Server#startを見るとServer#appを呼ばれていて、その中でRack::Builder::parse_fileが呼ばれています。ここで、指定した設定ファイルをinstance_evalしているようです。結局rackアプリがServer#appから得られます。appはRack::Handler(webrick的にはServlet)に渡されて...あとの処理はwebrick(標準ライブラリ)を見ると分かります。


ところでRails::Server(書いたときの最新のコード)のstartメソッドはrackが自力でshutdownできるのにtrap {exit}を書いていて無駄かなと思います。