「全裸で学ぶMVC事始め」をruby + Sinatraでやってみた

勉強のため、ゆーすけべーさんの「全裸で学ぶMVC事始め」をruby + Sinatraで書いてみました。
MVCとは何か、どのような処理をするのかについては元エントリで分かりやすく解説されているのでそちらを参照してください。(なぜ全裸なのかも)

つくるもの = zenrize

入力されたテキストを改変して表示する簡単なWebサービスを作成します。
例えば「これから歯磨きをするよ」→「これから全裸で歯磨きをするよ」のようになります。
【全裸で】を差し込む箇所については、全裸botの作者sugyanさん色々調整を行なっていますが、
今回は単純に「文章内の動詞の前に【全裸で】を必ずつける」とします。

なお、テキスト中の品詞を特定するのにはYahoo!形態素解析APIを使用します。

実装

まずはモデル部分です。(こちらのページを大いに大いに*1参考にさせていただきました)
Zenraクラスを定義し、その中にzenrizeメソッドを定義します

class Zenra

  def initialize(position='動詞', text='全裸で')
    @appid    = 'YOUR_APP_ID'
    @position = position
    @text     = text
    @base_url = 'http://jlp.yahooapis.jp/MAService/V1/parse'
  end

  def zenrize(sentence)
    raise "appid is necessary!" if @appid.nil? || @appid.empty?
    raise "Japanese sentence is necessary!" if sentence.nil? || sentence.empty?

    req = "#{@base_url}?results=ma&appid=#{@appid}&sentence=#{URI.encode(sentence)}"
    res = open(req)
    xml = REXML::Document.new(res.read)

    return sentence if xml.elements['ResultSet/ma_result/total_count'].text == '0'

    result = ''
    xml.elements.each('ResultSet/ma_result/word_list/word') do |e|
      result << @text if e.elements['pos'].text == @position
      result << e.elements['surface'].text
    end
    result
  end

end

次にコントローラ部分です。
get, postメソッドに応じたルーティングを設定してリクエストを処理し、ビューを用いてHTMLをレンダリングしています。

get '/' do
  erb :index
end

post '/result' do
  @model = Zenra.new
  erb :result, :locals => {:res => @model.zenrize(params[:text])}
end

最後にビュー部分です。
今回はerbテンプレートを使用しています。

@@ layout
<!DOCTYPE html>
<html>
<head><title>zenrize</title></head>
<body style="width:500px;margin:0 auto;"><h1>zenrize</h1><%= yield %></body>
</html>

@@ index
<form action="/result" method="post">
<textarea rows="3" cols="60" name="text"></textarea>
<br />
<input type='submit' value='zenrize' />
</form>

@@ result
<p><%= h res %></p>
<a href='/'>戻る</a>

以上の3つを繋ぎ合わせたコードは以下のようになります。

# coding: utf-8
require 'rubygems'
require 'sinatra'
require 'open-uri'
require 'rexml/document'

helpers do
  include Rack::Utils; alias_method :h, :escape_html
end

class Zenra

  def initialize(position='動詞', text='全裸で')
    @appid    = 'YOUR_APP_ID'
    @position = position
    @text     = text
    @base_url = 'http://jlp.yahooapis.jp/MAService/V1/parse'
  end

  def zenrize(sentence)
    raise "appid is necessary!" if @appid.nil? || @appid.empty?
    raise "Japanese sentence is necessary!" if sentence.nil? || sentence.empty?

    req = "#{@base_url}?results=ma&appid=#{@appid}&sentence=#{URI.encode(sentence)}"
    res = open(req)
    xml = REXML::Document.new(res.read)

    return sentence if xml.elements['ResultSet/ma_result/total_count'].text == '0'

    result = ''
    xml.elements.each('ResultSet/ma_result/word_list/word') do |e|
      result << @text if e.elements['pos'].text == @position
      result << e.elements['surface'].text
    end
    result
  end

end

get '/' do
  erb :index
end

post '/result' do
  @model = Zenra.new
  erb :result, :locals => {:res => @model.zenrize(params[:text])}
end

__END__

@@ layout
<!DOCTYPE html>
<html>
<head><title>zenrize</title></head>
<body style="width:500px;margin:0 auto;"><h1>zenrize</h1><%= yield %></body>
</html>

@@ index
<form action="/result" method="post">
<textarea rows="3" cols="60" name="text"></textarea>
<br />
<input type='submit' value='zenrize' />
</form>

@@ result
<p><%= h res %></p>
<a href='/'>戻る</a>


これをzenra.rbとして保存し、

ruby zenra.rb

と実行するとWebブラウザからzenrizeを試すことができます

こちらが入力画面

こちらが結果画面

すごく…全裸です…

まとめ的な

"MVCという概念を学ぶにはこうした一連の流れを網羅する小さなサンプルをつくるのが一番取っ付きやすい(元エントリより)"気がします。
Sinatraいいですね。初めて触った(rubyも初心者状態)にも関わらず、すんなり理解出来ました。
全裸寒い。

最後に

上でも述べていますが、ruby初心者+今回がSinatraデビューな未熟者ですので
ここがおかしいとか、こうした方がいい等あればコメント、もしくはTwitterで教えていただけると幸いです。

*1:丸パクリなレベルで。すいません…