Try ruby
Table of Contents
謹賀新年
本年もよろしく お願いいたします。
ラクビーのトライになぞらえて、年始はTry rubyでスタートします。そして箱根の 山への駅伝に範をとって、running rubyと続く予定です。 その前に、去年からの積み残しである、型を、かたしてしまいます。
pythonの型
標準ライブラリィーに、どの程度、型が浸透しているか、表面をなぞってみた。 まずは、現役の3.12.11
te$ egrep -l '(.*:.*) -> ' *.py _aix_support.py _collections_abc.py ftplib.py optparse.py statistics.py textwrap.py typing.py
こちらは、git clone した head版
ob$ egrep -l '(.*:.*) -> ' *.py _aix_support.py _collections_abc.py _colorize.py _py_warnings.py argparse.py doctest.py ftplib.py optparse.py random.py statistics.py textwrap.py token.py turtle.py typing.py
python vs. ruby
とかく対比されがちな両雄について、チャッピーに聞いてみた。
Q: python(3.12.3)とruby(3.4.1)での標準添付されるライブラリィーについて質問します。 1. それぞれで、方向性は有りますか? 2. 本体機能にしたもの、そこから外れて標準添付になったもの。
A: 良い切り口の質問ですね。 Python と Ruby はどちらも「 batteries included / すぐ使える 」文化を持ちますが、/標準添付ライブラリの方向性と整理の仕方はかなり違います/。
以下、/Python 3.12.3/ と Ruby 3.4.1 を念頭に説明します。
## 1. 標準添付ライブラリの「方向性」
### Python の方向性
「汎用基盤・参照実装・保守重視」
Python 標準ライブラリは、
- OS・ネットワーク・並行処理などの/基盤機能/
- 言語仕様を補完する/参照実装/
- 「標準で動くこと」が重視される/保守的なAPI/
を中心に構成されています。
特徴的なのは:
- 後方互換性を極めて重視
- 一度入ったものは、よほどの理由がない限り消えない
- 標準は「最低限信頼できる実装」、高機能化は PyPI に任せる
その結果:
- stdlib は「広いが浅い」
- 本格用途は第三者ライブラリ前提
という構造になります。
### Ruby の方向性
「実用性・表現力・言語体験の完成度」
Ruby 標準添付は、
- Ruby らしい書き心地を完成させる
- 「普通に書くと自然に使うもの」を最初から入れる
- 実用寄り・DSL寄り
という傾向があります。
特徴として:
- 言語体験を損なわないことを優先
- 標準添付でも Gem として管理されるものが多い
- 「標準だが交換可能」という思想
つまり:
- stdlib は「狭めだが深い」
- 言語機能とライブラリの境界が曖昧
## 2. 本体機能 vs 標準添付になったもの
ここが Python と Ruby で一番違う点です。
### Python:明確な線引き
Python では、/原則として/:
- 言語コア:構文・型・VMレベル
- 標準添付:ライブラリ(import するもの)
が明確に分かれています。
#### 本体(言語仕様・VM)
- オブジェクトモデル
- GC(参照カウント+世代)
- 型システム
- import 機構
- GIL
- 例外・yield・async/await
#### 標準添付ライブラリ例
os,sys,pathlibsocket,ssl,http.clientthreading,multiprocessingsubprocessloggingunittest,doctesttyping,dataclasses
重要なのは:
stdlib は「言語機能ではない」
という扱いです。
そのため最近は:
distutils→ 削除asyncioの整理importlibの内製化- typing 関連は「仕様」として別管理
など、/標準添付でも再設計・削減が進む/傾向があります。
### Ruby:言語とライブラリが混ざる
Ruby では、/歴史的に/:
- 標準添付 = 言語体験の一部
- 「require するが、実質コア」
というものが多いです。
#### 本体に近いもの
EnumerableComparableKernelObject,Module,ClassFiberThreadEnumerator
これらは/構文・言語設計と不可分/です。
#### 標準添付だが Gem 化されたもの
jsonpsych(YAML)rexmlnet/httpopensslrakeirbbundler
Ruby 2.x 以降は特に:
「標準添付 = default gem」
という考え方が定着しました。
つまり:
- 標準で入っている
- しかし独立して更新可能
- 必要なら外せる
という柔軟構造です。
## 3. なぜこう違うのか(思想的背景)
### Python
- 学術・教育・基盤用途が強い
- 複数実装(CPython / PyPy / Jython)を意識
- 仕様と実装を分離したい
- 保守性・再現性重視
→ stdlib は「参照点」
### Ruby
- 開発者体験(DX)重視
- 書いて楽しいことが最優先
- Matz の「プログラマの幸福」
- Ruby VM = Ruby 言語
→ stdlib は「言語の延長」
## 4. まとめ(短く)
| 観点 | Python | Ruby |
| --------- | ------- | -------- |
| 標準添付の思想 | 基盤・参照実装 | 実用・言語体験 |
| 本体とstdlib | 明確に分離 | 境界が曖昧 |
| 削除・整理 | あり得る | Gem 化で対応 |
| 拡張の場 | PyPI | RubyGems |
| 安定性 | 非常に高い | 比較的柔軟 |
Q: 標準添付でも Gem として管理されるものが多い との事。 3.4/ と gems/ ですね。 何となく、3.4/ の方は、老舗で、gems/ は、新興勢力のように感じられます。 どちらに配置するとかの、基準は有るのでしょうか? それと、gems/ への 殿堂入りは、誰が決めるんでしょうか? 選定基準って 有るのかな? Ruby の default gem 戦略と、からめて説明してください。
A: とても本質的な観察です。 その 「3.4 は老舗、gems/ は新興」/ という感覚は、実装・運用の実態をかなり正確に捉えています。
以下、/Ruby 3.4 系の構成/と /default gem 戦略/を軸に、 「どこに置かれるのか」「誰が決めるのか」「どういう基準か」を整理します。
## 0. 前提:3.4/ と gems/ は何が違うのか
Ruby のインストールツリーを単純化すると:
lib/ruby/
3.4.0/
├─ core / stdlib 的ライブラリ
gems/
3.4.0/
└─ gems/
├─ json-x.y.z
├─ rake-x.y.z
├─ bundler-x.y.z
ここで:
- 3.4/ → Ruby 本体と 同じリリースサイクルで管理されるライブラリ
- gems/ → RubyGems によって 独立して更新される default gem
という違いがあります。
## 1. 配置基準はあるのか? →「あるが、文書化されていない」
### 大原則(Matz + core の合意)
3.4/ に置かれるもの:
Ruby 言語の「成立」に深く関与しているもの
gems/ に置かれるもの:
Ruby を「便利にするが、言語そのものではないもの」
ただしこれは/厳密なルールではなく、運用上の合意/です。
## 2. 3.4/ に残る(老舗)ライブラリの特徴
### 条件①:言語仕様・コアクラスと不可分
例:
enumeratorfiberrational,complexsetforwardable
これらは:
EnumerableやKernelと密結合- 削除すると Ruby の書き味が変わる
- 「require しないと Ruby っぽくならない」もの
→ /言語機能の延長/扱い
### 条件②:後方互換を絶対に壊せない
例:
pp- =irb=(※今は default gem 化されたが特例)
optparse
過去 20 年以上のスクリプトが依存しているため:
- バージョン不整合を起こせない
- Ruby 本体と常に一緒にテストされる必要がある
### 条件③:C 拡張が VM と強く結びつく
例:
- =psych=(一部)
- =openssl=(歴史的理由)
ripper
VM 内部 API と密接なため:
- gem として切り離すと壊れやすい
- ABI 問題が出やすい
## 3. gems/(default gem)に行く「新興勢力」
### default gem の定義
default gem とは:
- Ruby を入れると最初から使える
- しかし
gem updateで更新できる - Ruby 本体とは独立してバージョン管理される
という立場です。
### default gem に送られる条件
#### 条件①:言語仕様と直接関係しない
例:
jsonnet/httpcsvrexmlwebrick
→ 便利だが「Ruby である必然性」は薄い
#### 条件②:セキュリティ更新が頻繁
例:
opensslnet/httpwebrick
Ruby 本体リリースを待たずに:
- CVE 対応
- プロトコル更新
が必要
#### 条件③:開発スピードを上げたい
例:
bundlerrakeirb
Ruby 本体は年 1 回前後だが:
- gem なら月単位で改善可能
## 4. 「殿堂入り」を決めるのは誰か?
### 決定主体
明確な「委員会」はありません。
実態は:
- ライブラリ作者
- Ruby core(特に Matz / naruse / hsbt あたり)
- Ruby committers の合意
- RubyKaigi 等での合意形成
という、/極めて Ruby らしい合議制/です。
### 典型的な流れ(昇格パターン)
- Gem として広く使われる
- Ruby 本体でも事実上必須になる
- 「標準で入ってないと困る」という空気ができる
- default gem として同梱
lib/ruby/3.4/ではなくgems/に配置
※ core に戻ることはほぼ無い
## 5. 選定基準はあるのか?(実質的チェックリスト)
暗黙的ですが、だいたい以下です:
- ✔ Ruby 文化に合うか
- ✔ メンテナが継続的に存在するか
- ✔ API が安定しているか
- ✔ 依存関係が少ないか
- ✔ Ruby 本体の哲学を壊さないか
- ✔ 削除可能であるか(gem なので)
逆に:
- ❌ 実験的すぎる
- ❌ DSL が強すぎる
- ❌ 巨大すぎる
ものは default gem になりません。
## 6. default gem 戦略の本質
### Ruby がやりたかったこと
「標準は欲しい。でも固定したくない」
これが default gem 戦略です。
- Python:stdlib は凍結 → PyPI に逃がす
- Ruby:stdlib を gem 化 → 標準のまま更新可能
つまり Ruby は:
標準添付 = 特権ではない
という思想を選びました。
## 7. あなたの感覚の答え合わせ
3.4/ は老舗、gems/ は新興
これは /ほぼ正解/で、より正確には:
- 3.4/ → Ruby そのものを成立させる「文化財」
- gems/ → 実用性重視の「殿堂入りだが可動式」
です。
try ruby
OpenBSDに入れてみる。ドキュメントは本体と分離されてるんで、どれ様なのが有るか 確認。これを入れておくと、irbした時、説明が出てくるぞ。
te$ doas pkg_add ruby
Ambiguous: choose package for ruby
a 0: <None>
1: ruby-3.2.9
2: ruby-3.3.9
3: ruby-3.4.6
Your choice:
rdoc経由で作成されるriも確認。
te$ pkg_info -Q ri_doc ruby32-ri_docs-3.2.9 ruby33-ri_docs-3.3.9 ruby34-ri_docs-3.4.6
3系統をサポートしてるのね。最新でいいだろう。
te$ doas pkg_add ruby-3.4.6 : --- +ruby-3.4.6 ------------------- If you want to use this package as your default system ruby, as root create symbolic links like so (overwriting any previous default): ln -sf /usr/local/bin/ruby34 /usr/local/bin/ruby ln -sf /usr/local/bin/bundle34 /usr/local/bin/bundle ln -sf /usr/local/bin/bundler34 /usr/local/bin/bundler ln -sf /usr/local/bin/erb34 /usr/local/bin/erb ln -sf /usr/local/bin/gem34 /usr/local/bin/gem ln -sf /usr/local/bin/irb34 /usr/local/bin/irb ln -sf /usr/local/bin/racc34 /usr/local/bin/racc ln -sf /usr/local/bin/rake34 /usr/local/bin/rake ln -sf /usr/local/bin/rbs34 /usr/local/bin/rbs ln -sf /usr/local/bin/rdbg34 /usr/local/bin/rdbg ln -sf /usr/local/bin/rdoc34 /usr/local/bin/rdoc ln -sf /usr/local/bin/ri34 /usr/local/bin/ri ln -sf /usr/local/bin/syntax_suggest34 /usr/local/bin/syntax_suggest ln -sf /usr/local/bin/typeprof34 /usr/local/bin/typeprof
それぞれが別の名前になってるんで、主力で使うものをリンクしとくといいよと 案内が出てきた。
te$ ruby -v ruby 3.4.6 (2025-09-16 revision dbd83256b1) +PRISM [i386-openbsd]
ちゃんとインストールされたか、確認。+PRISM って、何だ?
Prism:エラートレラントな、まったく新しいRubyパーサ
ユーザーへのご利益。
def hello(name)
puts "Hello #{name}"
hello('Matz')
こんな、中途半端なコード。
ob$ ruby test.rb
test.rb: --> test.rb
Unmatched keyword, missing `end' ?
> 1 def hello(name)
> 5 hello('Matz')
test.rb:6: syntax errors found (SyntaxError)
4 |
5 | hello('Matz')
> 6 |
| ^ expected an `end` to close the `def` statement
| ^ unexpected end-of-input, assuming it is closing the parent top level context
ちゃんと指摘してくれる。オイラーのruby 1.4.X 時代にサポートされてればなあ。 こういうつまらないエラーには、泣かされましたから。
debug
何はともあれdebuggrだな。標準添付になってるはずって事で、ドキュメント3.4の ライブラリィ一覧を調べてみたよ。目的別に整理されてて中々便利だ。 library debug
これによると、emacs用は別途、rubydb3x.el を入れろとなってた。 が、その通りにしても動作せす。
ruby/debug こちらが現代風な物らしいだよね、笹田先生(ko1)。何が現代風かと言うとvs code対応ね。 毒されているな。おまけに、
$ rdbg --open=chrome sample.rb
表示器をブラウザーに任せてしまう事もサポートされている。世はすっかりGUIで あります。ガラパゴス携帯を今だに愛用してるオイラーは、すっかり浦島太郎だな。
でもきっとガラパゴスを愛しているemacs派は希少種として、存在してるはず。 同士を探してみる。
GNU Emacs で VS Code 相当のコード・デバッグ支援機能を設定する (1) – Eglot
dape/dap-modeの2種が有るけど、dapeの方が小粒で良さそう。と思ったら、色々な 言語用を内蔵してた。TCP/IP 接続してるのね。
(rdbg
modes (ruby-mode ruby-ts-mode)
ensure dape-ensure-command
command "rdbg"
command-args ("-O" "--host" "0.0.0.0" "--port" :autoport "-c" "--" :-c)
fn (lambda (config)
(plist-put config 'command-args
(mapcar (lambda (arg)
(if (eq arg :-c) (plist-get config '-c) arg))
(plist-get config 'command-args))))
port :autoport
command-cwd dape-command-cwd
:type "Ruby"
;; -- examples:
;; rails server
;; bundle exec ruby foo.rb
;; bundle exec rake test
-c (concat "ruby " (dape-buffer-default)))
ちょいと使ってみたけど、コンソール上のemacsでは、枠が幅を効かせてしまって 不便だな。素直にrdbgするのが良さそう。
ruby 4.0.0
ruby生誕30周年で、看板が新らしくなってた。記念版は切り良い番号にしました (これで、完全にpythonの番号を出し抜きできました)。
記念にコンパイルしてみる。
sakae@lu:ruby-4.0.0$ ./configure --enable-shared
:
BASERUBY -v: ruby 3.4.1 (2024-12-25 revision 48d4efcb85) \
+PRISM [x86_64-linux]
去年、Windows 10を捨ててLubuntuにした時、コンパイル環境のチェックを兼ねて 入れたのが残っていた。baserubyが存在すると、minirubyを作成せずに、tool/ に有るものを使って、最終的なrubyを作成するそうだ。先端を追求する人向け。
make -j2 で、4分弱でコンパイル完了。
sakae@lu:~$ ruby -v ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [x86_64-linux]
libruby.so.3.4.1とか/usr/local/share/riにも、3.4.0/ なんてのが、残って いるんだよな。make installする前に、bin/ruby -> bin/ruby34 にでもしておけば、 二重生活ができたね。
sakae@lu:~$ gdb -q ruby
:
(gdb) b main
Breakpoint 1 at 0x1120: file ./main.c, line 53.
(gdb) r -v
Starting program: /usr/local/bin/ruby -v
:
Breakpoint 1, main (argc=2, argv=0x7fffffffdd48) at ./main.c:53
53 {
(gdb) l
48 int wmain(void) {return main(0, NULL);}
49 #endif
50
51 int
52 main(int argc, char **argv)
53 {
54 #if defined(RUBY_DEBUG_ENV) || USE_RUBY_DEBUG_LOG
55 ruby_set_debug_option(getenv("RUBY_DEBUG"));
56 #endif
57 #ifdef HAVE_LOCALE_H
コンパイルの残骸は1.1Gになってた。tar玉を展開しただけだと150Mだ。これだけ でも有ると上記のように一応gdbできる。
残骸が肥大化してる理由は、yjit/ が rust になってるから。yjitが組み込まれた 証拠でもあります。尚、OpenBSD版でもyjitを内包してます。もう、portsに、4.0.0 が登場してるよ。
README
ギーク思考 なんて本を読んだ。
本の紹介の所に、計画よりも失敗 なんてのが挙げられている。グダグダと考えて いるより、体を動かせ、そして色々と失敗しろって理解した。
その方が得る所が大きいからね。例えば、ruby 4.0をコンパイルした。コンパイルに 当っての事前準備なんて全く眼中に無かったぞ。configureなんて失敗するのが あたり前と思っていたからね。
そしたら、既存のrubyを検出して、それをminirubyの代わりに使ってくれた。 じゃ、既存のrubyが存在しない場合は?
3秒考えて、rubyをPATHから外した。そして、rubyが居ない事を確認する為に 下記のコマンドを投入。
sakae@lu:~$ ruby -v コマンド 'ruby' が見つかりません。次の方法でインストールできます: sudo snap install ruby # version 3.4.7, or sudo apt install ruby # version 1:3.1 他のバージョンについては 'snap info ruby' を確認してください。
snap版でも提供されるんかって無駄知識が得られた。snap infoなんてコマンドも 知らなかったしね。こういうの、失敗してこその知見です。
それから、4.0のニュース解説を読んでいると、調整よりもカオス、忖度よりも議論 ってのがrubyには似合っているねと良く分る。