support `-` as an argument to `rails runner`

in Rails 4.0, you could use `/dev/stdin` on both Linux and Mac, but with
the switch to Kernel.load in Rails 4.1, this broke on Linux (you get
a LoadError). Instead, explicitly detect `-` as meaning stdin, then
read from stdin explicitly, instead of performing file gymnastics. This
should now work on any platform uniformly.

Passing a script via stdin is useful when you're sshing to a server,
and the script you want to run is stored locally. You could theoretically
pass the entire script on the command line, but in reality you'll run
into problems with the command being too long.
This commit is contained in:
Cody Cutrer 2016-08-31 09:28:44 -06:00 committed by Cody Cutrer
parent c24be36932
commit ed44b145bd
4 changed files with 20 additions and 2 deletions

View File

@ -1,3 +1,8 @@
* Support `-` as a platform-agnostic way to run a script from stdin with
`rails runner`
*Cody Cutrer*
* Add `bootsnap` to default `Gemfile`. * Add `bootsnap` to default `Gemfile`.
*Burke Libbey* *Burke Libbey*

View File

@ -8,6 +8,9 @@ Run the Ruby file located at `path/to/filename.rb` after loading the app:
<%= executable %> path/to/filename.rb <%= executable %> path/to/filename.rb
Run the Ruby script read from stdin after loading the app:
<%= executable %> -
<% unless Gem.win_platform? %> <% unless Gem.win_platform? %>
You can also use the runner command as a shebang line for your executables: You can also use the runner command as a shebang line for your executables:

View File

@ -13,7 +13,7 @@ module Rails
end end
def self.banner(*) def self.banner(*)
"#{super} [<'Some.ruby(code)'> | <filename.rb>]" "#{super} [<'Some.ruby(code)'> | <filename.rb> | -]"
end end
def perform(code_or_file = nil, *command_argv) def perform(code_or_file = nil, *command_argv)
@ -29,7 +29,9 @@ module Rails
ARGV.replace(command_argv) ARGV.replace(command_argv)
if File.exist?(code_or_file) if code_or_file == "-"
eval($stdin.read, binding, "stdin")
elsif File.exist?(code_or_file)
$0 = code_or_file $0 = code_or_file
Kernel.load code_or_file Kernel.load code_or_file
else else

View File

@ -84,6 +84,14 @@ module ApplicationTests
assert_match %w( a b ).to_s, Dir.chdir(app_path) { `bin/rails runner "bin/program_name.rb" a b` } assert_match %w( a b ).to_s, Dir.chdir(app_path) { `bin/rails runner "bin/program_name.rb" a b` }
end end
def test_should_run_stdin
app_file "bin/count_users.rb", <<-SCRIPT
puts User.count
SCRIPT
assert_match "42", Dir.chdir(app_path) { `cat bin/count_users.rb | bin/rails runner -` }
end
def test_with_hook def test_with_hook
add_to_config <<-RUBY add_to_config <<-RUBY
runner do |app| runner do |app|