Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

Rails Hidden Gems:ActiveSupport StringInquirer

Railsは大きなフレームワークであり、毎年大きくなります。これにより、いくつかの便利な機能が見過ごされやすくなります。このシリーズでは、特定のタスクのためにRailsに組み込まれているあまり知られていない機能をいくつか見ていきます。

このシリーズの最初の記事では、Rails.env.test?を呼び出す方法を見ていきます。 あまり知られていないStringInquirerを使用することで、実際には内部で機能します ActiveSupportのクラス。さらに一歩進んで、StringInquirerについても説明します。 それがどのように機能するかを確認するためのソースコード。これは(ネタバレ注意)特別なmethod_missingを介したRubyのメタプログラミングの簡単な例です。 メソッド。

Rails.envヘルパー

Rails環境をチェックするコードを見たことがあるでしょう:

if Rails.env.test?
  # return hard-coded value...
else
  # contact external API...
end

ただし、test? 実際にそうです、そしてこの方法はどこから来たのですか?

Rails.envをチェックすると コンソールでは、文字列のように機能します:

=> Rails.env
"development"

ここでの文字列は、RAILS*ENV環境変数が設定されているものです。ただし、文字列だけではありません。コンソールでクラスを読むと、次のように表示されます。

=> Rails.env.class
ActiveSupport::StringInquirer

Rails.env 実際にはStringInquirerです。

StringInquirer

StringInquirerのコードは簡潔で、十分に文書化されています。ただし、Rubyのメタプログラミング機能に精通していない限り、どのように機能するかは明らかではないかもしれません。ここで何が起こっているのかを見ていきます。

class StringInquirer < String
...
end

まず、StringInquirerがStringのサブクラスであることがわかります。これがRails.envの理由です 呼び出すと文字列のように機能します。 Stringから継承することで、Stringに似た機能がすべて自動的に取得されるため、Stringのように扱うことができます。 Rails.env.upcase ActiveRecordModel.find_by(string_column: Rails.env)と同様に機能します 。

Rails.env はStringInquirerの便利な組み込みの例であり、独自の例を自由に作成することもできます:

def type
  result = "old"
  result = "new" if @new

  ActiveSupport::StringInquirer.new(result)
end

次に、戻り値に疑問符のメソッドを取得します。

=> @new = false
=> type.old?
true
=> type.new?
false
=> type.testvalue?
false

=> @new = true
=> type.new?
true
=> type.old?
false

method_missing

method_missing ここの本当の秘密のソースです。 Rubyでは、オブジェクトのメソッドを呼び出すたびに、Rubyは、メソッドのオブジェクトのすべての祖先(つまり、基本クラスまたは含まれているモジュール)を調べることから始めます。見つからない場合、Rubyはmethod_missingを呼び出します 、探しているメソッドの名前と引数を渡します。

デフォルトでは、このメソッドは例外を発生させるだけです。私たちはおそらく、NoMethodError: undefined method 'test' for nil:NilClassに精通しているでしょう。 エラーメッセージの種類。独自のmethod_missingを実装できます これは例外を発生させません。これはまさにStringInquirerです。 する:

def method_missing(method_name, *arguments)
  if method_name.end_with?("?")
    self == method_name[0..-2]
  else
    super
  end
end

任意の場合 ?で終わるメソッド名 、selfの値を確認します (つまり、文字列)?のないメソッド名に対して 。言い換えると、StringInquirer.new("test").long_test_method_name?を呼び出す場合 、戻り値は"test" == "long_test_method_name"です。 。

メソッド名がない場合 疑問符で終わると、元のmethod_missingにフォールバックします (例外を発生させるもの)

Respond_to_missing?

ファイルにはもう1つのメソッドがあります:respond_to_missing? 。これはmethod_missingのコンパニオンメソッドであると言えます。 。 method_missing 機能を提供します。また、これらの疑問符の終了方法を受け入れることをRubyに通知する方法も必要です。

def respond_to_missing?(method_name, include_private = false)
  method_name.end_with?("?") || super
end

これは、respond_to?を呼び出すと機能します。 このオブジェクトに。これがないと、StringInquirer.new("test").respond_to?(:test?)を呼び出した場合 、結果はfalseになります test?という明示的なメソッドがないためです。 。 Rails.env.respond_to?(:test?)を呼び出すとtrueが返されると予想されるため、これは明らかに誤解を招く恐れがあります。 。

