「全裸で学ぶ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も初心者状態)にも関わらず、すんなり理解出来ました。
全裸寒い。
*1:丸パクリなレベルで。すいません…