需要澄清退出和中止脚本Ruby

时间:2014-08-24 18:42:38

标签: ruby

我正在撰写一个包含ifelse的练习计划。代码如下:

puts "What is your name?"
user_name = $stdin.gets.chomp

print "Hello #{user_name}! Welcome to Puzzles and Riddles v.1!"

puts "There are two doors \n 1. Riddles \n 2. Puzzles. \n Which door do you go through?"
answer_1 = $stdin.gets.chomp
if 
    answer_1 == "1"
    puts "You have taken the Riddle room!"
    print "Here is your riddle: \n You use a knife to slice my head and weep beside me when I am dead. \n What am I?"
    end

    riddle_1_answer = $stdin.gets.chomp

    if 
    riddle_1_answer == ( riddle_1_answer == "An onion" ) || ( riddle_1_answer == "an onion" ) || ( riddle_1_answer == "Onion" ) || ( riddle_1_answer == "onion" )
    puts "The correct answer is: An onion! \n You have advanced to round two."

    else
        puts "Sorry, your answer is incorrect. Think about it."
end

puts "Riddle 2. \n What has 4 fingers and a thumb, but is not living?"

riddle_2_answer = $stdin.gets.chomp

现在,如果用户错误riddle_1_answer我将如何制作,以便程序退出/中止? 我尝试将exit(0)添加到else部分,它将终止程序,但也会出现错误。所以我不确定错误是导致程序结束还是退出(0)命令

1 个答案:

答案 0 :(得分:0)

从您的问题,示例代码以及您对@AndrewMarshall的回答中可以明显看出,您需要一些指导。

你走了。

首先,ruby是众多编程语言中的一种,并且有许多经验丰富的程序员最终倾向于它的原因:ruby是面向对象的,富有表现力的,强大的,并且相当简洁而不是不自然的简洁。所以,如果你要学习红宝石,可以通过阅读大量优秀的红宝石代码来学习,从中学习良好实践。

其次,外观很重要,因为它会影响或增强可读性和理解力。良好的外观有助于提高可读性和更快速的理解。一个糟糕的外表恰恰相反。

代码中ifelseend令牌的对齐情况不佳;它使得很难看到代码逻辑的结构。

编程中有许多经验法则。以下是一些适用于大多数语言的规则:

  • 正确使用对齐和缩进
  • 总是想着"边缘情况" (或错误)
  • 限制和隔离复杂性(使用函数,模块,类和方法)
  • 不要重复自己(DRY)

因此,让我们将这两个原则应用到您的代码中并对其进行一些转换。

前两行:

puts "What is your name?"
user_name = $stdin.gets.chomp
  • 如果用户输入CTRL-D(EOF)怎么办?
  • 如果用户输入空行怎么办?

错误是否可以接受? STDIN上的EOF返回nil,这会导致chomp出错。

是否可以接受空字符串(零长度)名称?如果没有,我们应该怎么做呢?

当做一些相对简单的事情很复杂时,例如获取用户名,将复杂性封装在函数或方法中,因此需要用户名的代码不会因为获取它的复杂性而变得混乱。

这是一个替代品。首先,让我们管理在一个小函数中获取用户名的细节(和复杂性)。

def get_user_name
  name = ''
  while name.size == 0 do
    print "What is your name? "
    name = gets
    exit(1) if name.nil?  # exit program on EOF
    name.strip!
  end
  name
end

请注意,我们不会在chomp上使用name,直到我们确定它不是nil为止。许多程序通过退出,中止或继续对EOF的输入作出反应而没有任何其他问题。在这个例子中,我们假设用户想要退出。

另请注意,我们使用的是strip!而不是chomp!?这是因为strip!将删除前导空格和尾随空格,包括尾随换行符。

另请注意,我们没有使用$stdin.gets,而只是使用gets?这是因为gets的默认对象是$stdin

在小函数(方法)中管理异常情况的更好方法可能是raise异常,让更高级别的应用程序逻辑决定如何管理它。考虑到这一点,这是一个修订的定义:

def get_user_name
  name = ''
  while name.size < 1 do
    print "What is your name? "
    name = gets
    raise "End of input" if name.nil?  # raise exception on EOF
    name.strip!
  end
  name
end

现在,定义了get_user_name,我们可以在需要用户名的任何地方使用它。我们知道EOF是管理的,我们知道我们不会得到一个空字符串。

 user_name = get_user_name

现在,让我们执行原始代码的其余部分,但要正确对齐和缩进。

print "Hello #{user_name}! Welcome to Puzzles and Riddles v.1!"

puts "There are two doors \n 1. Riddles \n 2. Puzzles. \n Which door do you go through?"
answer_1 = $stdin.gets.chomp
if answer_1 == "1"
  puts "You have taken the Riddle room!"
  print "Here is your riddle: \n You use a knife to slice my head and weep beside me when I am dead. \n What am I?"
