ruby 1.9.3 can't use open3 (uninitialized constant ConfigureController::Open3) - ruby

The project works fine in Ruby 1.9.2, but I want to use 1.9.3.
This line worked fine in 1.9.2:
o, e, s = Open3.capture3("echo a; sort >&2", :stdin_data=>"foo\nbar\nbaz\n")
However in 1.9.3, I get
uninitialized constant ConfigureController::Open3
Do I have to install the module, or something? thanks!

Did you require 'open3' at the top of your source file? It's possible that before, it was required in turn by something else you were requiring, but now in 1.9.3 it is not. You may need to explicitly require it.

Related

JRuby require fails when I change case, but Ruby doesn't?

I'm using the RMagick gem. If you require 'RMagick', it will give you an error, saying to use require 'rmagick', lowercase, instead. If I follow its advice, Ruby and Rubinius work fine, but JRuby throws a no such file to load -- rmagick exception.
It looks like Ruby has changed whether it wants lowercase gem names, but JRuby hasn't? What's the problem here and what would the proper solution be?
you're probably using two different require "paths" (gems) ... since RMagick is C-ext based it works under MRI+Rubinius. under JRuby if you'd had the very same RMagick gem trying to load it would sure fail. take a look at what gets actually loaded under JRuby.

Nokogiri Ruby 'require' Issues

I'm new to Ruby and I'm having a lot of trouble trying to use Nokogiri. I've been trying to find a resolution for hours now, so any help is appreciated. I tried searching for and using solutions from other related SO posts before caving and posting my own. When I run ruby -v I get: ruby 1.8.7 (2011-06-30 patchlevel 352) [x86_64-linux]
(Edit: I have updated ruby with updates-alternatives --config ruby and selected /usr/bin/ruby1.9.1 but when I do ruby -v it is now showing version 1.9.3 WTF am I doing wrong here?)
I have a new project directory at ~/workspace/ruby/rubycrawler/ and I used Bundler to install nokogiri, which installed correctly:
Using mini_portile (0.5.2)
Using nokogiri (1.6.1)
Using bundler (1.5.1)
Your bundle is complete!
Running bundle show nokogiri returns /var/lib/gems/1.9.1/gems/nokogiri-1.6.1.
In the directory I'm running the script from I have a simple html file named "index.html". The script I'm trying to run is even simpler (or so I thought):
require 'nokogiri'
page = Nokogiri::HTML(open("index.html"))
puts page.class # Nokogiri::HTML::Document
The error is rubycrawler.rb:1:in 'require': no such file to load -- nokogiri (LoadError).
I also added require 'rubygems' even though I read it isn't needed for 1.9+ and still no luck.
A lot of searching shows "Did you put this gem in your Gemfile?". So I generate a Gemfile and add gem 'nokogiri'. I try running the small script again and get the same error. I read "Try deleting Gemfile.lock." so I did but still couldn't get it to work. I then read to try testing it out in irb so I tested "open-uri" and "nokogiri" and here's what I got:
irb(main):001:0> require 'open-uri'
=> true
irb(main):003:0> require 'nokogiri'
LoadError: no such file to load -- nokogiri
I'm really having a lot of trouble figuring this out, so really any help at all is really appreciated.
Ruby tools like RVM, Bundler, etc., to the novice, appear to do a lot of magic, but really, there is no magic to them. The key here lies in what Bundler actually does for you. It manages a manifest of dependencies, BUT at runtime, those dependencies STILL have to get loaded somehow, and my gut feeling is that is what is not happening here.
Regardless of what version of Ruby you are using, if you are using Bundler, there's an easy way to do this. Precede the command that starts your program with "bundle exec" and that will make Bundler edit Ruby's load path so that it includes all the things in the manifest (Gemfile.lock).
For example:
$ bundle exec ruby foo.rb
A additional note for anyone using RVM: RVM generally will modify the shebangs in the scripts that launch programs like "ruby" or "rake" so that they use the "ruby_no_exec" shell (or similar) instead of the plain old "ruby" shell. That alternate shell is Bundler-aware and makes it generally unnecessary to type "bundle exec," but since the OP is using system Ruby, that's not applicable and commands should be manually prefixed with "bundle exec".
Hope this helps!
In addition to Kent's answer, I would recommend switching to RVM instead of using the system installed ruby. System rubies tend to be horribly out of date, especially when it comes to important things like features and security updates. It might not help you in your current situation, but it would be well worth the time. If you are unfamiliar: http://rvm.io

Call Ruby 1.8 script from Ruby 2.0 script

