unpacking/freezing gems into a non-rails ruby app - ruby

I'm writing a non-Rails ruby application (gasp!) and would like to be able to include all the gem dependencies which the application requires in a vendor subdirectory. This would be similar to how http://gemsonrails.rubyforge.org/ works for Rails apps.
The goal here is to avoid the situation my team currently experiences when a new dependency is added. Every developer on my team has to install the gem manually, and then someone has to manually update each test and staging and production machine. If we can freeze the dependencies into the distributed application itself then a simple svn update (or git pull for those hipsters in the crowd) would be all that is needed.

UPDATE (New Solution):
Try Yehuda Katz's new bundler gem. gem install bundler then create a Gemfile with all your dependencies. See the documentation for more info.
Old Recommendation:
One easy way is to just manually unpack the gems into your vendor directory and add the lib path of the unpacked gems to the front of the $LOAD_PATH.
To unpack a gem:
$ cd vendor/gems
$ gem unpack active_support
Unpacked gem: '/path/to/myproject/vendor/gems/activesupport-2.3.2'
Just make sure you unpack all the necessary gems and their dependencies (using the correct versions).
To add all gems under vendor/gems to your $LOAD_PATH, try adding something like this to your application's initialization:
Dir.glob(File.join("vendor", "gems", "*", "lib")).each do |lib|
$LOAD_PATH.unshift(File.expand_path(lib))
end
Update: Sarah (in the comments) convinced me it might also be necessary to override the GEM_PATH. Here's one way to do that:
require 'rubygems'
gem_paths = [File.expand_path(File.join("vendor", "gems")), Gem.default_dir]
Gem.clear_paths
Gem.send :set_paths, gem_paths.join(":")
Another option is to look into Rip (Ruby’s Intelligent Packaging) for managing your dependencies. Rip looks really sweet, but it's still new.

Related

How do I make a gem with a binary, when it depends on bundler to find its dependencies?

