Edward Loveall

Building a Waiting git Editor

When I commit to a git repository, I don’t like using a command line editor, but using a GUI editor sometimes takes a while to boot up. I’ve settled on using TextWrangler for now since it opens a window reasonably fast, especially if the app is already open.

I always thought it would be cool to build a dedicated git editor that you can launch from the command line, see a nice diff of my changes, and edit using native Mac text editing. If I ever want to do that, I need to figure out how git creates a commit with an external editor.

My git config for the editor looks like this:

$ git config --get core.editor

edit --wait --new-window

Git will open TextWrangler using a couple of options:

--new-window makes sense to me, but how does --wait work? Well, a bunch of things happen when you type git commit:

(I’m sure it does much more than just that, but this is all I need to know for now.)

Great, so now all I have to do is make an editor that writes text and closes its process when its done. A ruby script will exit automatically when its done running, so if I can create a script to write some text to a file, it should work.

Here’s what I came up with:

#!/usr/bin/env ruby

commit_message_path = ARGV.last
puts File.read(commit_message_path)

print 'Commit Message: '
message = $stdin.gets

File.write(commit_message_path, message)

The first line uses a hashbang to tell the rest of the script to be interpreted as a ruby program.

Then, I grab the last argument passed into the program and print all its contents out to the screen. That way I can see all the changes that have happened since the last commit. This printing is optional.

Next, I give the user a prompt to input their commit message. Once they hit return, I write the commit message to the original file. The ruby process closes, git does its thing, and I have a new commit message!

This is obviously very primitive. It’s still a command line UI, not a GUI. It can’t do multiline strings. In fact, it’s less useful than using the -m option with git commit. But now I know (and so do you) how to build a waiting editor.

The Imperfect Feminist

My friend Casey said to me recently:

For me I just accept that there is no such thing as the perfect feminist.

It made me realize that I had been considering feminism a binary term: you are, or you aren’t. This, in hindsight, is stupid.

Maybe you consider yourself a programmer, or an artist, or a chef. When did you become that? For me, I became a programmer when I switched from being a designer to using Rails full time. But so what? Does that mean I’m done? Absolutely not. I’m still learning how to be a better programmer all the time.

This is now how I feel about being a feminist. I’m a feminist, but that doesn’t mean I’m “done”, or that I won’t make mistakes again, or that I have nothing left to learn.

It doesn’t matter if someone calls themselves a feminist or not. What matters is that they are willing to learn, listen, and get better.

An Incredibly Dumb Way to Make Sentences

For a long time, Markov chains seemed unapproachable to me. I’m not exactly sure why; perhaps they were always brought up in the context of artificial intelligence, or academic math, or their impossible-to-understand Wikipedia page.

I’m here to tell you: Markov chains are easy to understand, especially the first-order ones. Let’s take a look.


Take the following sentence fragment:

the cat and the dog

Look at each word and count the words that come after it:

the -> cat: 1
    -> dog: 1
cat -> and: 1
and -> the: 1

Let’s go through each word in the cat and the dog. the has two words that follow it: cat (the cat) and dog (the dog). cat is followed by and. and is followed by the. With those pairings, the whole sentence is accounted for: we’ve already mapped the the after and, and dog has no words that follow it. The numbers next to each “follower word” are the number of times it appears after the first word. For example, cat appears only once after the.

This is the basic structure of the words in this sentence. It allows us to to make new, similar sentences. We can do that by picking a word at random, then picking one of it’s follower words at random, then repeat. For example, we can randomly start with cat:

cat and the cat and the dog

We stopped at dog because it has no followers. As you can see this is a semi-plausible sentence, and looks quite a bit like our original sentence. Even with the randomness, there’s just not a lot of followers to choose from.

More words

Here’s an excerpt of the word structure from Shakespeare’s Much Ado About Nothing. It’s massive so I’ll only show you some of the structure for “a”:

a -> man: 22
  -> good: 17
  -> very: 7
  -> young: 3
  -> kind: 3
  -> lord: 3
  -> messenger: 2
  -> lady: 2
  -> new: 2
  -> lion: 1
  -> headborough: 1
  -> sexton: 1
  -> lamb: 1
  -> badge: 1
  -> constable: 1
  -> victory: 1
  -> stuffed: 1
  -> skirmish: 1
  -> difference: 1
  -> reasonable: 1
  -> boy: 1
  ...

That’s a lot more to work with, and it goes on for quite some time! Here are some examples of the sentences we can generate with all that text:

scholar would modestly examine your answer

husband have you welcome my place

purse such matter there’s a rougher task in your friend

Now, I know what you’re thinking: “Wow! That’s literally as good as Shakespeare!” I know. I used a little something extra to pull off this convincing effect: weighting.

