Does Bundler Gem take in consideration your Ruby environment? - ruby-on-rails

My question is simple one, does gem bundler considers your ruby environment (e.g. 1.8.7 | 1.9.2) before deciding which gem to take based on gem file?
Let's say your gemfile contains
gem 'thor'
gem 'json'
gem 'grit'
When you run bundle install will take versions of the gem that are compatible with your current ruby environment or just latest gems?

It depends! Bundler relies on the configuration of the Gemspecs that each Gem provides.
Gemspecs offer the posibility to provide different or additional dependencies based on the runtime environment. IE you can change the dependencies for JRuby or provide different binaries for i386 architectures.
As far as i know, it's not possible to declare a gem as 1.9 or 1.8 compatible (which would have made sense to me). I think it's partly so, because 1.9 is 99% downward compatible.
You are always forced to have a look at the gems themselves. Because of this, there are sites like http://isitruby19.com/
As you might see, it's not an issue of Bundler, but RubyGems.

Related

Manage gem dependencies based on Ruby version

I'm working on a gem that works on Ruby 1.9.3, but installing an up-to-date Gemfile works only on Ruby 2.2. Is there a way of separating dependencies based on Ruby versions?
I've seen this approach in the past:
pry_debugger = RUBY_VERSION < '2.0.0' ? 'pry-debugger' : 'pry-byebug'
spec.add_development_dependency pry_debugger
Or should I just consider supporting one Ruby version (let's say 2.0) and find the supported gems? What's the easiest way of finding what gems work on my local Ruby version?
Logic like you show will work fine for development dependencies since it will be evaluated at bundle install time.
It will not work for runtime dependencies since the logic will be evaluated at gem-build time and not when the gem runs in another environment.
RubyGems does not provide a way for you to specify different gems based on the runtime environment, so the only way you could support that would be to release two differently named versions of your gem with different gemspecs.
Personally, I don't see the point of putting development dependencies in the .gemspec, so I always just add these to my Gemfile and reserve the gemspec for runtime dependencies only.
This separates the concerns better and makes it clear that gem selection logic can be used in the Gemfile, but not in the gemspec.

How can I find out what gem is dependent on termios in my Gemfile?

I have updated all of my gems, including to Rails 3.2.8, prior to a new deployment. However, my application is now broken because something is trying to install gem "termios" version 0.9.4.
Apparently, 0.9.4 does not work on any computer or server I own. There are some newer versions, 0.9.6 specifically, but they are not posted in wherever bundler looks for gems.
There are some version on Github, but they have been mysteriously renamed "ruby-termios". Well, some gem in my Gemfile is not looking for ruby-termios. It's looking for termios. Failure.
How can I find out which gem is trying to install this so I can see if it can be whacked?
Check your Gemfile.lock - it has all the gems and their dependencies listed in it. As long as you've been able to install these gems in the past, you'll be able to tell where that dependency is coming from.
The gem command will dump out the tree of dependencies for you.
$ gem dependency
Or if you want to check just a specific gem.
$ gem dependency foo

Why prawnto gem installs rails 3.x when there is already a rails 2.x?

I have rails (2.3.5) and prawn (0.12.0) installed. When I install prawnto, gem installs rails version 3.2.6 also.
The dependency of prawnto is:
prawn >= 0
rails >= 2.1
Why gem install Rails 3.x when the prawnto dependency is already there?
tl;dr Use Bundler. It rocks.
Alright, this is basically down to how dependency resolution works in RubyGems. If you're not terribly familiar with it, get up to speed real quick like with the Primer panel from this XKCD comic. RubyGems dependency management and the Primer storyline are very similar in terms of complexity.
When a gem specifies a dependency of, say rails >= 2.1, when you go to install that gem, RubyGems conveniently ignores all the gems that you've currently got installed and then queries the web API to find the absolute latest version of Rails that's greater than or equal to 2.1.
It will find, as of this writing, version 3.2.6, and so will dutifully install that version of Rails because it fits the dependency requirements. It will also install every single dependency of Rails, and their dependencies, and the sub-sub-sub-sub-dependencies all the way down until there's not a gem left without a dependency installed.
I won't go into exactly how that works because it makes my vision go blurry when I think about it.
Now, if you were using something that's not pure-RubyGems such as Bundler, you'd be able to have a Gemfile like this:
source 'http://rubygems.org'
gem 'rails', '2.3.4'
gem 'prawnto', '0.1.1'
And then run bundle install and then something magical will happen. Bundler will figure out the dependencies for all the gems specified in the Gemfile, as well as the gems that they depend on, and then install only those gems.
This means that if you have prawnto wanting Rails >= 2.1, it won't install 3.2.6 because there's another dependency saying that Rails must precisely be 2.3.4. So therefore Rails 2.3.4 will be installed.
If you have conflicting versions, with a gem A specifying a dependency on gem B of ~> 1.0, but then gem C specifying a dependency that gem B must be '= 0.5.0', Bundler won't be very happy and will raise an error because the dependencies can't be resolved.
I'd really recommend using Bundler for all your Rails projects. Even those that are running on Rails 2. There's a page on the Bundler website which will get you started with a Rails 2.3 project and Bundler.

Beginning with Ruby on Rails. How do Gemfile and how gems work when specifying versions to download?

I tried reading the documentation but this still wasn't clear to me:
Suppose my I have the following statements in my Gemfile:
source 'https://rubygems.org'
gem 'rails', '3.2.2'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'sqlite3'
gem 'json'
...
I'm trying to learn how to use Ruby on Rails this website: http://ruby.railstutorial.org/ and it says that I need to have the sqlite3 gem for this version of rails (3.2.2).
My question is: if I don't specify the exact version of the sqlite3 gem for the system to download when I run bundle install then will it install the latest version that works with the version of rails and ruby that I'm working with (suppose it's 3.2.2 and 1.8.7 p-352 respectively) or will it just download the latest version of the sqlite3 gem available whether it works with what I have installed or not?
I'm not really sure how this aspect of the Gemfile works and the documentation hasn't been clear or I haven't found where it explicitly says this or otherwise.
So, it will install the latest version of sqlite3 that is compatible with the dependencies specified by the other gems you've listed.
Say, rails said it only worked with sqlite3 that was greater than 1.0 but less than 4.0, it might install 3.9.5. I'm making all these numbers up, just an example.
In fact, I don't know if rails does specify any particular versions of sqlite3 it requires. Presumably 'json' doesn't either, since it's got nothing to do with databases. If none of the other gems you list specify any requirements for sqlite3, it'll just install the latest version available.
'bundle install' is using bundler, some more about how it resolves dependencies is here.
So bundler will download the latest gem that meets the requirements of all the other gems you list. Say you listed a gem A which required sqlite3 earlier than 2.0 and a gem B that required sqlite3 later than 2.1 -- 'bundle install' would complain and say it can't satisfy them all.
This relies on the gems own advertisements of each of their own requirements for the other gems they rely on though. Sometimes they can be wrong, or missing. It may be that rails doesn't actually specify what version of sqlite3 it requires -- since it doesn't actually require sqlite3 at all (you don't have to use sqlite with rails), this may very well be. In which case bundler can't do much but get the latest version of sqlite3. Which doesn't guarantee that version will work. But it can only do so much.
You also mention the issue of compatibility with specific versions of ruby, like 1.8.7-p352. Bundler is less capable there, you can't generally count on it knowing what version is compatible with a particular version of ruby (because there's not a great way for gems to express this in a way that bundler can use, alas).
But in general, things work out. If you don't know or care what version of sqlite3 (or any other gem) you want, but know you want one -- do what you did, run 'bundle install', see if it works. It probably will. If it doesn't, google the error message and you'll probably find someone explaining why it didn't and what you need to do instead.
PS: If that wasn't enough. sqlite3 is sort of an odd case, because while Rails is designed to work with it, it's not required. But Rails by default, when creating a new app with latest version of rails rails new my_app, will already put sqlite3 in your Gemfile for you. And it'll do it just like you did, without a version constraint. That's reason to feel pretty confident it will work fine. Note that in rails 3.2.2, rails new my_app will put some other things in your Gemfile that do have more specific versions listed, like gem 'sass-rails', '~> 3.2.3', because while those things aren't absolutely required for Rails (or else they'd be expressed as requirements and not need to be explicitly in your app's Gemfile), the rails installer knows that only certain versions will work.
Fairly new to Rails as well so correct me if I am wrong.
The Gemfile looks to the gems directory for the gems listed and has no impact on actually "installing" them. Performing a "gem install" command without a version will grab the most recent version listed no matter what your Gemfile says. When you "bundle install", that is when version-specific lookups happen in your gems directory.
Bundler always looks at your Gemfile.lock file first when you're doing bundle install. If you open that file, you'll see the gems as well as the version used by your application. This is convenient for existing projects because you're always sure that every other developer involved with the project will be working with the same gem versions.
If it doesn't find that file (i.e. doing rails new projectname), or the specified gem or version in Gemfile isn't consistent with Gemfile.lock, it will download the latest or specified version of the gem.

Gem compatibility in rails 2.3.4

I have currently moved to a appplication on rails 2.3.4 and ruby 1.8.7 using rvm.
There are a no of gems installed in the app.When i do gem install gem_name ,it installs it but iam not sure whether the gem version is compatible with my app.The gem versions are not specified in case of many gems listed config/environment.rb.Iam unable to figure out ,how to install the correct version as unable to run the application till now. Any suggestions are welcome..
To provide true gem-consistency in your app, you should consider use Bundler to manage these dependencies. The Gembundler site has a good guide on setup for rails 2.x apps.
Once you have your dependencies in bundler, you can start to work out what is compatible and what isn't. In the case of third-party gems, you can search for them on the RubyGems site, and work out which version was the last to be released before Rails 3.x was released. Of course most gems will just work, but any breaking gems will possibly need to run an older version.
I would use Bundler, and add the gems to the Gemfile. Here is the syntax to use a specific version:
gem 'gem-name', '1.0.4'

Resources