I'm learning ruby recently and I'm a front-end developer, I found the dependecies are installed to C:/Ruby31-x64/lib/ruby/gems/3.1.0 folder when I use bundle install. it seems dependencies are installed globally by default like the npm install -g. I know that Bundler also have a way to install the gems to the local folder, so I wonder is
it recommend to install the dependencies to the local folder like npm does?
Similar to Composer, Bundler takes care of maintaining your dependencies, but rather than installing everything in the project folder, it distributes your gems system-wide, which are then shared by all of your projects. Using the Gemfile in your project folder, it keeps track of which libraries each project needs. Bundler is the default package manager for Rails, so you should simply let it do its thing. It does it quite well.
Hope this helps.
Use a Version Manager for Ruby, and Bundler for Gem Version Management
There are occasionally reasons to install gems in from one another isolation, but most often you should use a Ruby version manager to manage your non-system Rubies and Bundler to handle multiple gem versions and locations. Avoid modifying your system Ruby or its gems whenever possible. Also, be aware that even using RVM gemsets (or similar features in other version managers) without tweaking some poorly documented features like rvm gemset globalcache enable can create a level of isolation that is likely unnecessary and can bloat disk usage dramatically.
If You Need Gem Isolation...
That said, if you want to ensure you are isolating your gems or localizing them to your application and aren't using direnv's Ruby layout to manage all the various environment variables involved, you can use Bundler's BUNDLE_PATH environment variable to "vendor" your gems into the local application directory (these days usually under vendor/bundle). For deployments or containerization, you can also invoke bundle-install with the --deployment or --standalone flags and a list of gem groups to install if you don't want to rely on the availability of Bundler itself after installing the gems.
This sort of thing might be useful for building containers or tarballs, but isn't really very useful for development. Don't do it unless you have a really strong reason.
Related
I have a ruby program in my git repo, used by a team. It's executed directly out of the git repo. I don't want all the team members to have to deal with gems, so I want the production-level gems to be installed system-wide (on shared disk). Bundler will use the git-controlled Gemfile.lock to decide which gems to pick up.
For development, I often install gems using --user-install.
Problem: I might accidentally push changes that use gems which are only user-installed, which will break other team members when they pull and try to run.
How can I ensure that all non-development gems are installed system-wide?
Is there a bundle command I can run that will detect this and throw an error? Or can I somehow get my cucumber tests to run using only system gems?
There is no way to get Bundler to use System gems, though I think there should be: https://github.com/bundler/bundler/issues/1964
The most straightforward solution for you would be to package the gems into your Git repo: http://bundler.io/v1.12/bundle_package.html.
This is really how the bundler team recommend that it should be run in a case where you want a user to be able to run your app without having to install gems locally.
A second option would be for you to use the --path option to bundle install and point that to a shared location visible to all your users. This option is remembered, so check .bundle into your Git repo and then your users would use the same configuration and reference the same location when they run bundle. Since all of the gems would already be installed there by you, they would have no problems.
I am writing a dev command-line tool gem (let's say called "tool") which I would like to use in any place in the system. I use RVM for different projects, but this tool should be available from the command-line inside those projects.
If I simply install the gem globally using "gem install" (let's say it installs to /usr/local/bin/tool), the executable is of course available inside of other projects, but since the gemset changed when executing "tool" it fails saying that it cannot find the "tool" gem (because "tool" was never installed to that gemset). I don't want to add the gem to all the Gemfiles of all the projects.
What's the best way of dealing with this? Perhaps there is a way to "lock" the gem_path/gem_home in the executable at the time of installation?
It turned out that https://github.com/sportngin/brew-gem does what I want, installing a Rubygems gem via brew and locking its GEM_HOME and GEM_PATH in a bin wrapper it generates, so that everything works even when executed in the context of a different RVM gemset.
I forked it into https://github.com/gtmax/brew-gem, adding support for installing a brew gem from a local.gem file or from a gem project on github.
I am trying to make an CLI tool with ruby.
My tool require some library in bundle (log4r, ...). So problem appear when i switch my ruby version (2.0.0 -> 2.1.2) or when switch gemset, some gem are not install in new ruby environment.
So how can i make my app work like vagrant, which work in every version of ruby i am using?
If you package your application as a Gem, you can include a Gemspec that describes your application. One of the things you can specify is its runtime dependencies; when the user runs gem install myapp, then the gem command will make sure it includes everything you specified (like log4r).
It will be harder to make this happen without Rubygems. You can package your application along with a defined version of Ruby and all its requirements - that's what Vagrant does - but that makes your application a larger download and means you have more to maintain. It's going to be hard work if you want to install your app system-wide and have it work with every single Ruby environment. It's far better to let the gem application install your app (whether systemwide, or via rbenv/rvm) and let that manage your dependencies for you. There's the default gems plugin for rbenv and rvm gemsets to help manage this.
The rbenv documentation states that you can use the gemsets plugin to sandbox your gems if you aren't using bundler:
Manage gemsets. Bundler is a better way to manage application dependencies. If you have projects that are not yet using Bundler you can install the rbenv-gemset plugin.
However, I am using bundler and when I switch between projects that have different gemsets I need to re-bundle. When I was using rvm, this was simple due to the .gemsets file.
Is there a sandboxing functionality in bundler that I am not aware of or have I misunderstood the documentation?
I found this clear, well-documented solution:
Setting up and installing rbenv, ruby-build, rubies, rbenv-gemset, and bundler
Now when you gem install (see “Bundler” section below) something it will go to your helloset gem area.
You can combine use of multiple gemsets with it.
The big benefit to this setup is enabling each project to use a different set of differently versioned gems.
Read the section entitled Enable RVM-style “gemsets” (optional).
It uses the rbenv plugin for gemsets: https://github.com/jamis/rbenv-gemset.
Update 8/12/2012 I am using this to manage two projects with different versions of Ruby, and separate sets of gems. It works well.
bundler uses the Gemfile and Gemfile.lock files in, in essense, to make a "gemset" for that particular project that you access via commands prefixed with bundle exec
It may have to do with the way rbevn uses shims. You might want check out
https://github.com/carsomyr/rbenv-bundler
Try using chgems with Bundler. chgems is like chroot for RubyGems. It spawns a new sub-shell with PATH, GEM_HOME and GEM_PATH updated to use $project/.gem/$ruby/$version as the primary GEM_HOME. Since all gems are installed inside of the project directory, cleaning up after a project is as easy as rm -rf $project/.
I am not sure what the differences are between these two tools. There seems to be a big overlap, but I have been using RVM and facing some miss-compatibility issues.
What does Bundler do that RVM does not?
They serve different purposes. RVM creates a sandbox to manage your Ruby installations. As a part of that, it also lets you define gemsets.
Bundler doesn't manage your Rubies, it works with the currently selected Ruby.
So, I think you should consider RVM as the configuration manager for your development environment, and Bundler the gem manager for an application.
EDIT: Additional thoughts -
Whether we use RVM or not, typically we'd have to load all the gems we're going to use for an app by hand, using gem install blah, for every gem we want to use.
I end up managing my gems across multiple Rubies by hand. Once they're installed I can create gemsets using RVM, but RVM won't automatically retrieve a particular version of a gem if it's not installed, or go get it again if it was removed. Because RVM is more concerned with your Ruby environment, it mostly leaves the versioning of gems to gem and to us.
Bundler, on the other hand, does care about those missing parts in RVM. When you create the Gemfile for bundler, it will retrieve the necessary gems and specific versions if specified. So, the task of installing a Ruby app on a different machine becomes much simpler. Push the files to the other machine, then run bundle install and it'll do the rest.
It works nicely with Rails and is a sensible solution for my production files. It will be much simpler than how I have to handle Perl distributions in order to run Perl apps on the same hosts.
RVM is more like a containment unit. While Bundler is like a manifest (dependency manager) of what the application will require or use in it's lifecycle (among other things).
If you are working in Rails, you will not be able to escape Bundler. But I use it all the time just so I know what Gems I'll need, and so will others who later come into the project.
RVM helps me separate out my Rubies and then further into Rubies/projects. This way I don't have a slew of Gems and different versions all in one pile.
Not exactly the most action packed answer, but hope it helps a little.
To directly answer your question...
What does Bundler do that RVM does
not?
Bunlder will install all gems that are needed by a project (that uses bundler, and have all needed gems specified in a Gemfile). RVM does not do this.
Using the Gemfile you can specify what gem groups (ie: development, testing)...
There are many 'small' things like these that bundler does but RVM does not. In general as the good people above explained, RVM has a different set of goals from that of bundler. RVMs about managing ruby runtimes while bundler is about managing dependent gems for a application.
Bundler is a tool for managing dependencies in your code -- i.e., all the gems it requires. It will make sure that all the gems you specify in your Gemfile, and any dependencies, are installed on your system. It doesn't really care which version of ruby you are using, it just installs the gems for you under whichever interpreter is in use.
RVM is a tool for running multiple rubies, and in theory, multiple gemsets as well. It doesn't handle dependencies for you at all -- it's still up to you to install the gems.
My experience (and I'm new to RVM), is that you don't want to bother with RVM unless you have a need for running multiple rubies, or need gems installed for different projects that somehow conflict with each other. Even if you are using RVM, it makes sense to use Bundler to manage gem dependencies so that your Gemfile can be tracked in whatever code repository you are using.