-> English version



るびくる&RBのRubyプログラミング大作戦!
Ruby FacetsでおしゃれなRubyistになろう!(パート2:facets/kernel/try編)

このエントリーをはてなブックマークに追加

るびくる:
Rubyの自称マスコットキャラクター。
好きなお茶は生茶。お茶の甘みだけを純粋に引き出したかのような味わいがクセになる。

RB(あーるびー):
解説役兼るびくるの指導役。
好きなお茶は伊右衛門茶。抹茶の甘みと渋みの一体感がクセになる。


(ドタドタドタ)

(ガラッ)RB! Facetsのライブラリについて教えて!

この最初にドアを開けるくだり、もしかして前回だけじゃなくて毎回やるの?


1. 今回のサンプルコード

それじゃ今回は、facets/kernel/tryを紹介するよ。
これは読み込むことで、すべてのオブジェクトにtryメソッドが使えるようになるライブラリなんだ。

このtryメソッドは、元々はっていう
別のライブラリから取り込まれたメソッドなんだけど
いろいろな場面で便利に使うことができる、汎用的で良いメソッドだよ。

前回のパート1で、RBが例に出してたやつだね。

その通り。
使い方については、あれこれ説明するよりも、コードを見てもらった方がわかりやすいだろうから
まずはサンプルコードを見てもらおうか。

file: kernel-try-example.rb

# encoding: utf-8
require 'facets/kernel/try'

#-------------------------------------------------------------------------------
# try: 後ろに続くメソッドを、通常通りに呼び出すが
#      nilに対して存在しないメソッドを呼び出した場合でもエラーにならない(nilを返す)
#
#      主に「nilかもしれない変数」に対して、なにかのメソッドを呼び出したいときに使う

options = {:output_path => ' /var/gems/1.9.1/ '}
@stripped_path = options[:output_path].try.strip
p @stripped_path # => "/var/gems/1.9.1/"

options = {}
@stripped_path = options[:output_path].try.strip
p @stripped_path # => nil


# 上記のコードと同じ意味の処理を、tryメソッドなしで書くとこうなる
options = {:output_path => ' /var/gems/1.9.1/ '}
@stripped_path = (options[:output_path].nil? ? nil : options[:output_path].strip)
p @stripped_path # => "/var/gems/1.9.1/"

options = {}
@stripped_path = (options[:output_path].nil? ? nil : options[:output_path].strip)
p @stripped_path # => nil



# tryメソッドに、直接メソッド名や引数を渡すこともできる
'rubicle'.try.slice(0..4)   # => "rubic"
'rubicle'.try(:slice, 0..4) # => "rubic"

# 注意点:nil以外のオブジェクトに対して存在しない名前のメソッドを呼ぶと、通常通りNoMethodErrorが発生する
nil.try.strip # => nil
100.try.strip # => 
# ~> -:36:in `<top (required)>': undefined method `strip' for 100:Fixnum (NoMethodError)
# ~>   from -e:1:in `load'
# ~>   from -e:1:in `<main>'
# ~> !XMP1431260298_1208_763152![1] => String "/var/gems/1.9.1/"
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![2] => NilClass nil
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![3] => String "/var/gems/1.9.1/"
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![4] => NilClass nil
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![5] => String "rubic"
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![6] => String "rubic"
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![7] => NilClass nil
# ~> options
# ~> _xmp_1431260298_1208_591716

サンプルコードを見てもらえば分かるとおり、使い方自体がシンプルだから
あえて解説するほどのことも少ないんだけど……
一応、簡単な説明だけしていくよ。

お願いします!


2. サンプルコードの流れを見てみよう!

#-------------------------------------------------------------------------------
# try: 後ろに続くメソッドを、通常通りに呼び出すが
#      nilに対して存在しないメソッドを呼び出した場合でもエラーにならない(nilを返す)
#
#      主に「nilかもしれない変数」に対して、なにかのメソッドを呼び出したいときに使う

options = {:output_path => ' /var/gems/1.9.1/ '}
@stripped_path = options[:output_path].try.strip
p @stripped_path # => "/var/gems/1.9.1/"

options = {}
@stripped_path = options[:output_path].try.strip
p @stripped_path # => nil


# 上記のコードと同じ意味の処理を、tryメソッドなしで書くとこうなる
options = {:output_path => ' /var/gems/1.9.1/ '}
@stripped_path = (options[:output_path].nil? ? nil : options[:output_path].strip)
p @stripped_path # => "/var/gems/1.9.1/"

options = {}
@stripped_path = (options[:output_path].nil? ? nil : options[:output_path].strip)
p @stripped_path # => nil

まずはtryメソッドの、基本的な使い方の例だね。

確か、前回の話では……

  • options[:output_path]がnil以外なら、stripメソッドを実行して前後の空白を取り除いたものを、@stripped_pathに入れる
  • options[:output_path]がnilなら、(stripメソッドを実行せずに)nilを@stripped_pathに入れる

ってことだったよね。

