2009-11-10 6 views
1

게임과 같은 텍스트 로그가 있습니다. 예를 들어 두 가지 유형의 항목이 있습니다. 채팅 및 이벤트. 대부분의 경우 매우 유사하므로 LogEntry 클래스를 정의했습니다.자기 = 루비의 자손?

class LogEntry < Array 
    def initialize(str) 
    super str.split 
    end 

    def parse 
    LogEntry.parse self 
    end 

    def LogEntry.parse(entry) 
    # Processes the elements that are in any Entry 
    # Figure out whether it's a Chat entry or an Event entry 
    # Returns an object of type LogChat or LogEvent 
    end 
end 

LogChat 및 LogEvent는 모두 LogEntry를 확장하고 해당 도메인과 관련된 추가 처리를 수행합니다. 모든 것이 예상대로 작동합니다.

chat = LogEntry.new("some chat") 
event = LogEntry.new("some event") 

chat.parse.class # => LogChat 
event.parse.class # => LogEvent 

질문 : 클래스 메소드는 본질적으로 LogEntry.parse 해당 클래스의 구문 분석 항목을 반환합니다. 이 문맥에서, 파싱 된 엔트리는 중요한 비트이다. 하지만 인스턴스 메소드 'parse'의 이름을 'what_type_should_i_be?'로 바꿀 수 있습니다. 객체가 그 정보에 따라 행동하기를 원합니다. 'self.become LogEntry.parse (self)'

바로 지금 엔트리를 파싱하려면이 작업을 수행해야합니다.

entry = entry.parse 

나는이 결과를 얻기 위해 더 밀어주고 싶다.

entry.parse 

나는 분명했습니다.

class LogEntry 
    def parse 
    self = LogEntry.parse(self) 
    end 
end 

그러나 오류 Can't change the value of self가 표시됩니다. 아무도 내가 이것을 달성하는 방법에 대해 알아야합니까?

편집 : 많은 답변이 많은 항목에 걸쳐 반복에 초점을 맞추기 때문에 예제를 변경했습니다. Chuck의 대답은이 상황이 문제가 아니라는 것을 우아하게 보여줍니다.

이렇게하면 누군가의 관심을 불러 일으키고, 나는 Evil Ruby을 우연히 만났고, 그것은`self.class '로 간섭했다. 그것에 대해 좋은 Orielly 기사는 Ruby code that will swallow your soul!라고합니다. 나는 그것이 어떤 대답을 제시하는지 알아보기 위해 조사 중입니다. (편집 : evil.rb는 잘 명명 된 것입니다. 저수준이 안정적/장기적 분포에 적합하지 않은 것처럼 보입니다.)

답변

2

근본적인 문제는 each이 잘못된 방법이라고 생각합니다. parse을 사용하여 개체 자체가 아닌 개체의 내부 상태를 변경하거나 map!을 사용하여 컬렉션의 개체를 새 버전으로 바꿉니다.

entries.map! {|entry| entry.parse} 

는 그들에 parse를 호출 한 결과와 배열의 개체를 업데이트 할 것이다, 그래서 parse 방법 self에 이상한 물건을 할 이유가 없습니다. 서로 다른 모듈로 기능을 깰 수 있다면

+0

+1 재미있는 사고 방식을 시작합니다. 나는 이것을'parse' 메쏘드 안에서 구현할 수 있는지를 알 것입니다. 나는 그 물건을 보면서 "실제로, 나는 그런 종류의 물건에 관한 것"이라고 말하고 싶다. – deau

+0

내가 너 자신에게 이상한 일을하고 있다고 생각하니? 이론적으로 말해서, 이런 식으로 자신을 통제하는 물체를 갖는 것은 위험할까요? – deau

+1

글쎄, 기술적으로 "self"를 설정하는 것이 불가능합니다. 이것은 실제로 "저조한 물건을 자기에게하는 것"이라는 의미입니다. 객체는 자신의 ID를 변경할 수 없습니다 (메소드에'self '를 설정할 수 있더라도 메소드 외부에서 객체의 ID를 변경하지 않습니다 - 변수는 참조 만 사용합니다). 객체는 내부 상태 만 제어 할 수 있습니다. 그래서 내가 그런 식으로 바꿀 수있는 것을 나타내는 것이 좋습니다. – Chuck

0

처음에는 LogEntry.parse가 LogChat 또는 LogEvent 객체를 반환한다고 말합니다. 그래서 당신은 객체가 다른 유형의 객체로 변경되도록 요구하고 있습니다. 또한 클래스 메소드와 인스턴스 메소드처럼 보이는

는 조금 내가 조금 추측하고 혼란되고있다 그런데 왜 당신은 할 수 없었 :

entries.each do |entry| 
    some_type_log = entry.parse 
    some_type_of_log.save! 
end 

편집이 : 죄송합니다, 무엇인가를 명확히하고 싶었다. LogEntry의 일부인 데이터를 파싱하고 항목 자체가 구문 분석되기를 원하기 때문에 매개 변수를 전달할 필요가 없습니다. 구문 분석 방법을 매개 변수가없는 상태로 유지하십시오. 당신이 로그 무언가의 유형을 알고있는 경우

, 당신은 단계를 건너 뛰고에서 길을 구문 분석 할 수 chat_entry = LogChat.new. (=> LogEntry 로그)

다음 방법이라는 기록을 이는 채팅 관련 항목을 명시 적으로 처리하는 파서입니다.

+0

시간 내 주셔서 감사합니다.하지만 인스턴스/클래스 메서드를 혼동하지 않습니다. 클래스 메소드'LogEntry.parse'는 점점 더 구체적인'EntryType.parse' 메소드를 따라 캐스케이드를 발생시킵니다. 결과는 완전히 파싱되고 분류 된 (클래스 별) 입력 개체입니다. 인스턴스 메소드 parse는 LogEntry의 클래스 메소드를 호출하여 새 계단식을 트리거하므로 이미 구문 분석 된 항목을 다시 계산할 수 있습니다. 귀하의 솔루션은 괜찮습니다. 이미 가지고있는 것과 비슷합니다. (질문 참조) – deau

0

당신은 여기에 몇 가지 문자열/배열/LogEntry 혼란을 가지고 있지만, 당신이 밖으로 일을 간다면, 당신은 여전히 ​​자신의 내용을 대체 배열의 서브 클래스를 갖고 싶어 끝에, 당신은 replace를 사용해야했습니다

self.replace(LogEntry.parse(self)) 
+0

슬프게도 교체하면 배열의 내용 만 복사됩니다. LogEntry의 서브 클래스는 대체 할 수없는 인스턴스 변수 (및 of course of!)를 가지고 있습니다. – deau

2

, 당신은 당신이 좋아 extend()self을 변이 할 수 있습니다 : 당신은 self.extend()에 호출을 반복와 투박한 case 문을 수행 할 필요가 없습니다

class LogEntry 
    ... 
    def parse!  # This mutates self! 
    case LogEntry.parse! 
    when :chat 
     self.extend MyApp::LogChat 
    when :event 
     self.extend MyApp::LogEvent 
    else 
     raise MyApp::Exception, "waaah" 
    end 
    end 
end 

, 당연히, 그러나 당신은 아이디어를 얻는다.

+0

맞아. 'self.class' 대신'self. @ type'을 사용하여 모든 것을 시뮬레이션 할 수 있습니다. Mixins은 관련 기능과 인스턴스 변수를 추가 할 수 있습니다. 나는 그것에 대해 좀 더 생각할 필요가있을 것이다. – deau