【问题标题】:How do I return early from a rake task?如何从 rake 任务中提前返回?
【发布时间】:2011-01-19 23:07:10
【问题描述】:

我有一个 rake 任务,我在开始时会进行一些检查,如果其中一个检查失败,我想从 rake 任务中提前返回,我不想执行任何剩余的代码。

我认为解决方案是在我想从代码返回的地方放置一个返回,但我收到以下错误

unexpected return

【问题讨论】:

    标签: ruby rake


    【解决方案1】:

    Rake 任务基本上是一个块。一个块,除了 lambdas,不支持 return,但是你可以使用 next 跳到下一个语句,这在 rake 任务中具有与在方法中使用 return 相同的效果。

    task :foo do
      puts "printed"
      next
      puts "never printed"
    end
    

    或者你可以在方法中移动代码并在方法中使用return。

    task :foo do
      do_something
    end
    
    def do_something
      puts "startd"
      return
      puts "end"
    end
    

    我更喜欢第二种选择。

    【讨论】:

    • 我也最喜欢第二个。我使用 rake 的次数越多,我就越喜欢将重要的代码保留在任务定义之外。不是 100% 严格的规则,但似乎是一个很好的工作指南。
    • 我已经尝试使用break,但我遇到了这个错误:rake aborted!从 proc-closure 中断(通过使用 --trace 运行任务查看完整跟踪)
    • 我更喜欢使用下一个。为什么我们要声明一个新方法只是为了支持提前返回?
    • 如果你嵌套在多个块​​中,你会怎么做? (next 仅在有“级别”的块需要突破时才有效。
    • 警告:在 Rake 任务中声明方法是个坏主意,因为它们对所有加载的 Rake 任务都是全局的,与命名空间无关。使用 Next 而不是 break,因为块中的代码可能会被执行块的任何东西多次调用(想想 .each 方法)。
    【解决方案2】:

    您可以在任务内部使用abort(message) 来通过消息中止该任务。

    【讨论】:

    • @TylerRick 不,是Kernel#abort
    • 这种方式非常适合在不成功的情况下退出,因为它会自动设置退出状态。
    • 这是赢家。也是为参数错误提供使用反馈的简单方法。
    • 内联且比next 更具解释性。喜欢它。
    • 如果您正在测试您的 rake 任务,这可能不是一个好主意,这很可能会导致测试失败。
    【解决方案3】:

    返回错误❌

    如果您返回 with 错误(即退出代码 1),您将需要使用 abort,它还需要一个可选参数退出时输出的字符串参数:

    task :check do
      
      # If any of your checks fail, you can exit early like this.
      abort( "One of the checks has failed!" ) if check_failed?
    
    end
    

    在命令行上:

    $ rake check && echo "All good"
    #=> One of the checks has failed!
    

    成功归来✅

    如果您返回没有错误(即退出代码0),您需要使用exit确实如此不 采用字符串参数。

    task :check do
      
      # If any of your checks fail, you can exit early like this.
      exit if check_failed?
      
    end
    

    在命令行上:

    $ rake check && echo "All good"
    #=> All good
    

    如果您在 cron 作业中使用它,或者需要根据 rake 任务是否成功执行某些操作,这一点很重要。


    奖励:从没有堆栈跟踪的 rescue 块返回错误。

    默认情况下,如果您在 rescue 块内使用 abort,它将输出整个堆栈跟踪,即使您只使用 abort 而不会重新引发错误。

    要解决这个问题,您可以向exit 命令提供一个非零退出代码,例如:

    
    task :check do
    
      begin
        do_the_thing_that_raises_an_exception
      rescue => error
        puts error.message
     
        exit( 1 )
      end
    
    end
    

    【讨论】:

    • 这个应该被接受答案@simone-carletti
    【解决方案4】:

    我倾向于使用abort,在这种情况下这是一个更好的选择,例如:

    task :foo do
      something = false
      abort 'Failed to proceed' unless something
    end
    

    【讨论】:

    • 但是你如何abort 而不使用1 退出代码退出? Rake 任务通常在命令行中用于确定成功或失败。有没有“成功”的abort
    • 回答了我自己的问题:看起来exit 是成功退出的好方法。
    【解决方案5】:

    如果您需要突破多个块级别,可以使用fail

    例如

    task :something do
      [1,2,3].each do |i|
        ...
        fail "some error" if ...
      end
    end
    

    (见https://stackoverflow.com/a/3753955/11543。)

    【讨论】:

      【解决方案6】:

      如果您的意思是退出 rake 任务而不导致“rake 中止!”要打印的消息,那么您可以使用“中止”或“退出”。但是,当在救援块中使用“中止”时,会终止任务并打印整个错误(即使不使用 --trace)。所以“退出”是我使用的。

      【讨论】:

      • 总的来说,我认为使用“exit”而不是 return/break 是一个坏主意,因为它不只是跳出 current proc/method/etc。 -- 它退出整个过程并跳过调用者方法可能打算在之后运行的任何代码(可能包括一些清理)。但对于 rake 任务,我想这可能不是问题......
      • "abort",当在救援块中使用时,会终止任务并打印整个错误(即使不使用 --trace)。 你说对了这!在其他任何地方都找不到这个。我也更新了我的答案以表明这一点。谢谢!
      【解决方案7】:

      我使用了 Simone Carletti 建议的 next 方法,因为在测试 rake 任务时,abort(实际上只是 exit 的包装器)不是所需的行为。

      例子:

      task auto_invoice: :environment do
        if Application.feature_disabled?(:auto_invoice)
          $stderr.puts 'Feature is disabled, aborting.'
        next
      end
      

      【讨论】:

        猜你喜欢
        • 2013-03-27
        • 2010-10-09
        • 2016-05-01
        • 2011-07-10
        • 2023-03-28
        • 2012-11-15
        • 2014-07-03
        • 2012-03-19
        • 2015-11-29
        相关资源
        最近更新 更多