Saying stuff about stuff.

v, a Vim command line wrapper

I wrote v to help with a couple of my common wants when starting Vim. It’s a script written in Ruby and the source is on GitHub, here are the two things it does.

Open path/to/file:line-number

If v is passed an argument matching path/to/file:line-number it will load the file and place the cursor on the specified line, this allows you to easily copy/paste output from tools such as RSpec and start editing in the correct place.

Example:

v ./spec/path/to/failure_spec.rb:123

Automatically load ./Session.vim

When v is run with no arguments it looks in the current directory for a file called Session.vim and loads it as a Vim session. Note that this only occurs when no arguments are passed, so you can load other specified files without spoiling your session.

--dry-run

To see what v will execute for the given arguments add --dry-run.

Example:

$ v --dry-run ./spec/path/to/failure_spec.rb:123
vim ./spec/path/to/failure_spec.rb +123

--help

What command line script would be complete without corresponding help? Run v --help for usage.

Trying my hand at (code) golf

I’ve never attempted code golf before but encountered the following tweet that looked achievable.

JS Golf #4: play(“hello=goodbye&answer=42&x=y”) === {hello:”goodbye”,answer:”42”,x:”y”} (parse url encoded parameter strings into objects)

JS Golf #4

I thought I’d describe the journey to my shortest solution (lower score is better) which ended up touching on a few of JavaScript’s newer language features.

An unoptimised solution

Here’s my starting “normal” code that does the job.

function play(querystring) {
  return querystring.split('&').reduce(function(object, param) {
    const parts = param.split('=')
    object[parts[0]] = parts[1]
    return object
  }, {})
}

Score: 104

Apply some manual minification.

function play(q){return q.split('&').reduce(function(o,p){let k=p.split('=');o[k[0]]=k[1];return o},{})}

Score: 81

Arrow functions are shorter, don’t require parentheses when there’s a single argument, and implicitly return when used without braces.

play=q=>q.split('&').reduce((o,p)=>{let a=p.split('=');o[a[0]]=a[1];return o},{})

Score: 79

Use destructuring assignment.

play=q=>q.split('&').reduce((o,p)=>{let [k,v]=p.split('=');o[k]=v;return o},{})

Score: 75

Don’t worry about setting global variables 😱

play=q=>q.split('&').reduce((o,p)=>{[k,v]=p.split('=');o[k]=v;return o},{})

Score: 71

Template literals also call a function so there’s no need for parentheses.

play=q=>q.split`&`.reduce((o,p)=>{[k,v]=p.split`=`;o[k]=v;return o},{})

Score: 65

Arrow function implicit returns again. I couldn’t use a semicolon to turn the function body into a single line but a comma works.

play=q=>q.split`&`.reduce((o,p)=>([k,v]=p.split`=`,o[k]=v)&&o,{})

Score: 64

Using another comma instead of && is possible as the comma operator returns the last expression.

play=q=>q.split`&`.reduce((o,p)=>([k,v]=p.split`=`,o[k]=v,o),{})

Score: 60

I started looking at whether I could use something other than reduce as its multiple arguments mean parenthesis can’t be removed. In the good old days before ES5 introduced reduce and friends I would have created the data object manually by looping through the array adding properties to it like so:

function play(querystring) {
  var object = {}
  var params = querystring.split('&')

  for (var i = 0; i < params.length; i++) {
    var keyvalue = params[i].split('=')
    object[keyvalue[0]] = keyvalue[1]
  }

  return object
}

It turns out that this technique actually shortens the code by a further 4 characters, particularly as nowadays we don’t need to use a verbose for loop. So play now loops over the querystring’s parameters setting key/value pairs on an accumulator object which it then returns — using map instead of forEach for its shorter name.

o={},play=q=>q.split`&`.map(p=>([k,v]=p.split`=`,o[k]=v))&&o

The winner? Yes!

This solution currently shares the top score of 60 characters — someone got there first with an essentially identical version.

It’s been an interesting exercise and taking a deeper look into some of JavaScript’s features has been useful — despite being focussed on hacky ways to shorten code. Re-adding whitespace and proper variable names gives us the shape of the code which looks remarkably Lisp-ish and very un-JavaScript.

object = {},
  play = querystring =>
    querystring.split `&`
      .map(
        param => (
          [key, value] = param.split `=`,
            object[key] = value
        )
      ) && object

Bonus round: a different approach. Score: 63

I wondered if something could be done about the two uses of split so tried a different approach, this time creating an array of key/values with a single split. Combined with the lessons learned so far it’s a good effort but falls just short at 63 characters.

o={},play=q=>q.split(/[&=]/).map((p,i,a)=>i%2?o[a[i-1]]=p:p)&&o

Update: Thanks to @Benjie for removing another valuable character:

o={},play=q=>q.split(/&|=/).map((p,i,a)=>i%2?o[a[i-1]]=p:p)&&o

