在运行时写程序

最后,让我们回到我们之前看过的程序(eval4.rb),它提示用户输入字符串以在运行时(runtime)定义代码,执行这些字符串并从中创建新的可运行方法。

该程序的一个缺点是它必须要求每个方法的代码都输入一行中。事实上,编写一个允许用户输入跨越多行的方法的程序非常简单。例如,这里是一个程序,它执行输入的所有代码,直到输入一个空行:

writeprog.rb
  1. program = ""
  2. input = ""
  3. line = ""
  4. until line.strip() == "q"
  5. print( "?- " )
  6. line = gets()
  7. case( line.strip() )
  8. when ''
  9. puts( "Evaluating..." )
  10. eval( input )
  11. program += input
  12. input = ""
  13. when 'l'
  14. puts( "Program Listing..." )
  15. puts( program )
  16. else
  17. input += line
  18. end
  19. end

你可以通过输入整个方法然后输入空行来尝试一下(当然只输入代码,而不是注释):

  1. def a(s) # <= press Enter after each line
  2. return s.reverse # <= press enter (and so on...)
  3. end
  4. # <- Enter a blank line here to eval these two methods
  5. def b(s)
  6. return a(s).upcase
  7. end
  8. # <- Enter a blank line here to eval these two methods
  9. puts( a("hello" ) )
  10. # <- Enter a blank line to eval
  11. #=> Displays "olleh"
  12. puts( b("goodbye" ) )
  13. # <- Enter a blank line to eval
  14. #=> Displays "EYBDOOG"

输入每行后,会出现提示符('?-'),除非程序正在执行代码的过程中,在这种情况下,它会显示 “Evaluating” 或显示执行结果,例如 “olleh”

如果你完全按照上面的说明输入文本,那么你应该看到:

  1. Write a program interactively.
  2. Enter a blank line to evaluate.
  3. Enter 'q' to quit.
  4. ?- def a(s)
  5. ?- return s.reverse
  6. ?- end
  7. ?-
  8. Evaluating...
  9. ?- def b(s)
  10. ?- return a(s).upcase
  11. ?- end
  12. ?-
  13. Evaluating...
  14. ?- puts(a("hello"))
  15. ?-
  16. Evaluating...
  17. olleh
  18. ?- b("goodbye")
  19. ?-
  20. Evaluating...
  21. EYBDOOG

这个程序还很简单。它没有任何基本的错误恢复功能,更不用说花哨的东西,如文件保存和加载功能。即便如此,这个小示例也证明了在 Ruby 中编写自修改(self-modifying)程序是多么容易。使用本章概述的技术,你可以从给定语法规则的自然语言解析器为冒险游戏创造任何东西,这个过程中你可以探索新的困惑。

在本书中,我们涵盖了很多基础内容 - 从 “hello world” 到动态编程(dynamic programming)。剩下的要靠你自己了。

这才是冒险真正开始的地方。