Ruby Ruby 的 REPL:编程的交互艺术

suzulang · 2024年08月18日 · 最后由 jamessmith84840026 回复于 2024年09月18日 · 500 次阅读

比如,开发软件的时候,一个"交互式顶层解释器"(interactive toplevel)会带来巨大的优势。在 Lisp 语言中,这种解释器就叫做"读取 - 求值 - 打印"循环(read-eval-print loop)。有了这个解释器后,语言的设计就会受到巨大影响。静态类型语言不适合部署这样的解释器,因为静态类型语言要求在使用变量前先声明类型,这对于"交互式顶层解释器"行不通。当你在解释器中输入表达式,然后对变量 x 进行赋值,接着再对 x 做进一步处理时,你只想尽快看到结果,肯定不想很麻烦地先声明 x 的类型。你也许不同意"交互式顶层解释器"为软件开发带来便利的说法,但是如果你接受它,同意易于使用的编程语言必须有一个这样的解释器,那么强制声明变量类型的做法就是与这个解释器不兼容,因此结论就是所有的静态类型语言都不易于编程。 ——《黑客与画家》15. 设计与研究

作为 Ruby 新手,今天我尝试讲 2 个点,如果有讲错的,欢迎大佬指正

  1. Ruby 语言中 REPL(读取 - 求值 - 打印循环)的实现工具
  2. 探讨 REPL 如何提高开发效率

Ruby 语言中 REPL(读取 - 求值 - 打印循环)的实现工具

安装和基本使用

首先,安装 Pry:

gem install pry

启动 Pry:

$ pry
[1] pry(main)> 1 + 2
=> 3
[2] pry(main)> "Hello, " + "Pry!"
=> "Hello, Pry!"

Pry 的高级特性

代码探索

Pry 允许你轻松查看类和方法的定义:

[3] pry(main)> show-source Array#map

From: array.c (C Method):
Owner: Array
Visibility: public
Number of lines: 17

static VALUE
rb_ary_map(VALUE ary)
{
    long i;
    VALUE collect;

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, rb_ary_length);
    collect = rb_ary_new2(RARRAY_LEN(ary));
    for (i = 0; i < RARRAY_LEN(ary); i++) {
        rb_ary_push(collect, rb_yield(RARRAY_AREF(ary, i)));
    }
    return collect;
}

上下文导航

可以轻松在不同的上下文中切换:

[4] pry(main)> cd Array
[5] pry(Array):> ls
Enumerable# methods: all?  any?  chunk  collect  ...
Array# methods: &  *  +  -  <<  <=>  ==  []  []=  ...
[6] pry(Array):> cd ..
[7] pry(main)>

实时编辑

可以直接在 Pry 中编辑和测试方法:

[8] pry(main)> edit-method Array#select

# 这会打开你的默认编辑器,允许你编辑方法
# 保存并退出后,更改会立即生效

探讨 REPL 如何提高开发效率

快速原型开发

使用 Pry,你可以快速测试想法:

[9] pry(main)> def factorial(n)
[9] pry(main)*   n <= 1 ? 1 : n * factorial(n-1)
[9] pry(main)* end
=> :factorial
[10] pry(main)> factorial(5)
=> 120

交互式学习

探索新的 gem 或 API:

[11] pry(main)> require 'json'
[12] pry(main)> JSON.methods - Object.methods
=> [:[]:create_id=:create_id:load:restore:fast_generate:pretty_generate:generator=:generator:parser=:parser:dump:parse:generate:pretty_unparse:unparse]
[13] pry(main)> JSON.parse('{"name": "Ruby", "awesome": true}')
=> {"name"=>"Ruby", "awesome"=>true}

调试

结合 pry-byebug 进行调试:

[14] pry(main)> require 'pry-byebug'
[15] pry(main)> def complex_method(x)
[15] pry(main)*   y = x * 2
[15] pry(main)*   binding.pry  # 设置断点
[15] pry(main)*   z = y ** 2
[15] pry(main)*   z - x
[15] pry(main)* end
=> :complex_method
[16] pry(main)> complex_method(4)

From: (pry) @ line 3 Object#complex_method:

    1: def complex_method(x)
    2:   y = x * 2
 => 3:   binding.pry  # 设置断点
    4:   z = y ** 2
    5:   z - x
    6: end

[17] pry(#<Object>):1> y
=> 8
[18] pry(#<Object>):1> next

From: (pry) @ line 4 Object#complex_method:

    1: def complex_method(x)
    2:   y = x * 2
    3:   binding.pry  # 设置断点
 => 4:   z = y ** 2
    5:   z - x
    6: end

[19] pry(#<Object>):1> z
=> 64

Ruby:一门符合直觉的语言

如果要总结 Ruby 这门语言的特质,我会说,这是一门符合直觉的语言。Ruby 的设计哲学"最小惊讶原则"和"程序员的快乐"与 REPL 环境完美契合。

例如,当我们想查询一个数组是否为空时,我们可以直接使用 Array#empty?方法:

[20] pry(main)> [].empty?
=> true
[21] pry(main)> [1, 2, 3].empty?
=> false

这种设计让人感觉像是在与 Ruby 对话,提出问题,然后 Ruby 就能给出答案。正因如此,即使在纯文本的 REPL 界面中,不借助 IDE 的自动补全功能,我们也能轻易猜出想要调用的方法。

Ruby 的简洁语法在 REPL 中特别有用:

[22] pry(main)> [1, 2, 3, 4, 5].select(&:even?).map { |n| n ** 2 }
=> [4, 16]

这种直观的语法使得在 REPL 环境中快速实验和原型开发变得非常自然和高效。虽然现代编辑器越来越智能,甚至在命令行界面也能提供自动补全功能,但 Ruby 语言本身的直观性仍然是其独特魅力所在。

总结

通过这些实际的代码示例,我们可以看到 REPL(特别是像 Pry 这样的高级 REPL 工具)如何显著提高开发效率,促进学习和探索,并影响了 Ruby 语言的整体设计和使用方式。它鼓励了一种更加交互式、探索性的编程风格,这正是 Ruby 语言的核心优势之一。

Ruby 的 REPL 环境不仅是一个强大的开发工具,更是体现了这门语言的设计哲学——简洁、直观、富有表现力。它让编程变得更像是一种对话,一种探索,而不仅仅是编写代码。这种特质使得 Ruby 在快速原型开发、脚本编写、Web 开发等领域备受青睐,也使得学习和使用 Ruby 成为一种愉悦的体验。

Ruby 3.0 以上直接使用自带的 irb 和 debug 就可以了,也内置方法补全

jiting 回复

你说的没错。 如果想要再多一点功能的话可以考虑用 Pry,不过还是看自己的喜好。 我一般写 rails 的时候,不会配置 pry,因为启动的时候还要多一些其他的配置 但是如果在写算法题的话,会考虑用 pry 替代 irb

show-source 也可以用 $

4 楼 已删除
需要 登录 后方可回复, 如果你还没有账号请 注册新账号