For good measure here it is deminified:

object = {},
  play = querystring =>
    querystring.split(/&|=/)
      .map(
        (param, index, array) =>
          index % 2
            ? object[array[index - 1]] = param
            : 1
      ) && object

My open source contributions in 2016

I find it immensely satisfying to be able to contribute to open source, here’s what I managed in 2016.

Screamshot

I created Screamshot for a personal project and especially wanted to make it open source once I had an idea for a logo.

Dragonfly S3 Server

Another open source creation that sprung from a personal project — and something I have yet to write about separately. The motivation is to remove Dragonfly requests from being served by the main Rails app.

Allow Dragonfly to fetch a URL with basic auth

Whilst creating Screamshot I discovered that Dragonfly didn’t understand URLs containing authentication credentials. A quick pull request and it was taken care of.

Keep rspec-rails’ gem description up-to-date

A tiny, seemingly pointless, but nevertheless helpful, pull request.

A Ruby API client for Medium

I made the decision to cross-post my blog posts to Medium but didn’t like the look of the existing Ruby libraries so I wrote my own. It was also featured in Ruby Weekly Issue 312.

Open source libraries are great and so is open source documentation; I found Medium’s API documentation to be good and readable which makes being able to contribute more satisfying.

The funny thing about some larger companies’ open source projects is that you are required to sign a licence agreement to contribute. I think I understand why this might potentially be required from a just-in-case cover-all-bases legal perspective but it seems slightly at odds with the whole point of an open source licence.

Quotesplit

Another little ditty that I haven’t yet written about separately, Quotesplit is a Ruby library for quote-aware whitespace string splitting — like Shellwords.split but without raising ArgumentError: Unmatched double quote.

Rails: don’t introduce Uglifier to an app when JavaScipt has specifically been turned off

I wrote about my ~/.railsrc and found a small something that I could contribute to Rails.

A tiny amendment to Paperclip’s regular expressions

This is one of those annoying (for the receiver) pull requests on the one hand making the project a tiny bit “better” — which is what open source enables — but on the other hand creating work and introducing risk for little to no gain.

Peity

Peity is my most “successful” open source project to date but, having been created in 2009, it’s stable and mature and saw only a scattering of minor commits and a patch release during 2016.

My ~/.railsrc

I create a new Rails app remarkably often and over the years have found it difficult to remember my preferred options for rails new. The out-of-the-box experience of Rails has always been one of its strong points but I end up taking a lot out of a freshly created Rails project. I can’t believe it took me so long to discover ~/.railsrc, a file that stores your default preferences for rails new — it must have passed me by on its arrival years ago with Rails 3.2. From what I can gather this feature is also underutilised by other experienced Rails devs so it’s time to evangelise.

Some of my choices are purely personal preference but some are slightly more quantifiable and follow the principle that gems, configuration, and other files should enter a project when they serve a purpose instead of being added by default (on a related note I recently had a pull request merged to ensure that Uglifier isn’t added unnecessarily) — this seems to be the opposite approach to something like Suspenders which configures everything up-front.

My preferences

Here are the current contents of my ~/.railsrc:

--database=postgresql
--skip-action-cable
--skip-action-mailer
--skip-bundle
--skip-javascript
--skip-keeps
--skip-spring
--skip-test

--database=postgresql

Heroku uses PostgreSQL. I use Heroku. I use PostgreSQL.

--skip-action-cable

I haven’t tried Action Cable yet and am not sure where it fits into the way I typically apply “realtime” so until I find out I’ll continue using Pusher.

--skip-action-mailer

Sending email isn’t usually the initial functionality of an app, there’ll also be a bit of configuration to integrate with an email-sending service, so I choose to leave it all until then.

--skip-bundle

If I’m somewhere with no (or even worse, slow) internet I’d rather get on with writing code as soon as possible instead of waiting for my machine to notice it’s offline so I run bundle install --local which usually does the job.

--skip-javascript

If and when I want jQuery — or React, or something completely different like browserify — I’ll add it myself. (This also skips Turbolinks.)

--skip-keeps

I know where everything goes so the scattering of .keep files are just noise for me.

--skip-spring

I’ve never actually used Spring.

--skip-test

After many years of actively disliking RSpec (!) it’s now my testing framework of choice. My first few commits of a project tend to be about validating an idea so I’ll add and configure rspec-rails later.

What am I missing?

Tweet me your ~/.railsrc preferences.

#FirstSevenLanguages

Lingo (Macromedia Director)
ActionScript
JavaScript
VBScript
SQL
CFScript
Ruby

Ruby Medium API Client

Medium have a few official API clients (Go / Node / Python) but there isn’t one for Ruby and although there already appear to be (at least) a couple of “unofficial” Ruby Medium API clients I wasn’t entirely convinced by them (lack of tests / lack of source code).