Notice how in the word chain above, man appears 22 times after a, but a word like headborough only appears once. That means, if we come to the word a and we’re picking a follower word, man is 22 times more likely to follow than headborough. This is a weighted algorithm and it will create more plausible sentences.

Second-order Markov chains

We’re just tracking a single follower after each word. This is called a single-order Markov chain. But if we were to extend that to two words, we could have a second-order Markov chain:

the -> cat: 1 -> and: 1
cat -> and: 1 -> the: 1
and -> the: 1 -> dog: 1

The really bad example sentence that I picked is… well, really bad at showing this, but now we have two words to look at when choosing a follower word. That is, if we generate the cat, we can see that it’s always followed by and. This can give us more realistic sentences because it has more context.


Learning a new programming language

A Markov chain is now my go-to project for learning a new programming language. It’s relatively simple and gets me working with basic data structures, file loading, randomness, and loops. I recently started learning Swift and made one.

Pun generator

However, programming a Markov chain won’t expose you to all parts of a language. My friend Gabe wrote a blog post about learning a new programming language that outlines the steps to make a pun generator. It is a fantastic post that will end in you having a program that will generate the lamest of puns.

I went through it and created a Swift version.

I’m writing this post as sort of a prequel to Gabe’s. I found the pun generator to be a large undertaking compared to a Markov chain. If you’re looking for a something between “hello world” and generating puns, I suggest you give Markov chains a try.

Service Objects in Rails

I want to introduce you to an idea. You may have already heard about things like skinny controllers, skinny models, etc. But then you start coding and have to do something extra. It’s more than just User.new and redirect_to user. How are we supposed to keep those files small when we have to do all this stuff?! Answer: Service objects.

These are plain ruby classes. Ruby, not rails. Back in the day when you were writing things like a Greeting class that spat out "hello world", that’s what we’re going to build. I emphasize this because it took far too long for that to work its way into my brain. It is a plain. Ruby. Class.

So let’s make one. Here’s the scenario: In your app, a user gets a random color assigned to them when they sign up.

Where do service objects go?

I usually create a directory called app/services. This (for the most part) is where all of my plain ruby classes go. I know some people who also put them in app/models. There’s no technical advantage to either, and they can actually go anywhere. It’s just an organizational preference. I prefer my models to be separate, some people think all Class-like files should be grouped together. Your choice. For this tutorial, I’ll be putting them in app/services.

What should we call it?

My current preference is to name service objects as NounVerb. Example: If you have a class that that emails customers, you could name it CustomerMailer. A class that calculates tax on a particular item could be named TaxCalculator. Try to use sensible names, but you have to be pragmatic about it as well. UserSignerUpper is terrible as a class name, so we’re going to use UserRegistrar instead.

Code

We’ll set up the model and controller first:

app/models/user.rb

class User < ActiveRecord::Base
  validates :email, presence: true, uniqueness: true
end

app/controllers/userscontrollers.rb_

class UsersController < ApplicationController
  def new
    @user = User.new
  end

  def create
    @user = UserRegistrar.perform(user_params)

    if @user.save
      redirect_to @user
    else
      render :new
    end
  end

  def show
    @user = User.find(params[:id])
  end

  private

  def users_params
    params.require(:user).permit(:email)
  end
end

Pretty basic. Notice the @user = UserRegistrar.perform(user_params) line. This is the service object (that we haven’t written yet) in action. I like writing the code for how I will use the class before the class itself. It gives me a goal for when I’m writing it. In this case, it tells me:

Let’s write it.

app/services/userregistrar.rb_

class UserRegistrar
  COLORS = ['red', 'orange', 'yellow', 'green', 'blue', 'violet'].freeze

  attr_reader :params

  def initialize(params)
    @params = params
  end

  def self.perform(params)
    new(params).perform
  end

  def perform
    User.new(user_params)
  end

  private

  def user_params
    {
      color: random_color,
      email: params[:email]
    }
  end

  def random_color
    COLORS.sample
  end
end

Ok so here’s our service object. Again, plain old ruby object, often called by the funny sounding acronym PORO. No rails in sight. Walking through the object:

COLORS = ['red', 'orange', ...].freeze

A constant named COLORS holds all of our color values. I decided to call .freeze on it at the end because those values never, ever change. For this use case, we will always have those six colors. In general if you’re going to use a constant, freeze it. If you need something that can change, use a variable or attribute, not a constant.

attr_reader :params

This is so we can have easy access to whatever I set @params to later. You’ll see in a sec.

def initialize(params)
  @params = params
end

We set @params to the user parameters we pass in from the controller. I always structure initialization around only setting those attr_* variables. That’s all it does. Nothing more.

