2012-07-10 4 views
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는 루비보고 라이브러리입니다. 당신은 테이블 형식의 데이터를 생성하기 위해하는 Ruport :: 데이터 :: 표 클래스를 사용하는 예를 들어, 다른 형식으로 텍스트로 변환 할 수 있습니다 :의 당신은 프랑스 와인을 선택한다고 가정 해 봅시다과로 변환

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 클래스는 위에 정의 된대로 다소 있습니다. argu- , 표준으로 열 이름을 취합니다 (국가),

호출 rows_with_country하는()는 전통적인 보이는 방법, rows_with에 호출된다. 또한 to_csv()에 대한 호출은 as (: csv)에 대한 호출이됩니다. 메서드 이 두 접두사 중 하나로 시작하지 않으면 Ruport는 NoMethodError를 throw하는 커널 # method_missing()에 을 반환합니다. (즉, 슈퍼 키워드가 무엇인지입니다.)

+0

짧은 답변 : 첫 번째 일치 그룹을 가져 와서 기호 (이 경우 'rows_with_'또는 'to_'후행 값)로 변환하고 메서드 매개 변수로 전달하거나 해시 키로 사용합니다 첫 번째 인수는 method_missing입니다. –

답변

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은 블록이있는 경우 Proc이거나 nil이됩니다.

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

실행은 정말 if에서, 끝에서 시작합니다 : 그것은이 기본적으로 호출 방법의 문자열을 정규 표현식의 일치를 수행 조건을

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

를 확인합니다. x =~ y은 에있는 정수 오프셋을 반환합니다. 여기서 y이 일치하면 어디든지 그렇지 않으면 nil입니다. 예컨대 :

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

0 부울 조건에서 진리로 처리됩니다, 그래서 if 만 호출 된 함수의 이름이 to_로 시작하면 사실로 간주됩니다 것을 기억하십시오. 나머지 메서드 이름은 (.*)에 의해 캡처됩니다.

이제 캡쳐 그룹을 명시 적으로 저장하지 않지만 Ruby는 Perl에서 빌려 오면 첫 번째 캡처 그룹의 내용이 $1에 저장되고 두 번째 캡처 그룹의 내용은 $2에 저장됩니다.:

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

이제, 문제의 라인에 : 호출 된 메소드의 이름은 형태 to_XYZ의 경우

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

그래서, 그것은 :XYZ로 설정 첫 번째 인수로 as() 메소드를 호출, 호출의 나머지 인수가 추가되고 블록이 통과합니다 (있는 경우).

계속하려면

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

이 기본적으로 동일 : 메소드 이름이 rows_with_ABC 같은 경우, 다음이 args[0] 누락 된 메소드 호출에 주어진 첫 번째 인수 인 해시 {:ABC => args[0]}rows_with()를 호출 .

+0

해시 {: ABC => args [0]}의 사용법은 무엇입니까? – shailesh

+1

@shaileish : 그것은 단지 해시이며, args [0]에 매핑되는 ': ABC'의 단일 키 - 값 매핑을 사용합니다. 즉, 예제에 따라'table.rows_with_country ("France")'를 호출하면,'table.rows_with ({: country => "France"})'에 대한 호출로'method_missing'에 의해 변환됩니다. – Ashe