- なぜRubyが好きなのか
- なぜRubyを使い続けるのか
- Rubyの何が「楽しい」のか
自分の整理がてらこのあたりを言語化してみたいと思い、この記事を書く。
Rubyは「楽しい」
Rubyはよく「書いていて楽しい」とか「書いていて気持ちがいい」とか言われている。
僕自身もこの感覚は持っているし、Rubyを使い続けている人の殆どは少ならからず同じような感覚を持ったことがあるんじゃないかと思っている。
いくつかその例を。
以下は『Rubyソースコード完全解説』を書かれた青木峰郎さんのサイトから引用。
Ruby が Ruby たる所以は「書くのが楽しい」ところなのである。
これはめちゃくちゃ重要なことだからもう一度書こう。
Ruby は書くのが楽しいプログラム言語なのだ!
以下は伊藤直也さんのブログから引用。
※ ただし、RubyではなくRubyMotionが主題の記事
生粋のRubyistが何かRubyに「気持ちがいい」とか「楽しい」とか、個別機能論ではなく総体としてのRubyにそういう体験を感じたりするように、
RubyMotionにもまた、個別の事象だけを切り取って議論したときにはわからない手触り感の良さのようなものがあるように思います。
最後にもう1つ。Wikipediaだけど、Matz自身の言葉。
開発者のまつもとゆきひろは、「Rubyの言語仕様策定において最も重視しているのはストレスなくプログラミングを楽しむことである (enjoy programming)」と述べている。
1. 純粋オブジェクト指向
Rubyは全ての値がオブジェクトになっている。以下の例を見て欲しい。
※ Object#class
はレシーバのクラスを返すメソッド。
100.class # => Fixnum
'Ruby'.class # => String
['R', 'u', 'b', 'y'].class # => Array
{'key' => 'value'}.class # => Hash
true.class # => TrueClass
false.class # => FalseClass
nil.class # => NilClass
100や'Ruby'といった値から、trueやnilに至る値まで全てオブジェクトになっていることがわかる。
また、オブジェクトだからこそObject#class
を実行できている。
知識として持つべきこと、あるいは調べる際の領域が限定されている
「オブジェクト」であるということは何らかのクラスのインスタンスであるということであり、その性質からRubyプログラミングの多くの操作はインスタンスに対するメソッド呼び出しになる。
このなんらかの操作をするときに知っておく必要があるのは、自分がどのクラスのインスタンスを対象としていて、そのインスタンスがどんなメソッドを持っているかということだけ。
__このように、知識として持つべきこと、あるいは調べる際の領域が限定されている。__このおかげで、自然とプログラミングに費やす時間が長くなる。
例えば、カンマ区切りの文字列を配列に変換する処理を実装したい場合があったとしよう。
str = 'Ruby,Python,PHP'
# まずstrがどのクラスのインスタンスかを把握する
# -> Stringクラスのインスタンスであることがわかった
# 次にStringクラスのインスタンスメソッドに何があるかを調べる
# -> String#splitが見つかる
languages = str.split(',') # => ['Ruby', 'Python', 'PHP']
PHPのように、関数を駆使してプログラミングをするスタイルだと大量の関数から自分が目的とする処理を実現できるものを見つけ出す必要がある。一方Rubyの場合、メソッドを使って操作できることは、基本インスタンスに実装されたメソッドだけなので、そこだけ調べれば良いことになる。そのインスタンスに該当するメソッドがあれば実現できるし、なければ別の方法を考えればいいときっぱり割り切れる。
直感的かつ統一されたメソッド名
メソッドに関しては最初のうちはどうしてもWebや書籍を見て調べる必要があると思うが、その回数はRubyに触れる時間が長くなるにつれて雪だるま式に少なくなると思う。
それは メソッド名がわかりやすい直感的な名称で設計されているので覚えやすいということと、クラス全体で統一された名称になっているため、1度覚えると別のクラスに対しても知識を転移しやすくなっているからである。
例えば、Fixnum#next
は数値オブジェクトの次の値を返すので、レシーバが100であれば101。
このクラス、メソッド名から考えてこの動き以外考えようが無い。
100.next # => 101
Hash#has_key?
はレシーバのハッシュに指定したキーが存在するか検証する。
メソッド名の最後に「?」がつくものは真/偽を意味する値を返すという慣習がある(ただしあくまで慣習であり、強制されているものではない)。
この最後の「?」は個人的にすごく気に入ってる。「isXXX」というメソッド名よりわかりやすい。
{'lang' => 'Ruby'}.has_key?('lang') # => true
String#include?
はレシーバの文字列に指定した文字が存在するか検証する。
また、Array#include?
はレシーバの配列に指定した要素が存在するか検証する。
クラスは違うがメソッド名は同じであり、かつレシーバから考えて期待する動きになっていると思う。
'Ruby'.include?('P') # => false
['Ruby', 'PHP', 'Python'].include?('Ruby') # => true
文字列から整数に変換するときはString#to_i
を使う。
逆に整数から文字列に変換するときはFixnum#to_s
を使う。
初見はちょっとわかりにくいかもしれないけど、命名規則が統一されているので1度覚えれば忘れにくい。HashからArrayに変換するHash#to_a
やArrayからHashに変換するArray#to_h
などもある。
'100'.to_i # => 100
100.to_s # => "100"
オブジェクトのクラスやメソッドをすぐに調べることができる
なんのクラスかわからなかったり、どんなメソッドを実装しているかわからない場合でもすぐに見つけることができる。Webで調べてもいいけれど、Ruby自身がその情報を持っているのでRubyに聞いた方が楽だし、何より確実。
クラスはObject#class
でわかり、メソッド一覧はObject#methods
でわかる。
後述するPryを使えばより簡単かつ詳細に調べることができる。
ary = ['Ruby', 'PHP', 'Python']
# クラスを調べる
ary.class # => Array
# メソッドを調べる
ary.methods
# => [:inspect,
# :to_s,
# :to_a,
# :to_h,
# .
# .
# .
※ 参考
Rubyの凄く面白い特徴をRailsのコードを例に解説
2. 表現豊かな文法
Rubyは表現豊かであり、同じことを様々な方法で記述できる。
特定の記法を強制されない楽しさ。自分が好きな書き方を選べる楽しさ。新しい書き方を発見したときの喜びがある。
例えば、メソッドを呼び出す際は括弧があってもなくても良い。
puts 'ruby'
puts('ruby')
ブロックはdo-endでも良いし、波括弧を使っても良い。
※ ただし1行の時は波括弧、複数行の時はdo-endという暗黙のルールがあったりする
['a', 'b', 'c'].each do |v|
puts v
end
['a', 'b', 'c'].each {|v| puts v}
if修飾子も使える。
if 1 == 1
puts 'equal!'
end
puts 'equal!' if 1 == 1
無限ループなら、whileを使ってもいいし、loopを使ってもいい。
※ break文は挟んでください
while (true) do
print 'ruby'
end
loop do
print 'ruby'
end
%記法も便利。
message = "Hello, \"Ruby\"."
message = %(Hello "Ruby".)
languages = ['Ruby', 'Python', 'PHP']
languages = %w(Ruby Python PHP)
メソッドチェーンを使うと、不要なローカル変数を作らないで済む。
Rubyは返り値が全てオブジェクトだからこそメソッドチェーンができる。
# (例)カンマ区切りの文字列で渡された数値を配列に変換し、配列の各要素を2倍して出力する
numbers_str = '100,200,300,400'
numbers = numbers_str.split(',')
numbers.map{|num| num.to_i * 2}.each do |num|
puts n
end
# => 200
# => 400
# => 600
# => 800
'100,200,300,400'.split(',').map{|num| num.to_i * 2}.each do |num|
puts n
end
# => 200
# => 400
# => 600
# => 800
3. REPLが賢い
PryというREPLが非常に賢くて多機能で、Rubyプログラミングにおいて欠かせない存在になっている。
Pryがあるおかげで動作確認のための短いスクリプトファイルもいらないし、クラスやメソッドを調べるのがすぐにできるし、Webでドキュメントやソースを探す手間も省ける。
コードのハイライト、インデント
標準REPLのirbにはない、自動インデントと自動ハイライト機能。
irb
pry
オブジェクトの中に入り込み、内部を見る
オブジェクトにcd
し、ls
を実行すると実装されたメソッド一覧を閲覧できる
[4] pry(main)> str = 'foo'
=> "foo"
[5] pry(main)> cd str
[6] pry("foo"):1> ls
Comparable#methods: < <= > >= between?
String#methods:
% bytesize codepoints empty? include? oct scrub strip to_s
.
.
(省略)
self.methods: __pry__
locals: _ __ _dir_ _ex_ _file_ _in_ _out_ _pry_
ドキュメントを見る
show-doc
で、Pry上でメソッドのドキュメントを閲覧することができる。例えば、String#split
をshow-docで見るとこんな感じになる。使い方のサンプルが載っているのが非常に良い。
[1] pry(main) > show-doc String#split
From: string.c (C Method):
Owner: String
Visibility: public
Signature: split(*arg1)
Number of lines: 41
Divides str into substrings based on a delimiter, returning an array
of these substrings.
.
.
(省略)
.
.
When the input str is empty an empty Array is returned as the string is
considered to have no fields to split.
" now's the time".split #=> ["now's", "the", "time"]
" now's the time".split(' ') #=> ["now's", "the", "time"]
" now's the time".split(/ /) #=> ["", "now's", "", "the", "time"]
"1, 2.34,56, 7".split(%r{,\s*}) #=> ["1", "2.34", "56", "7"]
"hello".split(//) #=> ["h", "e", "l", "l", "o"]
"hello".split(//, 3) #=> ["h", "e", "llo"]
"hi mom".split(%r{\s*}) #=> ["h", "i", "m", "o", "m"]
"mellow yellow".split("ello") #=> ["m", "w y", "w"]
"1,2,,3,4,,".split(',') #=> ["1", "2", "", "3", "4"]
"1,2,,3,4,,".split(',', 4) #=> ["1", "2", "", "3,4,,"]
"1,2,,3,4,,".split(',', -4) #=> ["1", "2", "", "3", "4", "", ""]
"".split(',', -1) #=> []
ソースを見る
show-source
でメソッドの実装を見ることができる。使う頻度は低めだけど、Cの勉強なんかにも役立つ。
[1] pry(main)> show-source String#split
From: string.c (C Method):
Owner: String
Visibility: public
Number of lines: 214
static VALUE
rb_str_split_m(int argc, VALUE *argv, VALUE str)
{
rb_encoding *enc;
VALUE spat;
VALUE limit;
enum {awk, string, regexp} split_type;
long beg, end, i = 0;
int lim = 0;
VALUE result, tmp;
if (rb_scan_args(argc, argv, "02", &spat, &limit) == 2) {
.
.
.
(省略)
※ 参考
Rubyistよ、irbを捨ててPryを使おう
Pryが真の力を発揮してくれる19個のコマンドとコマンドの自作方法[Rails]
Home -pry/pry Wiki
4. WAFの選択で迷わない
Rubyには有名なWAFが3つほどあると思う。
- Ruby on Rails
- Sinatra
- Padrino
これらはそれぞれ明確に異なる特徴や性質を持っているので、どれを使うかの選択に時間を費やすことはほとんど無い。また、有名なものが限られた数しか無いので、チーム内でのノウハウが蓄積されやすいのも良い点。
以下は、それぞれのWAFの簡単な特徴と僕の印象。
Ruby on Rails
- フルスタックWAF
- MVC
- DRYの理念が色濃く反映されている
- 「設定より規約」。規約に従うと爆速開発ができる
- 堅い規約があるのでチーム開発に向いている気がする
- 小規模から大規模まで
Sinatra
- マイクロフレームワーク
- 4行で"Hello, world!"ができる
- 最小構成なので、必要なものは自分で組み込んだり、実装する必要がある
- 学習コストはかなり低い
- 小さいWebアプリをサクッと作りたい人や、初めてWAFを使う人、規約に縛られずに開発したい人に向いていると思う
Padrino
- SinatraベースのWAF
- Sinatraに標準ライブラリ、ヘルパー等の機能を追加
- RailsとSinatraの中間に位置する
- Sinatraでやるには少し手間がかかりそうだけどRails使うほどでは...という場合に向いている
Railsはフルコース、Sinatraはお皿、Padrinoはビュッフェ
5. 豊富な組み込みライブラリ、標準ライブラリ
標準ライブラリが充実しているというのは、仕事で使う上では必要条件になるのではないだろうか。サードパーティ製や独自のものではなく、可能な限り標準で装備されているライブラリやクラスだけで実装したい。
PythonやPHP等の言語も充実したライブラリが存在するが、Rubyにも豊富な組み込みライブラリと標準ライブラリがあり、大抵のことはこれらだけで実装できると思う。
- HTTPクライアントを使いたい ➔
net/http
- ロガーが欲しい ➔
logger
- マルチスレッドプログラミングがしたい ➔
thread
- JSONを扱いたい ➔
json
- CSVを扱いたい ➔
csv
- yamlを扱いたい ➔
yaml
- コードのベンチマークを取りたい ➔
benchmark
- 日付、日時操作をしたい ➔
time
、date
- ディレクトリ、ファイル操作をしたい ➔
Dir
、File
、fileutils
- プロセスを扱いたい ➔
Process
- コマンドラインプログラムを書きたい ➔
optparse
- ユニットテストを書きたい ➔
minitest
- プロファイリングした ➔
profile
- Webサーバを使いたい ➔
webrick
- etc...
※ 参考
組み込みライブラリ一覧
標準添付ライブラリ一覧
6. 真偽判定が明快
Rubyは真偽値判定が非常に明快だ。 nilとfalse以外は全て真になる。
条件文などの真偽値判定のミスがバグにつながるというのはよくあることだと思うが、Rubyでは「nilとfalse以外全て真」というルールさえ覚えればいいので、真偽値判定での実装ミスはかなり減ると思う。
これまでPHPをメインで使ってきたが、PHPの真偽値判定はかなり複雑で、使い始めは実装ミスをしてしまったことが結構あったし、今でも慎重に書かないとミスをする..。
# trueは当然真
if true
puts 'true' # => こっち
else
puts 'false'
end
# falseは当然偽
if false
puts 'true'
else
puts 'false' # => こっち
end
# nilも偽
if nil
puts 'true'
else
puts 'false' # => こっち
end
# 0は真
if 0
puts 'true' # => こっち
else
puts 'false'
end
# 空文字も真
str = ''
if str
puts 'true' # => こっち
else
puts 'false'
end
# 空配列も真
ary = []
if ary
puts 'true' # => こっち
else
puts 'false'
end
最後に
Rubyは..
- 使い手にとって直感的でわかりやすい(純粋オブジェクト指向、真偽判定が明快)
- 覚えやすい、調べやすい(純粋オブジェクト指向、REPLが賢い)
- プログラミングに没頭しやすい。本質的ではない作業を簡易化あるいは排除してくれている(純粋オブジェクト指向/REPLが賢い/WAFの選択で迷わない)
- 実現したいこと、つくりたいものをサポートする強力なツールがある(豊富な組み込みライブラリ、標準ライブラリ/WAFの選択でまよわない/REPLが賢い)
- 新しい発見が多い(表現豊かな文法/豊富な組み込みライブラリ、標準ライブラリ)
Rubyの「楽しさ」はこんなところから来ているんじゃないかなぁ。
Let's Ruby Programming!