在 `irb` 中,反引号会抛出异常,但在 `rails c` 中,它们不会
In `irb`, backticks throw an exception, but in `rails c`, they don't
- OS: 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
做同样的事情时,没有抛出异常。反引号 return nil
改为:
irb(main):001:0> `foobar`
rails_console: No such file or directory - foobar
=> nil
这种不一致似乎反映在 Rails 控制台之外。在我的 Rails 应用程序中,反引号也 return 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 "#[=10=]: #{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
中的方法而不是反引号来解决 Rails 覆盖。您也可以通过分解 PATH
环境变量(使用 File::PATH_SEPARATOR
)和 File.executable?
.
来手动查找 lv
您使用哪种组合取决于您的可移植性要求以及适合您的环境。
- OS: 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
做同样的事情时,没有抛出异常。反引号 return nil
改为:
irb(main):001:0> `foobar`
rails_console: No such file or directory - foobar
=> nil
这种不一致似乎反映在 Rails 控制台之外。在我的 Rails 应用程序中,反引号也 return 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 "#[=10=]: #{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
中的方法而不是反引号来解决 Rails 覆盖。您也可以通过分解 PATH
环境变量(使用 File::PATH_SEPARATOR
)和 File.executable?
.
lv
您使用哪种组合取决于您的可移植性要求以及适合您的环境。