Skip to content

Instantly share code, notes, and snippets.

@natchiketa
Last active August 29, 2015 14:06
Show Gist options
  • Save natchiketa/40aae3fe47d40e26d938 to your computer and use it in GitHub Desktop.
Save natchiketa/40aae3fe47d40e26d938 to your computer and use it in GitHub Desktop.
Creating Alfred 2 Workflows

Search Results

The caniuse workflow

Say you look up 'transform':

To build this type of result:

caniuse result item

Your script is going to have to output XML.

<?xml version="1.0"?>
<items>
  <item arg="http://caniuse.com/#feat=transforms2d" autocomplete="" uid="CSS3 Transforms" valid="yes">
    <title>CSS3 Transforms [IE:9-px-, FF:9-px-, GC:9-px-, S:8-px-]</title>
    <subtitle>Method of transforming an element including rotating, scaling, etc.</subtitle>
    <icon>icon.png</icon>
  </item>
</items>

Blecch! But with the builder ruby gem, or any other library that abstracts the generation of the XML node, it's not so bad.

Breakdown of an <item/>

To get a result like the one above you have to populate the XML node with a few things, singled out with XPath (double blecch!) below:

  • /items/item[@arg] (e.g. above is "http://caniuse.com/#feat=transforms2d") This is what will be used for the action, be it opening a URL or putting something in the clipboard, etc.
  • /items/item[@uid] (e.g. above is "CSS3 Transforms") This is a value that should be unique across all of the results that your script may return. I assume this is for Alfred's internal use.
  • /items/item[@valid] (e.g. above is "yes"). Not sure what this is, but I'm guessing it's so that Alfred can format something differently if the attempt to fetch the item resulted in an error.
  • /items/item/title/text() (e.g. above is "CSS3 Transforms [IE:9-px-, FF:9-px-, GC:9-px-, S:8-px-]") This is the big text in each result.
  • /items/item/subtitle/text() (e.g. above is "Method of transforming an element including rotating, scaling, etc.") This is the little text in each result.

Generating <item/> with Ruby using the builder library

This script will generate the XML node above, given some command-line arguments (that's what ARGV is for), using the 'builder' gem. I didn't have to gem install anything, so I'm assuming it's part of the standard library.

require 'builder'

arg       = ARGV[0] || 'arg'
title     = ARGV[1] || 'title'
subtitle  = ARGV[2] || ''
valid     = ARGV[3] || 'yes'
uid       = ARGV[4] || (0...8).map { (65 + rand(26)).chr }.join
icon_path = ARGV[5] || 'icon.png'

xml = Builder::XmlMarkup.new target: STDOUT, indent: 2

xml.item(arg: arg, uid: uid, valid: valid) { |i|
  i.title(title)
  i.subtitle(subtitle)
  i.icon(icon_path)
}

So—say it's called item_xml.rb—from the command line you would do:

$ ruby item_xml.rb "http://caniuse.com/#feat=transforms2d" "CSS3 Transforms [IE:9-px-, FF:9-px-, GC:9-px-, S:8-px-]" "Method of transforming an element including rotating, scaling, etc." "yes" "CSS3 Transforms"
<item arg="http://caniuse.com/#feat=transforms2d" uid="CSS3 Transforms" valid="yes">
  <title>CSS3 Transforms [IE:9-px-, FF:9-px-, GC:9-px-, S:8-px-]</title>
  <subtitle>Method of transforming an element including rotating, scaling, etc.</subtitle>
  <icon>icon.png</icon>
</item>
```bash

Now you can use this script in any workflow, from a main script. For example, this workflow will evaluate a ruby expression, so in the "main" script, in bash:

```bash
expr='{query}'
result=$(ruby -e "puts($expr)")

echo "<?xml version="1.0"?>"
echo "<items>"
ruby item_xml.rb "$result" "$result" "{query} => $result" "yes"

Now, it's entirely likely that I'll enter something that will raise an exception in Ruby, so let's add a bit that'll catch the exit code from ruby:

expr='{query}'
result=$(ruby -e "puts($expr)")

valid=$([[ $? = 0 ]] && echo "yes" || echo "no")

echo "<?xml version="1.0"?>"
echo "<items>"
ruby item_xml.rb "$result" "$result" "{query} => $result" "$valid"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment