Edited at

Ruby のココがダメ

タイトルは釣りです。Ruby に盲目的に惚れている迂生には Ruby の痘痕(あばた)はエクボです。

それはともかく。


メソッド名の別名がありすぎ

「あなたは map 派? それとも collect 派?」っていう問いがまず嫌い。

いや,別名にも意義があるとは思うんだけど,記憶の負担が大きい。

自分では map しか使わなくても,他人のコード読むんだったら collect を知っていなくちゃならない。

しばらく前に reduce っていうメソッド見て,そんなのあったっけ?と思ったら inject の別名だった。

map/collectinject/reduce の名前とその背景にある発想については,Rubyist Magazine に良い記事がある:

http://magazine.rubyist.net/?0038-MapAndCollect

そうかと思えば,Array#delete_ifArray#reject! みたいに,働きは基本的に同じだけど,削除が行われなかった場合の返り値だけが違う,みたいな「わずかに違うメソッド」のペアがあったりして,覚えられない。

脱線ついでに言うと,Proc オブジェクト(手続きオブジェクト)を作る手段がいろいろあって,できたやつの挙動が微妙に違う。解説を読んだときは分ったつもりでも,覚えられない。

http://docs.ruby-lang.org/ja/2.2.0/doc/spec=2flambda_proc.html

これについては Qiita にも良い記事があったと思うけど,どれがベストか分らないので,とりあえずリンク張らない。


何かにつけて「nil にそんなメソッドねえよ」

しばしばこういうエラーに出くわす:

