Functional Robots With Wisp

April, 2, 201409:30 PM

Wisp is a really cool project for compiling a subset of Clojure syntax to JavaScript, without having to go through all the hoops that ClojureScript forces you through.

Wisp also compiles to plain JavaScript, without setting up a number of data structures and language idioms the way ClojureScript or other [lang]-to-JS compilers sometimes do. This lets you write Clojure with a fairly good idea of how it’ll map to the resulting JavaScript.

For an example, I decided to convert the Cylon.JS cat toy example to it, just to get a feel for the process.

The example robot I’m converting hooks up to a Digispark with a couple servos and a Leap Motion. The robot uses hand positions picked up by the Leap Motion to control the servos. Simple enough.

It’s pretty straight-forward JavaScript, so it shouldn’t be too hard to convert. Now let’s write an analogue in Clojure.

(def Cylon (require "cylon"))

; We're re-writing how the -> special form works here to allow for method
; chaining later on.
(defmacro ->
  [& operations]
  (reduce
   (fn [form operation]
     (cons (first operation)
           (cons form (rest operation))))
   (first operations)
   (rest operations)))

(def robot {
  connections [
    { :name "digispark" :adaptor "digispark" }
    { :name "leapmotion" :adaptor "leapmotion" :port "127.0.0.1:6437" }]

  devices [
    { :name "servo1" :driver "servo" :pin 0 :connection "digispark" }
    { :name "servo2" :driver "servo" :pin 1 :connection "digispark" }
    { :name "leapmotion" :driver "leapmotion" :connection "leapmotion" }]

  work (fn [my]
    (let [x 90
          z 90]
      (my.leapmotion.on
        :hand
        (fn [hand]
          ; wisp gives us this set! form to let us change variables,
          ; and also using the redefined -> macro we wrote earlier
          (set! x (-> hand.palmX (.fromScale -300 300) (.toScale 30 150)))
          (set! y (-> hand.palmY (.fromScale -300 300) (.toScale 30 150)))))

      (every
        100
        (fn []
          (my.servo1.angle x)
          (my.servo2.angle z)
          (console.log
            "Current Angle:"
            (my.servo1.currentAngle)
            ","
            (my.servo2.currentAngle))))))})

(.start (Cylon.Robot robot))

It still looks a fair bit like the original example, but it’s clear we’re not in Kansas anymore. We even had to write a macro to get method chaining working properly, but that’s another cool thing: we wrote a macro, and it works.

The wisp binary has a couple modes; it can run files directly (wisp robot.wisp), or will print a compiled version of code passed to STDIN.

Running this with cat robot.wisp | wisp > robot.js, we get a fairly decent approximation of the original, which even comes with a generated sourcemap to help with debugging.

var Cylon = exports.Cylon = require('cylon');
void 0;
var robot = exports.robot = {
        connections: [
            {
                'name': 'digispark',
                'adaptor': 'digispark'
            },
            {
                'name': 'leapmotion',
                'adaptor': 'leapmotion',
                'port': '127.0.0.1:6437'
            }
        ],
        devices: [
            {
                'name': 'servo1',
                'driver': 'servo',
                'pin': 0,
                'connection': 'digispark'
            },
            {
                'name': 'servo2',
                'driver': 'servo',
                'pin': 1,
                'connection': 'digispark'
            },
            {
                'name': 'leapmotion',
                'driver': 'leapmotion',
                'connection': 'leapmotion'
            }
        ],
        work: function (my) {
            return function () {
                var xø1 = 90;
                var zø1 = 90;
                my.leapmotion.on('hand', function (hand) {
                    xø1 = hand.palmX.fromScale(-300, 300).toScale(30, 150);
                    return zø1 = hand.palmY.fromScale(-300, 300).toScale(30, 150);
                });
                return every(100, function () {
                    my.servo1.angle(xø1);
                    my.servo2.angle(zø1);
                    return console.log('Current Angle:', my.servo1.currentAngle(), ',', my.servo2.currentAngle());
                });
            }.call(this);
        }
    };
Cylon.Robot(robot).start();
// [source map removed for formatting reasons]

