1

次のコード行で何をし$1.to_sym => args[0]、何をしますか?($1.to_sym,*args,&block)

class Table
  def method_missing(id,*args,&block)
    return as($1.to_sym,*args,&block) if id.to_s =~ /^to_(.*)/
    return rows_with($1.to_sym => args[0]) if id.to_s =~ /^rows_with_(.*)/
    super
  end
  # ...
end

コンテキスト:
RuportはRubyレポートライブラリです。Ruport :: Data :: Tableクラスを使用して、表形式のデータを作成し、それをさまざまな形式(テキストなど)に変換できます。

require 'ruport'  
table = Ruport::Data::Table.new :column_names => ["country" , "wine" ], :data => [["France" , "Bordeaux" ], ["Italy" , "Chianti" ], ["France" , "Chablis" ]]  
puts table.to_text

⇒    
+--------------------+
| country |   wine   |
+--------------------+
| France | Bordeaux |
| Italy  | Chianti |
| France | Chablis |
+--------------------+

フランスワインのみを選択し、それらをコンマ区切りの値に変換するとします。

found = table.rows_with_country("France" )
found.each do |row|
  puts row.to_csv
end

⇒
France, Bordeaux
France, Chablis

今行ったことは、Ruport :: Data :: Tableでrows_with_country()という名前のメソッドを呼び出すことです。しかし、このクラスの作成者は、countryという名前の列が作成されることをどのようにして知ることができますか?実は、作者はそれを知りませんでした。Ruportの内部を見ると、rows_with_country()とto_csv()の両方がゴーストメソッドであることがわかります。Ruport :: Data::Tableクラスは上記で定義されたとおりです。

rows_with_country()の呼び出しは、より伝統的な方法であるrows_with(:country)の呼び出しになります。このメソッドは、列名を引数として取ります。また、to_csv()の呼び出しはas(:csv)の呼び出しになります。メソッド名がこれらの2つのプレフィックスのいずれでも始まらない場合、RuportはKernel#method_missing()にフォールバックし、NoMethodErrorをスローします。(それがスーパーキーワードの目的です。)

4

1 に答える 1

2

見てみましょうmethod_missing

def method_missing(id,*args,&block)
  return as($1.to_sym,*args,&block) if id.to_s =~ /^to_(.*)/
  return rows_with($1.to_sym => args[0]) if id.to_s =~ /^rows_with_(.*)/
  super
end

必要な背景:method_missing要求されたメソッドが明示的に定義されていない場合に、オブジェクトに対して呼び出されます。id呼び出されるメソッドのシンボルになります。args引数の配列になり、ブロックがあった場合は、、またはにblockなります。Procnil

  return as($1.to_sym,*args,&block) if id.to_s =~ /^to_(.*)/

実行は実際には最後から始まりますif:それは条件をチェックします

id.to_s =~ /to_(.*)/

これは基本的に、呼び出されたメソッドの文字列に対する正規表現の一致を行います。一致する場所x =~ yの整数オフセットを返します。一致する場合は、それ以外の場合はnilを返します。例えば:xy

> "abc" =~ /a/
 => 0
> "abc" =~ /.$/
 => 2
> "abc" =~ /\d/
 => nil

これはブール条件で0は真として扱われるためif、呼び出された関数の名前が。で始まる場合にのみ、が真であると見なされることに注意してto_ください。メソッド名の残りの部分は、によってキャプチャされ(.*)ます。

ここでは、キャプチャグループを明示的に保存しませんが、RubyはPerlから借用しており、最初のキャプチャグループのコンテンツはに保存され$1、2番目はに保存されます$2

> "abc" =~ /a(.)(.)/
 => 0
> $1
 => "b"
> $2
 => "c"

ここで、問題の行に戻ります。

  return as($1.to_sym,*args,&block) if id.to_s =~ /^to_(.*)/

したがって、呼び出されたメソッドの名前がの形式の場合to_XYZas()最初の引数がに設定されたメソッド:XYZが呼び出され、呼び出しの残りの引数が追加され、ブロックが渡されます(存在する場合)。

続行するには:

  return rows_with($1.to_sym => args[0]) if id.to_s =~ /^rows_with_(.*)/

これは基本的に同じです。メソッド名がのような場合、ハッシュを使用しrows_with_ABCて呼び出します。ここで、は欠落しているメソッド呼び出しに指定された最初の引数です。rows_with(){:ABC => args[0]}args[0]

于 2012-07-10T12:06:00.383 に答える