Ruby ベストプラクティス |
作成日: 2010-06-12 最終更新日: |
Ruby で問題解決に取り組む際のやり方を身に付ける。
付録は次の3点である。
正規表現を使うコツは次のように紹介されている。
第2の点。ショートカットとは、特定の文字集合を表す記法だ。
. \s \S \w \W \d \D
第3の点。アンカーは「錨」の意味で、特定の文字にマッチするのではなく、
文字と文字の関係や文字列の関係にマッチする。次の記法がある。
\A \Z \Z ^ $ \b
最後の点は最近身に染みて感じたことである。
L10N (Localization)と M17N (Multilingualization) について述べられている。 ここを検証したかったが、sinatra と gibberish::simple の稼働がうまくできず諦めた。 再度挑戦したい。(2010-06-12)
再度挑戦と書いてから 10 年が経過した。今、試してみてみることにした。 WSL の Ubuntu 20.04 で確認している。 まず、果たして Sinatra は今でも使えるのだろうか。 調べてみると、今でも使えそうである。インストールしてみることにした。
$ gem install sinatra (前略) Sucessfully installed sinatra-2.1.0 (中略) Parsing documentation for sinatra-2.1.0 Installing ri documentation for sinatra-2.1.0
ここでプロンプトが返ってこない。
^CERROR: Interrupted $ gem install sinatra Successfully installed sinatra-2.1.0 Parsing documentation for sinatra-2.1.0 Done installing documentation for sinatra after 1 seconds 1 gem installed $ gem install sinatra-reloader (中略) 3 gems installed
なんとか終わったようだ。いよいよ Sinatra である。
Sinatra が動作することを試すため、次のようにフォルダとファイルを配置した。 ch7 というのは、対象が本書の第7章にあることを反映している。
ch7 + + rbs.rb | + views + rps_start.erb + rps_end.rb
p.216 の上段の ERB テンプレートが rps_start.rb 、 下段の ERP テンプレートが rps_end.rb 、 p.217 のソースが rbs.rb である。 なお、p.217 のソースの、require "sinatra" の次に、 require "sinatra/reloads" を加えておくといいだろう。 このアプリケーションは次のように起動する。
$ ruby rbs.rb
WEBrick による簡易サーバが動いた。 ブラウザから、http://localhost:4567/rps を起動すると、 本書図 7-1 の画面が現れる。この画面で、 Rock, Paper, Scissors のいずれを選択して Shoot! ボタンをクリックすると、 図 7-2 の画面が表示される。ひとまずは Sinatra の動作が確認できた。
次は gibberish である。Sinatra は使えたが、こちらはどうか。 調べてみると、さすがに今は更新されていないようだ。 もともと gibberish は暗号化・復号を行なうライブラリである。 この用途そのものが、既に別ライブラリに道を譲ったようなのだ。
では、他に M17N や L10N を実現できるライブラリはあるのだろうか。 どうやら、Ruby on Rails (RoR) に適用されることを目指して作られた i18n というライブラリがあることがわかった。これが事実上の Ruby での標準らしい。 I18N は Internationalization の略で、国際化を意味する。 では、i18n はどのように使うのか。今回は RoR とは無関係だから、 これに適した用例があるのだろうか。i18n 単独で使う用法があれば知りたい。 また、Sinatra で使えればその方法も知りたい。
gibberish を用いた本書の方法では、言語コード xx に応じて URI を /rps/xx/ とすることで対応している。 たとえば日本語であれば、 xx = ja として /rps/ja でグー・パー・チョキ、 フランス語であれば xx = fr だから /rps/fr で Caillou, Feuille, Ciseaux のように変えている。
ということで調べると、https://hawksnowlog.blogspot.com/2020/10/ruby-i18n-samples-with-sinatra.html というブログの記事が見つかった。これを参考にできないだろうか。
このブログ記事では、ブラウザなどのユーザーエージェントが保持する Accept-Language ヘッダを見て言語を分けている。 WEB のアプリケーションであれば、Accept-Language ヘッダを使うのがスマートだと思う。
さらにいろいろ調べてみると、sinatra-r18n というライブラリが見つかったので、
これを使ってみるのがよいのではないかと考えた。
2020-11-03 時点でバージョンは 4.0.0 である。
https://rubygems.org/gems/sinatra-r18n/
まずはインストールしてみた。
$ gem install sinatra-r18n
さて、r18n は、sinatra だけではないらしい。
https://github.com/r18n/r18n
を見ると、RoR 、Sinatra、
デスクトップ(いわゆる web アプリケーションではないことを指すのだろう)
の例があるようだ。
https://github.com/r18n/r18n/tree/master/sinatra-r18n
の How To に従って確認する。
なお、(省略)とした個所は、
上記の URL を見てほしい。
1. 翻訳用のディレクトリ ./i18n を作る。これは決め打ちのようだ。 現在のディレクトリは、ruby hoge.rb の hoge.rb があるディレクトリと 考えてよい。
2. 翻訳ファイルを ./i18n/ の下、言語名をファイル名に含めて作成する。
例:英語なら en.yml 、アメリカ英語なら en-us.yml など。
./i18n/en.yml の例
post: friends: Post only for friends tags: Post tags are %1 comments: !!pl 0: No comments 1: One comment n: '%1 comments' html: !!html <b>Don't escape HTML</b>
3. Sinatra アプリケーションに r18n を追加する。
require 'sinatra/i18n'
これは追加である。もとのアプリケーションで、
require 'sinatra/i18n'
や
require 'sinatra/reload'
があれば、
当然そのままである。
アプリケーションのクラスが Sinatra::Base を継承しているときは、
追記が必要だ(省略)。
4. locale を URL に追記する(省略)。 ユーザーが locale を変更するときはセーブする(省略)。
5. ビューの翻訳メッセージを使う。HAML の例:
%p= t.post.friends %p= t.post.tags(@post.tags.join(', ')) %h2= t.comments(@post.comments.size)
t がグローバルなオブジェクトである。 t のメンバーに post や comments があって、 post メンバーに friends や tags などがある。これは yml ファイルに対応している。
6. locale に対応した時間や数値を表示する(省略)。
7. 利用可能な翻訳を表示する。HAML の例(省略)。
ここまでの情報でうまくいったと思い込んだが、誤りだった。 だいぶ苦労したが、苦労したところを明かすのは恥ずかしいので隠す。 言語ファイルを合わせて次のディレクトリとファイルで構成する。
ch7 + + rps_i18n.rb | + views + rps_start.erb | + rps_end.rb + i18n + en.yml + ja.yml + fr.yml + eo.yml
サーバーとなるプログラムの中心である。
# rps_i18n.rb # Ruby ベストプラクティス p.217 をもとに改変 # サーバー # $ ruby rps_i18n.rb # クライアント # http://localhost:4567/rps require 'sinatra' require 'sinatra/reloader' require 'sinatra/r18n' get '/rps' do erb :rps_start end post '/rps' do @player_weapon = params[:weapon] @opponent_weapon = %w[Rock Paper Scissors].sample erb :rps_end end helpers do def end_game_message return "#{t.rps.tie}" if @player_weapon == @opponent_weapon winning_combos = [["Paper","Rock"],["Rock","Scissors"],["Scissors","Paper"]] if winning_combos.include?([@player_weapon, @opponent_weapon]) "#{t.rps.win}" else "#{t.rps.loose}" end end def weapon_name(weapon) t.rps.send(weapon.downcase) end end
じゃんけんの手を決める画面である。
<html> <head> <meta charset="utf-8"> </head> <body> <form method="post"> <% ["Rock", "Paper", "Scissors"].each do |weapon| %> <input type="radio" name="weapon" value="<%= weapon %>"> <%= weapon_name(weapon) %> <% end %> <input type="submit" value="<%= t.rps.shoot %>"> </form> </body> </html>
結果を示す画面である。
<html> <head> <meta charset="utf-8"> </head> <body> <p> <%= t.rbs.you(@get) %> : <%= weapon_name(@player_weapon) %></p> <p> <%= t.rbs.opponent(@get) %> : <%= weapon_name(@opponent_weapon) %></p> <p> <%= end_game_message %></p> </body> </html>
英語である。決着をつけるタイミングは Shoot であることを初めて知った。 映画で本番撮影をする掛け声が Shoot! だったと思う。
rps: win: You win loose: You loose tie: Tie rock: Rock paper: Paper scissors: Scissors shoot: Shoot you: You opponent: Opponent
日本語である。日本語の順番ではグー、チョキ、パーなのだが、この順番までは直せなかった。 なお、表示を直すのは、rps_start.rb で行う必要がある。
rps: win: あなたの勝ち loose: あなたの負け tie: あいこ rock: グー paper: パー scissors: チョキ shoot: じゃんけん you: あなた opponent: 相手
フランス語である。あいこを表す「Égalité」にどこか既視感があった。少し考えて、 フランス共和国の標語の「平等」と同じであることに気づいた。 なお、本書では、Egalité のように頭文字にアクサンテギュ(アクセント記号)がない形で印刷されている。 大文字の場合は記号をつけなくてもいいのだが、せっかくなのでここでは記号をつけている。
rps: win: Tu gagnes loose: Tu perds tie: Égalité rock: Caillou paper: Feuille scissors: Ciseaux shoot: On y va ! you: Toi opponent: Adversaire
エスペラントである。じゃんけん決着のためのかけ言葉は Ek! としたが、 自信がない。
rps: win: Vi gajnas loose: Vi perdas tie: Egalforta rock: Ŝtono paper: Papero scissors: Tondilo shoot: Ek! you: Vi opponent: Adverso
これで、$ ruby rps_i18n.rb としてサーバーを起動する。 そして、ブラウザの URL で http://localhost:4567/rps を指定する。 ブラウザの言語のオプションで、表示をさせたい言語を一番最初に持っていけば、 その言語で表示される。
再帰関数とメモ化について確認した。
再帰関数では速度が低下するというのは、 現在の 2.7.2 でも変わっていないようだ。
メモ化についての確認は一部にとどまる。配列のメモ化についてはその効果を確かめた。 なお、p.153 のメモ化のコード
def fib(n) @series || = [] @series[n] || = fib(n-1) + fin(n-2) end
は、このままでは動かない。まず、誤植がある。そして、n=0 と n= 1 の停止条件もない。 実際には p.152 のコード断片と見比べて、次のような書き方になる。
def fib(n) @series || = [] @series[n] || = (0..1).include?(n) ? n : fib(n-2) + fib(n-1) end
こんなことがあるから、やはりこの本は上級者向きなのだと思う。私は初心者であるから、 難しい。
コードの例は下記にある。
https://github.com/practicingruby/rbp
この章の題名は偶然俳句に近い。1章を「第1章」とすれば、「だいいっしょう テストでコードを くどうする」と読めるからだ。 それはともかく、最初の章なのに、読めない。読めるところを探すと、1.3 節ならば読めそうなことがわかった。
この章では、Test::Unit を使っているテストコードで、 must() メソッドなるものが頻出している。これは、本書の p.5 では、 activesupport ライブラリの test() メソッドに基づいたカスタム追加となっている。 私はこの must() メソッドを使おうとしたが、次のエラーが返ってくるだけで、結局使えなかった。
Traceback (most recent call last): 1: from test_volume_bad.rb:14:in `<main>' test_volume_bad.rb:15:in `<class:VolumeTest>': undefined method `must' for VolumeTest:Class (NoMethodError)
本書に掲載されている例をみたが、メソッドの名前の代わりに「そうあってしかるべき」 である条件が英語の文法通りに並べられているのだった。だから、 わざわざ must メソッドを使わずとも(使う方法がわからなかったからだが)コメントとメソッド名を適切に組み合わせたら、 それで問題はない。
題だけでは、「うつくしい えーぴーあいを せっけいする」で、字余りだ。 それはともかく、私のような低レベルでこの章で役に立ったことは、 attr_read、attr_writer、attr_accessor を使おう、 ということぐらいだ。
ほかには、「ドッグフードを食べる」という言い回しが、 「ソフトウェア開発者や開発会社が、開発したソフトウェアを自社で実際に業務などで使うこと」 を意味するのが面白かった。
動的な機能と聞いただけで、使いこなせない、勘弁してください、と叫んでしまいそうだ。 3.2.2 項では、method_missing() と send() を使ってメッセージを扱うことが主題である。 この send() というメソッドは、引数にシンボルまたは文字列をとって、 そのシンボルまたは文字列のメソッドを実行する、というメソッドである。 私はこのようなメソッドがわからなかったために、 8章のじゃんけんプログラムの書き直しに大変苦労したのだった。 send がどこで使われているかを見たければ、send をこのページで検索すればいい。 weapon_name の定義で出てくる。それはともかく、動的な機能は勘弁してください、である。
書 名 | Ruby ベストプラクティス |
著 者 | Gregory Brown |
監訳者 | 高橋 征義 |
訳 者 | 笹井 崇司 |
発行日 | 2010 年 3 月 25 日 初版第1刷 |
発行所 | オライリー・ジャパン |
発売元 | オーム社 |
定 価 | 3200 円(税別) |
サイズ | 版 |
ISBN | 978-4-87311-445-3 |
その他 | 越谷市南部図書室で借りて読む |
NDC |
まりんきょ学問所 > Rubyの浮き輪 > Ruby ベストプラクティス