ruby: code to install gem if missing - ruby

is there some ruby code I can use to install a gem from a local file, if that gem is not installed?
i'm thinking it would look something like:
if !gem_installed("some gem name")
system "gem install -l local_copy.gem"
end
i don't know if anything exists that lets me check for gems like this or not...

Checking availability is covered in this previous StackOverflow Quesiton
begin
gem "somegem"
# with requirements
gem "somegem", ">=2.0"
rescue Gem::LoadError
# not installed
end
or
matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
As for the install, it looks like rails uses the system for gem install also
puts %x(#{cmd})

This is my way of doing this
['json','date','mail'].each { |req|
begin
gem req
rescue Gem::LoadError
puts " -> install gem " + req
Gem.install(req)
gem req
end
require req
}

Related

How can I install a gem (via bundler using gemspec) before parsing the gemspec?

I have a gem that exists for the purpose of helping with versioning. It's useful to have this gem available when defining the version in the gemspec file.
The problem, however, is that running bundle install first causes the gemspec to be parsed, which results in an error because the required gem isn't installed yet.
I can get around it by running gem install <other_gem> before bundle install, but I'd much prefer bundler manage it, especially when taking into account that I'm using a custom gem server.
I've tried adding the gem to the Gemfile directly before the gemspec line, but no luck.
Gemfile:
source 'https://my.gemserver.com/gems'
gemspec
mygem.gemspec:
require 'external/dependency'
Gem::Specification.new do |spec|
spec.name = 'mygem'
spec.version = External::Dependency.version_helper
....
spec.add_development_dependency 'external-dependency'
end
EDIT:
Another workaround is to rescue the LoadError and specify a default version if the dependency isn't loaded. Also, not ideal
begin
require 'external/dependency'
rescue LoadError; end
Gem::Specification.new do |spec|
spec.name = 'mygem'
spec.version = defined?(External::Dependency) ? External::Dependency.version_helper : ''
....
spec.add_development_dependency 'external-dependency'
end
I think you're stuck with gem install. But I would solve this by adding that step to the Dockerfile I use for the project.
Maybe it's possible to do something like this using rbenv or rvm? Haven't used either of those since migrating to Docker, but rvm gemset is kind of a bootstrap...
I got around it by making the gemspec install the gem during a bundle update or install.
EXTERNAL_DEPENDENCY = Gem::Dependency.new('external-dependency', '~> 0.1')
if File.basename($0) == 'bundle' && ARGV.include?('update') || ARGV.include?('install')
require 'rubygems/dependency_installer'
Gem::DependencyInstaller.new.install(EXTERNAL_DEPENDENCY)
end
and then...
spec.add_development_dependency EXTERNAL_DEPENDENCY.name, EXTERNAL_DEPENDENCY.requirements_list

Install ruby gem in rescue block when 'LoadError' occurs

I am trying to install a ruby gem from a ruby script when it can't load the required gem from local system. Here is my code.
begin
require '<gem name here>'
rescue LoadError
puts `gem install <gem name here>`
require '<gem name here>'
end
The code above installs the gem in the rescue block. But when it requires the gem, it shows this error:
.rvm/rubies/ruby-2.4.2/lib/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb
:55:in require': cannot load such file -- <gem name here> (LoadError)
How can this be solved? I want the gem to be loaded within the rescue block if not already present in the system.
After rigorous searching, I found an answer. If we use Gem.clear_paths after installing the gem, it will now available to the script. Total updated code is :
begin
require '<gem name here>'
rescue LoadError
puts `gem install <gem name here>`
Gem.clear_paths
require '<gem name here>'
end

gemspec extensions - conditionally install gem

I'm forking the gem and I'd like to add some conditional dependencies to gemspec file, depending on ruby version. I found that it could by done using spec.extensions. So in gem directory I created a file: ext/mkrf_conf.rb:
require 'rubygems/dependency_installer.rb'
begin
Gem::Command.build_args = ARGV
rescue NoMethodError
end
inst = Gem::DependencyInstaller.new
begin
if RUBY_VERSION < "2.1.0"
inst.install "activerecord", ">2.0", "< 4.0"
else
inst.install "activerecord", ">4.0"
end
rescue
exit(1)
end
f = File.open(File.join(File.dirname(__FILE__), "Rakefile"), "w") # create dummy rakefile to indicate success
f.write("task :default\n")
f.close
Then I added the extension to gemspec file:
spec.extensions << 'ext/mkrf_conf.rb'
I created a test project, with Gemfile when I have:
gem 'my_gem', path: '/Users/xxx/Documents/my_projects/my_gem'
I'd like to test if this is work, but when I do bundle install, activerecord is not installing at all. As this extension is not exist. Can somebody can point me what I'm doing wrong. Thanks!
This might be not an exact answer on your question, but I wonder whether you see that Gemfile is a plain ruby file. That said, you might simply drop your logic in your Gemfile:
if RUBY_VERSION < "2.1.0"
gem "activerecord", ">2.0", "< 4.0"
else
gem "activerecord", ">4.0"
end
gem ...
Hope it solves your issue.

How to unzip a file with ruby

Okay I've found the following code for unzippping a file with Ruby.
def unzip_file (file, destination)
Zip::ZipFile.open(file_path) { |zip_file|
zip_file.each { |f|
f_path=File.join("destination_path", f.name)
FileUtils.mkdir_p(File.dirname(f_path))
zip_file.extract(f, f_path) unless File.exist?(f_path)
}
}
end
Above this I'm using the following to ensure the needed gems are installed.
begin
require 'rubygems'
rescue LoadError
'gem install rubygems'
end
begin
require 'zip/zip'
rescue LoadError
'gem install rubyzip'
end
So when I call unzip_file I get the following error:
in `unzip_file': uninitialized constant Zip (NameError)
What am I doing wrong?
Thanks!
Beware: the sample script will also unpack symlinks, and will unpack ../../../../etc/passwd without complaining. The rubyzip gem expects you to do your own pathname laundering.
Note that in rubyzip 1.1.4, Zip::Zipfile was renamed to Zip::File.
The problem with installing the gem that way is that you're shelling out to another process with:
`gem install rubyzip`
and after that finishes installing the gem, your current irb session still won't see it. You'd have to reload irb with exec "irb" and then calling require 'zip' again.
Note: those are backticks not single quotes.
Try this:
begin
require 'zip'
rescue LoadError
`gem install rubyzip`
exec "irb"
retry
end
For me require 'zip' works. I have rubyzip-1.1.2
Now you should be able to use Zip
Also, the gem command is rubygems. So you can't install rubygems with itself. It should already be installed, but if not try this: http://rubygems.org/pages/download

Why can't I load Nokogiri?

I installed Nokogiri without any issues by running:
$ sudo gem install nokogiri
Building native extensions. This could take a while...
Successfully installed nokogiri-1.5.9
1 gem installed
Installing ri documentation for nokogiri-1.5.9...
Installing RDoc documentation for nokogiri-1.5.9...
When I run nokogiri.rb:
#!/usr/bin/ruby -w
require 'nokogiri'
puts "Current directory is: #{ Dir.pwd }"
Dir.chdir("/home/askar/xml_files1") do |dirname|
puts "Now in: #{ Dir.pwd }"
xml_files = Dir.glob("ShipmentRequest*.xml")
if xml_files.empty?
puts "#{ dirname } is empty."
else
xml_files.each do |file|
doc = Nokogiri::XML(open(file))
# ... do something with the doc ...
end
end
end
I got the error:
$ ruby nokogiri.rb
/home/askar/.rvm/rubies/ruby-1.9.3-p429/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require': cannot load such file -- nokogiri (LoadError)
from /home/askar/.rvm/rubies/ruby-1.9.3-p429/lib/ruby/site_ruby/1.9.1/rubygems/custom_require.rb:36:in `require'
I'm using Ruby 1.9.3, but for some reason it refers to Ruby 1.9.1. Can this be the cause?
If you observe closely, the path starts with /home/askar/.rvm/rubies/ruby-1.9.3-p429 so the load path should be correct.
Your problem is that you used sudo which will do a gem installation for the system ruby. Try again without sudo, just
gem install nokogiri
to install gems for the current rvm ruby.

Resources