NoMethodError: undefined method `XXXXX' for nil:NilClass

配列や文字列だと思ってメソッドを叩いたら実は nil だった,という話。

開発段階ではうまく動いていたのに,実稼働すると特定の条件に合致してエラーが出たりする。

メソッド名が empty?sliceinject みたいな,いろんなクラスで動くメソッドだったりすると,これだけの情報ではいったい本当は何のクラスであるべきだったのかが分らない。

例外が発生した箇所と,誰かが nil を返した箇所がけっこう離れていることがあって,コードを丹念に遡っていかないとバグが突き止められなかったりする。

Ruby には「○○ または nil」を返すメソッドが多いからなあ。


ローカル変数なのかメソッド呼び出しなのか

Ruby ではローカル変数の名前とメソッドの名前の命名規則は同じなので,しばしば見分けづらいことがある。

メソッド呼び出しは引数の ( ) が省略できるし,レシーバーが self ならレシーバーも省略できる。

そのため,コード中に

a = b

とあっても,b がローカル変数の参照なのかメソッドの呼び出しなのか,この行だけでは判断できない。

もし,( ) があって

a = b()

なら確実にメソッド呼び出しだし,( ) が無くても

a = b c

なら c を引数とするメソッド呼び出しだと分かる。

また,

a = x.b

の場合も,x をレシーバーとするメソッド呼び出しだと分かる。

でも,

a = b

の場合は,同じローカル変数スコープ内を上に遡って見てみて,b への代入が一つでもあればローカル変数,そうでなければメソッド呼び出し,と判断しなくちゃなんない。

スコープが長いと一目で分からない。まあ「そんな長いメソッド書くなよ」という話ではあるんだけど。でも case で場合分けしてると,構造はごく単純なのにメソッドが長くなっちゃうことはあるんだよねえ。

こんなブログページありました:

ありえるえりあ「Rubyの好きなところと嫌いなところ」


ブロックなのかハッシュなのか

p {foo: 3, bar: 4} #=> SyntaxError

冗談きついなあ。

まあ記号の数が足りないから兼任させざるを得ないんだろうけど。

ブロックって,{{ }} とかではダメだったのかしらん?


遅い

「科学技術計算にはそれに適した言語を使え」だって?

いや,CSV のテキスト処理とかしたいんすけど? Ruby の強力な文字列操作機能で楽に書きたいんすけど?

Ruby 1.9 でバーチャルマシンが導入されてすげー速くなったけど,文字列は却って遅くなった。まあそんだけ高級な String に生まれ変わったってことだろうけど。

何にしても,いろんな面で地道に速度の向上の努力がされ続けていて(Flonum の導入とか BigDecimal のアルゴリズムの改善とか),ユーザーとしては本当に頭が下がる思いです。


ドキュメントが不十分

ドキュメントがコードよりも一段低く見られるのは Ruby の文化だ,という話もあるようだけど,それではイケナイと思う。

そのせいかどうか,長らく Ruby 自体のリファレンスマニュアルが貧弱だった時代があった。いくら「PHP の仕様はクソ」とか蔑んでみても,あちらにはかなりよく出来たオンラインマニュアルがあった。

Rails 前夜,あるいは Rails 初期に英語圏で Ruby 普及の起爆剤になった本を書いてくれた米国の達人さんたち,よく何もドキュメントが無いなかであれだけの本を書いてくれましたね。おおきに,三球・照代。

時は過ぎ,リファレンスマニュアル刷新プロジェクトで精鋭さんたちが大車輪の活躍をして,現在のリファンレスマニュアル(通称るりま)が出来た。「Ruby はドキュメントがダメ」はおおかた払拭されたのかもしれない。ダンケ,めるしーぼく,スパシーバ,かむさはむにだ。

でも,まだ道半ば。実行しても意図通りに動かないスクリプト例が載ってたり,説明の間違いとかが残ってる。それに,基本的な概念の説明が無かったり不十分だったりする。

Ruby 1.9 で導入された新しい lambda の記法

->(x){x ** 2}

がるりまのどこに載ってるか探せますか?


用語集が無いよ

Ruby には公式の用語集が(たぶん)無い。うーん,基礎的な用語の整理はドキュメント作りの基本じゃないのかな。

るりまにも用語集

http://docs.ruby-lang.org/ja/2.2.0/doc/glossary.html

があるけど,これはたぶん,まつもとさんが著書に〈ユーモア〉として載せていた用語集を持ってきてちょっと直しただけ。これはこれで面白いけど,公式リファレンスマニュアルに入れるようなものではないと思う。

「インスタンスメソッド」すら載っていないし,Ruby の重要概念である「イミュータブル」も載ってない。

「ブロック」の説明なんて


ループを構成したり、家や塀を建てたり、人を殴ったりするもの。


だぜ?


Windows ユーザーがいつも置き去り

具体例は覚えてないけど,Ruby 1.6 とか 1.8 の頃は Windows だとダメなことが多くて,「どうせ Unix の人は Windows なんかどうでもいいんだろ」ってふてくされてた。

いまはかなり改善されてる気がする。ありがとうございます,ありがとうございます。(ぺこぺこ)

でも ReVIEW(簡易マークアップした原稿を TeX とか InDesign とか EPUB とかにしてくれるやつ)を動かそうとしたらいきなりエラー。ああ,Windows 版の Ruby では fork って無いんスよ。とほほ。

もっと最近だと。

Ruby 2.2 が出た,やたー,早速使うゾ。

あれ? sqlite3 をインストールしたのに動かすとエラーが。何が原因だ?(gem の中身を調べる) ぐぬ,Ruby 2.2 用のバイナリーファイルが gem に入ってないじゃないか。ナニナニ? DLL をココでダウンロードして? ココに入れろだ? 俺はいいけど,そんなことスクリプトのユーザーに頼めるかよ。

ええと,GitHub に行って issue 立てなくちゃ。ぁんだよ,とっくに issue に上がってんじゃんかよ。

それから半年。ま,まだ,ダメですかい。orz

この件はつい先日解決。よーしこれからバリバリ Ruby 2.2 で書くぞ。

なぬ? Nokogiri もダメ? そうか sqlite3 でつまずいて,Nokogiri を試すところまで行ってなかった。早速 GitHub に行って,お,issue があるぞ。ふむふむ,解決した版がリリース候補まで行ってるのか。あとは待つのみだな。

えーと,あとは bcrypt か。GitHub と。issue はあるけど,当分前進は無さそうっスね。

ん? もしや DevKit でインストールすればイケたりして?

そりゃっ

gem install bcrypt --platform=ruby

お,インストールできた。む,require してもエラーにならん。むほ。

しかも readme のサンプルコードがちゃんと動くぞ。なーんだ,早く試せばよかった。

よし,早速 Ruby 2.2 で Rails! GO!

rails s

動いた。よし,認証だ!


BCrypt::Errors::InvalidHash


orz

あの,もう帰っていいっすか。

※この件については 2017-01-09 の追記を参照してください。


既定の文字コード

もはや Ruby がダメという話ではないんだけど,Ruby のライブラリーの作者はやはり圧倒的に Linux や Mac だったり,ラテン文字圏の人が多いんだと思う。その人たちの世界ではすべてが UTF-8 で完結しているのかもしれない。すると,「この文字列は何のコードだろう?」といちいち意識せずにテキトウに書いても問題無かったりするのだろう。しかし,日本の Windows ユーザーが実行すると,しばしば例外

Encoding::CompatibilityError: incompatible character encodings: Windows-31J and UTF-8

が発生する。

いや,ライブラリーの機能に関することではちゃんと作り込んであるんだけど,エラーが起こったりすると,なんかエラーメッセージを持ってきて,文字コード考えずにテキトウに他の文字列と結合したりするもんだから,そこで想定外のエラーが出るわけ。

Rails の better_errors がたしかそうだったよね。

仕方ないのでライブラリーのコードをだーっと遡っていくんだけど,問題の箇所が見つけられなくて報告できなかったりする。


フリップフロップ ワケわかめ

Ruby を学び始めたごく初期に(存在を)知って,現在に至るまで理解できず,一度も使ったことの無い「フリップフロップ」。

Perl にあったから Ruby にも取り入れたようなんだけど,なんなのコレ?

次のスクリプトは,人名リストが与えられて,山田くんから高橋くんまでの名前だけ表示する,というもの。

%w(田中 小山 山田 鈴木 高橋 本田).each do |name|

puts name if (name=="山田")..(name=="高橋")
end
#=> 山田
# 鈴木
# 高橋

いや,まあ,使い方は何となく分かるんだけど,どうなってるわけ?

〈状態〉を保持して,それによって真偽が変わるんだろうけど,誰が状態を持ってんの?

ワケわからーん!


さいごに

あちこちからマサカリが飛んできそう。

繰り返すけど,本当は「ダメなところ」と思ってないです。


追記(2015-11-02)

40 年以上生きているが,Qiita で 100 ストックを越えたのは生まれて初めてなので素直に嬉しい。

結局,マサカリは一本も飛んでこず,他の人の見方や追加のネタを得ることはできなかった。

記事を書いたハッキリした目的は無くて,「Ruby のココが好き」的な記事は既にあるからその逆を行こうかと思った。Ruby を dis る記事に見せかけたタイトルを付けたら目立つかなと思った。

Ruby は本当に好きなので,もちろん dis る気は無い。

いや,嫌いな言語の嫌いなところを書くときだって,罵ったり嘲ったりしたような書き方をするのは避けようと思う。その言語を気に入っている人が読んでも「ふふふ」ですむような。

「ダメとかって言いながら,コミュニティーを恐れて予防線張ってるじゃん」と思った人もいるかもしれないけど,関係者を傷つけたり嫌な気持ちにさせるのをなるべく避ようとしただけ(偽善?)

書いた内容はほとんどが古くから言われていることで,目新しさは無い。フリップフロップを入れたのはギャグ。


追記(2015-12-08)

Ruby のオススメの機能7選」で「Flip Flop 演算子」がオススメ 7 選の一つに。


追記(2016-03-06)

Windows ユーザーがいつも置き去り」で書いた bcrypt の問題はついに解決したようです!

すなわち,さきほど(この追記を書いてるちょっと前に)リリースされた 3.1.11 には,Windows 用バイナリーを積んだ版があります。ぃやほぅ!

よーし,これで最新の Ruby,最新の Rails でバリバリ書くぞぅ!

あ,RubyInstaller for Windows の最新版は Ruby 2.3 じゃなくて Ruby 2.2 なんだった orz


追記(2016-03-11)

フリップフロップについて,@Ping さんが「Ruby でフリップフロップ」という記事を書かれました。フリップフロップに好意的な記事ですが,


「書いてもないのに誰か勝手に状態を記憶していて判定処理をしてくれる」というもやもやさ


という表現を使われています。


追記(2016-04-06)

昨日あたりで RubyInstaller for Windows の最新版が Ruby 2.3 になった!

リリースから三ヶ月以上かかったけど,ようやく最先端に追いついた,と。

よーし,ぼっちオペレーターHash#digEnumerable#grep_v も,ばりばり使うぞ!

あ,先日の bcrypt のアップデートでは Ruby 2.2 にしか対応しなかったんだった。orz

これが無いと Rails で認証できひんやんけ!


追記 Windows の bcrypt 問題は解決(2017-01-09)

Windows で bcrypt gem が最新の Ruby に追いついていない問題は解決している。自分自身がちょっと誤解していたことに気づいたので,追記する。

何が問題だったかというと,bcrypt は Windows 向けのバイナリー版も提供されているのだが,Ruby の新しいバージョンが出てからそれに対応するまで何ヶ月もかかる,というサイクルがずーっと続いてきたこと。このため,bcrypt の issues には「Windows で動かない」「Ruby 2.x に対応してくれ」というのが繰り返し挙がっている。

で,実はバイナリー版が最新 Ruby に未対応でも,DevKit を入れていれば

gem install bcrypt --platform=ruby

のように --platform=ruby を付けてインストールすればいい。

さて,ここからが私の誤解。「Windows ユーザーがいつも置き去り」にも書いたとおり,上記のようにして bcrypt をインストールしたあと,bcrypt を使った既存の Rails プロジェクトを動かすと,


BCrypt::Errors::InvalidHash


が出た。そこで「--platform=ruby でインストールするのは完全な解決方法ではない」と思い込んでしまった。

ところが InvalidHash が出たのは,データベースに記録されていたハッシュ化されたパスワードのフォーマットが現行と合ってないということだった。パスワードを再設定するなどすれば解消する。

フォーマットが合ってなかった原因は bcypt のバージョンが変わったからなのかどうか,追及してないので分からない。

ただ,Windows での bcrypt のインストールの仕方は上述のとおりで間違いない。