ひさびさにRailsをやる

ちょっと卒論で作ろうと思ってるシステムをRailsで作りたいなぁと思ってひさびさにRailsをやる。

題材は[Ruby][Rails] Ruby on RailsでWiki
http://d.hatena.ne.jp/muscovyduck/20060511#1147307789

以下少し違ったところと要点をまとめる。

開発&実行環境

walf443@ruribita:railswiki% script/about
About your application's environment
Ruby version 1.8.2 (i386-linux)
RubyGems version 0.8.11
Rails version 1.1.2
Active Record version 1.14.2
Action Pack version 1.12.1
Action Web Service version 1.1.2
Action Mailer version 1.2.1
Active Support version 1.3.1
Application root /home/walf443/railswiki
Environment development
Database adapter mysql
Database schema version 2

データベース周り

自分はMySQL4.0を使った。

後々FrontPageがないとハマることになるので、自分はマイグレーションスキーマを更に次のように変更した。

# db/migrate/002_initial_schema.rb

class Contents < ActiveRecord::Base
end

class InitialSchema < ActiveRecord::Migration
  def self.up
    Contents.create :title => 'FrontPage', :body => 'This is FrontPage.'
  end
  
  def self.down
    frontpage = Contents.find_by_title 'FrontPage'
    frontpage.destroy
  end
end

Contentsのアイテムを作成するので事前にクラスだけ定義しておくのがポイント。

$rake migrate

スキーマを上げたり戻したり出来るのでファイルは分けておいた方が良いと思われる。

self.upメソッドには今回追加する処理を記述。self.downメソッドには前回のスキーマに戻すためのメソッドを記述する。

Helper

Helperにはscript/generate helperとかないのかな。うまく動作しなかった。

題材のページでは一つのファイルにHelperを記述しているけど、こちらでは動かず。ということで以下のようにした。

walf443@ruribita:railswiki% cat app/helpers/railswiki_helper.rb
module RailswikiHelper
end

walf443@ruribita:railswiki% cat app/helpers/railswiki_helper/to_html_with_links.rb 
require 'rdoc/markup/simple_markup'
require 'rdoc/markup/simple_markup/to_html'

module RailswikiHelper
  class ToHtmlWithLinks < SM::ToHtml
    def handle_special_WIKIWORD(special)
      %Q|<a href="/railswiki/show/#{special.text}">#{special.text}</a>|
    end
    
    def handle_special_HTTP(special)
      %Q|<a href="#{special.text}">#{special.text}</a>|
    end
    
    def handle_special_BRACKET(special)
      %Q|<a href="/railswiki/show/#{special.text[2..-3]}">#{special.text[2..3]}</a>|
    end
  end
end

walf443@ruribita:railswiki% cat app/helpers/railswiki_helper/railswiki_template.rb 
require 'rdoc/markup/simple_markup'
require 'rdoc/markup/simple_markup/to_html'

