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( ) 都是 Ghost 方法。Ruport::Data::Table 类有点像上面的定义。

对 rows_with_country( ) 的调用变成了对看起来更传统的方法 rows_with(:country) 的调用,它以列名作为参数。此外,对 to_csv( ) 的调用变成了对 as(:csv) 的调用。如果方法名不是以这两个前缀中的任何一个开头,Ruport 就会退回到 Kernel#method_missing(),这会抛出 NoMethodError。(这就是 super 关键字的用途。)

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将是a ,或者.Procnil

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

执行真正从最后开始,在if: 它检查条件

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

这基本上是在被调用方法的字符串上匹配正则表达式。如果在任何地方,则x =~ y返回匹配位置的整数偏移量,否则为零。例如:xy

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

请记住,0在布尔条件下它被视为真值,因此if只有被调用函数的名称以 . 开头时才会被认为是真值to_。方法名称的其余部分由(.*).

现在,我们没有显式保存捕获组,但是 Ruby 从 Perl 中借用了第一个捕获组的内容将保存在 中$1,第二个保存在 中$2,依此类推:

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

现在,回到有问题的行:

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

因此,如果被调用方法的名称为 形式to_XYZ,它调用as()方法时将第一个参数设置为:XYZ,并附加来自调用的其余参数,并通过该块(如果有)。

继续:

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

这基本上是一样的:如果方法名是 like rows_with_ABC,那么它rows_with()使用一个 hash进行调用{:ABC => args[0]},其中args[0]是给缺失方法调用的第一个参数。

于 2012-07-10T12:06:00.383 回答