1

ゲームのテキストログがあり、(たとえば)2種類のエントリがあります。チャットとイベント。ほとんどの場合、それらは非常に似ているので、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。誰かが私がこれを達成するためにどのように行くべきか知っていますか?

編集: 多くの回答が多くのエントリの反復に焦点を合わせていたため、例を変更しました。チャックの答えは、この状況が問題ではないことをエレガントに示しています。

これが誰かの興味をそそる場合に備えて、私はあなたが`self.class'に干渉しようとするEvilRubyに出くわしました。あなたの魂を飲み込むRubyコードと呼ばれるそれについての素晴らしいOriellyの記事があります! 私はそれが何か答えを提供するかどうかを調べるためにそれを調べています。(編集:evil.rbはよく名付けられています!低レベルでは安定した/長期的な配布には適していないようです。)

4

4 に答える 4

2

each根本的な問題は、ここでは間違った方法だと思います。parseオブジェクト自体ではなくオブジェクトの内部状態を変更するかmap!、コレクション内のオブジェクトを新しいバージョンに置き換えるために使用します。

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

配列内のオブジェクトを呼び出した結果で更新するため、メソッドでparse奇妙なことをする理由はありません。selfparse

于 2009-11-10T17:50:15.693 に答える
2

機能をさまざまなモジュールに分割できる場合は、必要に応じて変更できextend() selfます。

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

caseもちろん、を繰り返し呼び出すことで不格好なステートメントを実行する必要はありませんがself.extend()、アイデアは得られます。

于 2009-11-10T20:48:20.007 に答える
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(:log => LogEntry)

次に、チャット関連のアイテムを明示的に処理するパーサーであるlogというメソッドを作成します。

于 2009-11-10T17:40:41.080 に答える
0

ここで文字列/配列/LogEntryの混乱がありますが、それがうまくいったと仮定すると、最後に、配列サブクラスがそれ自体のコンテンツを置き換えたい場合は、次を使用する必要がありますreplace

self.replace(LogEntry.parse(self))
于 2009-11-10T17:46:51.963 に答える