2010-03-20 9 views
3

다른 것들 중에서도, 그것을 혼합하는 클래스에 일반적인 'finder'타입의 기능을 추가 할 모듈을 만들고 있습니다. 문제 : 편의성과 미학을 이유로 외부에 기능을 클래스 자체와 동일한 범위에 포함하고자합니다. 예를 들어모듈 내에서 클래스의 포함하는 네임 스페이스에 액세스하기

: 나는 이러한 방법, 아무 문제 내에서 기능 을 할 수

class User include MyMagicMixin end # Should automagically enable: User.name('Bob') # Returns first user named Bob Users.name('Bob') # Returns ALL users named Bob User(5) # Returns the user with an ID of 5 Users # Returns all users 

. 케이스 1 (User.name('Bob'))은 쉽습니다. 그러나 케이스 2-4는 User 외부에 새로운 클래스와 메소드를 생성 할 수 있어야합니다. Module.included 메서드를 사용하면 클래스에 액세스 할 수 있지만 포함하는 범위에는 액세스 할 수 없습니다. Class 나 Module에서 볼 수있는 간단한 "부모"유형 메서드는 없습니다. (네임 스페이스의 경우 내 말은 슈퍼 클래스도 중첩 모듈이 아니더라도)

가장 좋은 방법은 클래스의 #name에있는 일부 문자열 구문 분석을 사용하여 네임 스페이스를 제거한 다음 해당 문자열을 다시 일정한. 하지만 그건 루머스럽고 루비라는 점을 감안할 때 좀 더 우아한 방법이 있어야한다고 생각합니다.

아이디어가 있습니까? 아니면 나는 단지 내 자신의 이익을 위해 너무 똑똑한가?

+1

** 업데이트 : ** J (Jörg, James and Jrallison)의 의견을 바탕으로 나는이 사실을 나쁜 생각으로 결정했으며 내 의미를 다른 방식으로 달성하려고합니다. 원한다면 답변하고 댓글을 달아주세요.하지만 지금은 지적 운동입니다. 필요한 것이 아닙니다. 여러분 모두에게 감사드립니다. – SFEley

답변

1

예에서 UserClass 개체를 가리키는 상수입니다. MyMagicMixin가 포함 된 경우 당신은 쉽게 다른 상수 포인터를 만들 수 있습니다

module MyMagicMixin 
    class <<self 
    def self.included(klass) 
     base.extend MyMagicMixin::ClassMethods 
     create_pluralized_alias(klass) 
    end 

    private 

    def create_pluralized_alias(klass) 
     fq_name = klass.to_s 
     class_name = fq_name.demodulize 
     including_module = fq_name.sub(Regexp.new("::#{class_name}$", '')) 
     including_module = including_module.blank? ? Object : including_module.constantize 
     including_module.const_set class_name.pluralize, klass 
    end 
    end 

    module ClassMethods 
    # cass methods here 
    end 
end 

물론 이것은 당신이 그런 일을 할 것인지 여부에 응답하지 않습니다.

+0

고마워요! 물론 당신 말이 맞습니다. 당신의 대답은 옳았습니다. 그러나 그것은 제가보기에 "와우, 일종의 추한 것"이라고 생각하는 것과 같은 것입니다. 루비 코드가 추악하게 변할 때 나는 올바른 길을 가고 있는지 여부를 멈추고 다시 생각하려고 노력합니다. 이 경우에는 다른 접근법을 택할 것입니다. 여러분 모두에게 감사드립니다. – SFEley

3

나는 너무 똑똑한쪽으로 기댈 것입니다. 우아한 용액이 된 경우에도

, 그것은 내부 모듈 외부 클래스 클래스를 생성하는 클래스를 포함 할 오히려 홀수 보인다.

+0

Nitpick : 사실, 클래스 밖에서 * 메소드 *를 만들지 만 동의합니다. –

+0

실제로는 _and_ 클래스의 클래스입니다. 가치가있는 것을 위해, 나도 동의한다. 하지만이 API에 대한 아이디어가 마음에 들었습니다. 다른 API (클래스 팩토리)를 달성하기 위해 다른 방법을 생각할 때도 마술 적이거나 Rubyish가 적었습니다. 위와 같이 보일지도 모르지만, 나는 적극적으로 마술을 의심하고 있으며, 일어날 때 그것을 한 곳으로 한정하고 싶습니다. – SFEley

+0

ActiveRecord API와 비슷한 점이 있습니까? User.find (: name => "Bob"), User.find (5), User.all? 덜 마법처럼 보이고 IMO는 더 의미가 있습니다. – jrallison

2

메일 링리스트에 때로는 문제가 발생합니다. Rails에서도 문제가 발생합니다. 당신이 이미 의심했듯이, 해결책은 기본적으로 Regexp munging입니다.

그러나 근본적인 문제가 있습니다. 루비에서는 클래스에 이름이 없습니다! 클래스는 다른 것과 마찬가지로 단지 객체입니다. 이를 인스턴스 변수, 지역 변수, 전역 변수, 상수에 할당하거나 심지어 에 할당하지 않을 수도 있습니다. Module#name 메서드는 기본적으로 다음과 같이 작동하는 편리한 메서드입니다. 수신기를 가리키는 상수가 발견 될 때까지 정의 된 상수 목록을 살펴 봅니다. 하나를 찾으면 찾을 수있는 첫 번째 값을 반환하고 그렇지 않으면 nil을 반환합니다. 클래스는 클래스가 하나 이상의 이름을 가질 수있는 모든

  • 에 이름을 가질 수 있지만 Module#name는 첫 번째를 반환합니다

    a = Class.new 
    a.name # => nil 
    B = a 
    B.name # => "B" 
    A = B 
    A.name # => "B" 
    
    • :

      그래서, 여기에이 개 고장 모드가있다 누군가가 A의 목록을 가져올 수 As를 호출하려고하면 그것은 그들이 그 방법은 전자를하지 않는 것을 발견 꽤 놀라게 될 것입니다, 지금

    발견 xist,하지만 그들은 대신 Bs을 호출하여 동일한 결과를 얻을 수 있습니다.

    이 실제로 실제로 발생합니다.MacRuby에서 예를 들어 String.nameNSMutableString이면 Hash.nameNSMutableDictionary이고 Object.nameNSObject을 반환합니다. 그 이유는 MacRuby가 Ruby 런타임과 Objective-C 런타임을 하나로 통합하기 때문이며 Objective-C 변경 가능 문자열의 의미가 Ruby 문자열과 동일하기 때문에 Ruby의 문자열 클래스 전체 구현은 본질적으로 단일 행입니다 : String = NSMutableString. 그리고 MacRuby가 Objective-C의 맨 위에 있기 때문에 Objective-C가 먼저 시작된다는 것을 의미합니다. 즉, NSMutableString이 먼저 심볼 테이블에 삽입되는 것을 의미합니다. 즉, 으로 시작되고 Module#name이 먼저 나타납니다.

  • +0

    감사합니다, Jörg, 직접적인 방법이 없음을 확인했습니다. 실패 모드는 너무 걱정하지 않습니다. 우선 우리는 클래스가 존재한다는 것을 거의 항상 압니다. 모듈이 섞여 있기 때문에 이름이 있습니다. (이 사용 사례는 익명 클래스로 혼합하는 것이 드물고 무의미 할 수도 있습니다.) 또 다른 경우에는 마법을 피하기위한 명시적인 선언 방법도 있습니다. 어쨌든, 좋은 점. 그리고 감사합니다. – SFEley

    관련 문제