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 代码,它会吞噬你的灵魂! 我正在调查它,看看它是否提供任何答案。(编辑: 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 一部分的数据,并且您希望条目能够自行解析,因此无需传入任何参数。只需保持 parse 方法无参数即可。

如果您知道某事是什么类型的日志,则可以跳过一个步骤并在进入的过程中对其进行解析。 chat_entry = LogChat.new(:log => LogEntry)

然后创建一个名为 log 的方法,它是您的解析器,可以显式处理与聊天相关的项目。

于 2009-11-10T17:40:41.080 回答
0

您在这里遇到了一些字符串/数组/LogEntry 混淆,但假设您解决了这个问题,并且最后您仍然希望有一个 Array 子类替换它自己的内容,您需要使用replace

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