Rubyのコードローダー:Zeitwerkを理解する
Rubyのコードローダー-Zeitwerkを理解する
Zeitwerkを使用すると、クラスとモジュールがどこでも利用できることを知って、プログラミングを合理化できます。
コードローダーを使用すると、開発者はclasses
を定義できます。 およびmodules
さまざまなファイルやフォルダにまたがって、明示的に要求することなくコードベース全体でそれらを使用します。 Railsは、コードローダーを使用するソフトウェアの良い例です。 Railsでのプログラミングには、明示的なrequire
は必要ありません。 コントローラで使用する前にモデルをロードするための呼び出し。実際、Rails 6では、app
のすべてが ディレクトリは、いくつかの例外を除いて、アプリの起動時に自動ロードされます。
コードの読み込みはrequire
を呼び出すことがすべてだと考えるのは簡単ですが 、それはそれほど単純ではありません。コードの読み込みは、次のようにさらに3つの部分に分けることができます。
- 自動読み込み: これは、コードが必要に応じてオンザフライでロードされることを意味します。たとえば、Railsでは、
rails s
を実行します すべてのモデル、コントローラーなどをロードするわけではありません。ただし、モデルの最初のヒット時にUser
、自動読み込みメカニズムを実行して、モデルを見つけて使用します。これは実際の自動読み込みです。より高速なアプリとrails console
があるため、これには開発環境にいくつかの利点があります。 起動時間。Rails.config.autoload_path
自動ロードされるパスを制御します。 - 積極的な読み込み: これは、アプリの起動時にコードがメモリに読み込まれ、定数が呼び出されるのを待たずにコードを要求することを意味します。 Railsでは、コードは本番環境で熱心にロードされます。上記の説明から、本番環境でコードを自動ロードすると、各定数がオンザフライで必要になるため、応答時間が遅くなります。
Rails.config.eager_load_paths
熱心にロードされるパスを制御します。 - リロード: コードローダーは、
autoload_path
内のファイルへの変更を常に監視しています。 変更に気付いたときにファイルをリロードします。 Railsでは、これによりrails s
を実行できるため、開発に非常に役立ちます。 同時に、Railsサーバーを再起動せずに変更を加えます。これは実際にリロードしています。
これらの概念のほとんどがRailsで開発され、実行されていることが簡単にわかります。 Zeitwerkはこれを変更します! Zeitwerkを使用すると、すべてのコード読み込みアクションを任意のRubyプロジェクトに導入できます。
Zeitwerkとは何ですか?
ZeitwerkはRuby用の効率的でスレッドセーフなコードローダーであり、Webフレームワーク(Rails、Hanami、Sinatra)、Cliツール、gemなどのRubyプロジェクトで使用できます。これを使用すると、クラスとモジュールがどこでも利用できることを知って、プログラミングを合理化できます。伝統的に、Railsと一部 他のgemには、この機能を有効にするためのコードローダーが組み込まれています。ただし、Zeitwerkはこれらの概念を宝石に抽出し、Rubyistがこれらの概念をプロジェクトに適用できるようにします。
Zeitwerkのインストール
まず最初に、gemをインストールする必要があります:
gem install zeitwerk
# OR in your Gemfile
gem 'zeitwerk', '~> 2.4.0'
Zeitwerkの構成
それでは、基本から始めましょう:
require 'zeitwerk'
loader = Zeitwerk::Loader.new
...
loader.setup
上記のコードはローダーインスタンスをインスタンス化し、setup
を呼び出します 。 setup
を呼び出した後 、ローダーはコードをロードする準備ができています。ただし、その前に、loader
で必要なすべての構成 すでにカバーされている必要があります。この記事では、loader
のいくつかの構成について説明します。 およびコードを構造化するための規則。
- ファイル構造:Zeitwerkが機能するには、ファイルとディレクトリ名が、それらが定義するモジュールとクラス名と一致している必要があります。たとえば、
lib/my_gem.rb -> MyGem
lib/my_gem/foo.rb -> MyGem::Foo
lib/my_gem/bar_baz.rb -> MyGem::BarBaz
lib/my_gem/woo/zoo.rb -> MyGem::Woo::Zoo
- ルート名前空間:ルート名前空間は、
Zeitwerk
が存在するディレクトリです。 あなたのコードを見つけることができます。modules
の場合 およびclasses
が参照されている場合、Zeitwerkは一致するファイル名でルート名前空間を検索することを認識しています。たとえば、
require 'zeitwerk'
loader = Zeitwerk::Loader.new
loader.push_dir("app/models")
loader.push_dir("app/controllers")
// matches as follows
app/models/user.rb -> User
app/controllers/admin/users_controller.rb -> Admin::UsersController
2つの異なるユースケースのルート名前空間を定義する主な方法は2つあります。デフォルトの方法を以下に示します:
// init.rb
require 'zeitwerk'
loader = Zeitwerk::Loader.new
loader.push_dir("#{__dir__}/bar")
...
loader.setup
// bar/foo.rb
class Foo; end
これは、クラスFoo
を意味します 明示的なBar::Foo
なしで参照できます 、barディレクトリがルート名前空間として機能するため。名前空間を定義する2番目の方法は、push_dir
の呼び出しで名前空間を明示的に指定することです。 :
// init.rb
require 'zeitwerk'
module Bar
end
loader = Zeitwerk::Loader.new
loader.push_dir("#{__dir__}/src", namespace: Bar)
loader.setup
// src/foo.rb
class Bar::Foo; end
このコードには注意すべき点がいくつかあります:
- モジュール
Bar
push_dir
によって使用される前にすでに定義されています 。使用するモジュールがサードパーティによって定義されている場合、push_dir
の呼び出しで使用する前に、単純なrequireによってモジュールが定義されます。 。 -
push_dir
名前空間Bar
を明示的に指定します 。 - ファイル
src/foo.rb
定義されたBar::Foo
、Foo
ではありません 、src/bar/foo.rb
のようにディレクトリを作成する必要はありませんでした 。
-
独立したコードローダー:設計上、Zeitwerkでは、各プロジェクトまたはアプリの依存関係で個々のプロジェクトツリーを管理できます。これは、各依存関係のコード読み込みメカニズムがその依存関係によって管理されることを意味します。たとえば、Rails 6では、ZeitwerkはRailsアプリのコードの読み込みを処理し、各gem依存関係が独自のプロジェクトツリーを個別に管理できるようにします。複数のコードローダー間でファイルが重複しているのはエラー状態です。
-
自動読み込み:上記の設定で、
setup
を呼び出したら 作成されると、すべてのクラスとモジュールがオンデマンドで利用できるようになります。 -
再読み込み:再読み込みを有効にするには、
loader
明示的に構成する必要があります。たとえば、
loader = Zeitwerk::Loader.new
...
loader.enable_reloading # you need to opt-in before setup
loader.setup
...
loader.reload
loader.reload
callはプロジェクトツリーをオンザフライでリロードし、新しい変更はすぐに表示されます。ただし、ファイルシステムへの変更を検出し、loader.reload
を呼び出すには、周囲のメカニズムが必要です。 。簡単なバージョンを以下に示します:
require 'filewatcher'
loader = Zeitwerk::Loader.new
...
loader.enable_reloading
loader.setup
...
my_filewatcher = Filewatcher.new('lib/')
Thread.new(my_filewatcher) {|fw| fw.watch {|filename| loader.reload } }
RailsでのZeitwerkの使用
ZeitwerkはRails6.0ではデフォルトで有効になっています。ただし、オプトアウトしてRails classic
を使用することはできます コードローダー。
# config/application.rb
config.load_defaults "6.0"
config.autoloader = :classic
Zeitwerkは、標準のgem構造(lib/special_gem
)を使用している限り、gemに便利なメソッドを提供します。 )。この便利な方法は、次のように使用できます。
# lib/special_gem.rb
require 'zeitwerk'
module SpecialGem
end
loader = Zeitwerk::Loader.for_gem
loader.setup
標準のgem構造では、for_gem
呼び出しはlib
を追加します ルート名前空間としてのディレクトリ。lib
内のすべてのコードを有効にします 自動的に見つかるディレクトリ。
さらにインスピレーションを得るために、Zeitwerkを使用して宝石をチェックすることができます:
- カラフカ
- ジェット
Railsの自動読み込み—どのように機能し、いつ機能しないか
Zeitwerk
-
Rubyでの複製とクローン:違いを理解する
Rubyでオブジェクトをコピーできることをご存知ですか?それだけでなく、これを行うには2つの異なる方法があります! これらの方法は : dup clone すぐに違いを探りますが、最初に… なぜオブジェクトのクローンを作成するのですか? ? Rubyの多くのオブジェクトは変更可能であり、変更することができます。 オブジェクトを変更したいが、元のコピーを保持する場合 その後、クローンを作成できます。 たとえば。 最初の要素を除くすべての要素を含む配列が必要な場合があります。 これを行う1つの方法 : a = [1,2,3,4,5] a[1..-1] # [2,3,4
-
Rubyでの静的分析
ソースコードを解析して、すべてのメソッド、それらが定義されている場所、およびそれらが取る引数を見つけたいとします。 どうすればこれができますか? あなたの最初のアイデアはそれのために正規表現を書くことかもしれません… しかし、もっと良い方法はありますか? はい! 静的分析 は、ソースコード自体から情報を抽出する必要がある場合に使用できる手法です。 これは、ソースコードをトークンに変換する(解析する)ことによって行われます。 さっそく始めましょう! パーサージェムの使用 Rubyには標準ライブラリで利用可能なパーサーがあります。名前はRipperです。出力を操作するのは難し