そう。この処理は、もちろんtryメソッドを使わなくても書くことはできるんだけど
条件判定式が必要になっちゃうから、どうしても読みにくくなっちゃう。
tryメソッドを使えば、この判断をすっきりと書くことができるんだ。

見た目もすごくおしゃれな感じだし、いろいろな場面で使うことができそうだね!

# tryメソッドに、直接メソッド名や引数を渡すこともできる
'rubicle'.try.slice(0..4)   # => "rubic"
'rubicle'.try(:slice, 0..4) # => "rubic"

これはtryメソッドの別記法。
普通は 'rubicle'.try.slice(0..4) の方の書き方を使うと思うんだけど、
いちおうこういう書き方もできるよ、ってことで。

メソッド名(Symbol)をtryメソッドの引数に渡すこともできるんだね。
でも、確かにこの書き方を使いたくなる場面、あんまり思いつかないなぁ……。

'rubicle'.try.slice(0..4)っぽくて見た目ちょっといやだ、って人は使うかもしれないね。

あとは、もともとtryメソッドがあったでは、逆に後者の書き方しか使えないみたいだから
それから移行してくる人は使いたくなるのかも。

# 注意点:nil以外のオブジェクトに対して存在しない名前のメソッドを呼ぶと、通常通りNoMethodErrorが発生する
nil.try.strip # => nil
100.try.strip # => 
# ~> -:36:in `<top (required)>': undefined method `strip' for 100:Fixnum (NoMethodError)
# ~>   from -e:1:in `load'
# ~>   from -e:1:in `<main>'
# ~> !XMP1431260298_1208_763152![1] => String "/var/gems/1.9.1/"
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![2] => NilClass nil
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![3] => String "/var/gems/1.9.1/"
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![4] => NilClass nil
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![5] => String "rubic"
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![6] => String "rubic"
# ~> options
# ~> _xmp_1431260298_1208_591716
# ~> !XMP1431260298_1208_763152![7] => NilClass nil
# ~> options
# ~> _xmp_1431260298_1208_591716

で、最後にtryメソッドの使い方に関する注意。

tryメソッドの効果があるのは、nilだけで
ほかのオブジェクト(false、数値、文字列など)に対しては、通常通りNoMethodErrorが発生してしまうんだ。
ここはtryメソッドを使う上で、地味にハマりやすいポイントだから、気をつけてね。

あくまで対nil用限定のメソッド、ってことなんだね。
確かに今までの話を聞いてると、なんとなくほかのオブジェクトにも使えそうなイメージだったよ。

でも逆に、なんでnilだけに使えるようになってるんだろう?

そうだね、僕もそこの意図ははっきりとはわからないないんだけど
たぶんnil以外の意図しないオブジェクトが来たときに、「意図しない値が来た」ことをわかりやすくするためじゃないかな。
数値かnilのどちらかしか引数にとれないメソッドで、文字列が来た!ってときとか。


それじゃ、今回のパート2は短いけどこれでおしまい。
次回パート3では、Timeクラスを拡張する、もう少し大きめのライブラリ「facets/time」を紹介する予定だよ!

日時を指定したフォーマットで文字列化するTime#stampや、指定した時間分ずらすTime#shiftなど
地味だけど役に立つメソッドがいろいろあるから、お楽しみにね!

ちょっと待ってRB!
「もう少し大きめのライブラリ」ってことは、最初のサンプルコードもその分長くなるってこと!?

うん。次回は5つくらいのメソッドを一度に紹介する予定だから、その分どうしても長くはなっちゃうだろうね。

だったら、今回みたいな「最初にサンプルコードを全部出して、その後にコードを少しずつ解説していく」ってやり方じゃなくて
話の流れに沿って、ちょっとずつ、順々にサンプルコードを出していった方がいいんじゃない?
いきなり長いサンプルコードで始まると、人によっては引いちゃうかもしれないし。

そうだね、わかりやすくするって意味ではそっちの方がいいんだけど……

「解説はいらないから情報だけほしい、サンプルコードだけ読みたい!」って人のことを考えると
どうしても、サンプルコードを最初に全部出すスタイルがいいってことになっちゃうんだよね。

あー。確かにわたしたちの記事、「会社では周りの目が気になって読みづらい」って評判があるもんね……。

パート3:facets/time編に続きます。


注意事項
  • 本記事の内容は、Facets 2.9.3 時点での動作を元にしています。
  • 本記事内で使用しているアイコン画像は、桜去ほとりさんが制作されたものです。クリエイティブ・コモンズ 表示-非営利 3.0ライセンスのもとで、再配布や変更などを行っていただくことができます。
  • 本記事内の文章やソースコードは、CC0ライセンスのもとで、ご自由に利用していただくことができます。
  • ツンツク・モモコのお買い物大作戦と形式が類似していますが、本記事側が一方的に参考にさせていただいただけであり、とくに関連性はありません。

一言メッセージフォーム

るびくるへの質問や、やってほしい企画のリクエスト、Webサイト管理スタッフへの感想・意見・質問など、なんでもお気軽にどうぞ。