I don’t know if it’s something I’d use in day-to-day yet, but Wisp seems like a really cool project for trying out some functional programming ideas in JavaScript.

I also think this could be a great learning tool for people who want to learn Clojure without getting a full JVM set up. It’s easy enough to setup (installs through NPM), and generates clear results in a familiar language, allowing users to clearly see what their Clojure source is doing.

Parsing RSS with Ruby

February, 13, 201410:21 AM

Last night, I decided to write a small script that involved parsing an RSS feed I’d fetched over HTTP.

I thought I’d need to install Nokogiri to be able to accomplish this, and wasn’t relishing having to manually construct XPath queries to find the data I wanted to extract from the RSS.

After browsing around for a bit, I found out that Ruby has a built-in RSS class, and that it’s actually pretty good.

Here’s a quick example of using it to print the name, URL, and description of every item in a feed:

require 'rss'
require 'httparty'

response = HTTParty.get 'http://coolwebsite.com/path/to/feed.rss'

feed = RSS::Parser.parse response.body

feed.items.each do |item|
  puts "Title: #{item.title}"
  puts "URL: #{item.link}"
  puts item.description
end

# => Title: Cool Podcast Episode
# => URL: http://coolwebsite.com/episodes/404
# => Description: This is a cool podcast episode and you should listen to it.

Fairly simple, but very useful if you don’t want to rely on third-party gems. Check out more about it here.

Running Leap Motion Manually

November, 13, 20137:40 PM

Note: these instructions apply to OS X only. I’m not sure how you’d accomplish something similar on a regular Linux distro.

I got a Leap Motion recently, and wanted to use it with my MacBook. It’s pretty cool tech, and communicates with apps by running a WebSockets server daemon on startup. I’ve been working on plugging into this WebSockets server for a Cylon module, actually.

Unfortunately, even if I’m not using the Leap Motion, this server is still running, and still using up battery power. I try to make sure my laptop’s battery life is good, but I still want to be able to hack on the Leap Motion from time to time. So we need to kill the daemon, along with the Leap Motion app it runs at startup. We still want to be able to run them manually, though.

First, let’s stop the currently running leapd daemon instance:

sudo launchctl unload /Library/LaunchDaemons/com.leapmotion.leapd.plist

Now that we’ve gotten rid of that, let’s remove it and the LaunchAgent that starts Leap Motion.app on startup:

sudo rm -rf /Library/LaunchDaemons/com.leapmotion.leapd.plist
sudo rm -rf /Library/LaunchAgents/com.leapmotion.Leap-Motion.plist

Now that we’ve got those out of the way, Leap Motion will not work if we plug it in, and won’t work on startup. Now we need to manually start the Leap Motion app and leapd server if we want to use the Leap Motion. We can make a couple quick shell functions to make starting up and tearing down this arrangement easier:

function leap-up() {
    (sleep 1 && open /Applications/Leap\ Motion.app)&
    /Applications/Leap\ Motion.app/Contents/MacOS/leapd
}

function leap-down() {
    killall leapd
    killall Leap\ Motion
}

Now if we run the leap-up function in the shell, we get output like this:

$ leap-up
[2] 3088
[2]  + done       ( sleep 1 && open /Applications/Leap\ Motion.app; )
[19:37:25] [Info] WebSocket server started

And now leapd is running in the foreground, and will continue to do so until we close it or run the leap-down command.

DuckDuckGo in Safari

September, 27, 201311:58 PM

I’ve been toying around with using Safari as my default browser for a while now, and one of the pain points in transitioning is that I wasn’t able to set DuckDuckGo as my default search engine. The only options in Safari’s settings are Google, Bing, and Yahoo.

Luckily, last night I discovered the Safari Keyword Search plugin. After installing this extension:

  1. Right click anywhere in a Safari page
  2. Select “Keyword Search Settings…”
  3. In the “URL Expansion” field, replace the current item with https://duckduckgo.com/?q=@@@
  4. Click “Save”

And there you go. Your default Omnibar search engine is now DuckDuckGo.

Installing Rubinius with Rbenv

September, 6, 201308:20 PM

EDIT: (2013-09-27) - Updated to reflect that RBENV_VERSION is now ‘rbx’ (at least for me). Check the value yourself if it isn’t working.