respond_to_missing? これが、Rubyに「はい、そのメソッドを処理できます」と言える理由です。メソッド名が疑問符で終わっていない場合は、スーパークラスメソッドにフォールバックします。

実用的なユースケース

方法がわかったので StringInquirerは機能します。それが役立つ可能性のあるインスタンスを見てみましょう:

1。環境変数

環境変数は、StringInquirerに最適な2つの基準を満たしています。まず、多くの場合、可能な値の限られた既知のセット(enumなど)があります。 )、そして次に、それらの値に依存する条件付きロジックがあることがよくあります。

アプリが支払いAPIに接続されており、環境変数にクレデンシャルが保存されているとします。本番システムでは、これは明らかに実際のAPIですが、ステージングバージョンまたは開発バージョンでは、サンドボックスAPIを使用します。

# ENV["PAYMENT_API_MODE"] = sandbox/production

class PaymentGateway
  def api_mode
    # We use ENV.fetch because we want to raise if the value is missing
    @api_mode ||= ENV.fetch("PAYMENT_API_MODE").inquiry
  end

  def api_url
    # Pro-tip: We *only* use production if MODE == 'production', and default
    # to sandbox if the value is anything else, this prevents us using production
    # values if the value is mistyped or incorrect
    if api_mode.production?
      PRODUCTION_URL
    else
      SANDBOX_URL
    end
  end
end

上記では、ActiveSupportのString#inquiryを使用していることに注意してください 文字列をStringInquirerに簡単に変換するメソッド。

2。 APIレスポンス

上記の支払いAPIの例を続けると、APIは成功/失敗の状態を含む応答を送信します。繰り返しになりますが、これはStringInquirerの候補となる2つの基準を満たしています。可能な値の限定されたセットと、これらの値をテストする条件付きロジックです。

class PaymentGateway
  def create_charge
    response = JSON.parse(api_call(...))

    result = response["result"].inquiry

    if result.success?
      ...
    else
      ...
    end

    # result still acts like a string
    Rails.logger.info("Payment result was: #{result}")
  end
end
結論

StringInquirerはあなたの後ろポケットに入れるのに面白いツールですが、個人的にはあまり頻繁に手を伸ばすことはありません。いくつかの用途がありますが、ほとんどの場合、オブジェクトの明示的なメソッドは同じ結果をもたらします。明示的に名前が付けられたメソッドにもいくつかの利点があります。値を変更する必要がある場合は、1つの場所を更新するだけで済みます。および 開発者がメソッドを見つけようとしている場合、コードベースを簡単に検索できます。

StringInquirerに焦点を当てていますが、この記事は、method_missingを使用したRubyのメタプログラミング機能のいくつかをより穏やかに紹介することを目的としています。 。おそらくmethod_missingは使いたくないと思います アプリケーションで。ただし、Railsやgemが提供するドメイン固有言語などのフレームワークでよく使用されるため、問題が発生したときに「ソーセージがどのように作られるか」を知ることは非常に役立ちます。


  1. Google Play ストアの 2022 年ベスト ヒドゥン ジェムズ

    Google Play ストアには、ゲーム、ソーシャル アプリ、最適化、バッテリー セーバー アプリなど、各カテゴリに数百万のアプリがあります。他のアプリほど人気が​​ないアプリは他にもたくさんありますが、それらは仕事を成し遂げるのに本当に役立ち、頻繁に使用するのが大好きです.隔年と同様に、Google Play ストアは 2022 年に隠れた宝石カテゴリでチャートを突破したアプリをリストしました。 そこで今日は、2022 年の最高の隠れた宝石カテゴリで、受賞歴のある Android アプリのトップ 5 を共有します。 ソクラティック – 数学の答えと宿題のヘルプ Socratic は

  2. 知っておくべきWindows 11のヒントと隠された宝石

    Windows 11 は、互換性のあるデバイスの無料アップグレードとして利用でき、多くの新機能と改善が含まれています。新しく再設計されたスタート メニュー タスクバー、Andriod アプリをサポートする改良された Microsoft ストア、統合された Microsoft チーム、スナップ レイアウト、ウィジェットなどがあります。しかし、レドモンドの巨人によって公式に発表された大きなニュースと機能に加えて、Windows 11 には多くの小さな変更が含まれており、一見すると明らかではないかもしれません。この投稿では、Windows 11 の非表示の機能をいくつか紹介しました。 について知って