ruby-on-rails - 在 `irb` 中,反引号抛出异常,但在 `rails c` 中,它们不会

标签 ruby-on-rails ruby shell backticks

  • 操作系统:Debian GNU/Linux 8
  • ruby 版本:2.4.1
  • Rails 版本:5.1.4

我刚刚使用 rails new 创建了一个全新的 Rails 项目。在它的目录中,使用 irb,我试图为一个不存在的可执行文件执行 shell 命令,但抛出了异常:

irb(main):001:0> `foobar`
Errno::ENOENT: No such file or directory - foobar
    from (irb):1:in ``'
    from (irb):1
    from /home/jackson/.rbenv/versions/2.4.1/bin/irb:11:in `<top (required)>'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/cli/exec.rb:74:in `load'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/cli/exec.rb:74:in `kernel_load'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/cli/exec.rb:27:in `run'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/cli.rb:335:in `exec'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/vendor/thor/lib/thor/invocation.rb:126:in `invoke_command'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/vendor/thor/lib/thor.rb:359:in `dispatch'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/cli.rb:20:in `dispatch'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/vendor/thor/lib/thor/base.rb:440:in `start'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/cli.rb:11:in `start'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/exe/bundle:32:in `block in <top (required)>'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/lib/bundler/friendly_errors.rb:121:in `with_friendly_errors'
    from /home/jackson/.rbenv/versions/2.4.1/lib/ruby/gems/2.4.0/gems/bundler-1.14.6/exe/bundle:24:in `<top (required)>'
    from /home/jackson/.rbenv/versions/2.4.1/bin/bundle:22:in `load'
    from /home/jackson/.rbenv/versions/2.4.1/bin/bundle:22:in `<main>'

然而,当我尝试在我的 Rails 环境中使用 rails c 做同样的事情时,并没有抛出异常。反引号改为返回 nil:

irb(main):001:0> `foobar`
rails_console: No such file or directory - foobar
=> nil

这种不一致似乎反射(reflect)在 Rails 控制台之外。在我的 Rails 应用程序中,反引号也会返回 nil。这是一个问题,因为我们的一个 gem 中缺少命令的错误处理被破坏了,因为它没有抛出异常:https://github.com/dstil/localtunnel/blob/87b1e4b98f600c2a767654caf0a2d94fef5be0e5/lib/localtunnel/client.rb#L37-L41

这种行为差异是故意的吗?如果不是,出了什么问题,我该如何解决?

最佳答案

您的问题似乎是 Rails overrides backticks试图规范行为:

class Object
  # Makes backticks behave (somewhat more) similarly on all platforms.
  # On win32 `nonexistent_command` raises Errno::ENOENT; on Unix, the
  # spawned shell prints a message to stderr and sets $?. We emulate
  # Unix on the former but not the latter.
  def `(command) #:nodoc:
    super
  rescue Errno::ENOENT => e
    STDERR.puts "#$0: #{e}"
  end
end

到处都是责备:

  • 用于替换核心方法的 Rails。
  • 使用反引号的 gem,而不是像 Open3 这样更安全、更简洁的东西。
  • Ruby 没有指定 Kernel#` 的行为方式(如果您足够固执己见,甚至可能有反引号)。

有很多方法可以解决这个问题。您可以尝试在初始化程序中删除 ActiveSupport 覆盖:

Object.send(:remove_method, :'`')

以便使用来自 Kernel 的标准反引号。或者,如果您不希望有一个 lt 命令,您可以替换 gem 的方法:

module LocalTunnel
  class Client
    def self.package_installed?
      false
    end
  end
end

或者可以将 LocalTunnel::Client.package_installed? 替换为您自己的实现,通过检查反引号可能失败的各种方式或使用 Open3 而不是反引号。您也可以通过分解 PATH 环境变量(使用 File::PATH_SEPARATOR)和 File.executable 来手动查找 lv

您使用哪种组合取决于您的可移植性要求以及适合您的环境的组合。

关于ruby-on-rails - 在 `irb` 中,反引号抛出异常,但在 `rails c` 中,它们不会,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47166648/

相关文章:

ruby-on-rails - 从设计中覆盖注册 Controller 时,是否可以在创建操作中访问新创建的用户?

ruby-on-rails - Rails - 添加不在模型中的属性并更新模型属性

ruby - 优雅地关闭 sidekiq 进程

linux - 是否可以创建一个脚本来保存和恢复权限?

linux - Mercurial 并排差异(最大术语宽度)

linux - Bash 命令行参数通过 ssh 传递给 sed

ruby-on-rails - 在删除用户方法中传递条件时出错

ruby-on-rails - Rails cron 不发送电子邮件

ruby - 检查是否没有参数传递

Ruby yield 示例解释?