Bundler: Allow user added gems in an UserGemfile - ruby

I'm developing a ruby/rails application which should be highly extensible by adding plugins. A plugin is - obviously - a gem, which follows specific roules and contains library code, a rails engine with assets, routes, controllers, views and whatever. Additionally there wille be some kind of API which allows the plugin developer to register custom entries to abstract concepts of the app like adding cronjobs (theres some kind of cron in the main system), adding commands to the CLI and so on.
There will be some 'builtin' plugins containted in the Gemfile shipped with the app due they're part of the app and always activated. And there will be a pool of community written gems which are optional.
Now I'm searching for a possibility to let the user, who installs the app on his machine, addional gems (containing plugins) to the app.
The simplest (but not best) solution would be to say "Just add the plugin gems you want to the Gemfile before running bundle install)". But if there comes an update of the app, the Gemfile would be potentially conflicting and either be resetted or the user have to resolve those conflicts. That's something I don't want actually.
A nicer way would be to say "Hey, here's a UserGemfile, just add the plugin gems you want to that file and run bundle install". That UserGemfile would be listed in the .gitignore and everything would be nice.
Unfortunately it seems like bundler doesn't support something like that.
Do you have any advice how to tackle that issue?

You can do something like this, in, say, import_gems:
puts `cat Gemfile UserGemfile > EffectiveGemfile`
puts `bundle install --gemfile=EffectiveGemfile`
Then, when you run your application, specify the Gemfile:
BUNDLE_GEMFILE=EffectiveGemfile bundle list
Make sure to add EffectiveGemfile and EffectiveGemfile.lock to .gitignore as well.

Related

How do I create a config.ru file and a Rakefile?

I know you create a Gemfile from the command line by typing "bundle init." But how do you create config.ru file and a Rakefile?
Kristine, the real question is not how, but rather why would you want to create them.
Those three files serve three different purposes, and none are required for a Ruby application to get started:
Gemfile (and its companion Gemfile.lock that gets generated by the first bundle install and should be kept as safely as the other one) – this is one you meet most often.
It belongs and is used by a tool called Bundler. It's a dependency management tool. When your application needs some other library called "gem", you can list it in your Gemfile, do bundle install and later on when you run your application like bundle exec ruby yourapp.rb Bundler will take care of the environment in such a way, that your application always gets the same versions of gems that you have designed it to get (those versions are actually stored in Gemfile.lock file, you can peek there).
You can easily do without Bundler, but it usually makes sense to stick to certain gem versions. That's why people usually use it. I would highly suggest you taking a look at the tool's site.
config.ru – this is very common for web applications. It's a Rack configuration file. There's a widely spread in Ruby world web server API called Rack. It enables decoupling web applications (like your Rails app, or Sinatra app) from the underlying web application server (like Thin, Unicorn or WEBrick).
Though you can certainly create this on your own, you most certainly don't need to. It's been a long way in my Ruby/Rails experience before I had to actually do this. Usually this file gets bootstrapped when you create a new Rails app by calling rails new.
And vanilla command line Ruby apps just don't need it.
Rakefile – this is, again, a pretty wide-spread beast. What Makefile is for make, Rakefile is for rake. Rake is a Ruby tool to describe and invoke certain tasks from a command line. For example, when you do bundle exec rake db:migrate, you actually start a task described by a Rakefile.
You can easily design your own tasks, but as you start using Rails you usually don't need to. rails new drops a Rakefile for you that's just enough to start with, and unless you're doing some really custom (that should, exempli gratia, involve calling your Rails app code from the command line), there's no necessity in fiddling with it.
Needless to say, if you're doing some simple Ruby console app that just asks your name and greets you, you don't need this file either.
Hope this helps you getting your head around this and smooths your ride into the Rails world!

Bundling a forked gem inside a gem

I am trying to build a gem for a project that has a dependency on an unnamed external gem :)
During development I found a small bug in the external project and I added a one line fix that resolves it. I submitted a pull request on github, but I have no response from the maintainer for some time now.
I want to make my project available as a gem but it wont work without this fix. What can I do?
What would be the best way to fix this.
One option I thought about was to create a gem of the forked project and publish it under a convoluted name, and make a dependency on that. But I don't like the idea of polluting the servers with such a stupid gem.
So I was wondering if it is possible to bundle the external gem into my application, and make it install together with my gem. What would be the cleanest and easiest way to do this?
Have you considered overriding the function with your own code? I was having a similar problem with some software at work a few weeks ago and I just redefined the function.
Since it was just one line you found, it seems like this would be the easiest solution, but I am a little bit new to Ruby so maybe there is a problem with this plan that I have not considered.
You could publish it under a different name and once the upstream maintainer accepted your fix, you can yank your version.
It's quite simple, in fact. In your Gemfile add the dependency as:
gem "nokogiri", :git => "git://github.com/tenderlove/nokogiri.git"
To do this you would also need to be using bundler to manage your gem, you can get more info on this here.
The other option is to add the code you changed to a vendor directory in your gem and distribute it with your code, this way you can just add the main directory of this other gem to your load path and you will be able to require it without any issues.
To add something to the load path you simply do:
$LOAD_PATH.unshift( File.join(File.dirname(__FILE__), '..', 'vendor', 'some_gem', 'lib') )
And you will be able to directly require files at some_gem.

How do I change the default gemfile created with 'rails new' command?

