【问题标题】:Ruby script start from a specific line or methodRuby 脚本从特定的行或方法开始
【发布时间】:2016-12-04 21:17:51
【问题描述】:

假设我有一个脚本:

!#usr/bin/ruby

# step 1
puts "That's first"
# some code

#step 2
puts "That's second"
# some code

有没有办法将 ARGV 传递给将从特定行(或步骤、类或其他)开始执行的脚本? 例如执行$ ruby script.rb -s 2将从第二步开始。

我有过使用if\else 解析参数的想法,但在这种情况下,脚本会变得更加复杂,而且根本不会 DRY。

有什么想法吗?

【问题讨论】:

    标签: ruby command-line-interface argv


    【解决方案1】:

    Bad things 在您使用 GOTO 时发生。

    这是一个可以以更优雅的方式解决您的问题的建议:

    在'define_steps.rb'中定义你的步骤:

    # define_steps.rb
    #####################################################
    @steps = []
    
    def step(i, &block)
      @steps[i] = block
    end
    
    def launch_steps!(min = 0, max = @steps.size - 1)
      @steps[min..max].each.with_index(min) do |block, i|
        if block
          puts "Launching step #{i}"
          block.call
        end
      end
    end
    #####################################################
    
    step 1 do
      puts 'Step 1 with lots of code'
    end
    
    step 2 do
      puts 'Step 2 with lots of code'
    end
    
    step 3 do
      puts 'Step 3 with lots of code'
    end
    
    step 4 do
      puts 'Step 4 with lots of code'
    end
    

    使用launch_steps.rb 分别启动它们:

    # launch_steps.rb
    require_relative 'define_steps'
    
    launch_steps!
    puts "-----------------"
    launch_steps!(2,3)
    

    它输出:

    Launching step 1
    Step 1 with lots of code
    Launching step 2
    Step 2 with lots of code
    Launching step 3
    Step 3 with lots of code
    Launching step 4
    Step 4 with lots of code
    -----------------
    Launching step 2
    Step 2 with lots of code
    Launching step 3
    Step 3 with lots of code
    

    launch_steps! 不带参数运行每个定义的步骤,launch_steps!(min,max) 运行minmax 之间的每个步骤,launch_steps!(min) 运行步骤min 和之后的每个步骤。

    【讨论】:

    • 这里有一点 DSL(特定领域的语言)确实让这段代码很容易理解。不错!
    【解决方案2】:

    这是一个程序run_from_line.rb,它接受三个参数:路径和起始行以及结束行。结束行是可选的,默认为 -1。

    #/usr/bin/env ruby
    
    path = ARGV.shift
    program_text = File.readlines(path)
    start_line = ARGV.shift.to_i;
    end_line = ARGV.shift || '-1'
    end_line = end_line.to_i
    
    selected_code = program_text[start_line..end_line].join
    eval selected_code
    

    这个脚本在test.rb:

    puts "line 0"
    puts "line 1"
    puts "line 2"
    

    测试:

    > ruby run_from_line.rb test.rb 1
    line 1
    line 2
    
    > ruby run_from_line.rb test.rb 1 1
    line 1
    

    如果你想让它成为一个系统范围的脚本,运行chmod a+x run_from_line.rb 然后sudo mv run_from_line.rb /usr/local/sbin

    【讨论】:

    • shift 是相当严厉的。为什么不path = ARGV[0]path, start_l, end_l = ARGV
    • 人们经常因为 ARGV 干扰 gets.chomp 而感到困惑
    • 这两者有什么关系?一个来自 STDIN,另一个来自 ARGV。
    • 这是一个有趣的观点,Kernel#gets 确实如此,但我从未见过有人混淆了这两件事。它实际上是一个简洁的功能,因为您可以通过命令行指定输入文件,即使对于没有明确允许的程序也是如此。
    • 我看到一些人感到困惑,因为他们的 gets.chomp 没有停下来请求输入。这是一个很酷的提示
    【解决方案3】:

    max 的答案向您展示了一些方法,但您不应该这样做。 在你知道之前,有关于 Ruby 的 goto 语句的问题。 为什么要回到 BASIC 中使用的技术?向我们展示一个用法,我们会向您展示更好的方法。

    如果您刚开始使用 Ruby 和编程,您可以使用像这样的程序化编程方式

    def print_a
      puts "a"
    end
    

    以后,无论“puts a”这一行在你上次更新之间移动到了哪里

    print_a
    

    如果您更有经验,您可以结合使用面向对象或函数式编程方式。

    我想到了一个可接受的用法:条件 require 's 或 load's

    if condition
      require ./mycode_only_to be_executed_in_this_case.rb'
    end
    

    希望我能让你重新思考你的问题..

    评论后编辑

    你提到的例子不是 DRY,这是我注意到的第一件事。 请参阅https://en.wikipedia.org/wiki/Don't_repeat_yourself 了解 DRY 的定义

    这就是我的想法,我仍然使用一种方法来封装我的代码,以便它是我可以重复使用并且只有一个目的并且可测试的代码:连接到一个站点。没有重复的代码,所以 DRY。

    require 'watir'
    
    def goto_site site
      a = Watir::Browser.new :chrome
      a.goto site
      # a lot of code down here
      a.close
    end
    
    goto_site 'site.com'
    

    【讨论】:

    • 谢谢彼得,你的方法很深入。就我而言,我有一个脚本可以运行 watir webdriver 并检查多个实例。 Example here。所以我想知道如果不需要检查之前是否有办法从特定步骤执行脚本。
    • 我编辑了我的答案,请看一下。
    • 这取决于# a lot of code down here 在一种方法和另一种方法之间是否相同。
    • @peter:DRY 需要不同的结构,因为goto_site(site) 需要根据site 调用不同的代码。现在,它只节省了几行,并没有真正帮助解决原始问题。
    • @EricDuminil 我将不得不查看其余代码来决定如何使其保持干燥,但重要的是方法适合这里而不是 goto line 解决方案,Eric 的 DSL 解决方案也是某种方法,Max 解决方案很有趣,但不可取,他们都有我的 +1
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-01
    • 2021-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    相关资源
    最近更新 更多