【问题标题】:I have a conundrum involving blocks and passing them around, need help solving it我有一个涉及块并将它们传递的难题,需要帮助解决它
【发布时间】:2017-03-05 18:41:19
【问题描述】:

好的,所以我已经构建了一个 DSL,其中一部分需要 DSL 的用户定义我所谓的“编写器块”

  writer do |data_block|
    CSV.open("data.csv", "wb") do |csv|
      headers_written = false
      data_block do |hash|
        (csv << headers_written && headers_written = true) unless headers_written
        csv << hash.values
      end
    end
  end

编写器块被这样调用:

  def pull_and_store
    raise "No writer detected" unless @writer
    @writer.call( -> (&block) {
      pull(pull_initial,&block)
    })
  end

问题有两个方面,首先,这是处理这种事情的最佳方法,其次我遇到了一个奇怪的错误:

undefined method data_block' for Servo_City:Class (NoMethodError)

这很奇怪,因为我可以在那里看到data_block,或者至少它至少存在于CSV 块之前。

我正在尝试创建的是一种让用户编写包装块的方法,该包装块既可以环绕一个块,又可以为被包装的块生成一个块,哇,真是一口。

【问题讨论】:

  • 嗯,我不太明白你想要完成什么。有多种可能的失败原因,其中一些可能在您未显示的代码中。只是一个有根据的猜测:您调用 writer 的块接受一个块 data_block 反过来又接受一个块。对于 DSL 来说似乎非常复杂。尝试像这样取消引用它:writer do |&amp;data_block|,然后使用data_block.call do |hash| 调用它。我没有看到hash 被传入的位置。(pull 会这样做吗?)你为什么不首先像writer do |data_block, hash| 那样将它传递给 writer 块?
  • 这就是我问的原因,它有点复杂。 pull 接收一个块并为其生成一个哈希值;因此@writter.call 需要一个块,该块是传递给data_block 的块。我这样做的原因是我能想到的唯一方法是让我将pull 方法包装在CSV 块内。否则我必须创建一个 csv 对象,将散列附加到 csv 文件,然后为每个产生的散列关闭它。我觉得我过于复杂了,我可以传递一个 IO 对象或其他东西并使用它吗?

标签: ruby ruby-block


【解决方案1】:

内心深处不想在问题得到澄清之前写下答案。
其他人认为代码示例将有助于澄清问题。 p>


我假设 writer 块的任务是保存一些数据。你能以可枚举的形式将数据传递到块中吗?这将允许 DSL 用户编写如下内容:

writer do |data|
  CSV.open("data.csv", "wb") do |csv|
    csv << header_row
    data.each do |hash|
      data_row = hash.values
      csv << data_row
    end
  end
end

不需要块传递。

请注意,如果处理庞大的数据集,您可以传入 lazy 集合。

这能解决您的问题吗?

【讨论】:

  • 抱歉直到现在还没有回复,data.each 不会工作,因为它不会产生迭代器,而是调用块并将哈希传递给块。
  • 这就是重点。让它产生一个可枚举的。为什么必须是块?
  • 因为不可能使其可枚举,而不是代码的结构方式,并且块在使用该块之前就进行了几次方法调用。
  • 我很乐意帮助您完成这项工作,甚至为 DSL 用户简化它。我相当肯定这是可能的。您愿意向我展示您的代码,以便我向您展示如何执行此操作吗?我可能会建议稍微改变“代码的结构”。勇敢点;)
  • eck,我真的忘记了这个问题,一直忙于其他事情。嗯,由于我做了一些改变,现在这有点无关紧要了。首先是我现在使用 DBM 将我正在抓取的所有数据存储到基于文件的数据库中,然后从那里继续(这样我可以恢复并让它加快抓取速度,因为它忽略了抓取的 url)然后只是做一个.each 在 DBM 对象上。第二个是我现在创建了一个硬编码的 CSV 写入器,用户只用 writer({csv: "servo_city.csv"}) 选择它。因此,这个问题现在变得无关紧要了。
【解决方案2】:

每次要写入记录时都尝试打开 CSV 文件似乎过于复杂,并且可能会导致性能下降(除非写入是间歇性的)。除非您将文件模式从 wb 更改为 ab,否则每次它也会覆盖 CSV 文件。

我觉得很简单,比如:

csv = CSV.open('data.csv', 'wb')
csv << headers
writer do |hash|
  csv << hash.values
end

会更容易理解。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-06
    • 1970-01-01
    • 2015-02-11
    • 1970-01-01
    • 2020-08-06
    • 1970-01-01
    相关资源
    最近更新 更多