Search code examples
ruby-on-railsrubyopen-uri

Is it safe to require 'open-uri' in a Rails project?


I've seen plenty of examples of open-uri, it seems pretty great for simple things. It really bothers me that requiring it defines a method named open in the global scope, though.

This is particularly troubling since, after poking around in a Rails 5 console, there already seems to be a method named open defined:

irb(main):001:0> open
ArgumentError: wrong number of arguments (given 0, expected 1..3)
        from (irb):1:in `initialize'
        from (irb):1:in `open'
        from (irb):1
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands/console.rb:65:in `start'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands/console_helper.rb:9:in `start'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands/commands_tasks.rb:78:in `console'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/command.rb:20:in `run'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands.rb:18:in `<top (required)>'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:302:in `require'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:302:in `block in require'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:268:in `load_dependency'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:302:in `require'
        from /Users/ahamon/code/signist/bin/rails:9:in `<top (required)>'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:296:in `load'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:296:in `block in load'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:268:in `load_dependency'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:296:in `load'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/commands/rails.rb:6:in `call'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/command_wrapper.rb:38:in `call'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:185:in `block in serve'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:156:in `fork'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:156:in `serve'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:131:in `block in run'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:125:in `loop'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:125:in `run'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application/boot.rb:18:in `<top (required)>'
        from /Users/ahamon/.rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /Users/ahamon/.rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from -e:1:in `<main>'irb(main):002:0>

If I go ahead and require 'open-uri', the return value is true, and I have now obliterated the previous open, whatever it was:

irb(main):002:0> require 'open-uri'
=> true
irb(main):003:0> open
ArgumentError: wrong number of arguments (given 0, expected 1+)
        from /Users/ahamon/.rubies/ruby-2.3.0/lib/ruby/2.3.0/open-uri.rb:29:in `open'
        from (irb):3
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands/console.rb:65:in `start'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands/console_helper.rb:9:in `start'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands/commands_tasks.rb:78:in `console'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands/commands_tasks.rb:49:in `run_command!'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/command.rb:20:in `run'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/railties-5.0.0.beta3/lib/rails/commands.rb:18:in `<top (required)>'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:302:in `require'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:302:in `block in require'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:268:in `load_dependency'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:302:in `require'
        from /Users/ahamon/code/signist/bin/rails:9:in `<top (required)>'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:296:in `load'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:296:in `block in load'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:268:in `load_dependency'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/activesupport-5.0.0.beta3/lib/active_support/dependencies.rb:296:in `load'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/commands/rails.rb:6:in `call'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/command_wrapper.rb:38:in `call'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:185:in `block in serve'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:156:in `fork'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:156:in `serve'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:131:in `block in run'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:125:in `loop'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application.rb:125:in `run'
        from /Users/ahamon/.gem/ruby/2.3.0/gems/spring-1.6.4/lib/spring/application/boot.rb:18:in `<top (required)>'
        from /Users/ahamon/.rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from /Users/ahamon/.rubies/ruby-2.3.0/lib/ruby/2.3.0/rubygems/core_ext/kernel_require.rb:55:in `require'
        from -e:1:in `<main>'irb(main):004:0>

Notice the different arity specified in each stack trace.

So what is the open that was defined before? Is it safe to obliterate? Is there a way to use open-uri without defining global methods?


Solution

  • open is Kernel#open, not Rails. open-uri wraps Kernel#open: it checks if the target is an URL or knows #open, handles it if it is, passes everything on to real Kernel#open if it isn't.

    Thus, without open-uri, URLs don't work, openables don't work, everything else does. With open-uri, URLs work, openables work, everything else is the same. There should be no danger in requiring it, aside from the very, very slight performance hit when open-uri checks if your argument is an URL or responds to #open.