-
RubyGemsの内部構造を徹底解説!gemの仕組みと自作方法
皆さん、お集まりください。おじいさんが昔話をしてあげましょう。gemのインストールが頭痛の種で、髪を掻きむしり、歯を食いしばるような苦行だった時代の話です。 私がRubyを始めたばかりの頃は、まだBundlerは存在せず、gemは手作業でインストールするしかありませんでした。Railsでは、rake gems:install を何度も実行しては、途中で発生するバグを修正し、エラーなしでコマンドが通るまで繰り返す——そんなのが日常でした。今回は、gemとは何か、そしてどのように動作しているのかを見てから、あえて「古式ゆかりの」方法でgemを作ってみます。 gemとは何か? RubyGemsは、他
-
ゼロから始めるRuby C拡張機能の作り方 ― CライブラリをRubyから活用する
今回のRuby Magicでは、RubyからC言語で書かれたコードを利用する方法をご紹介します。この手法は、パフォーマンスが重要となる処理の最適化や、CライブラリとRubyをつなぐインターフェースの構築に活用できます。具体的には、Cで書かれたライブラリをラップする「拡張機能(エクステンション)」を作成することで実現します。C言語には、成熟していて高いパフォーマンスを持つライブラリが数多く存在します。それらをRubyに移植して車輪の再発明をするのではなく、既存のライブラリをそのまま活用するのが賢い選択です。こうすることで、普段どおり好きな言語であるRubyでコードを書きながら、Rubyが伝統的に
-
Rubyで非同期スレッドをテストする方法:トリガー・収集・検証のパターン
スレッドや非同期環境は、最初は少し扱いにくいものです。やり取りを整理するための適切なメンタルモデルがなければ、思わぬ結果に悩まされ、トラブルに陥りやすくなります。さらに、適切なツールやテストパターンがないと、非同期コードのテスト自体が難しくなってしまいます。スレッドを「人」に見立て、共有オブジェクトを「所有できる物」として考えると、マルチスレッドシステムの動作を整理しやすくなります。この記事では、具体的な例を通じて、Rubyの非同期コードのテスト方法を学んでいきます。RailsやRack、あるいはWebブラウザをフロントエンドとするアプリケーションを使っているなら、あなたはすでに非同期環境の中
-
RubyのFiberとEnumerator ― 実行中のブロックを裏返す
Rubyには、ループ、ブロック、エニュメレータなど、反復処理を行うためのさまざまな手段が用意されています。多くのRubyプログラマはループとブロックには慣れ親しんでいるものの、EnumeratorやFiberはあまり深く理解されていないことが多いでしょう。今回のRuby Magicでは、ゲスト著者のJulikがEnumerableとFiberに光を当て、フロー制御可能な列挙処理と「ブロックを裏返す」テクニックを解説します。 ブロックの一時停止と連鎖的な反復処理 以前のRuby MagicではEnumeratorについて取り上げ、独自の#eachメソッドからEnumeratorを返す方法とその活
-
平均値だけに頼るな:統計の平均とパーセンタイル入門
パフォーマンス監視は、アプリケーションを成功させるために欠かせない重要な取り組みです。何かのパフォーマンスを把握する最も基本的な方法のひとつが、処理が発生するたびにその所要時間を計測し、そこから統計値を導き出すことです。平均値(Mean)値の集合の平均値は、対象がどれほど良い、あるいは悪い挙動を示しているかを見るうえでの良い出発点になります。計算方法はシンプルで、対象となるすべての値を合計し、発生回数で割るだけです。Rubyでレスポンスタイムの平均を計算すると、次のようになります。def mean(array) (array.sum.to_f / array.length).round(2)
-
Rubyのバインディングとレキシカルスコープを徹底解説
あけましておめでとうございます。Ruby Magicへようこそ!今回の冬のエピソードでは、バインディングとスコープについて深く掘り下げます。それでは、スキーを履いて森の奥深くまでご一緒しましょう。前回は、ブロック・Proc・ラムダを比較しながらRubyのクロージャについて学びました。3つの違いに触れるとともに、「クロージャとは何か」についても簡単に説明しました。クロージャとは、環境(environment)を持つ第一級関数です。環境とは、クロージャが作成された時点で存在していた変数へのマッピングのこと。クロージャは、たとえその変数が別のスコープで定義されていても、アクセス権を保持し続けます。前
-
RubyではじめるGraphQL入門――音楽アプリのサンプルで学ぶスキーマ定義と実装
GraphQLの素晴らしさを絶賛する開発者の声を耳にしたことがある方も多いでしょう。このシリーズでは、実際に技術を手を動かしながら学んでいくスタイルを大切にしており、本記事ではGraphQLを活用したサンプルアプリケーションを通じて、その基本を解説します。 GraphQLとは何か GraphQLは、API構築に使えるクエリ言語およびランタイムです。開発スタックにおける位置づけはREST APIと似ていますが、より柔軟性が高いのが特徴です。RESTと異なり、GraphQLではレスポンスの形式や内容をクライアント側で指定できます。SQLのSELECT文で取得結果を指定できるように、GraphQLで
-
Rubyのクラス・インスタンス・メタクラスを徹底解説 ― メソッド定義の仕組みを理解する
Ruby Magicの新しいエピソードへようこそ! 今月のテーマはメタクラスです。二人の開発者による議論がきっかけで生まれたこのテーマ(こんにちは、Maudさん!)について、じっくり掘り下げていきます。メタクラスを調べることで、Rubyにおけるインスタンスメソッドとクラスメソッドの動作原理が見えてきます。さらに、明示的なレシーバを渡してメソッドを定義する方法と、class << self や instance_eval を使う方法との違いも理解できるでしょう。それでは始めましょう!クラスインスタンスとインスタンスメソッドRubyでなぜメタクラスが必要なのかを理解するために、まずはイ
-
Rubyの#dupと#cloneを徹底解説!内部実装から独自実装まで完全ガイド
本記事では、Rubyの#dupと#cloneについて詳しく掘り下げていきます。まず、このテーマに興味を持つきっかけとなった実際の開発事例を紹介し、その後、Rubyにおける#dupの内部実装や#cloneとの違いを深く学んでいきます。最後には、独自の#dupメソッドを実装して締めくくります。それでは始めましょう!dupを使い始めたきっかけかつて私は、NGOの寄付募集キャンペーンの構築を専門とする会社で働いていました。そこでは、既存のキャンペーンをコピーして新しいキャンペーンを作成する作業が頻繁に発生していました。例えば、2018年のキャンペーンが終了したら、2019年用の新キャンペーンが必要にな
-
Rubyの隠れた宝石「StringScanner」で文字列解析をマスターする
Rubyは楽しく書ける言語であるだけでなく、優秀な標準ライブラリも魅力のひとつです。その中にはあまり知られていない、いわば「隠れた宝石」と呼べるものがいくつかあります。今回はゲストライターのMichael Kohl氏が、そのお気に入りのひとつであるStringScannerを紹介します。 StringScannerとは何か Rubyでは、OpenStructやSetのようなデータ構造からCSVパース、ベンチマークまで、サードパーティのgemをインストールしなくてもかなりのことが実現できます。しかし、標準で同梱されているライブラリの中には、あまり知られていないながらも非常に便利なものがいくつか存
-
Rubyのオブジェクトマーシャリング入門:Marshalモジュールと_dump/_loadメソッドの使い方
本記事では、Rubyにおけるオブジェクトマーシャリング(Object Marshalling)について詳しく解説します。まず、マーシャリングが何であるかを説明し、標準ライブラリのMarshalモジュールの基本的な使い方を紹介します。その後、実際のコード例を通して理解を深め、さらに一歩踏み込んで_dumpメソッドとself._loadメソッドの違いや挙動まで掘り下げていきます。それでは始めましょう! オブジェクトマーシャリングとは? プログラムを書いていると、あるオブジェクトを保存しておき、別のプログラムへ受け渡したり、次回のプログラム実行時に再利用したりしたい場面があります。 身近な例としてS
-
KafkaとRuby、Sidekiqで紡ぐラブストーリー
成長を続けるオールインワンAPMとして、私たちは増え続けるトラフィックにAppSignalが対応できるよう、多大な時間をかけて取り組んでいます。普段はその手法について語ることはあまりありません。私たちのブログにはRubyの内部動作やElixirでの突拍子もない実験に関する記事は数多くありますが、AppSignalそのものを動かしている仕組みについてはほとんど触れてこなかったからです。しかし今回は、ここ数年でスタックに加えてきた大きな変更点のいくつかをご紹介したいと思います。おかげで、毎月私たちに送られてくる数百億件ものリクエストをリアルタイムで(しかも余裕をもって)処理できるようになりました。
-
Rubyの隠れた宝石:DelegatorとForwardableによる委譲パターン徹底解説
今回は、Ruby標準ライブラリに隠された宝石の中から「委譲(delegation)」について掘り下げていきます。残念ながら、この用語は他の多くの技術用語と同じように、長年の間に意味が曖昧になり、人によって異なる解釈をされるようになりました。Wikipediaによると、委譲とは次のように定義されています。委譲とは、あるオブジェクト(受信者)のメンバー(プロパティやメソッド)を、別の元オブジェクト(送信者)のコンテキストで評価することを指す。明示的な方法として、送信側オブジェクトを受信側オブジェクトに渡す方法があり、これはあらゆるオブジェクト指向言語で実現できる。また、言語のメンバールックアップ規
-
method_missingで祖先チェーンを遡る:Rubyのメソッド探索の仕組みを徹底解説
機内持ち込みの手荷物をお忘れなく。今日はRubyの祖先チェーン(Ancestor Chain)を最上部まで旅してみましょう。メソッド呼び出しがどのようにチェーンを駆け上がっていくのか、そして目的のメソッドが見つからなかったときに何が起こるのかを追跡します。さらに、火遊びがお好きな方のために、私たちはそこで止まりません。火遊びの続きとして、BasicObject#method_missingのオーバーライドにも挑戦します。うまくいけば、実践的な活用例もご紹介できるかもしれません。それでは出発しましょう! 祖先チェーン(Ancestor Chain)とは まずは、Rubyにおける祖先チェーンの基本
-
Rubyの内部実装:EnumeratorとEnumerableの仕組みを自作で理解する
Ruby Magicへようこそ!1年前、私たちはRubyのEnumerableモジュールについて学びました。これは配列、範囲、ハッシュなどの列挙可能なオブジェクトを操作する際に使うメソッドを提供します。 当時、LinkedListクラスを作成し、#eachメソッドを実装することでオブジェクトを列挙可能にする方法を示しました。Enumerableモジュールをincludeすることで、#count、#map、#selectなどのメソッドを、自前で実装せずともあらゆるリンクドリストで呼び出せるようになりました。 列挙可能オブジェクトの使い方は理解しましたが、それらは内部でどう動いているのでしょう?R
-
Deviseを適切に国際化するための究極のチェックリスト
最高のブログ記事は、自分自身の「痒いところ」を解決したいという欲求から生まれることがあります。今日の記事もまさにその一例です!Railsアプリケーション向けの定番認証ソリューションであるDeviseをご存知の方は多いでしょう。私がDeviseを使って作業していたとき、翻訳を実際に動かすまでには、想像以上に多くの手順と工夫が必要だと気づきました。「こんなとき、チェックリストがあれば迷わずに済むのに」と過去の自分は思っていたものです。というわけで、未来の自分と読者の皆さんのために——究極のDevise国際化チェックリストをご紹介します!devise-i18n gemを使うべきか、使わないべきか?ま
-
Rubyで独自のテンプレートレクサーを作成する
スキューバダイビングの装備を整え、ステンシルを用意してください。今日はテンプレートの世界へ潜ります! Webページのレンダリングやメール生成を行うほとんどのソフトウェアは、テンプレート機能を使って変数データをテキストドキュメントに埋め込みます。ドキュメントの主要構造は静的なテンプレートとして定義され、プレースホルダーにデータが入力されます。ユーザー名やWebページの内容などの変数データが、レンダリング時にプレースホルダーを置き換えます。 今回のテンプレート探求では、多くのプログラミング言語で利用可能なテンプレート言語「Mustache」のサブセットを実装します。この記事では、さまざまなテン
-
Rubyテンプレートエンジンを深掘り:パーサーの実装
前回はRubyテンプレートエンジンの旅の第一歩として、字句解析器(レキサー)を実装しました。今回は次のステップである構文解析器(パーサー)の実装に取り組みます。また、言語理論の基礎にも少し触れていきます。 抽象構文木(AST)とは 簡単なテンプレート Welcome to {{name}} を例に考えてみましょう。レキサーでトークン化すると、以下のようなトークン列が得られます。 Magicbars::Lexer.tokenize(Welcome to {{name}}) # => [[:CONTENT, Welcome to ], [:OPEN_EXPRESSION], [:IDENT
-
Rubyの文字列クリーンアップ、使い方次第で最大13倍速くなる
コードを書くとき、私たちは無意識のうちに「一番慣れているメソッド」を選びがちです。目の前の文字列を整形したいと思った瞬間、指が勝手にいつものメソッドを打ち込んでしまう——そんな経験はないでしょうか。自動的に選ばれるのは、たいてい最も汎用的なRubyのメソッドです。読む機会も書く機会も他より多いためです。例えば#gsubは、文字列内の文字を置換するための万能メソッドですが、Rubyには標準的な操作のための、より特化した便利なメソッドが数多く用意されています。Rubyの豊かなイディオムが好きな理由は、コードがよりエレガントになり、読みやすくなるからです。この豊かさの恩恵を受けるには、文字列のクリー
-
Rubyの型チェック入門——NoMethodErrorを防ぐSorbet、Steep、Type Profiler徹底解説
この記事は、ちょっとしたクイズから始めましょう。AppSignalがRubyアプリケーションで追跡している最も発生頻度の高いエラーは何だと思いますか? 多くの方がNoMethodErrorと答えたのではないでしょうか。これは、オブジェクトに存在しないメソッドを呼び出した際に発生する例外です。メソッド名のタイポが原因であることもありますが、より多いのは「誤った型のオブジェクト」に対してメソッドを呼び出したケースで、その多くは予期しないnilです。Ruby開発者として、こうしたエラーの発生頻度を減らすためにできることはあるのでしょうか? 型システムは救いの手になるのか? テキストエディタやプログラ