What does it mean when a Ruby script starts with Gem? - ruby

I am working on learning Ruby and one thing that I have seen in several instances and cannot understand are scripts that start with the keyword gem.
An example can been seen in the Sensu code.
gem "amqp", "1.3.0"
require "amqp"
require File.join(File.dirname(__FILE__), "base")
I understand the require statement for accessing another gem, but what does the exact gem "amqp", "1.3.0" mean?

This is the gem method that Rubygems adds to Kernel (Rubygems is required by default in current Ruby versions). It activates a specific version of a gem (version 1.3.0 of the amqp gem in this case), meaning that the gems lib dir (or whatever dirs the gem specifies) is added to your LOAD_PATH, as are the lib dirs of any dependent gems it has.
It also checks that there are no version incompatibilities with any already activated gems.
All gems are activated when you use them. This normally happens when you call require. Calling gem activates the gem but doesn’t require any files from it, hence the line require "amqp" below (note the difference between amqp the gem, which the gem method refers to, and amqp the file, which is contained in the amqp gem and is what the require method is refering to).
This method is used to ensure you are using a specific version of a gem, without needing to use Bundler (or something similar). Bundler also has a gem method used in Gemfiles, but this is a different (but similar) method.
It’s also used to specify that you want to use the gem version of a library that is also part of the standard library (say if you want to use a more recent version). For example the Yaml library distributed with Ruby is Psych which is also available as a gem.

Related

When is the 'require' necessary when using a ruby gem?

I noticed for some gems you must include it in the file where you want to use it like this require 'a_gem', but this is not always the case.
I am going to compose a gem by myself. What should I do if I do not want to add the require 'my_gem' to the .rb file when using it?
Usually, an application that is using a gem needs to require the gem:
require "my_awesome_gem"
MyAwesomeGem.do_something_great
However, if an application is using bundler, which defines the application's gem in a file called "Gemfile":
source 'http://rubygems.org'
gem 'my_awesome_gem'
then the application may invoke bundler in a way that automatically requires all of the gems specified in the Gemfile:
require "bundler"
Bundler.require
MyAwesomeGem.do_something_great
Rails projects use Bundler.require, so a Rails application will not need to explicitly require a gem in order to use it: Just add the gem to the Gemfile and go.
For more about Bundler.require, see the bundler documentation
For more about how Rails uses Bundler, see How Does Rails Handle Gems? by Justin Weiss.
This doesn't make sense. If you want to write a Gem and use it, it needs to be required somewhere.
This "somewhere" could be explicit in one of your scripts, it could be written in a Gemfile or it could be required by another script/gem that is required by your script.
If you write a gem, Ruby will not include it automatically in all your scripts.
Finally, if you publish it, should every single Ruby script on earth magically require it and execute your code?
I suppose that the project you have seen which didn't use require 'a_gem' was using a Gemfile.

ruby gem statement - what does it do?

I think I have a basic understanding of what require/include statements at the top of a ruby script are doing, like
require 'rspec'
These statements are easy to google and find relevant results. But sometimes I have seen a gem statement like
gem 'rspec'
What does this line do?
In ruby code, gem(gem_name, *requirements) defined in Kernel tells Ruby to load a specific version of gem_name. That's useful when you have installed more than one version of the same gem.
For example, if you have installed two versions of rspec, say 2.12.0 and 2.13.0, you can call gem before require to use specific version. Note that gem should come before the require call.
gem 'rspec', '=2.12.0'
require 'rspec'
A gem 'gem_name' without version uses the latest version on your machine, and that's unnecessary. You can call require without gem to get the same behavior.
And besides, in Bundler::Dsl, gem is used to tell bundler to prepare/install specific version of ruby gems. You'll see that in Gemfile
The original behaviour of require, before Rubygems, was to search all the directories listed in the $LOAD_FILES variable for the file, and to load the first one it finds that matches. If no matching file was found, require would raise a LoadError.
Rubygems changes this process. With Rubygems, require will search the existing $LOAD_PATH as before, but if there is no matching file found then Rubygems will search the installed gems on your machine for a match. If a gem is found that contains a matching file, that gem is activated, and then the $LOAD_PATH search is repeated. The main effect of activating a gem is that the gems lib directory is added to your load path. In this way the second search of the load path will find the file being required.
Normally this will mean that the latest version of a gem that you have installed gets activated. Sometimes you will want to use a different version of a gem, and to do that you can use the gem method. The gem method activates a gem, and you can specify the version you want, but doesn’t require any files. When you later require the files you want, you’ll get them from the gem version you specified.
In Ruby, gems are packages with functionality that can be used out of the box (as libraries in other Programming languages).
The gems that you use with your Ruby Project can easily be managed with a tool called "bundler", just google it. The snippet of code you posted is part of the spec file that bundler uses to install and update all the libraries that you specify for your project.
If you are developing a Ruby on Rails, using gems an managing them with bundler is very common and so to say best practice.
Gems are just great because there are so many useful libraries that extend default functionality, eg of rails, and that you can use out of the box!
For a list of gems, visit rubygems.org