After looking over Medium’s API docs and their existing clients — each of which is barely more than a single file — I decided to write my own Ruby Medium API client. It does little more than communicate with the correct endpoints and convert to and from JSON; I’d even argue that it’s thinner than the official clients as, for example, it doesn’t attempt to know the list of valid publishing licences or statuses or the valid attributes for a post — which seems like a losing game at the best of times but particularly for an “unofficial” client.

Medium’s API docs are particularly useful as they provide example HTTP responses for each endpoint making it easy to test by mocking responses with Webmock — in fact my first work on the library was test-first on a train with no internet*. I’ve been using it for a while as I now cross-post on Medium, it’s working well and helping to smooth my publishing flow (as opposed to doing it manually which is time-consuming and error-prone).

Here’s how to use it to create a post that points back to a canonical URL (an access token is required):

client = Medium::Client.new(access_token)
client.create_post(
  canonicalUrl: 'http://example.com/hello-world',
  content: '<p>Some interesting words.</p>',
  contentFormat: 'html',
  publishStatus: 'draft',
  title: 'Hello World',
)

* Pro-tip: prepare for an internet-less train journey by queueing up docs that might be required. Also, always use the most excellent DevDocs which feels like a web app from the future.

Peity and Interactive Data Visualization for the Web

Peity book shot

Did I ever tell you that Peity — “a jQuery plugin for generating progressive <svg> pie, donut, bar and line charts” and my most successful open source project to-date (it currently has more than 3500 stars on GitHub) — was mentioned in a real book made of paper and printed by O’Reilly?

The book is called Interactive Data Visualization for the Web and is available from:

It’s a short and sweet mention of Peity, my favourite remark is:

+10 cuteness points

This news is a couple of years old now (the book was published in 2013!) but it looks like a second edition is coming in 2017.


It’s also nice to see that a friend and fellow New Bamboo alumni is mentioned in the book for his project Dashku.

What happens when null is passed to a JavaScript regular expression?

It’s quite possible that the following is not the expected consequence of passing null to a JavaScript regular expression — it certainly surprised me:

/null/.test(null)
// => true

It looks like extra intentional work is being done to convert the value null to the string "null" whereas my assumption was that, particularly as it’s falsy, it would be interpreted as a blank string.

What’s happening?

I was impressed at how easy it was to find the answer in the ECMA spec that defines this behaviour. It turns out that it is doing extra intentional work to convert null to the string "null".

The spec also describes the following surprising (to me at least) cases:

/undefined/.test(undefined)
// => true

/true/.test(true)
// => true

/false/.test(false)
// => true

/\[object Object\]/.test({ a: 1 })
// => true

/1,2/.test([1, 2])
// => true

One example that does feel natural is converting a number to a string:

/123.45/.test(123.45)
// => true

But even this has some edge cases:

/Infinity/.test(1 / 0)
// => true

/NaN/.test(0 / 0)
// => true

Back to my problem, what’s the fix?

I could imagine this introducing a type of Scunthorpe problem — albeit with a relatively small window of opportunity — and for the non-falsy cases is the sort of issue that a type-checking system like Flow could help mitigate. Fortunately in my case the value was either a string or null so it was enough to default to an empty string:

var value = null
/null/.test(value || '')
// => false

Introducing Screamshot

Screamshot

I’ve been playing with programmatically fetching screenshots for years but never felt happy with the end result. Using PhantomJS directly seemed cumbersome and things didn’t work reliably for me when they reached production. It was whilst playing with Aesthetic that I learned how easy it was to use Capybara outside of a test environment as a tool for saving screenshots — I was struck by a thought:

My next screenshot-fetching app will use PhantomJS via Capybara and Poltergeist and will be just great!

— Me, before I’d written any code.

So I wrote a Rails app that receives a request, creates a database record, returns an identifier, queues up a job, fetches the screenshot and writes it to a file, and finally notifies the requesting app via a webhook that the screenshot is ready. It did seem a bit much for such a “simple” thing but I was quite pleased with it — and webhooks are cool. As usual it brought my server to its knees.

I started wondering about using Heroku which made me think that being synchronous might be the way to go — as in, the motivation was mostly $$$-driven… Anyway, I rewrote it again*.

It’s called Screamshot and can be found on GitHub, this time it’s synchronous and built on Sinatra and PhantomJS (via Capybara/Poltergeist).

Here’s how to use Screamshot:

$ curl "http://API_TOKEN@screamshot.dev/screenshot?url=http://example.com"

It has plenty of room for improvement: it doesn’t appreciate slow ad servers and therefore often times out, the fonts don’t look great, and it’s currently utilising the limited concurrency of WEBrick.

But I still like it*** — and you might too.

* To be honest part of my motivation for making this again is because I like the idea** for the logo!

** I said I like the idea for the logo…

*** Again, mainly just the logo and colour scheme.

This is amazing! I would love to spend my days performing this silliness.