(Disclaimer: These steps may not work for you. This is just what got my system working. If you have any feedback or step suggestions, let me know.)

While gearing up for a new release of the gitnesse gem, I noticed the RSpec suite was failing in JRuby and Rubinius on Travis. To fix this, I had to install both Rubies on my system.

Let’s start by installing them through ruby-build. Easy enough, right?

$ rbenv install jruby-1.7.4
Downloading jruby-1.7.4.tar.gz...
-> http://jruby.org.s3.amazonaws.com/downloads/1.7.4/jruby-bin-1.7.4.tar.gz
Installing jruby-1.7.4...
Installed jruby-1.7.4 to /Users/stewart/.rbenv/versions/jruby-1.7.4

Ok, That went well. Now let’s install Rubinius!

$ rbenv install rbx-2.0.0-dev
Downloading yaml-0.1.4.tar.gz...
-> http://dqw8nmjcqpjn7.cloudfront.net/36c852831d02cf90508c29852361d01b
Installing yaml-0.1.4...
Installed yaml-0.1.4 to /Users/stewart/.rbenv/versions/rbx-2.0.0-dev

Cloning https://github.com/rubinius/rubinius.git...
Installing rubinius-2.0.0-dev...

BUILD FAILED

Inspect or clean up the working tree at /var/folders/6n/pd5r9l_x73s6vv656xzy1rph0000gn/T/ruby-build.20130906193908.56657
Results logged to /var/folders/6n/pd5r9l_x73s6vv656xzy1rph0000gn/T/ruby-build.20130906193908.56657.log

Last 10 log lines:
  --without-fibers           Disable fibers
  --with-dtrace              Enable dtrace
  --without-dtrace           Disable dtrace

Help!
  --show                     Print the current configuration and exit
  -V, --verbose              Print additional info
  -h, --help                 Show this message

Unrecognized option: --with-readline-dir=/usr/local/opt/readline

Ah. That’s not quite what I was expecting. We can still built it manually, though, since rbenv doesn’t really care how the Ruby gets installed:

$ git clone https://github.com/rubinius/rubinius.git && cd rubinius
$ ./configure --prefix=~/.rbenv/versions/rbx-2.0.0-dev
$ rake install

After this is done, we can switch over to using Rubinius:

$ rbenv shell rbx-2.0.0-dev

Alright. Now let’s try installing Bundler, so we can install RSpec and run the tests:

$ cd ~/dev/project

$ gem install bundler && rbenv rehash
Fetching: bundler-1.3.5.gem (100%)
Successfully installed bundler-1.3.5
1 gem installed

$ rbenv which bundle
rbenv: bundle: command not found

