Ruby Gem 9章のロードを構築

5505 ワード

≪ロード|Load|emdw≫
その使用中に線と下線が多くの規範がなかった時代に戻り、多くのライブラリが前者を選択した.これにより、下線が基準となると、ユーザは非常に困惑する.
私たちの議論がmegaにあることを覚えています.lotto.gemspecファイルのヘッダ宣言ロードパスですか?うん...Gemfileでgemを指定するとbundlerは、ロードパスと同じ名前のファイルをロードします.そして、私たちのgemのlib/ディレクトリからロードパスに追加したため(bundlerはgemspecファイルで設定してくれました)、私たちのエントリファイルはすでにロードされています.
だからmega_に参加することでlottoはGemfileに着いて、bundlerは入り口のファイルlib/megaを探すことを知っています.lotto.rb. これはすべて約束の俗成で、あなたが知っているため、私达のRubyist、私达の約束を爱します.
すべてのクラスライブラリが実行時にロードされる必要はありません.ポータルファイルでの宣言は、私たちに依存します.これは、gemのクラスライブラリがデフォルトでロードされていないことがよくあります.いくつかの例は、コマンドライン実行可能ファイルのクラス、webエンジン、およびテストをサポートするクラスライブラリです.この章では、上記のベストプラクティスのようなオプションクラスライブラリのロードについて説明し、私たちのgemでRuby基本クラスライブラリを拡張する方法について説明します.
サポートクラスライブラリ
私たちがmegaのためにlotto gemは、Webエンジンを作成し、ホストアプリケーションにロードしたいと考えています.Webインタフェースをサポートするクラスライブラリはlib/mega_lotto/web.rbにある可能性があります.そうすれば、Gemfileでrequireをロードできます.これにより、自動的にロードされます.
あるいは、Railsのinitializerで他のプロファイルと一緒にロードすることもできます.
# config/initializers/mega_lotto.rb

require "mega_lotto/web"
# other gem configuration...

Railsアプリケーションでは、config/routesファイルのようにクラスライブラリをマウントできます.
mount MegaLotto::Web => '/mega_lotto'

このWebクラスライブラリをロードするのはオプションなので、lib/mega_には含まれません.lotto.rbのエントリファイル:
require "mega_lotto/version"
require "mega_lotto/drawing"
# notice that "mega_lotto/web" is not included here

module MegaLotto 
end

現実世界の例
Sidekiq gemには、デフォルト依存を必要としないWebライブラリに関する絶好の例があります.require sidekiq/webクラスライブラリを選択し、含まれるSinatraをホストアプリケーションにマウントすることができます.
テストをサポートするクラスライブラリは、テストのモジュール/クラスがgemの一部である可能性がありますが、デフォルトでロードされているわけではありません.Sidekiqには、非同期ではなくバックグラウンドスクリプトを直接実行するテストクラスがあります.私のgem Sucker Punchには似たようなテストライブラリがありますが、デフォルトではロードされません.
この2つの例では、クラスライブラリはエントリファイルに含まれず、ユーザーにspec/spec_を含めるように残されていません.helper.rbファイルの権力は、もし彼らがこの機能を望んでいるならば.
コア拡張
active_support gemはRailsの依存であり、トンの価値を提供している.見てごらんextディレクトリ.
これらは、Ruby標準ライブラリのクラスのように見える拡張子です.これらの拡張は私たちの生活をもっと美しくします.たとえば、次のような方法があります.
5.seconds # => 5 seconds "asdf".present? # => true (1..42).to_a.forty_two # => 42

すべてが役に立つわけではないかもしれませんが、多くは役に立ちます.これらの機能はもともと不要なクラスに配置される可能性がありますが、RailsコアチームはRubyのデフォルトの動作を拡張することを選択し、フレームワークが新しい開発者に適応しやすいようにしました.そのため、多くのRubyとRailsの初心者は、Railsの方法とRubyの方法を見分けにくい.
Rubyは標準クラスライブラリの拡張を非常に容易にした.たとえば、Stringクラスに#banansメソッドを追加したい場合は、次のようにします.
class String 
  def bananas 
    "bananas"
  end
end

...これがコア拡張です!簡単ですね.
しかし、能力が大きいほど責任が大きい.コア拡張をあちこちに組み込むのはいい考えではありません.実際、ほとんどの場合、私たちのgemのネーミングスペースに追加の機能を追加する個別のクラスを作成するのがより良い選択だと言わなければなりません.
拡張メソッドをあなたのgemに含めるより良い方法がないことを発見したと仮定し、私たちのgemでRubyのサルパッチを使用することについて議論しましょう.
1つまたは2つのメソッドのみを1つまたは2つのクラスに追加する場合、core_という名前のメソッドを作成するのが一般的です.ext.rbのファイルは私たちのgemのlib/ディレクトリの下にあります.
私たちがmegaを開発していることを想像してみてください.lotto gemでは、drawメソッドをArrayクラスに追加したいと考えています(本当にしないでください).drawメソッドはarrayでランダム要素を選択し、返します.幸いなことに、Rubyはすでにこのことをする方法があるので、私たちの実現はそれを依頼します.
# lib/mega_lotto/core_ext.rb