I'm not sure if this belongs here or somewhere else (SuperUser?) but anyway:
I've got two Ruby scripts, one which requires Ruby 2.0 (A) and another which requires 1.8 (B). A needs to call B with a forked processes. A is something like this:
require "fileutils"
require "json"
...
`name_of_B`
B is an executable script with a shebang, starting like this:
#!/Users/user_name/.rvm/rubies/ruby-1.8.7-p374/bin/ruby
require 'rubygems'
require 'json'
...
I use RVM to manage my Ruby versions:
> rvm list
rvm rubies
ruby-1.8.7-p374 [ i686 ]
ruby-1.9.3-p448 [ x86_64 ]
=* ruby-2.0.0-p247 [ x86_64 ]
I run A with:
> ruby name_of_A
but end up with:
/Users/jacobevelyn/.rvm/gems/ruby-2.0.0-p247/gems/json-1.8.1/lib/json/ext/parser.bundle: [BUG] Segmentation fault
ruby 1.8.7 (2013-06-27 patchlevel 374) [i686-darwin12.5.0]
Any thoughts on what I can do? I don't know a whole lot about gems but it appears that B tries to look at gems installed under Ruby 2.0, rather than 1.8. (Yes, I've run gem install json under 1.8 already.) Obviously the scripts are more complicated than they appear here and absolutely cannot be ported or combined (this doesn't mean I don't want to, it means I can't for my use case), otherwise I would.
you need to change the shebang to:
#!/Users/user_name/.rvm/wrappers/ruby-1.8.7-p374/ruby
it will not only use that ruby but also its gems.
in case you use bundler (Gemfile) you might also need to wrap the command invocation in:
Bundler.with_clean_env do
...
end
which will reset loaded bundler environment
Call:
result = `\path\to\ruby_1_8 \path\to\ruby_1_8_script.rb`
This will use the correct ruby binary to execute the script that expects it. The result is saved into the var.
You can call which ruby to find the version of the ruby in your current directory. Go to your project / source dir and call it to see the version (presumably Ruby 2) that you're using for the main app. Then, go to your old project / repo (associated with the 1.8 script) and run it again. Hopefully that will show you the path to Ruby 1.8. If not, try it from root (/). Or use RVM to confidently switch to Ruby 1.8 and then call it there to get the path.
I've never used RVM much. If it is confused, and filters things through the wrong gem set, etc, then you may need instead to switch to rbenv. Also, you may need to use its own functions to display the true path to the Ruby 1.8 binary (i.e. maybe it messes with which?) Again, I don't RVM.

How to search for gems inside of Ruby code, or where did Gem::RemoteInstaller go?

In the Ruby Cookbook recipe 18.1, it is said that
Gem::RemoteInstaller.new.search('rails')
can search for gems on the remote site, defaulted to rubygems.org
but I tried in ruby 1.8.6, 1.8.7, and 1.9.2, and it all says
in `<main>': uninitialized constant Gem::RemoteInstaller (NameError)
I already tried
require 'rubygems'
and even
require 'rubygems/remote_installer'
Is there a new way to search using Gem inside of Ruby?
(please don't give answers such as system("gem list rails")
Gem::RemoteInstaller has been removed from the rubygems since version 1.0. This was a while ago. If you are looking for the ability to set someone up with gems that they may not have, I would strongly suggest bundler (actually I think all ruby projects should use it) http://gembundler.com
OK, you can try:
require 'rubygems'
r = Gem::SpecFetcher.new
r.suggest_gems_from_name('rails')
=> ["rails"]

Check for Ruby Gem availability

Is there a way to check if some gem is currently installed, via the Gem module? From ruby code, not by executing 'gem list'...
To clarify - I don't want to load the library. I just want to check if it's available, so all the rescue LoadError solutions don't help me. Also I don't care if the gem itself will work or not, only whether it's installed.
In Ruby 1.9.3 only there is also:
Gem.available?('somegem')
You can use regex expressions too. Handy if I want to allow 'rcov' and GitHub variants like 'relevance-rcov':
Gem.available?(/-?rcov$/)
Looking at the Gem API documentation, using Gem::Specification::find_all_by_name to test for gem availability seems reasonable.
if Gem::Specification::find_all_by_name('gemname').any?
do stuff
end
find_all_by_name always returns an array (of Specification objects), as opposed to find_by_name which raises an exception if no match is found.
IMHO the best way is to try to load/require the GEM and rescue the Exception, as Ray has already shown. It's safe to rescue the LoadError exception because it's not raised by the GEM itself but it's the standard behavior of the require command.
You can also use the gem command instead.
begin
gem "somegem"
# with requirements
gem "somegem", ">=2.0"
rescue Gem::LoadError
# not installed
end
The gem command has the same behavior of the require command, with some slight differences. AFAIK, it still tries to autoload the main GEM file.
Digging into the rubygems.rb file (line 310) I found the following execution
matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
report_activate_error(gem) if matches.empty?
It can provide you some hints about how to make a dirty check without actually loading the library.
Since Gem.available? is deprecated (argh!), you have to rescue again (double aaargh). Yes, find_by_name throws an exception if the gem is not found. So to be backwards-compatible with older rubygems, the common solution seems to be :
def gem_available?(name)
Gem::Specification.find_by_name(name)
rescue Gem::LoadError
false
rescue
Gem.available?(name)
end
Note that the new method allows you to pass a specific version to see if that's loaded:
Gem::Specification.find_by_name('rails', '3.0.4')
You could:
begin
require "somegem"
rescue LoadError
# not installed
end
This wouldn't, however, tell you if the module was installed through gem or some other means.
I use this code and it works smoothly.
def gem_available?(gem_name, version = nil)
version.nil? gem(gem_name) : gem(gem_name, version)
rescue Gem::LoadError
false
end
Examples to use
Let's assume you have rack 1.9.1 installed.
puts gem_available?('rack') # => true
puts gem_available?('rack', '>=2') => # false
Didn't see this anywhere here, but you can also pass fuzzy version strings to find_by_name and find_all_by_name:
Gem::Specification.find_all_by_name('gemname', '>= 4.0').any?

Resources