The `bundle' command exists in these Ruby versions:
  1.9.3
  1.9.3-p194
  2.0.0
  2.0.0-p247
  jruby-1.7.4

It turns out that Rubinius uses a different install path for gem binaries than most other Rubies, so rbenv can’t find them by default. Luckily, there’s a plugin that fixes that. Let’s install it:

$ mkdir -p ~/.rbenv/plugins
$ cd ~/.rbenv/plugins
$ git clone https://github.com/rmm5t/rbenv-rbx.git

This plugin helps, but it’s not compatible with the most recent (as of this writing) version of Rubinius. We can fix that by changing the relevant files:

# ~/.rbenv/plugins/rbenv-rbx/etc/rbenv.d/rehash/rbx.bash
make_shims ../versions/rbx-2*/gems/bin/*
# ~/.rbenv/plugins/rbenv-rbx/etc/rbenv.d/which/rbx.bash
if [ ! -x "$RBENV_COMMAND_PATH" ] && [[ $RBENV_VERSION =~ rbx ]]; then
  export RBENV_COMMAND_PATH="${RBENV_ROOT}/versions/${RBENV_VERSION}/gems/bin/${RBENV_COMMAND}"
fi

And now we’re off to the races:

$ cd ~/dev/project
$ rbenv which bundle
/Users/stewart/.rbenv/versions/rbx-2.0.0-dev/gems/bin/bundle

While I was writing this, Brian tweeted at me, letting me know that I should use Chruby instead of Rbenv. Currently rbenv is too integrated into my workflow and shell to switch over to chruby on a whim, but I’ll have to give it a shot at some point and see if it makes it easier to get up and running with multiple Rubies.

UPDATE: It does.

Plural

March, 28, 20136:44 PM

I don’t like pulling in all of ActiveSupport when all I need to do is pluralize some text. So I pulled out the relevant bits of ActiveSupport into a gem called plural.

How It’s Used

"post".plural
# => "posts"

"octopus".plural
# => "octopi"

"sheep".plural
# => "sheep"

"words".plural
# => "words"

"CamelOctopus".plural
#=> "CamelOctopi"

What It Supports

Plural supports Rubies with 1.9 syntax, and is tested on the following:

  • MRI 1.9.2
  • MRI 1.9.3
  • MRI 2.0.0
  • jruby-19mode
  • rbx-19mode

Tell Me More

You can grab it from rubygems or check out more about it on github.

each_with_object

January, 30, 201310:30 PM

Ruby 1.9 introduced more than a few useful methods. I’ve been able to wring a lot of use out of Enumerable’s new method #each_with_object

Usage

In situations where you’d do something like the following:

array = %w(alpha bravo charlie delta)
results = []

array.each do |item|
  results << item.to_sym
end

results.reverse!

You can do something like this instead:

array = %w(alpha bravo charlie delta)

results = array.each_with_object([]) do |item, results|
  results << item.to_sym
end.reverse

This reduces lines of code while making the source more readable at the same time.

Project Specific .vimrc Files

January, 23, 201311:49 AM

I work on a bunch of different projects, and some have different code standards than others. Some projects also have a slightly different directory structure, which might conflict with some of my CtrlP mappings.

To make sure everything always works the way I want it to, I use project specific .vimrc files.

How To

Vim allows for per-project configuration files, although this is turned off by default. To enable this, drop this line into your ~/.vimrc:

set exrc

If you enable this, it’s also a good idea to add this to the end of your ~/.vimrc to disable unsafe commands in your project-specific .vimrc files:

set secure

This will prevent :autocmd, shell and write commands from being run inside project-specific .vimrc files unless they’re owned by you.

Now you can write per-project .vimrc files like the following:

set tabstop=2
set shiftwidth=2
set softtabstop=2
set expandtab
set nosmarttab

set textwidth=80

map <leader>gf :CtrlPClearAllCaches<cr> :CtrlP features_wip<cr>

Installing vim with Ruby 1.9.3

December, 23, 201204:25 PM

I’ve been running into an issue lately where vim segfaults when I try to use omnicompletion or any vim-based plugins. It’s happened since I started using Ruby 1.9.3. The error messages look something like this:

dyld: lazy symbol binding failed: Symbol not found: _rb_encdb_declare
Referenced from: /Users/stewart/.rbenv/versions/1.9.3-p327/lib/ruby/1.9.1/x86_64-darwin10.8.0/enc/encdb.bundle
Expected in: flat namespace

dyld: Symbol not found: _rb_encdb_declare
Referenced from: /Users/stewart/.rbenv/versions/1.9.3-p327/lib/ruby/1.9.1/x86_64-darwin10.8.0/enc/encdb.bundle
Expected in: flat namespace

Vim: Caught deadly signal SEGV

The Fix

After looking around online, I found that the fix is a trivial patch, applied to Ruby before it’s compiled:

diff --git a/missing/setproctitle.c b/missing/setproctitle.c
index 169ba8b..4dc6d03 100644
--- a/missing/setproctitle.c
+++ b/missing/setproctitle.c
@@ -48,6 +48,12 @@
 #endif
 #include <string.h>

+#if defined(__APPLE__)
+#include <crt_externs.h>
+#undef environ
+#define environ (*_NSGetEnviron())
+#endif
+
 #define SPT_NONE   0   /* don't use it at all */
 #define SPT_PSTAT  1   /* use pstat(PSTAT_SETCMD, ...) */
 #define SPT_REUSEARGV  2   /* cover argv with title information */

This stops vim from segfaulting.

What do?

Note: This is assuming you’ve got a setup similar to mine, running OS X, using Homebrew to install packages, and using rbenv/ruby-build to compile/install rubies.

First, uninstall vim:

brew rm vim

Then copy this script:

build_package_combined_patch() {
  local package_name="$1"

  {
    curl https://raw.github.com/gist/3905045/bf9d1c84c72cdce5be52d8b2dfd4d86a1cdbf185/gistfile1.txt | git apply
    autoconf
    ./configure --prefix="$PREFIX_PATH" $CONFIGURE_OPTS --enable-shared
    make -j 8
    make install
  } >&4 2>&1

}

require_gcc

install_package "yaml-0.1.4" "http://pyyaml.org/download/libyaml/yaml-0.1.4.tar.gz"
install_package "ruby-1.9.3-p327" "http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p327.tar.gz" combined_patch

And put in in a file called 1.9.3-p327-patch.

Then, install it with ruby-build:

rbenv install ./1.9.3-p327-patch

And reinstall vim:

brew install vim

Sinatra Code Organization

November, 15, 201201:25 PM

I try to avoid the approach many people take to writing Sinatra apps, which is to place everything in the app.rb file. This gets very cluttered very fast.

Instead, I split out persistance and objects into models and lib directories, respectively.

So for example, a project might look like this:

$ tree
.
├── Gemfile
├── Gemfile.lock
├── config.ru
├── lib
|   ├── user_list_filter.rb
│   └── api_key_generator.rb
├── models
│   └── user.rb
├── app.rb
└── spec
    ├── lib
    │   ├── user_list_filter_spec.rb
    │   └── api_key_generator_spec.rb
    └── spec_helper.rb

To require everything in lib and models, I’ve got this in config.ru:

directories = %w(models lib)

directories.each do |directory|
  Dir["#{File.dirname(__FILE__)}/#{directory}/*.rb"].each do |file|
    require file
  end
end

Simple enough, and allows for better code organization and much faster tests.

Jekyll Plugin - Image Tag

November, 4, 201206:50 PM

I wrote a quick Jekyll plugin that makes it easy to add images with captions to posts.

Examples:

Here’s a few examples:

{% image http://share.stwrt.ca/blog/blue-pink-gradient.jpg %}
{% image full http://share.stwrt.ca/blog/blue-pink-gradient.jpg %}
{% image full http://share.stwrt.ca/blog/blue-pink-gradient.jpg "Image caption" %}
Image caption

Source

Here’s the plugin, as it exists:1

module Jekyll
  class ImageTag < Liquid::Tag
    @url = nil
    @caption = nil
    @class = nil

    IMAGE_URL_WITH_CLASS_AND_CAPTION = /(\w+)(\s+)((https?:\/\/|\/)(\S+))(\s+)"(.*?)"/i
    IMAGE_URL_WITH_CAPTION = /((https?:\/\/|\/)(\S+))(\s+)"(.*?)"/i
    IMAGE_URL_WITH_CLASS = /(\w+)(\s+)((https?:\/\/|\/)(\S+))/i
    IMAGE_URL = /((https?:\/\/|\/)(\S+))/i

    def initialize(tag_name, markup, tokens)
      super

      if markup =~ IMAGE_URL_WITH_CLASS_AND_CAPTION
        @class   = $1
        @url     = $3
        @caption = $7
      elsif markup =~ IMAGE_URL_WITH_CAPTION
        @url     = $1
        @caption = $5
      elsif markup =~ IMAGE_URL_WITH_CLASS
        @class = $1
        @url   = $3
      elsif markup =~ IMAGE_URL
        @url = $1
      end
    end

    def render(context)
      if @class
        source = "<figure class='#{@class}'>"
      else
        source = "<figure>"
      end

      source += "<img src=\"#{@url}\">"
      source += "<figcaption>#{@caption}</figcaption>" if @caption
      source += "</figure>"

      source
    end
  end
end

Liquid::Template.register_tag('image', Jekyll::ImageTag)
  1. The up-to-date version can be found on GitHub

Vim and Ctags

October, 31, 201208:30 PM

Combining vim with ctags yields a powerful combination for working with large or unfamiliar codebases.

What is ctags?

Ctags is a tool that will sift through your code, indexing methods, classes, variables, and other identifiers, storing the index in a tags file. The tags file contains a single tag per line. Depending on command line arguments and the language ctags is run against, a lot of information can be obtained from this index.

Ctags currently supports 41 programming languages, and it’s relatively easy to add definitions for more.

Ctags makes it much easier to navigate a larger project, particularly if the code you’re working with is unfamiliar. If you’re unsure of what a method does or how it’s supposed to be called, you can jump straight to it’s definition. If you’re in the downward spiral of a 500+ line Perl script and want to know where a variable was defined three hours ago, you can jump right back to it. And afterwards, you can jump right back to where you were working.

Installing ctags

You can install ctags using a package manager.1 If you’re on OS X, use homebrew:

brew install ctags

OS X comes with a ctags executable, but it’s not exuberant-ctags, and is missing most of the useful features.

Using ctags

If you’re currently sitting in the directory you want to index, just run:

ctags -R .

Ctags will walk through the directory recursively, tagging all source files it encounters. For very large projects, this might take a while, but normally it’s pretty fast.

I normally don’t like having a tags file in plain sight in the source directory, so I keep it a little bit more hidden, in the .git folder:

ctags -R -f ./.git/tags .

This can be a pain in the ass to run regularly, so you might like to bind it to a vim keyboard shortcut so you can run it every so often, or add some git hooks to run ctags every time you check out, commit, or fetch with git.

Using ctags from vim

If you’ve already run ctags in the current project folder, vim will automatically pick up your tags file (even in the .git directory), and you can start using it right away. Take this bit of Ruby code, for example:

class TestCase
  def assert_equal(expected, value)
     # do_stuff_with_args
  end
end

class ModelTest < TestCase
  assert_equal true, model_function
end

If you put your cursor over ModelTest’s assert_true call in normal mode and press <C-]>, vim will jump to assert_true’s definition in the TestCase class, even if they’re in different files. You can continue down this rabbit hole, if you choose, and when you’re done, press <C-t> to climb back up the tree.2

You can also go directly to a tag’s definition by entering one of the following in vim’s command mode:

:tag function_name
:ta function_name

These commands will also accept regular expressions, so, for example, :tag /^asserts_* would find all tags that start with ‘asserts_’. By default vim will jump to the first result, but a number of commands can be used to sort through the list of tags:

  • :ts or :tselect shows the list
  • :tn or :tnext goes to the next tag in that list
  • :tp or :tprev goes to the previous tag in that list
  • :tf or :tfirst goes to the first tag of the list
  • :tl or :tlast goes to the last tag of the list

To show the tags you’ve traversed since you opened vim, run :tags.

Vim + Ctags + Ctrlp

If you’re using the Ctrlp plugin for vim, running :CtrlPTag will let you search through your tags file and jump to where tags are defined. Very useful when you need to jump around a project in a hurry.

It’s also handy to bind this to a keyboard shortcut. I use this in my ~/.vimrc:

nnoremap <leader>. :CtrlPTag<cr>

Vim + Ctags + Tagbar

Tagbar is another useful vim plugin for working with a tags file. Install it, and map a key to it (I use ,b):

nnoremap <silent> <Leader>b :TagbarToggle<CR>

When the tagbar is toggled, it will pop up on the right side of the vim window and show the tags picked up by ctags for the current file, organized by tag type, e.g. function, variable, class, etc. This effectively gives you a birds-eye view of the code you’re working on.

.ctags

You can put extra configuration for ctags in a ~/.ctags file, and ctags will use the contents as arguments every time it’s run. You can use this to establish basic options, define regular expressions for additional languages, and set options for specific languages.

For example, here’s my ~/.ctags file:

# Basic options
--recurse=yes
--tag-relative=yes
--exclude=.git

# Regex for Clojure
--langdef=Clojure
--langmap=Clojure:.clj
--regex-clojure=/\([ \t]*create-ns[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/n,namespace/
--regex-clojure=/\([ \t]*def[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/d,definition/
--regex-clojure=/\([ \t]*defn-?[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/f,function/
--regex-clojure=/\([ \t]*defmacro[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/m,macro/
--regex-clojure=/\([ \t]*definline[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/i,inline/
--regex-clojure=/\([ \t]*defmulti[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/a,multimethod definition/
--regex-clojure=/\([ \t]*defmethod[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/b,multimethod instance/
--regex-clojure=/\([ \t]*defonce[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/c,definition (once)/
--regex-clojure=/\([ \t]*defstruct[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/s,struct/
--regex-clojure=/\([ \t]*intern[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/v,intern/
--regex-clojure=/\([ \t]*ns[ \t]+([-[:alnum:]*+!_:\/.?]+)/\1/n,namespace/

# PHP
--langmap=php:.engine.inc.module.theme.install.php --PHP-kinds=+cf-v
  1. It might be available as exuberant-ctags, depending on your package manager.

  2. For more on this stuff, run :help tags and :help CTRL-].

Using CoffeeScript and SASS with Sinatra

October, 26, 201210:42 AM

Most of my newer projects tend to be smaller projects where I don’t want to have the massive overhead that Rails brings with it, or what I’m trying to build doesn’t necessarily fit the Rails use case.

But I’d still like at least some of the benefits of the Asset Pipeline, namely being able to use SASS/SCSS in place of CSS, and using CoffeeScript to write my app’s Javascript.

To do this, I’m using the sass gem’s Sass::Plugin::Rack functionality, and the rack-coffee gem.

How

First, add them both to your Gemfile:

source :rubygems

gem 'sinatra'

gem 'sass'
gem 'rack-coffee'

Then bundle install.

Then add the hooks into config.ru:

require 'rubygems'
require 'bundler'
Bundler.require(:default)
require 'sass/plugin/rack'
require './myapp'

# use scss for stylesheets
Sass::Plugin.options[:style] = :compressed
use Sass::Plugin::Rack

# use coffeescript for javascript
use Rack::Coffee, root: 'public', urls: '/javascripts'

run MyApp

So now you can put your stylesheets into the public/stylesheets/sass/ folder, and they will be automatically compiled to CSS when changes are made.

You can put either CoffeeScript or regular Javascript files in public/javascripts/ and they will be available in your app’s layout.

Example

For an example app with a directory structure like this:

.
├── Gemfile
├── config.ru
├── myapp.rb
├── public
│   ├── javascripts
│   │   └── script.coffee
│   └── stylesheets
│       └── sass
│           └── style.sass
└── views
    ├── layout.haml
    └── index.haml

In layout.haml you might have something like this:

!!! 5
%html
  %head
    %title MyApp
    %link{rel: 'stylesheet', href: '/stylesheets/style.css'}
  %body
    .container= yield

    %script{src: "/javascripts/script.js"}

There are also a few alternatives, and sprockets can be rigged to work with Sinatra apps, but this is the solution that works for me. It also helps to supply a long cache lifetime for stylesheets and scripts if you’re using this method.

Notes on the iPhone 5

October, 1, 201209:56 PM

I’ve had my iPhone 5 for a little over a week now, and while I don’t want to write a full review of it, since there’s already a couple hundred of those online, I’d like to share a few of my thoughts after some time with the device.

I bought a locked iPhone 4 from Telus a little over a year ago, and still have a couple years left on my contract. The iPhone 4 is starting to fall apart and show it’s age, so I preordered an iPhone 5 from Apple, a Nano-SIM from Telus, and switched to the iPhone 5 as my main phone.

Design

I chose the black version of the iPhone, and as I noted to a friend on Twitter, it almost looks like a Batman gadget. The aluminum definitely feels very different compared to the glass on the 4 and 4S, but I like the new look.

The phone feels almost impossibly light compared to the iPhone 4. This is partly because it’s thinner and lighter, but making the phone larger also shifts the center of gravity higher in your hand, which also enhances the perception of lightness. It consequentially also feels much more fragile than the iPhone 4.

So far, I’ve only got one chip, in the beveled edge right next to the headphone jack on the bottom of the phone. It didn’t come that way out of the box, and it happened within the first day or two. I’m not sure where it came from, and I’m not too torn up about it. It’s life.

LTE

Telus activated their LTE coverage in the Victoria area the day after the iPhone came out.

It’s fast.

It’s faster than my apartment’s WiFi, and upload speeds are amazing. Unfortunately, I’m hamstrung by my Telus plan’s 1GB/month data limit.

The Display

In addition to making the screen bigger, Apple also moved it more than a few millimeters lower, which makes it easier to hit all the corners. And I can still operate the phone one-handed, despite it being a stretch at some points until I got used to holding it slightly differently.

Battery Life

A marked improvement over my iPhone 4, which had been taking a battery life nosedive over the past couple months.

The iPhone 5’s battery will last through an average day, assuming moderate use. If you’re watching video, constantly on Twitter, or taking a bunch of pictures and videos, this is not going to hold true.

Siri

I’m kind of surprised by this, but I’ve actually been using Siri more than a little bit. Not for anything major, but it’s a huge convenience for some tasks. Here’s what I’ve been using it for:

  • Setting reminders for myself (e.g. “remind me to check on my laundry in 45 minutes”)
  • Movie showtimes
  • Quick conversions (e.g. “what’s 40 pounds in Canadian dollars”)

Lightning

The name is kind of silly, but the cable is sturdy. Very, very sturdy. Even though it’s USB 2.0, it still syncs faster than the old Dock connector.

Speaking of which, I’m disappointed that Apple isn’t making a dock for the iPhone 5. Would have pre-ordered it with the phone.

Sound and Phone Calls

The built-in speaker is much louder and crisper than the iPhone 4’s. I can actually hear my phone ringing while it’s in my pocket now.

Telus supports Wideband Audio for phone calls, but I don’t call anyone else with an iPhone 5, so I haven’t been able to notice that. The earpiece, however, is still much better than what went into the iPhone 4 and also sounds much better than its predecessor.

Maps

I’m not enraged by the quality of Apple’s map coverage, but it does suck. When I first moved to Victoria, I ended up relying on iOS 5 Maps’ BC Transit integration for getting around town quickly. Now that that’s ripped out of iOS 6, I’ve been using The Transit App. It’s pretty good.

Cameras

The resolution bump for the front camera to 720p is very noticable and very welcome. I’m apparently the one person I know who makes FaceTime calls regularly, so a quality bump in the camera is much appreciated.

The main camera on this phone is ridiculous for a secondary feature of the device. The quality of this photos and videos I’m able to take with this phone just continues to impress.

Besides quality, the huge difference with the camera coming from the iPhone 4 is that the iPhone 5 shoots much faster. If you’re taking plain pictures, the iPhone 5 will save them as fast as you can hit the shutter. It takes less than a second to process a HDR image, compared to the 5+ seconds the older iPhone 4 would require.

Panorama stitching is amazing, provided you’re not jittering too much when shooting and you’re not trying to capture a panorama of a busy street.

Apps

A bit over half the apps on my phone have been updated to take advantage of the bigger display, but some apps are making more use of the extra room than others.

Instacast, Instapaper, and Tweetbot, for example, will just show you extra content, without adding any new features or changing the layout too much. This is fine, and all that’s needed.

Instagram, on the other hand, just fills in the extra area with grey pixels, without adding any functionality or taking advantage of the extra space. I’m hoping this will be fixed at some point, because right now it just looks weird and silly.

The letterboxing done for un-updated apps is nice, and conveniently leaves enough room at the top of the screen for Notification Center notifications to drop down without obscuring whatever you’re doing in the app. On the other hand, though, the virtual keyboard for letterboxed apps isn’t glued to the bottom of the screen, it’s constrained to the letterbox. This makes typing awkward, but I guess there really isn’t any other solution at this point.

iOS 6

Nothing really “wow” here for me. Maps are mediocre at best, I’ll maybe use Passbook twice, and I don’t take huge advantage of iCloud outside iTunes Match.

I do like the new look for the Music app, but the play/pause/forward/back buttons in the new Music.app aren’t also applied to the lockscreen, which seems sloppy.

On the other hand, I hate the new look for the App Store. It’s reduced the usability of search to near-usefulness, partially due to the new layout for showing search results, and partly because the Apple Store’s search algorithm is bad.

Conclusion

It’s better.