class Array 
  def draw sample

  end 
end

私たちはやりました.
このファイルは今、gemで作成した他のファイルと同じです.メインエントリlib/megaに追加します.lotto.rbファイルでは、Arrayクラスからdrawメソッドにアクセスできます.
大量の方法
もし、いくつかの理由でRubyのコアクラスライブラリにいくつかの方法を追加する必要がある場合は、各ファイルがサルパッチを適用するクラスに対応する個別のファイルに分離するのが良いです.
例を挙げるために、drawメソッドを上記のメソッドに追加し、新しいメソッドmega_lottoはStringクラスで既存の文字列からランダムな名前を印刷します.
このように:
Stringクラスにメソッドを追加し、Arrayクラスにメソッドを追加し、プライマリcore_を作成します.ext.rbファイルは、作成する独立した拡張クラスをロードすることをします.
# lib/mega_lotto/core_ext.rb

require "mega_lotto/core_ext/array"
require "mega_lotto/core_ext/string"

drawメソッドの実装は、以前と同様に、異なるファイルにのみ存在します.
# lib/mega_lotto/core_ext/array.rb

class Array 
  def draw sample

  end 
end

このファイルがlib/megaにどのように置かれているかに注意してください.lotto/core_ext/ディレクトリの.これは、ネーミングスペースのクラスライブラリに複数のサブクラスが含まれている一般的な実践です.私たちの拡張はlib/megaですがlotto/ディレクトリの下で、このクラスはMegaLottネーミングスペースの派生ではありません.もしそうなら、Ruby標準ライブラリのStringクラスではなく、私たちのネーミングスペースに完全に新しいStringクラスが作成されます.
これは私たちのmegaです.lotto対応Stringクラスの実装:
# lib/mega_lotto/core_ext/string.rb

class String 
  def mega_lotto
    "Mega Lotto: #{self}" 
  end
end

私たちのlib/mega_lotto/core_ext.rbファイルは、個別の拡張をロードするタスクを完了しました.プライマリファイルlib/mega_lotto.rbはlib/mega_をもう一度ロードできます.lotto/core_ext.rbファイル.
lib/mega_lotto/core_ext.rbファイルは、含まれているすべてのライブラリを刻むことができます.
これは、gemが個別のクラス拡張子をロードしたときのファイル構造の様子です.
現実世界の例
私のsucker_punch gemでは、Stringクラスを下線法で拡張しました.これは完璧な例ですactiveからsuppoert. 全体をsupport gemは私のプロジェクトに引っ張って1つの方法のためだけに、私はunderscoreメソッドの実装をコピーして1つのcoreにコピーすることを選択しました.ext.rbファイルこのようなレプリケーション方法は必ずしも賢明ではないが、この実現は私のニーズを満たすことができ、今後アップグレードする必要はないと確信している.
Sidekiq gemにもRuby標準ライブラリを拡張するコードが加わった.このファイルのコードはより複雑であるが、使用例はいずれのgemにおいても同じである-標準Rubyクラスにコードを追加してgemを実現するコードをサポートする.
まとめ
深いネーミング空間システムを考えると、見失いやすい.私が新しいRubyクラスを作成したとき、私もそれが何の『bucket』に属しているのかを考える傾向があります.
この『bucket』は、多くの場合、Rubyネーミングスペースとそのディレクトリ名に翻訳できます.通常は関連しているからです.
この章では、Ruby gemsだけでなく、任意のRubyアプリケーションにも1つ以上のネーミングスペースがある限り、価値があるためです.
私は規範的な答えが好きですが、残念なことに、組織コードはプログラムに常に存在しません.通常、私は行動する前に苦しむのが好きです.しかし、あまりにも長い間待っていたら、あなたの道を掘り起こすのはもっと苦痛です.複雑さと過度なエンジニアリングのバランスは、すべての開発者の課題です.あなたの決定から経験した苦痛が多ければ多いほど、将来この問題を避けることができます.強引な規定はない.Rubyは開発者としての私たちのニーズを実現するのに十分な柔軟性を持っています.良好な組織と分かりやすさを維持する責任は私たちにある.
私たちがgemをオープンソースし、他の貢献者に注目したいなら、貢献者の観点から組織を考えるのは賢明です.あなたのgemがどんなにクールであっても、自分の時間を犠牲にしてめちゃくちゃなコードに貢献したい人は少ない.
次の章では、実行可能なコマンドをgemに結合する方法を探求します.