先日作ったプログラム
Qiitaにバズる記事をあげたいが、俊逸なタイトルが想像力が欠如した筆者には思い浮かばない。
人類の叡智であるプログラムと俊逸さの申し子である小説家になろうを頼りに筆者の低脳ぶりを補ってもらおう。
そうして作成したプログラムが下記のリンクにある。
このプログラムも結果から選ぶ手間はあるが、タイトルのおかげか、拙筆の中で最大級の評価(いいね)を誇った。
これに気を良くした筆者は、作成したプログラムを皆に使ってもらおうとHerokuにあげるのだった。
前作業
先日作成したプログラムは、小説になろうAPIの結果をファイルに保存し、形態素解析などの処理を行なっている。
しかし、HerokuにMecabを載せるのは、気が滅入る。
参考: Herokuでpython+mecab+ffmpegを使う
処理自体の入力は埋め込むキーワードのみであり、形態素解析をローカルで行い結果を保存してデプロイするのが道理である。
幸いRubyには、オブジェクトをファイルに保存するMarshalモジュールが存在したので、ありがたく使わせていただいた。
split_titles = []
noun_idxs = []
for t in titles do
split_title, noun_idx = tagger_title(t)
split_titles.push(split_title)
noun_idxs.push(noun_idx)
end
Marshal.dump(split_title, open('split_titles.marshal', 'w'))
Marshal.dump(noun_idxs, open('noun_idxs.marshal', 'w'))
tagger_title()は形態素解析の結果と名詞の位置を返す関数である。(中身が気になる方は一番上の拙筆をご参照)
Marshal.dump(object, file)
でobjectをfileに保存することができる。
また、Marshal.load(file)
で保存したobjectをfileから読み込むことができる。
Sinatraアプリの作成
今作の動作は、
- ユーザにキーワードを入力させる
- キーワードをもとに前回のプログラムを走らせる
- 結果を出力する
とした。
SinatraはWebフレームワークであり、一発アイデアありき単純な今作にはうってつけである。
インストールには、下記のようにGemfileを記述し、bundle
でインストールするとよい。
source "https://rubygems.org"
gem 'sinatra'
gem 'sinatra-contrib'
今回の欲しい処理をSinatraで実現しようと思うと下記のプログラムとなった。
まずは、リクエストを受けとるapp.rb
について紹介する。
- title()
- '/'で入力されたキーワードをもとに前回のプログラムを走らせる
- get '/'
- ユーザにキーワードを入力させる (formなどはindex.erb)
- post 'result'
- title()の返り値を受け取り、結果を出力する (実際の画面はresult.erb)
なお、erbファイルはviews
ディレクトリに入れなければならないのに留意しなくてはならない。
index.erbのformに入力されたデータはparams
に格納され、title()
に入力される。
その後、title()
の返り値を@narou_title
に代入することで、result.erb()
に渡している。
require 'sinatra'
require 'sinatra/reloader'
def title(key1, key2, key3)
keyword = [key1, key2, key3]
keyword.delete("")
split_titles = Marshal.load(open('split_titles.marshal', 'r'))
noun_idxs = Marshal.load(open('noun_idxs.marshal', 'r'))
idx = rand(1..split_titles.length)
split_title = split_titles[idx]
noun_idx = noun_idxs[idx]
if keyword.length > noun_idx.length
keyword = keyword.slice(0..noun_idx.length)
end
candidate = noun_idx.permutation(keyword.length)
narou_titles = []
for c in candidate do
original = Marshal.load(Marshal.dump(split_title))
c.each_with_index do |i, j|
original[i] = keyword[j]
end
narou_titles.push(original.join)
end
if narou_titles.length < 1
narou_titles = title(key1, key2, key3)
end
return narou_titles
end
get '/' do
erb :index
end
post '/result' do
narou_titles = title(params[:key1], params[:key2], params[:key3])
@narou_titles = narou_titles
erb :result
end
index.erb
はerbファイルではあるが、Rubyの処理を用いていない。
formに関しては、下記の通りでapp.rb
との整合性をつけている。
<form action="result" method="POST">
<div>
key1:<input type="text" name="key1" value="">
</div>
<div>
key2:<input type="text" name="key2" value="">
</div>
<div>
key3:<input type="text" name="key3" value="">
</div>
<div>
<input type="submit" value="生成する">
</div>
</form>
result.erb
は、title()
で得られたタイトルの配列を表示している。
app.rb
において@narou_title
を設定しておき、ここで繰り返しを用いて表示している。
<div>
<% @narou_titles.each do |title| %>
<p><%= title %></p>
<% end %>
</div>
デプロイ
SinatraアプリのHerokuへのデプロイは下記の記事が詳しい。
ここでは、最小限の説明で一通りやらなければならないことを列挙する。
Procfileの作成
Herokuが動かすべき、処理を書いている。
web: bundle exec rackup config.ru -p $PORT
config.ruの作成
Procfileにある処理を動かしたときに、Sinatraが動かすべきプログラムを書いている。
require './app'
run Sinatra::Application
Git
Herokuにデプロイするのに、Gitは便利である。
ちなみにこれをheroku create
する前にやっておかないと、
git remote add heroku ほにゃらら.git
をするハメになる。
git init
git add .
git commit -m "initial commit"
デプロイ
いよいよHeroku CLIにログインし、作ったアプリをデプロイしよう。
ただし、Heroku CLIはすでに導入済みとする。
heroku login
heroku create
git push heroku master
一連のコマンドを実行したのち成功していれば、以下のコマンドによりブラウザ上で、自分のアプリがお披露目されるはずである。
heroku open
あとがき
いかがだったであろうか。
一発屋的思いつきプログラムをSinatraに組み込むのは比較的容易であった。
筆者の懸念する点は、
- cssを適用して、華やかな見た目にしようか
- 結果をOGP画像つきでTwitterシェア機能をつけようか
といった点である。
最後になろうパロディ☆タイトルジェネレータを使ってみて