module RailswikiHelper
  class RailswikiTemplate
    def initialize(view=nil)
      @view = view
    end

    def render(template, assigns)
      markup = SM::SimpleMarkup.new
      markup.add_special /\b([A-Z][a-z]+[A-Z]\w+)/, :WIKIWORD
      markup.add_special %r|(https?://\s+)|, :HTTP
      markup.add_special /(\[\[.+?\]\])/, :BRACKET
      markup.convert template, ToHtmlWithLinks.new
    end
  end
end

SM::Simpleがなかなか認識されない(Const missing)ので仕方なく両方のファイルにrequireした。こういうときはどこにrequireするものなのだろうか。

Controller・View

hoge :action => ... とかいう感じのメソッドってどちらかというとSymbolを渡したくなるのは自分だけだろうか。特に:actionはメソッド名を指しているのでSymbolの方がそれっぽい気がする。エディタ的には色がつかないので文字列の方が見やすいのだけど。

その他

WEBrickでサーバを起動したとき、.irbrcでプロンプトの設定をしているとActiveSupportの拡張によりエラーが発生するようです。具体的には以下のような記述。

  IRB.conf[:PROMPT][:SIMPLEST] = {
    :PROMPT_I => "",
    :PROMPT_S => "",
    :PROMPT_C => "",
    :RETURN => "  #=> %s\n\n"
  }  

エラーメッセージを頼りにunless IRB.conf[:PROMPT].nil? .. end で囲むと大丈夫になった。

まとめ

簡単にできると思っていたが割といろんな場面でハマった。というわけで色々作りながら覚えていこうかと思う。

?表現

[ruby-list:42301]によると文字コードを調べるリテラルだそうです。こんなのあるとは知らなかった…。

マニュアルを引いてみました。

?a
文字aのコード(97)

ruby 1.7 feature: 空白類を指定する場合は、?\s, ?\t などとする必要があります。

?\C-a
コントロール a のコード(1)

?\M-a
メタ a のコード(225)

?\M-\C-a
メタ-コントロール a のコード(129)


From: http://www.ruby-lang.org/ja/man/?cmd=view;name=%A5%EA%A5%C6%A5%E9%A5%EB#a.bf.f4.c3.cd.a5.ea.a5.c6.a5.e9.a5.eb

irbなどでちょっと確認したいときやキーコード判定をしたいときなどに良さそうです。ただ文字列の文字すべてをコードに直すなど動的に処理したいとき*1や日本語などの文字に関しては使えないのでそれほど使う機会はないかもしれません。

それにしてもruby-listのメールの数はphp-usersなどに比べると非常に少ないのですが、それはRubyの体系がうまく整理されていることとか、多少分からなくてもirbに打ち込んでみればどんな風に動くか手軽に調べられることが関係しているのかなぁと思いました。とはいえruby-talkは非常に数が多いけど。

*1:もちろんevalを使えば出来るでしょう

パスカルの三角形

コメント欄にてあいさんより質問を頂いたので挑戦してみました。

あい 『ちょっと質問なんですが、
パスカルの三角形で、

                                                            • -

m 0 1 2 3 4 ・・・
n
0 1
1 1 1
2 1 2
3 1 3 3 1
4 1 4 6 4 1


                                                            • -

P(n,m)を求める関数を作るとき
schemeでどう書いたらいいですか?
例えば
(P 4 2)
=6
みたいになるプログラムを作りたいんです。

From: http://d.hatena.ne.jp/walf443/20060512/1147448853#c1148982927

どうやったら良いか思いつかないのでid:hyukiさんのコード
http://sicp.g.hatena.ne.jp/hyuki/20060512/pascal
を参考にしてみる。

combinationとlineの定義はそのまま使えそう。。。

まずはn個までパスカルの三角形を求める関数を作成します。

(define (pascal n)
  (define (pascal-iter i n)
          (cond ((< i n)
                 (display (line i))
                 (newline)
                 (pascal-iter (+ i 1) n))))
  (pascal-iter 0 n))

(pascal 10)

(1)
(1 1)
(1 2 1)
(1 3 3 1)
(1 4 6 4 1)
(1 5 10 10 5 1)
(1 6 15 20 15 6 1)
(1 7 21 35 35 21 7 1)
(1 8 28 56 70 56 28 8 1)
(1 9 36 84 126 126 84 36 9 1)

ここまでやってみてcombinationの定義を眺めていると、ようやくパスカルの三角形は2項係数で表せたことを思い出した。よく考えてみるとcombinationというのは組み合わせという意味だ。(ってそのまんま)

ということで、

(define (P n m)
  (cond ((= k 0) 1)
        ((= k n) 1)
        (else (+ (P (- n 1) k) (P (- n 1) (- k 1))))))

要するに _nC_k = \frac{n!}{k!(n-k)!}を定義すればよいようです。

階乗を定義してやるとより分かりやすく書けそう。

(define (combination n k)
  (define (factorial x) 
    (if (= x 0) 
        1       
        (* x (factorial (- x 1)))))
  (/ (factorial n) 
     (* (factorial k)
        (factorial (- n k)))))

反復を使っていないのでかなり直感的。

しかし _nC_k = \frac{n(n - 1)...(n - k)}{(n-k)!}なので、

(define (combination n k)
  (define (fact-iter init last)
    (if (= init last)
        last    
        (* init (fact-iter (+ init 1) last))))
  (/ (fact-iter k n)
     (fact-iter 1 (- n k)))) 

とも書ける。反復使っているし余計なものを約分してるのでこちらの方が効率よさそう。

とここまで書いてid:hyukiさんのコメント欄を見ると全く同じメッセージがっ!!もしかしてスパム?まぁ、いいや勉強になったし…。