I have recently experienced an issue where I must add the following to my gemfile:
gem 'execjs'
gem 'therubyracer'
I must do this to avoid a javascript runtime error that occurs when starting the rails server. I would like to have this modification added to all new gemfiles created with the rails new command.
You're looking for application templates.
Rails documentation on Application Templates
If you want the option to customize each app individually instead of having a rigid template, a really good option is Rails Composer. It prompts you about common gems during setup, and it nails a lot of the more common gems.
Finally, if you like Rails Composer, but want to be able to re-use application templates, check out Rails Apps Composer. I haven't looked into this too much, but it seems to give you a lot of flexibility while doing most of the heavy lifting for you.

How can I install a gem as if it was specified in a Gemfile?

I want to install a gem via gem install, but I need it to resolve with dependencies of the current project.
Basically I want the functionality that bundler gives me when I specify gem 'xyz' in a Gemfile, but I don't want to add that specific gem into the Gemfile.
I tried doing bundle exec gem install ... but it doesn't seem to work.
edit: The reason why I don't want to add it to the Gemfile is that it might be something like metric_fu, metrical, saikuro, rails_best_practices, etc. Simply gems that are kind of utility use and might only cluttler the project.
I might only want to use them temporarily, or install them, try out, if it doesn't work out the way I want do rvm gemset empty and bundle install again to clean up.
The point of Bundler is, in part, to prevent you from doing things like that (to prevent you from injecting gems from outside when your project doesn't declare them).
Looking for a way of doing that is looking for a bug in Bundler. If you did manage to find some way of skirting Bundler's enforcement mechanisms, you should probably not use it; instead, you may consider filing it as a bug with Bundler's issue tracker.
Now we come to the real questions: what can you do? and what should you do?
You should use either RVM gemsets or Bundler to isolate your application and its gem dependencies. You don't need both. I would recommend Bundler for this purpose over RVM gemsets.
You should add to your Gemfile any gems that you want to use and that integrate with your application (i.e., that either load your application or that are loaded as part of your application). This is not a requirement for any gems that refrain from integrating with your application.
You should refrain from committing a changed Gemfile or Gemfile.lock to version control until you are satisfied that your application continues to operate acceptably (tests pass, new gem does something useful, etc.).
Or you should stop using Bundler, because you want to do things it is explicitly designed to prevent you from doing (not recommended).
At the risk of sounding dumb, why not add it to the gemfile? You can always add it to its own group if you don't want to have to install it everywhere.
A slightly different approach is, if you're using version control, such as Git, to create a new branch and install the gems. If it doesn't work out, uninstall the gem (I'm not sure this will be done by bundle update on the old branch) and trash the branch. If it does, work, merge your stuff into the old the branch.
Though I do believe the other answers and comments have some very good points.

What are the steps needed to create and publish a rubygem of your own?

So you've created a ruby library.
How do you create and publish your rubygem? And what common pitfalls and gotchas are there pertaining to creating and publishing rubygems?
There are several tools to help you build your own gems. hoe and newgem are the best-known, and have a lot of good qualities. However, hoe adds itself as a dependency to your gem, and newgem has become a very large tool, one that I find unwieldy when I want to create and deploy a gem quickly.
My favorite tool is Mr Bones by Tim Pease. It’s lightweight, featureful, and does not add dependencies to your project. To create a project with it, you just run bones <my_project_name> on the command line, and a skeleton is built for you, complete with a lib directory for your code, a bin directory for your tools, and a test directory. The configuration is in a Rakefile, and it’s clear and concise. Here's the configuration for a project I did a few months ago:
load 'tasks/setup.rb'
ensure_in_path 'lib'
require 'friend-feed'
task :default => 'test'
PROJ.name = 'friend-feed'
PROJ.authors = 'Clinton R. Nixon'
PROJ.email = 'crnixon#gmail.com'
PROJ.url = 'friend-feed.rubyforge.org'
PROJ.rubyforge_name = 'friend-feed'
PROJ.dependencies = ['json']
PROJ.version = FriendFeed::VERSION
PROJ.exclude = %w(.git pkg)
Mr Bones has the standard set of features you’d expect: you can use it to package up gems and tarfiles of your library, as well as release it on RubyForge and deploy your documentation there. Its killer feature, though, is its ability to freeze its skeleton in your home directory. When you run bones --freeze, a directory named .mrbones is copied into your home directory. You can edit the files in there to make a skeleton for your gems that works the way you work, and from then on, when you run bones to create a new gem, it will use your personal gem skeleton. You can unfreeze Mr Bones by running bones --unfreeze and your skeleton will be backed up, and the default skeleton will be used again.
(Editorial note: I wrote a blog post about this several months ago, and most of this is copied from it.)
I recommend github as a place to start, especially for open source projects.
And try a google search as well... Very first search result for me...
http://www.5dollarwhitebox.org/drupal/creating_a_rubygem_package
You may also want to checkout the Hoe gem, which can automate the gem creation process.
See: http://nubyonrails.com/articles/tutorial-publishing-rubygems-with-hoe
I actually wrote a tutorial on exactly this, and I wrote it as I was learning. It's more focused on the game I'd written than a library. Also, it assumes you want to build the gem via rake rather than on your own:
Part 1 on how to create the gem.
Part 2 on how to run binaries installed by your gem, and get to resources.
hoe no longer adds itself as a dependency as off rubygems 1.2. Its rake tasks are focused on deployment of the rubygem to rubyforge. If you just want to serve the gem from github I think there some new hoe-esque rake task tools to help.

Resources