I need two things from a language to take it seriously: good testing framework and some kind of package management. I've dealt with testing in my previous blog posts, now I compare two package management tools that I like, npm and bundler.
Early this year I went fairly deep into node.js development. I wanted to understand how it works and where I could use it in the future. Getting node on your local development environment is easy, but getting used to coding with async callbacks takes a bit of practice to master.
All I needed on OSX to get started with node was:
$: brew install nodeWhen I wanted to use a package - let's say mocha.js - I just used npm.
$: npm install mocha
It installed everything into the project root under the node_modules directory, locally by default like this:
$: lltree some_nodejs_project |--node_modules |----mocha |------bin |------images |- ...Sure you can have it installed globally, but you need to use the "-g" flag to do that. I did not want to pollute my node installation, I was glad with its default behavior where it installed everything under node_modules.
You do pay a price for this behavior. When you execute "mocha" in the terminal, the executable is not found.
% mocha zsh: command not found: mochaYou have to locate that file under the node_modules directory. It's in "node_modules/mocha/bin" dir, by the way.
To get around this I just use a Makefile with a couple tasks in it:
REPORTER = list test: test-bdd test-bdd: @./node_modules/mocha/bin/mocha \ --reporter $(REPORTER) \ --ui bdd \ -- spec/*.js test-doc: @./node_modules/mocha/bin/mocha \ --reporter $(REPORTER) \ --ui bdd \
This way I can easily run my tests by executing "make" in the terminal.
I switched from rvm to rbenv early this year. Rbenv with bundler makes a very powerful combo but when you install a gem it's going to install it globally by default.
Not good. I want to keep my gems local to the current project and I don't want to pollute my Ruby install with different versions of gems. What if I use Rails 3.2.9 in one project but I have to use 3.1.1 in another? Sure you could use rbenv-gemsets to get around this, but I already started using node with npm and I wanted to have a similar experience.
The "--path" switch in bundler lets me specify which directory I want to install my gems into. When I start a new project I immediately create a Gemfile. It's very simple, all you need is this:
source "http://rubygems.org" gem "light_service", "->0.0.6" gem "rspec"
Then I install all the gems through bundler with this command:
$: bundle install --path vendor/bundle --binstubs
Bundler puts all my gems under the vendor/bundle directory and creates a bin directory with executables for the gems that produce such a file. When I run rspec for my project this is what I do:
$: bin/rspec spec
You could either use "bin/rspec" or "bundle exec rspec", either works.
As you see, nor npm, neither bundler has the best solution. But they have facets that I like in both.
default local install | easy access to executables | |
---|---|---|
npm | ||
bundler |
Can we sync the good parts? Could both have local install by default with easy access to the executables?
Update
Shortly after I published this post, my good friend Joe Fiorini pinged me on twitter. Here is our conversation:
I did not know that npm creates a ".bin" directory under "node_modules" with symlinks pointing to the individual executable files. This way it's very easy to run these files:
$: node_modules/.bin/mocha -h
Thanks Joe for pointing this out!