Access Chef node’s attributes by JSONPath

I have just released chef-helpers 0.0.7. The gem is just a bag of helpers for Chef recipes, without any common theme. This release adds one feature that may be really useful: it overloads Chef::Node#[] to allow deep indexing with JSONPath.

When is it useful? A code snippet is worth a thousand words.

Accessing nested attribute

Often I need to get value of a deeply nested attribute – which may not exist. If it doesn’t exist, its parent and grandparent may not be there as well. I need to code defensively (or resort to a blanket rescue clause) to take care of that:

Accessing by JSONPath makes it simpler:

Avoiding traversal when I don’t know the path upfront

When I generate random passwords, and I want to be chef-solo compatible, I want to be able to say something like:

This is supposed to raise an error when I run on chef-solo and I don’t have the attribute defined, and set them to a secure password by default when I have chef server to store it. The syntax may be a bit nicer and DRYer, but it’s already better than enumerating the attributes line by line. The implementation, though, is quite hairy – the inject method is powerful, but it’s not obvious what is done when you read the code:

With JSONPath, I can replace this line simply by:

Selecting attributes by value

I need to check whether a partition is mounted at a given path. The code used to look like this:

With JSONPath, I can focus on specifying what I expect to find, rather than how to traverse the nested hash:

I hope it will be useful – for sure it simplifies many similar pieces of code I needed to write in my recipes. Happy hacking!


Bundler and rvm: remember about login shell

Bundler and the newest rvm (1.23.1) might give you a bit of a hard time, especially if you’re a less experienced Linux user. You install bundler by running gem install bundler in your GNOME Terminal and it’s a success, but when you want to actually run bundle  in your git repository folder, you might get a message like this:

/home/marta/.rvm/bin/bundle: line 32: gem: command not found

ERROR: Gem bundler is not installed, run gem install bundler first.

No matter how many times you run gem install bundler, nothing changes. You’ll receive a similar message if you run bundler in your Rails app folder:

ERROR: Gem bundler is not installed, run gem install bundler first.

Running gem list in the terminal will show you have bundler installed, and which bundle will return the path to the gem… but bundle -v will return the above mentioned error. So what’s going on?

Before you start digging in the ~/.rvm/bin/bundle source code and wonder what’s wrong with paths (it might seem as if there’s a problem with interpreting the proper path to the bundler gem), be sure to check if you have your Run command as login shell option ticked in your terminal’s preferences (in GNOME Terminal: Edit -> Profile Preferences -> Title and Command). When this option is left unchecked, Terminal won’t be able to find bundler when it’s being asked to execute it. That’s why you see bundler on the gem list, but it won’t be found when you call it.

Rvm might give you a hint on that login shell option, but unfortunately in completely different circumstances. If this option is left unchecked and for some reason you want to switch to an older version of Ruby, typing rvm use 1.8.7 will return:

RVM is not a function, selecting rubies with 'rvm use ...' will not work.

You need to change your terminal emulator preferences to allow login shell.
Sometimes it is required to use /bin/bash --login as the command.
Please visit https://rvm.io/integration/gnome-terminal/ for a example.

If all you want is to use the most recent version of Ruby, it might take some time before you actually run this command and thus stumble over that information. Whether you’re a less experienced Linux user or a regular that reinstalled her system recently, remembering about login shell might save you loads of time.


Help MiniGit: need opinion on syntax

MiniGit is a small Ruby gem to talk with Git command line in a straightforward way. You can write, say, git.commit(:amend => true, :reuse_message => true), and have it do the right thing. No fancy model objects for repos, commits, and branches. No magic. Well, a little bit of magic, just to make it simple and comfortable to use.

One of the quirks is capturing Git’s output. As of now, MiniGit either lets git use the original console, or captures its whole stdout and returns it as a string. Without stripping the trailing newline, or any logic. Simple and straightforward – but pretty uncomfortable: to, say, make sure there are no changes to the work tree, you write git.capturing.diff.strip.empty?. It’s a handful, and don’t get me started on splitting the output into lines.

I want it to be simple. I want to be able to get the output as string – stripped or not, as I prefer at the moment. I want to be able to iterate over the lines, and don’t have the lines include the trailing newline. I want to be able to discard the output, or to display it only when there’s an error. And I don’t want to type too much to achieve that. But I have no good concept of how to write it.

A custom magic method (such as MiniGit#capturing) for each case would clutter the namespace and be hard to maintain. And it would involve a lot of output. The next idea – a custom MiniGit#[] method to get a customized instance – this syntax is reserved for git config integration: git['user.email'] is too pretty and intuitive to waste it on anything else.

Next thing I thought of was overloading unary operators: -git could discard output (like prefixing Make lines), ~git could capture stdout, etc. Two issues here: one is that there’s still a very limited number of these operators. Still, there’s a limited number of things I may want to do with Git’s output, so this may not even be a problem. Second issue is that method call binds closer than any operator: -git.push would mean -(git.push), and I’d need to add extra parentheses to say (-git).push – ugly! Not to mention it would require users to memorize what each of the symbols means.

The idea I’m thinking of right now may be short enough, but it requires a bit of magic, and I’m not sure if it’s nice & convenient magic, or testrocket flashy & useless magic. If I’d need to use parentheses anyway, I may override binary operators to mimic shell redirection syntax. Instead of magic capturing method, one could write:

Each of these expressions would create a new, specialized instance (in most cases cached in the parent instance to avoid allocating too many short lived instances, at cost of sometimes storing a few too many) just the way MiniGit#capturing and #noncapturing. Other modifiers could make it e.g. return a boolean variable to indicate success rather than always raising exception on error and requiring user to rescue when they need to check status.

Update: a more straightforward option would be a method that would be quicker to type, and accept either a known keyword, or any MiniGit subclass; something like this:

Write me what you think

What do you think: nice? uselessly convoluted? confusing? stupid? Or maybe you have any better ideas for that? I’ll happy to hear any input. You can also help by upvoting on Hacker News to get more people here.

Just use the poll here – it’s not directly published as a comment, but sent directly to me. I will update the article to include the results after a few days. If you’d like me to be able to reply, include your e-mail – but it’s not required in any way.

Waiting to hear from you!