end

riddle_1_answer = $stdin.gets.chomp

if riddle_1_answer == ( riddle_1_answer == "An onion" ) || ( riddle_1_answer == "an onion" ) || ( riddle_1_answer == "Onion" ) || ( riddle_1_answer == "onion" )
  puts "The correct answer is: An onion! \n You have advanced to round two."

else
  puts "Sorry, your answer is incorrect. Think about it."
end

puts "Riddle 2. \n What has 4 fingers and a thumb, but is not living?"

riddle_2_answer = $stdin.gets.chomp

现在对齐和缩进是正确的,它更容易看到逻辑及其缺陷。它也更容易看到逻辑模式,每当你看到一个模式,然后干掉它,并制作方法(函数)来封装重复。

但首先,让我们解决明显的错误。

if表达式已被破坏。再看一遍,你会看到这个:

if riddle_1_answer == TEST1 || TEST2 || TEST3 || TEST4

我已使用TEST n 替换您所拥有的各种区分大小写的测试。

if表达式将始终失败,因为riddle_1_answer的值永远不会truefalse并且各种TEST n个表达式的结果将始终为truefalse。我很确定你想要这个:

if TEST1 || TEST2 || TEST3 || TEST4

其次,在测试字符串值时,没有必要测试所有案例变体。只需downcase答案并测试小写测试值(除非区分大小写非常重要)。或者,如果简单的字符串测试不够,则使用regular expression并使用i选项进行不区分大小写的匹配。例如:

if riddle_1_answer =~ /(?:an )?onion/i

将在大写,小写和混合大小写中测试"an onion""onion"

或许比这些小错误更重要,人们应该避免重复。一般模式似乎是:

  1. 提出问题
  2. 接受答案
  3. 检查答案
  4. 根据答案更改程序状态
  5. 重复
  6. 当你看到这样的事情时,你应该开始考虑数组哈希。当值可以用数字索引时使用数组,当你想获得与变化相关的值时使用散列。然后,可以使用一个简单的循环来迭代数组或散列的值。

    因此,看到上面的模式,我们需要一种方法来提示问题,得到答案,处理可能的EOF和空字符串,验证非空答案,可能重复问题和放大器,这一点变得更加清晰。 ;在需要时回答。

    因此,让我们定义一个方法来获得答案

    # prompt_and_get_answer PROMPT, ANSWERS_DATA
    #
    # issue PROMPT, and get an answer, which must be one of the 
    # values in ANSWERS_DATA array, or one of the keys of the 
    # ANSWERS_DATA hash.
    
    def prompt_and_get_answer prompt, answers_data
      ans = ''
      while ans.size < 1
        print prompt
        ans = $stdin.gets
        if ans.nil?
          raise "End of input"
        end
        ans.strip!
        if answers_data.class == Hash  # hash?
          answers = answers_data.keys.sort
        else
          answers = answers_data.sort
        end
        matches = answers.grep(/#{ans}/i)  # match possible valid answers
        case matches.size        # how many items found?
        when 0
          puts "#{ans} is not a valid answer.  Use one of:"
          puts answers.join(', ')
          ans = ''
        when 1                   # return the match or the value of the matching key
          ans = answers_data.class == Hash ? answers_data[matches[0]] : matches[0]
        else
          puts "#{ans} is ambiguous; be more specific to match one of:"
          puts answers.join(', ')
          ans = ''
        end
      end
      ans
    end
    

    现在,我们可以使用此方法将提示作为参数,并获得答案,因为它知道它不会是一个空答案,而且它不会是一个EOF。< / p>

    首先,让我们为问题命名,然后让我们显示输出中显示的提示,而不使用明确转义的换行符(\n)。

    $prompt1 = <<EOQ
    There are two doors
    1. Riddles
    2. Puzzles
    Which door do you go through?
    EOQ
    $answer1 = [ '1', '2' ]
    
    $prompt2 = <<EOQ
    Here is your riddle:
    You use a knife to slice my head and weep beside me when I am dead.
    What am I?
    EOQ
    $answer2 = [ 'onion' ]
    
    ans1 = prompt_and_get_answer $prompt1, $answer1
    if ans1 == '1'
      do_riddles
    elsif ans1 == '2'
      do_puzzles
    else
      raise "Bad answer to prompt1"
    end
    
    def do_riddles
      while true
        ans = prompt_and_get_answer $prompt2, $answer2
        if ans == 'onion'
          puts "yay!  you're right!"
          break
        else
          puts "nope.  Try again"
        end
      end
    end
    

    您可以从中看到,我们已经使用方法(函数)将逻辑分解为更小的部分,并将获得答案的细节与测试它们的细节分开。

    稍后,我们可以看到如何使用表格和哈希来建立问题列表。

    祝你好运。