def self.perform(params)
  new(params).perform
end

def perform
  User.new(user_params)
end

This is a little funky. The point of this is so I can call UserRegistrar.perform(user_params) instead of UserRegistrar.new(user_params).perform.

self.perform calls new and passes in user_params. Now we have an instance of UserRegistrar as opposed to the class. Then it immediately calls .perform on that instance, because .perform is an instance method, not a class method, such as self.perform. Convenience methods like these let your code look nicer.

.perform creates a new user object with some data (we’ll get to that next) and returns it. No magic, just User.new.

So that’s all the boring part. A bit of setup code, but we wanted to randomly assign a color! One more step first:

private

def user_params
  {
    color: random_color,
    email: params[:email]
  }
end

This is a convenience method letting us pass user_params to User.new back up in the .perform method. Astute readers may wonder “Why not just use params.merge(color: random_color)?”. Imagine a Company with a full address and a name and an industry and a stock symbol and… The number of parameters could be very large. We can mix values and other methods here to make up everything we need for User. .merge would be fine in this case, but messy in others, so I’m keeping it scaleable.

random_color gets our random color (duh) for us, and params[:email] is the email we got when we initialized the instance. All said and done, this is all the data a user needs to be whole.

def random_color
  COLORS.sample
end

And finally, our random color.

A note on private:

I use private when there’s no reason for anything outside the class to access the method. Nothing else outside of this class will call random_color so it goes in private. For the purpose of this example, I kept COLORS and attr_reader :params on the public side, but I often make those private too.

You’ll notice too that many of these methods only do one thing, like random_color. I like these methods because while I could put that code in user_params directly, random_color gives me more information. Using small, well named methods is a HUGE win for code readability. No one has to guess what random_color does.


So that’s service objects. It can be a little heady at first, but you’ll start seeing more and more reasons to use them in project. Check them out and your code will get cleaner.

You can see example code here: https://github.com/edwardloveall/examples/tree/service-objects

Pull Feed

Pull Feed Logo

I just launched Pull Feed. It will give you a feed url for new pull requests for any particular GitHub repository. I created it to solve an itch: I wanted to keep up with particular open source projects, but GitHub only offers the ability to “Watch” a repository. Watching means you get notifications for pretty much all forms of activity; new issues, new pull requests, comments, etc. That was too much. I just wanted to know what was being proposed.

I also really enjoy the feed model of consuming content. RSS feeds pile up in my feed reader and let me read them on my own terms. No alerts, just content when I decide I want to go check it out. It’s great!

So I made Pull Feed. It’s free, requires no sign up, and is 100% open source. Below are some technical details about how I made it. If you’re curious, read on.

The Tech

On a basic level, a feed url consists of an owner and repo component. Something like pullfeed.co/feeds/github/linguist. It then hits GitHub’s Pull Request API, parses the pull requests for that repository, and turns it into an Atom feed.

Pull Feed is built with Ruby on Rails. It runs on a Centos 7 box at Digital Ocean using nginx and a puma. This was my first real success deploying to a linux server on my own. Before this, I’d used Heroku, while great for quick deploys, gets very expensive.

If you’re familiar with common ruby gems, there aren’t too many surprising libraries used in the project. Of interest GitHub uses Markdown to format descriptions of each pull request. Redcarpet parses that Markdown. Bourbon and Neat remain my favorite gems for developing SCSS layouts and styles.

Atom vs RSS

When I originally started, I had RSS in mind. The problem came when I wanted to add authors to each entry. There are a few different ways to show authors in RSS:

<author><name>Edward Loveall</name></author>
<author>Edward Loveall</author>
<creator>Edward Loveall</creator>

Feed readers have varying levels of support for these tags. For example, I use ReadKit. It works great with the <creator> tag, but not so much with the others, that are defined in specs and seem far more semantic. No good. Feedbin does a great job at parsing all these random formats out and making this display nice, but not everyone uses Feedbin and I wanted something that would work well with as many feeds as possible.

I had heard that Atom was better for a while but I had it in my head that it was less ubiquitous. That doesn’t seem to be the case at all. Pretty much everything I’ve run across supports both Atom and RSS. And it solved my author problem too:

<author><name>Edward Loveall</name></author>

This is the only supported way in the Atom spec to define an author. And it’s nice and semantic. Nice.


So that’s Pull Feed. If you’re interested in keeping up with open source projects, check it out! I’ve so far been able to keep up with project like activemodelserializers, suspenders, til, and others. Maybe you can too.

Automatically Lock Your Computer Based on Wi-Fi

