自我= Ruby中的后代?

时间:2009-11-10 17:09:32

标签: ruby class-design self

我有来自游戏的文本日志(例如)两种类型的条目即。聊天和活动。在大多数情况下,它们非常相似,因此我定义了一个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本质上返回适当类的解析条目。在这种情况下,解析的条目是重要的一点。但我们可以将实例方法'解析'重命名为'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。有谁知道我应该如何实现这个目标?

修改 我已经改变了我的例子,因为许多答案都集中在许多条目的迭代上。查克的回答优雅地表明这种情况不是问题。

如果这引起了任何人的兴趣,我偶然发现Evil Ruby让你干涉'self.class'。关于它的一篇很好的Orielly文章称为Ruby code that will swallow your soul!我正在研究它是否能提供任何答案。 (编辑:evil.rb名字很好!低级别的东西似乎'不适合稳定/长期分发。)

4 个答案:

答案 0 :(得分:2)

我认为根本问题在于each是错误的方法。要么parse更改对象的内部状态而不是对象本身,要么使用map!用新版本替换集合中的对象。

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

将更新数组中的对象,并在其上调用parse,因此没有理由在self方法中对parse进行奇怪的处理。

答案 1 :(得分:2)

如果你可以将功能划分到不同的模块中,你可以随意 mutate 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()声明,但您明白了。

答案 2 :(得分: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 =&gt; LogEntry)

然后创建一个名为log的方法,这是一个明确处理聊天相关项目的解析器。

答案 3 :(得分:0)

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

self.replace(LogEntry.parse(self))