Difference between gem and require (require open-uri)

I just wanted to understand for my self.
I'm using the nokogiri gem (for parsing HTML). If I got it right to open URLs I need to use a method from the gem 'open-uri'.
But when I include it in my Gemfile (on Windows developer's machine):
gem 'open-uri' - there is an error while bundle install that it can not find gem.
So If I use require 'open-uri' - its working.
So can some explain what is going on?
You're using bundler for your gem dependecies and you're doing it right but OpenUri is part of the Ruby standard library. That's why you only need to require it if you want to use it in your code.
require is used to load another file and execute all its statements. This serves to import all class and method definitions in the file. require also keeps track of which files have been previously required so it doesn't execute it twice.
A RubyGem is a software package, commonly called a “gem”. Gems contain a packaged Ruby application or library. The RubyGems software itself allows you to easily download, install, and manipulate gems on your system.
- What is a Gem?:
The Gemfile is then used by bundler to install the specified gems.
open-uri is not a gem but part of the Ruby Standard Library so it just needs to be required.

Managing conflicting versions of ruby gems

I am building a framework that loads user provided ruby code. It is basically a plugin mechanism. I want the user provide ruby code to be able to require gems of its own. I intend to have the "plugin" package include a vendor directory with the gems.
How can I load gems that are required by the plugin without having them conflict with my framework's gems? For example, if my framework uses treetop version 1.3.0, and a plugin uses treetop 1.4.2 I want each to work with their specified version.
Likewise, is there a way to prevent plugins from conflicting with each other?
I have looked at gem_plugin, _why's sandbox, and some other tools. But I don't see any library that specifically handles this case - I assume its been done before.
I have also looked at the internals of Bundler to see how it manages gem versions. I am prepared to do some pretty complex stuff if need be. But I am still uncertain of how to go about it.
I also have a lot of freedom in how I implement this. So if you think I am barking up the wrong tree, please say so.
Thanks for any advice.
SIDE NOTE: It occurred to me while writing this that I need something similar to the Classloaders in a Java servlet container. A WAR file can include jar files, and the web application's class loader will prefer those over the jars that are on the global classpath. Is there any way in ruby to segment the ruby "classpath" (i.e. load_path, require, etc)?
To be blunt, you can't have two versions of the same gem loaded at the same time.
Bundler does a good (ish) job of looking through all of the required gems and finding a solution to the various overlapping dependencies, but even so it is limited to only loading one version of a gem at a time.
This leads to plugin developers constantly having to update to support any changes that are made in dependent gems in order to avoid just the situation you describe.
(Don't get me started on the screw up that results from the various competing JSON implementations and the pain you have to go through when you have several gem dependencies all requiring different ones.)
Respectfully disagree with the answer above. Here is how I do it:
ruby -S gem list my_gem
`*** LOCAL GEMS ***
my_gem (1.0.1, 1.0.0, 0.0.2)
`
ruby -S gem lock my_gem-1.0.0 > locklist.rb
which generates list of dependencies for a specific version into locklist
require 'rubygems'
gem 'my_gem', '= 1.0.0'
gem 'gem_base', '= 1.0.0'
gem 'rest-client', '= 1.7.2'
gem 'savon', '= 1.1.0'
gem 'addressable', '= 2.3.6'
gem 'mime-types', '= 1.25.1'
gem 'netrc', '= 0.11.0'
now you can do load('locklist.rb') which will load a specific version of a gem along with its dependencies. Look ma, no Bundler.

Writing a Jeweler Rakefile that adds dependencies depending on RUBY_ENGINE (ruby or jruby)

I have a Rakefile that includes this:
Jeweler::Tasks.new do |gem|
# ...
gem.add_dependency('json')
end
The gemspec that this generates builds a gem that can't be installed on jruby because the 'json' gem is native.
For jruby, this would have to be:
Jeweler::Tasks.new do |gem|
# ...
gem.add_dependency('json-jruby')
end
How do I conditionally add the dependency for 'json-jruby' when RUBY_ENGINE == 'java'?
It seems like my only option is to manually edit the gemspec file that jeweler generates to add the RUBY_ENGINE check. But I'd rather avoid this, since it kind of defeats the purpose of using jeweler in the first place.
Any ideas?
After some more digging around, I've come to the conclusion that the problem here isn't so much the limitation in Jeweler as it is a problem with how the json-jruby gem is named.
In a perfect world, the json-jruby gem should be named just json. That way when the gem file is built under JRuby (i.e. jgem build json-jruby.gem), the resulting gem file would be named json-1.4.3-universal-java-1.6.gem (RubyGems names the file based on the 'platform' property in the gemspec). When installed with the appropriate platform in the gem name, everything works transparently. There's no need to explicitly require json-jruby. RubyGems uses the appropriate version automatically.
I've contacted the maintainer of the json gem to see if he'd be willing to get json-1.4.3-universal-java-1.6.gem added to his gemcutter repo, but in the meantime you can download the drop-in jruby json gem here: http://roughest.net/json-1.4.3-universal-java-1.6.gem

Resources