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

需要澄清退出和中止脚本Ruby,ruby,Ruby,我正在用if和else编写一个小练习程序。代码如下: 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 = $

我正在用
if
else
编写一个小练习程序。代码如下:

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
现在,如果用户答错了
ridle\u 1\u answer
,我该如何使程序退出/中止?
我尝试将exit(0)添加到else部分,它将终止程序,但也会出现错误。因此,我不确定错误是否导致程序结束或退出(0)命令

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

给你

首先,ruby是许多编程语言中的一种,许多有经验的程序员最终被它所吸引是有原因的:ruby是面向对象的、有表现力的、功能强大的,并且相当简洁,但不自然地简洁。所以,如果你想学习ruby,就要通过阅读大量优秀的ruby代码来学习,从中你会学到很多好的实践

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

代码中的
if
else
end
标记缺乏对齐是错误的;这使得很难看到代码逻辑的结构

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

  • 正确使用对齐和缩进
  • 始终考虑“边缘情况”(或错误)
  • 限制和隔离复杂性(使用函数、模块、类和方法)
  • 不要重复你自己(干)
因此,让我们将这两个原则应用到您的代码中,并对其进行一些转换

前两行:

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
请注意,在我们确保它不是
nil
之前,我们不会在
name
上使用
chomp
。许多程序对输入的EOF作出反应,即退出、中止或继续,而不再提出任何问题。在本例中,我们假设用户想要退出

还要注意,我们使用了
strip而不是
chomp?那是因为
strip
将删除前导和尾随空格,包括尾随换行符

还要注意,我们没有使用
$stdin.get
,而是使用
get
?这是因为
获取的默认对象是
$stdin

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

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
现在,让我们完成原始代码的其余部分,但要正确对齐和缩进

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
既然对齐和缩进是正确的,就更容易看到逻辑及其缺陷。查看逻辑模式也更容易,每当您看到一个模式时,就将其晾干,并制作方法(函数)来封装重复

但首先,让我们修复明显的bug

if
表达式已损坏。再看一遍,你会看到:

if riddle_1_answer == TEST1 || TEST2 || TEST3 || TEST4
在这里,我使用了
TEST
n来替换您进行的各种区分大小写的测试

if
表达式将始终失败,因为
谜语1\u答案的值永远不会是
true
false
,并且各种
测试的结果总是
true
false
。我很确定你想要这个:

if TEST1 || TEST2 || TEST3 || TEST4
其次,在测试字符串值时,不必测试所有的大小写变化。只需
downcase
答案和测试小写测试值(除非区分大小写很重要)。或者,如果简单的字符串测试不够,则使用
正则表达式
并使用
i
选项进行不区分大小写的匹配。例如:

if riddle_1_answer =~ /(?:an )?onion/i
将以大写、小写和混合格式测试“洋葱”或“洋葱”

也许比这些小错误更重要的是,我们应该避免重复。总的模式似乎是:

  • 提问
  • 接受回答
  • 核对答案
  • 根据答案更改程序状态
  • 重复
  • 当您看到这样的情况时,您应该开始考虑数组和散列。当可以对值进行数字索引时,使用数组;当希望获取与不同键关联的值时,使用哈希。然后,可以使用一个简单的循环来迭代数组或散列的值

    因此,从上面的模式可以看出,我们需要一种方法来提示问题,获取答案,处理可能的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
    
    从中可以看出,我们使用了方法(函数)将逻辑分解为更小的部分,并将获取答案的细节与测试答案的细节分开

    稍后,我们可以看到如何使用表和散列来建立问题列表
    # 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
    
    $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