I use my computer in multiple environments, at home, the office, and out and about. I like having the password prompt after sleep or screensaver start. But I do not like having to enter my password all the time.

Solution: Enable password protection when not at home.

Problem: That’s annoying to remember.

Solution: Don’t.

I wrote a script to detect your what Wi-Fi network you’re on. If it’s not your home network, it sets the password lock. If it is your home network, disable it. This runs via a launchd plist every five minutes (adjustable) and is pretty dang fast.

Note: this only works on a Mac.

Installation

Now every five minutes (that 300 in the plist) it should run the autolock.sh script and set or unset the password protection. To make sure it’s working, change the SSID name to something else, unload and load the launchd job again and check in System Preferences under Security. “Require password X seconds after sleep or screensaver begins” should reflect the change, one way or another.

Bonus

I thought I was going to need a nice sanitized name for the current Wi-Fi network name, but the way this script works, it doesn’t really end up needing it. It just needs to know if you’re on that network or “something else”. If you do need that functionality, here are some ways to get it:

$ ioreg -rn en0 | grep -e '[^B]SSID' | ruby -e 'puts ARGF.read.chomp.split(/"/).last'

$ ioreg -rn en0 | grep -e '[^B]SSID' | awk 'BEGIN { FS = "\"" }; { print $4 }'

$ /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | grep -e '[^B]SSID' | awk 'BEGIN { FS = ": " }; { print $2 }'

Update

Gabe fixed up my awk code for me so the last two commands there can be:


$ ioreg -rn en0 | awk 'BEGIN { FS = "\"" }; /[^B]SSID/ { print $4 }'

$ /System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk 'BEGIN { FS = ": " }; /[^B]SSID/ { print $2 }'

The Rouge Website

I had the opportunity to work on the website for the Ruby gem Rouge. I designed and built the website, and created the logo. It’s probably been my biggest contribution to open source so far, and I’m very proud of it.

What is Rouge?

Rouge is a syntax highlighter. It comes with all the popular languages, and a bunch of less popular ones. It’s also built to be compatible with Pygments’ stylesheets. Pygments is a very popular (and good) syntax highlighting library written in Python. However, to use it in Ruby projects, you have to spawn a separate Python process and pipe in input and output, which is about as fun as it sounds.

Rouge aims to be a great stand-alone parser written entirely in Ruby, and I think it does a great job. The gem had a website but it was just a demo page of small code snippets from each language. I saw this in the gem’s readme:

Also, if anyone with design skills feels like helping me make a website for rouge, I’d really appreciate the help. So far all I’ve got is the demo page.

I emailed the maintainer, the very talented jneen, and she was thrilled to work with me on it. I spent roughly 35 hours total on everything over about four months from December through March.

Here’s the logo with some of the iterations I went through:

logo iterations

I started with the idea that rouge is a makeup. I tried to do a more-or-less photo-realistic version of a makeup compact which came out well but didn’t really work well in the context of a webpage. I also played with the {R} concept which led me to { Rouge }. It originally faded lighter and lighter to represent the different syntax tokens, but we eventually went away from that and the pinkish background. I also ended up using {R} concept in the favicon.

Website

I made the website in Rails, naturally. jneen wanted a paste service like Pastebin or GitHub’s gists. I used Hashids to obscure the paste IDs so they’re harder to spelunk around for. I also thought it would be good to show code being parsed right when a visitor gets to the page.

I started by highlighting (heh) the features of Rouge that I thought were the most valuable:

jneen wanted to feature the language parser. After playing around with words, designs, and code color schemes, we created the website as it is now.

Some tools I used to get it all done

All in all it was a great project and I’m super proud to have worked on it. Check out the website, the gem, and the website’s source code.

Authentication vs Authorization

I have long struggled with the difference between authentication and authorization. They both revolve around user permissions and signing in and out. But I recently found out the difference and made a small mnemonic for keeping them straight:

Naming Conventions for String Identifiers in Rails

Rails has many conventions. It’s one of the reasons I’ve felt so successful with it. I can let go of a lot of decisions and trust the framework to do the right thing. However, it doesn’t (and couldn’t) have a convention for everything. For instance, there’s no convention for what to call an identifying string on a model.

An Example

What is the field you identify a Category by? Here are some choices:

I think title is probably the best choice out of those. However there are many circumstances where name works just as well:

Or perhaps label:

There are many options and it starts to get pretty confusing, especially since there are multiple names that make sense in the same situation. I’ve been on many projects where we’ve used these interchangeably and it’s a mess.

The Convention

So here’s what I’m trying:

This won’t cover everything, of course. Categories can have a name and Products can have a label, but sticking to title instead doesn’t break many grammar rules. And like with everything in Rails, occasional exceptions are just fine.