Stratus3D

A blog on software engineering by Trevor Brown

Working With HTML in Vim

I discovered another Vim command this week that made working with raw HTML much easier and figured I would share it.

The command sequence is dit. Focus the cursor over an HTML tag and in normal mode type dit. The contents of the tag will be deleted and the empty tag will remain. The cursor will be positioned at the end of the first tag. In order to insert more content all you need to do is type i and begin entering the new contents of the tag. This command comes in very handy when having to make lots of manual changes to an HTML document.

Example: Before: Title

After:

When working with raw HTML it’s helpful to have the markup indented so you can easily see parent/child and sibling relationships. In your .vimrc you will want to have a line turning on the file type indent on: filetype indent on. Whenever you open up a html file or paste html into an empty buffer make sure the file type is set by running :set ft in normal mode. Vim should print filetype=html as the result. If it doesn’t you want to correct the file type before proceeding. Then select all the markup and simply type = in normal mode. The HTML should be nicely indented with the settings you specified in your .vimrc or filetype file. Note that on large files this can take a while (sometimes almost a minute).

If you have any other vim commands that you frequently use when working with Vim I would love to hear about them!

Currying and Partial Application in Elixir

I often forget what currying and partial application are and how they are used, so I am writing this blog post to solidify these concepts in my memory.

###Currying

Currying is when a single function with multiple arguments is converted into multiple functions, each expecting one of the arguments of the original function. For example, we could curry the :erlang.atom_to_binary/2 function in Elixir like this:

> binary_fn = fn(encoding) ->
>     fn(atom) ->
>         :erlang.atom_to_binary(atom, encoding)
>     end
> end
#Function<6.80484245 in :erl_eval.expr/5>

> binary_fn.(:utf8).(:bar)
"bar"

We now have a function that takes the first argument, and returns another function that expects the second. This is currying. As you can imagine there are many possible uses for this. Including partial application…

###Partial Application

Partial application is when you curry a function and pass fewer arguments than the original function expected. Continuing with our atom_to_binary example, this would be partial application:

> atom_to_utf8 = binary_fn.(:utf8)
#Function<6.80484245 in :erl_eval.expr/5>

We now have provide one of the two arguments required to invoke atom_to_binary/2. We receive a new function which we store in atom_to_utf8 variable. This function expects the second argument of atom_to_binary/2 to be passed in. When this function is invoked, it calls atom_to_binary/2 with the values :utf8 (which was passed in earlier) and :foo.

> atom_to_utf8.(:foo)
"foo"

This is partial application. Partial application relies on currying to produce functions that contain references to the arguments that have been provided(via closures) and expect the remaining arguments of the original function.

Currying allows us to break a function down into many functions, and partial application uses currying to create functions with some of the arguments already applied. Both of these concepts are extremely useful. We can, as we did above, create new functions on the fly by providing a subset of the arguments, and we can also pass around the curried functions, providing the arguments they require as those arguments become available. There are quite a few possible uses for currying. I may write another post about currying and closures in Elixir sometime in the future but this is all for today.

Splitting Pipe Delimited Data With Ruby

Today I was working with some pipe delimited data in Ruby and stumbled across some things in Ruby’s String#split method that I thought I would share. My code needed to take data like this and parse it into an array of strings.

Some|Fields|of random|data|1|2|3

Each line of the data looked something like this and had a varying number of fields. Sometimes data would have missing fields:

Some|Fields|of random|data|||3

I figured I would simply split the string based on the pipe character using something like this:

'Some|Fields|of random|data|||3'.split('|') #=> ["Some", "Fields", "of random", "data", "", "", "3"]

This works seems to work fine. Blank fields come across as empty strings. I used the length of the array to determine the number of fields contained in the string. In this case, seven fields of data, the 5th and 6th of which were empty. I thought this would work but I quickly ran into an issue:

'Some|Fields|of random|data|||'.split('|') #=> ["Some", "Fields", "of random", "data"]

Now I had a problem. The string of data contains seven fields, but the last three are empty. After splitting the string on the pipe character we get an array of only 4 items(fields). My program needed to know that there were three empty fields at the end. I did some research and it turns out that Ruby’s String#split method takes an optional second parameter. The second parameter is an integer which limits the number of fields returned. If omitted, all trailing null fields are ignored and not added to the array. If the second argument is a positive integer it limits the number of fields returned. split('|', 0) would return an array with the entire string as the only element. But if the second argument is a negative integer, trailing null fields are added to the array as empty strings. That allows us to do this:

'Some|Fields|of random|data|||'.split('|', -1) #=> ["Some", "Fields", "of random", "data", "", "", ""]

Perfect! Now even with trailing empty fields in our data we are still able to tell how many fields are present.

Ruby’s String#split method makes parsing strings of data very easy. In my case all I needed to do was split the data on every newline, then take the array of strings returned and split each one on the pipe character.

Hope you found this useful!