2009-09-30 2 views
0

File.dirname 메서드를 먼저 재정 의하여 % 20s를 공백으로 변경하려고합니다. 클래스 '파일'에 대한 'dirname은'File :: dirname ruby ​​메서드를 다시 정의하십시오.

이 작업을 수행하는 올바른 방법은 무엇입니까 정의되지 않은 메서드 :하지만 다음 날이가 나가서 설명하자면 NameError 예외를 trhows

class File 
    old_dirname = instance_method(:dirname)  

    define_method(:dirname) { |s| 
     s = s.gsub("%20"," ") 
     old_dirname.bind(self).call(s) 
    } 
end 

오류 준다?

답변

4

척이 이미 썼던 것처럼, File::dirnameFile 클래스 객체 (또는 File 클래스 개체의 메타 클래스의 더 정확하게 인스턴스 메서드)의 싱글 방식이 아닌 File 클래스의 인스턴스 방법입니다.

#!/usr/bin/env ruby 

class << File 
    old_dirname = instance_method :dirname 

    define_method :dirname do |*args| 
    old_dirname.bind(self).(*args).gsub '%20', ' ' 
    end 
end 

require 'test/unit' 
class TestFileDirname < Test::Unit::TestCase 
    def test_that_it_converts_percent20_to_space 
    assert_equal '/foo bar/baz', File.dirname('/foo%20bar/baz/quux.txt') 
    end 
end 

는 그러나, 나는 @sheldonh에 동의 :이 File::dirname의 API 계약을 나누기

그래서, 당신은하지 File 클래스 자체, File의 메타 클래스를 열어야합니다.

1

dirname은 인스턴스 메소드가 아닌 파일의 클래스 메소드이므로 새로운 인스턴스 메소드를 정의하는 것입니다. 또한 메소드의 별명을 지정하는 관용적 인 방법은 alias입니다. 그래서 :

class <<File 
    alias old_dirname dirname 
    def dirname(f) 
    old_dirname(f.gsub("%20", " ")) 
    end 
end 

class <<whatever 구문은 개별 객체에 메소드를 추가 -이 경우, File 클래스에서.

+0

감사합니다. – jrhicks

+2

이것은 그의 질문에 게시 된 @jrhicks 코드와 동일하지 않습니다 *! 이 코드는 잔여'File :: old_dirname' 메쏘드로'File' 메타 클래스의 네임 스페이스를 오염시키는 반면, 문제의 원래 코드는이 문제를 피하기 위해 각별한주의를 기울입니다. –

+0

범위에 대한 논의는 완전히 정확합니다.하지만 Jörg는 맞습니다. 'alias_method'는 "관용적"일 수 있지만 OP의 원래 방법보다 안전하지 않습니다. –

3

주의하십시오.

메소드의 구현이 아니라 메소드의 동작이 변경됩니다. 이는 일반적으로 신뢰할 수없는 계약으로 API의 가치를 약화시키기 때문에 좋지 않습니다.

대신 입력을 수신 지점에 가깝게 변환하는 것을 고려하십시오.

관련 문제