I have a gem which depends on Bundler's Gemfile to find its dependencies (they are hosted on github:enterprise). I want it to be usable as a lib and also to provide a binary.
Currently it works fine as a binary if I am running it from its own directory, where the binary can load the bundled gems. However, if I run it from a different directory, it can't find the dependencies (they are in their own rvm gemset). I can't install it as a gem because Rubygems can't find the dependencies (currently they are listed in the .gemspec, and then told where to be found in the Gemfile).
I am currently trying bundle package, and it placed all the gems in the vendor/cache directory. As far as I can tell, this will mean that I need to remove the dependencies from the .gemspec and instead into the Gemfile (because Rubygems shouldn't install them since they are vendored). This means that any code using this gem will need to know about these dependencies, and add them to their Gemspecs, but I'm okay with that. I think this could work if I modify the .gemspec to include the vendored gems when building, and if I can manage the load path such that the binary sets the vendored gems at the front of the load path, but any code using it as a library will not add these to the load path, so they will get whatever versions they've installed.
Unfortunately, I don't know how to do that (short of reading in all the gemspecs, reflecting on their require_paths to add them to the $LOAD_PATH), and I'm not really sure that this is the correct way to handle this situation.
So, how do I make a gem that can be used as a lib, or just for its binary, when it needs Bundler to find its gems?
if you are hosting the code in your own github enterprise instance, then it might be a good idea to have a custom rubygems server. you can then publish your internal gems to that server and have bundler retrieve them from there.
this should make a transparent workflow like you would be running your binaries in the real world!

Making an executable GEM from a script

I started developing ruby lately and I really like it, But I feel somehow lost. I developed a script that does "whatever" and that scripts requires many gems like nokogiri and colorize. I now want to deploy the script, so after reading a while I found many people saying that deploying as a gem is the best approach. So my question is simple? Is there any tool that I can use to create a gem of my script file and include all the gem dependencies(nokogiri) in the new gem?
I am using ubuntu!
Thanks alot
Building a gem consists of basically creating a simple directory structure for your script, and a special file known as a gemspec that will list all its dependencies. That gemspec can be used with rubygems to create a gem file (*.gem), which can be installed using rubygems or uploaded to rubygems.org for public consumption.
There are several tools that automate part of this process. A relatively simple one is the Bundler gem, which will both take care of dependencies during development, and make it easy for you to package your gem. This article contains enough information to get you started with gem development using bundler.
The best way to make a gem is to use the bundler program to build a skeleton:
# bundler gem (gem_name)
bundler gem geil_gem
This will create a template gemspec file and give you the basic structure needed for your gem to have a setup command, a console and be ready to build into a working gem (both found in the bin folder of your skeleton project). From here you can add a command binary or build out the gem as a library using the lib directory or start with tests by adding rspec to the gemspec and creating a test folder.

Where do I have to do my Bundler setup?

If I'm developing a gem using Bundler and RSpec for testing. Where do I do my Bundler.setup? Let's assume my gem is called fancy-gem and my directory setup is similar to the following:
Gemfile
Gemfile.lock
lib/
fancy-gem.rb
Rakefile
README
spec/
...
Should I execute Bundler.setup in my 'fancy-gem.rb' or does this cause problems with other gems which might use bundler? I'm thinking, when I'm not doing this, then there is no way to guarantee that the right version of the third party libraries I'm requiring is loaded.
I already asked, if I need to add Bundler itself to the Gemfile. The answer was no, but now I'm not so sure, because if I do execute Bundler.setup somewhere then Bundler actually is a dependency of my Gem and should be installed along with my Gem when it is downloaded from rubygems.org
In my opinion you should neither depend on bundler, nor use it in your gem. The way I'd do it is simply require your gem's dependencies in lib/fancy-gem.rb (almost every gem only has a handful of runtime dependencies, so this should not be too much of a hassle) and I'd call Bundler.setup only in the development files (like spec_helper.rb or Rakefile). This way you don't screw with applications that use your gem and still get all the convenience of automatic dependency management when developing your gem.

How to create a new Ruby gem?

To create a new Ruby gem, should I use Jeweler or should I use Bundler's built-in gem skeleton to create a base gem? What are the differences that matter?
Use Bundler
From the command line:
bundle gem your_new_gem
This will create a directory called your_new_gem with just a basic set of files and directory structure that are now considered best-practice. It's quick, easy, and a great place to start.
Creating a Gem isn't that difficult and I would advise to try building a gem from scratch, without any tools. After you know what's involved (creating a gemspec, building and pushing it to rubygems.org), you can use tools to speed up the process. My guess is you won't because making a gem is hardly the trouble at all.
I would go with Jeweler. The Bundler skeleton is only going to give you the basics. Jeweler has alot more options to work with and many helpful rake tasks for versioning, pushing to github, creating the gemspec, building and installing.
If you are working with Rails 3 engines, I have a Jeweler fork (definitely a work-in-progress) that will generate the app skelaton and include the engine file. You just have to run the jeweler command with --rails3-engine as an option. Here is the fork if you are interested:
https://github.com/johnmcaliley/jeweler
I would recommend using the built-in bundler command.
bundle gem your_gem_name
There are some rules that you should follow when creating a gem. Such as naming conventions and versioning rules.
I recently wrote a post on creating gems in netguru's blog. I think you'll find what you need in there.
https://netguru.co/blog/posts/creating-a-gem-a-step-by-step-tutorial
Hope this helps.
Here's an alternative that's worth looking at: ore
Bundler gives you a single template for ruby gems, whereas ore has multiple built in templates, plus the ability to create your own. It also supports Git, SVN (urgh) and Mercurial.
You can build a gem in RubyMine too. File > New Project > New Gem. It is that easy. But I want to make some notes about this approach:
For debugging, RubyMine will use the Fast Debugger gem, ruby-debug-ide. I know that most people now are using Pry with Byebug, but ruby-debug-ide is an interface which glues ruby-debug to IDEs like Eclipse (RDT), NetBeans and RubyMine.
Under Run > Edit Configurations > + > Ruby, I add a new debug configuration, according to the documentation here: https://www.jetbrains.com/help/ruby/run-debug-configuration-gem-command.html#1
Under Configuration, under 'Ruby Script', I add the path to the ruby gem file under lib: lib/my_gem.rb
Under Configuration, under 'Ruby SDK', I specify an RVM gemset I am using.
Under Bundler section, I check 'Run the script in context of bundler'. This would use bundle exec, which will read the dependencies in my Gemfile in my project's root. Now for gems, the Gemfile contains a method call "gemspec", which in turn reads the dependencies in dependencies in my_gem.gemspec. There, I have dependencies passed to the Gem::Specification.new block:
spec.add_development_dependency "bundler", "~> 1.7"
spec.add_development_dependency "rake", "~> 10.0"

Questions about building a new gem using Wycats template

I'm writing a new gem I'm basing off of Yehuda's new gem template and I'm slightly confused. Having a Gemfile with dependencies, and also specifying a gemspec with dependencies seems redundant to me. Can someone explain why this is desirable and if it's truly necessary?
Note, this is the first gem I've ever written so I'm new to all of this.
The .gemspec dependencies tell rubygems what it needs to grab to resolve the dependencies when a user installs your gem. The Gemfile is to manage the dependencies while you develop the gem. Rubygems and Bundler aren't connected, at least not yet.
The gemspec is required to build the gem. The Gemfile is more of a convenience, so that people who are working on your gem can easily pull in all the dependencies via Bundler. In the case that you're developing multiple related gems at once, you may also want to put git sources in the Gemfile, so all of the HEAD versions can be tested against.

Resources