Hardscrabble šŸ«

By Max Jacobson

See also: the archives and an RSS feed

Has Chris Pratt Been Enchanted?

December 8, 2013

I canā€™t think of Chris Pratt, the very funny actor who plays Andy on Parks and Rec, without thinking about this tweet, by that showā€™s creator, Mike Schur:

This tweet accompanied the news that Pratt was cast in the lead role of Marvelā€™s upcoming, probably huge superhero movie Guardians of the Galaxy. Obviously Schur has some bias, being friends and colleagues with the guy, but I canā€™t help but agree. I think Chris Pratt has been enchanted.

Andy wasnā€™t supposed to be a regular on Parks and Rec but they kept him.

Heā€™s like, really funny on Twitter.

Heā€™s married to Anna Farris and they seem really happy.

He apparently has no trouble losing weight and becoming muscular in a cinematic way.

No like, really, Hollywood is happy to cast him as the funny guy, one of the guys in Oscar-bait like Zero Dark Thirty.

Who is Chris Pratt? There seems to be no undercurrent of anxiety like drives some artists, heā€™s too busy soliciting his fans to tell him the best moment in their life, and dishing out positive affirmations:

His simple positivity almost reminds me of artists like Steve Roggenbuck or Ryland Maserang without the poetry?

Heā€™s charming, politically neutral, and probably, I think, enchanted. Iā€™d buy that stock.

this is my suitcase

November 30, 2013

We are not ā€œbreaking upā€, because we all still love each other. Mary Lynn writes great music. I still write music all over. We all still exist and we all still create. We are simply putting a lid on This Is My Suitcase to capture everything weā€™ve done; We are merely writing a really good ending to our own wild story.

ā€“ Joseph Anthony Camerlengo

I donā€™t remember where I first heard of This Is My Suitcase, but I think it was on the absolute punk forums, probably in some thread for links to zips of weird albums from bands no one has heard of, many of which I downloaded and sifted through and deleted. One of them was ā€œMissent to Thailandā€. I have a vague memory of listening to it in an airport and being shocked by how much I liked this weird out of tune pop about being in love. I subscribed to the RSS feed of their Myspace blog (!?) and watched their careers as they almost went mainstream (I think Fall Out Boy were fans and tried to help them out, but it didnā€™t go anywhere) but they never quite left Ohio, where I think theyā€™re local hometown hero types.

But of course, this is the internet, so this weirdo in New York got to become quite a fan of theirs. I had a few other bands or filmmakers or artists whose careers I casually followed through various feeds, who I never would have known about without the internet. Some I forgot about, and some I lost the bead on1, others. And Iā€™m really grateful for all of that, because itā€™s got some of that magic of what I imagine earlier generations found in digging through crates of records or whatever.

Iā€™m bummed I never saw them live, but they kind of only existed on the internet anyway? To me.

When I made my short film ā€œIā€™m So Happy Iā€™m Ecstaticā€ I knew I needed to include one of their songs. Iā€™m really glad itā€™s in there.

I donā€™t remember exactly when I started, but I guess Iā€™ve been listening to them a while. (myspace rears again in that tweet)

Their last album, ā€œIn The Wake Of Atrophy: a poignant album for heartsick humansā€, came out yesterday. Itā€™s available to stream or buy on bandcamp. The first music video for My Organs Are Our Organs just came out too.

If youā€™re a heartsick human (and you are) then you know what to do.

  1. the memory of one myspace band called ā€œisaā€ continues to haunt / elude meĀ 

Synchronize Our Dictionaries

November 30, 2013

Recently Iā€™ve been melting the butter stick of my brain against the griddle of Reginald Braithwaite, whose twin books on JavaScript and CoffeeScript as functional programming languages, JavaScript Allonge and CoffeeScript Ristretto have been tripping me out hard.

I bought them yesterday for their Black Friday half-off prices and loaded them into iBooks on my Mac and iPad (so glad to have a good ePub reader for Mac) after having their full-text-for-free web pages open for weeks in my browser, teasing me to read them while I do Ruby stuff all day.

In order to talk about how this works, we should agree on a few terms (you may already know them, but letā€™s check-in together and ā€œsynchronize our dictionariesā€). The first x, the one in (x) ->, is an argument. The y in (y) -> is another argument. The second x, the one in -> x, is not an argument, itā€™s an expression referring to a variable. Arguments and variables work the same way whether weā€™re talking about (x) -> (y) -> x or just plain (x) -> x.

The particulars of this passage arenā€™t as important as that one phrase I plucked as the title of the blog post which I just really like a lot. Any kind of writing is basically just that. Itā€™s as much about synchronizing your minds as it is synchronizing your language but thatā€™s kind of the same thing.

open blog

November 24, 2013

This blog is open for business. Also itā€™s open like, itā€™s on on github, which means you can fork it, read the drafts, submit pull requests, etc.

This isnā€™t a big deal. Itā€™s true of all jekyll blogs on github. While reading about ā€œopen companiesā€ like Balanced and Gittip, I thought that this is also true of my blog.

I kind of want to be a better blogger. Iā€™m pretty proud of how I put together this new blog. It feels sturdy, with well-organized source code.

Today I bought a hoodie at American Apparel and the guy ringing me up asked for my email address because ā€œweā€™re kind of going green and sending by receipts via emailā€ and I told him itā€™s max@hardscrabble.net and he asked me to spell it. I said, ā€œitā€™s max at hard, like difficult, and scrabble, like the gameā€ and the other cashier laughed like, what kind of email address is that? I said, ā€œI just think itā€™s a fun wordā€ and got the hell out of there.


edit November 2014: I edited a link to point to the new home of the blogā€™s github repo, which moved from my user to a new organization called hardscrabble

javascript resources

August 16, 2013

Here are some links to free, online resources I found helpful while learning JavaScript.

Start with some introductory materials. My favorite is jQuery Fundamentals. Itā€™s an awesome, brief book by Rebecca Murphey. It starts with the fundamentals of JavaScript and then covers the fundamentals of jQuery. Itā€™s really awesome. Murphey and some friends used to do a video podcast about jQuery called yayQuery which is a cute as hell name. I havenā€™t really watched any of those though. Focus on the book/site. Try to follow along in the built-in editor / sandbox environment.

Try to understand everything she covers in that guide because itā€™s all ā€¦ fundamental ā€¦ haha.

Check out Airbnbā€™s JavaScript style guide on github at airbnb/javascript. Beyond (interesting) style-related-stuff like how they recommend you indent your code, itā€™s also super instructive for learning the language itself because it covers the conventions they recommend for pretty much every aspect of the language, so if thereā€™s something you havenā€™t been exposed to yet, youā€™ll find out and learn about the concept in a way that has been thought about carefully.

I liked this recommendation of theirs:

// bad
var sidebar = $('.sidebar');

// good
var $sidebar = $('.sidebar');

because, yeah, totally, if youā€™re caching a jQuery object why not prefix it with a dollar sign so you remember thatā€™s what it is? Thereā€™s a lot of good stuff like that.

This is a funny video about jQuery: Paul Irish : 10 Things I Learned from the jQuery Source. I mean itā€™s insightful too. Itā€™s just this guy reading the source code and explaining how jQuery works. It makes you feel like you could just read and understand the source code of any major library or framework.

The next thing to do is try making some static sites with jQuery and maybe put them on GitHub Pages. Just create a repo and do your work on a branch called gh-pages. You can just delete your master branch. When youā€™re ready to show off your work you can push it to GitHub and people can look at the actual site as well as the source code. Itā€™s really cool, this becomes this just because of the branch name. Btw the location of the page is always http://YOUR_GITHUB_USERNAME.github.io/REPO_NAME.

Some things to make:

  • a calculator
  • a todo list
  • a page that pulls in JSON data from some API and renders it on a page. maybe make a page where you can enter a github handle and it will fetch the JSON at, eg, https://github.com/maxjacobson.json and print some of the data to the page. Or any other API. Maybe one from a web app you made.

Maybe also install node. Just brew install node and then you have node. Now you can run JavaScript programs from your command line with just like node whatever.js. They donā€™t even have to be web apps. Just little programs! Maybe Project Euler problems. Definitely solve some of those problems. Do as many as you can. I should do more of those. Damn. Just write some out in JavaScript. Use console.log wherever you would use puts in Ruby.

By this point in the blog post you should feel like youā€™re pretty good at JavaScript. I feel like you are. Maybe take Rebecca Murpheyā€™s JS Assessment which is kind of like a less meditative version of Ruby Koans used in job interviews to assess your level of JavaScript knowledge. I found this super hard and educational. I got less than halfway through. I want to revisit this.

Take a detour into CoffeeScript with me. The main reason I like JavaScript is CoffeeScript. I like it a lot. Install it with sudo npm install -g coffee-script (npm is ā€œnode package managerā€ and itā€™s a lot like RubyGems. The main difference is that by default, without the -g flag, it doesnā€™t install globally on your computer, it installs into the current directory in a subdirectory called ā€œnode_modulesā€). If the syntax appeals to you, try rewriting an earlier project or program from JavaScript to CoffeeScript. You can run it with coffee whatever.coffee or compile it into JavaScript by running coffee -c whatever.coffee which will create whatever.js for you.

CoffeeScript is kind of confusing at first but I really like it. Itā€™s like, why use this. It took me a while to figure out how to use CoffeeScript with jQuery but itā€™s actually super simple, hereā€™s a basic example:

$(document).ready ->
  $("#shout").on "click", ->
    alert "YO WHAT UP"

Which could be written even more compactly as:

$ -> $("#shout").on "click", -> alert "YO WHAT UP"

Which is kind of ridiculous and unreadable but cool that itā€™s valid?

I guess all thatā€™s left is to keep going and start learning how to build complicated software in this cool language. I want to learn a JS framework next and canā€™t figure out where to start. But thatā€¦ is a tale for another blog post.

the woods

July 22, 2013

Kings of Summer

A few months ago I saw a newish movie called ā€œThe Kings of Summerā€, which is about a trio of teenage boys who get fed up with their loving parents, move into the woods, build a ramshackle house, and live in it. Theyā€™re trying to make a statement. I think itā€™s something like, ā€œWeā€™re men. Stop treating us like kids; we can live off the land.ā€

programmers, drawn to the woods

As Iā€™ve been learning to program within the Ruby on Rails web application framework Iā€™ve, at times, felt like those kids suffocated by their loving parents:

Rails Mom

And drawn to that ugly pile of sticks in that clearing in the woods. Not because itā€™s better, but because itā€™s more mine.

Iā€™m drawn to the woods when I read blog posts like this and want to replace OS X with Linux and Sublime Text 2 with Vim.

I was drawn to the woods when I got this eyebrow-raising keyboard I type fast as hell on.

Iā€™m drawn to the woods when I read about Node JS even though Iā€™m in the middle of a program learning Rails.

Summer is a pretty good movie. I like the way it pokes fun at these kidsā€™ naĆÆve concept of what it means to be an adult. At one point the protagonist is proud to grow a mustache. But in the end, they go home to their parents, and itā€™s the most grown-up thing they do all movie.

Iā€™m slowly coming around to the Rails idea of ā€œconvention over configurationā€. Not that I was opposed to it or anything, but I didnā€™t immediately appreciate or understand it. Learning and using Rails still feels a little like moving into a fully-furnished apartment where the previous tenant and I wouldnā€™t have necessarily hung out. But itā€™s got AC and a well-stocked fridge and who am I to complain?

Going to the woods is fine. You might find and bring something amazing back with you, like Rails or For Emma, Forever Ago. I really donā€™t mean to bolster any societal hegemony. Just try not to get lost.

all the thoughts that went through my head while trying to pass the first test in the test suite of a warm up exercise this morning before coffee and then again this evening after painkillers

July 3, 2013

Recently at school weā€™ve been doing code exercises to warm up in the morning. Weā€™re given contained problems to solve with code. Problems that would be possible to solve without code but tedious or prohibitively time-consuming. Sometimes we move on to lecture before I can solve one and it haunts me all day.

Hereā€™s this morningā€™s:

Palindrome Product

A palindromic number reads the same both ways.

The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 x 99.

Write a program that can detect palindrome products in a given range.

The specifics of what this means were ostensibly made more clear by a provided test-suite.

Iā€™ve done a problem like this before at a coding meetup and I remembered how Iā€™d wrestled with it for minutes and got it working and then seen someone elseā€™s impossibly elegant solution and felt inspired.

Mine was probably something like this:

def is_palindrome?(num)
  digits = num.to_s.split("")
  i = 0
  while i < digits.length
    if digits[i] != digits[-i-1]
      return false
    end
    i += 1
  end
  return true
end

ugh

And hers was something like this:

def is_palindrome?(num)
  num.to_s == num.to_s.reverse
end

And I was just like oh.

So this morning I had a moment of thinking I already knew the hard part of this problem, and then I looked at the tests. Hereā€™s the first one:

test 'largest_palindrome_from_single_digit_factors' do
  palindromes = Palindromes.new(max_factor: 9)
  palindromes.generate
  largest = palindromes.largest
  assert_equal 9, largest.value
  assert [[[3, 3], [1, 9]], [[1, 9], [3, 3]]].include? largest.factors
end

first test

Oh thereā€™s a lot more going on there.

But thatā€™s fine, I think, Iā€™ll make a Palindromes class, give it a few methods, thatā€™s fine, letā€™s do it. So I started with something like this:

class Palindromes
  def initialize(options)
    max = options[:max_factor]
    # then I decided the range would begin at 1 mainly because it has to start somewhere and the test's assertion seemed to suggest 1
    min = 1
    @range = min..max

    # At this point I sort of paused to think about what to do next and Kristen noticed I stopped typing and said something about how I should host a show called "Max Factor" and I laughed.
  end

  # this felt as good a place as any to write that ace method I had in my back pocket
  def is_palindrome?(num)
    num.to_s == num.to_s.reverse
  end

  # then I was like uhh I guess I need a generate method
  # what does that even mean though
  def generate
    @range.each do |num1|
      @range.each do |num2|
        # what if I like... iterate over the range twice nested like this
        # this looks too ugly to be right but I think maybe...
        if is_palindrome?(num1 * num2)
          [num1, num2] # I know I have to do something with this array
          num1 * num2  # And also their product maybe?
          # but what
        end
      end
    end
  end
end

first draft

At this point something about the test bubbled to the surface of my mind.

largest = palindromes.largest
assert_equal 9, largest.value

wait what?

Wait, what the what is the largest method returning that it has a value method?

Damnit Jeff do we have to create another class?

OK fine I guess palindrome factors are a sufficiently interesting thing that they should be their own class. I kind of reached a point in the generate method where I had some data I didnā€™t know what to do with, and that makes some sense as a place to put it, so I started rewritingā€¦ and ran out of time.

Iā€™m going to finish it now, I have to. Itā€™s very late. I used to stay up this late. Jeez.

class PalindromeFactors
  attr_accessor :value, :factors
  def initialize(num1, num2)
    @value = num1 * num2
    @factors = [num1, num2]
  end
  # that should maybe be enough for now?
  # the value will be a palindrome
end

class Palindromes
  def initialize(options)
    max = options[:max_factor]
    min = 1
    @range = min..max
    # so let's keep track of the factors whose product is a palindrome
    @palindrome_factors = []
  end

  def is_palindrome?(num)
    num.to_s == num.to_s.reverse
  end

  def generate
    @range.each do |num1|
      @range.each do |num2|
        if is_palindrome?(num1 * num2)
          # create the new object and shovel it into the array
          @palindrome_factors << PalindromeFactors.new(num1, num2)
        end
      end
    end
  end

  def largest
    @palindrome_factors.sort_by{ |pf| pf.value }.last
  end

end

second draft

Up until this point, running the tests hasnā€™t felt worth doing, because I didnā€™t even have the methods itā€™s trying to call. But now I do. And maybe itā€™ll even pass.

It doesnā€™t make them pass.

Before I knew about proper test-driven development, I did a sort of shake-and-bake version where I manually tested things, and my favorite tool for that is CodeRunner which lets me just run little bits of code and see what happens. Kind of like irb/pry but with a GUI. So I copy my code into there without the tests and add this:

palindromes = Palindromes.new(max_factor: 9)
palindromes.generate
largest = palindromes.largest
puts palindromes.inspect

poking at it

And this is what it printed:

#<Palindromes:0x007f902a10a100 @range=1..9, @palindrome_factors=[#<PalindromeFactors:0x007f902a10a010 @value=1, @factors=[1, 1]>, #<PalindromeFactors:0x007f902a109f48 @value=2, @factors=[1, 2]>, #<PalindromeFactors:0x007f902a109e80 @value=3, @factors=[1, 3]>, #<PalindromeFactors:0x007f902a109db8 @value=4, @factors=[1, 4]>, #<PalindromeFactors:0x007f902a109cf0 @value=5, @factors=[1, 5]>, #<PalindromeFactors:0x007f902a109c28 @value=6, @factors=[1, 6]>, #<PalindromeFactors:0x007f902a109b60 @value=7, @factors=[1, 7]>, #<PalindromeFactors:0x007f902a109a98 @value=8, @factors=[1, 8]>, #<PalindromeFactors:0x007f902a1099d0 @value=9, @factors=[1, 9]>, #<PalindromeFactors:0x007f902a109908 @value=2, @factors=[2, 1]>, #<PalindromeFactors:0x007f902a109840 @value=4, @factors=[2, 2]>, #<PalindromeFactors:0x007f902a109778 @value=6, @factors=[2, 3]>, #<PalindromeFactors:0x007f902a1096b0 @value=8, @factors=[2, 4]>, #<PalindromeFactors:0x007f902a109390 @value=3, @factors=[3, 1]>, #<PalindromeFactors:0x007f902a1092c8 @value=6, @factors=[3, 2]>, #<PalindromeFactors:0x007f902a109200 @value=9, @factors=[3, 3]>, #<PalindromeFactors:0x007f902a04c100 @value=4, @factors=[4, 1]>, #<PalindromeFactors:0x007f902a04be08 @value=8, @factors=[4, 2]>, #<PalindromeFactors:0x007f902a04b098 @value=5, @factors=[5, 1]>, #<PalindromeFactors:0x007f902a04a210 @value=6, @factors=[6, 1]>, #<PalindromeFactors:0x007f902a0494a0 @value=7, @factors=[7, 1]>, #<PalindromeFactors:0x007f902a048708 @value=8, @factors=[8, 1]>, #<PalindromeFactors:0x007f902a112cb0 @value=9, @factors=[9, 1]>]>

whoa nelly

Iā€™m always surprised by the dumbest things, but that seems really long to me. Thatā€™s not even every permutation of 1..9, itā€™s just the ones whose product is a palindrome.

Even though it surprised me, I still donā€™t really see why itā€™s wrong. So I take a look at the first assertion and try to test it

# the assertion:
# largest = palindromes.largest
# assert_equal 9, largest.value
puts largest.value

testing first assertion

And it printed: 9. Hey! That probably passed! Shouldnā€™t it turn like half green or something?

OK funā€™s over letā€™s look at the next test.

palindromes = Palindromes.new(max_factor: 9)
palindromes.generate
largest = palindromes.largest
# assert [[[3, 3], [1, 9]], [[1, 9], [3, 3]]].include? largest.factors
puts largest.factors.inspect

testing second assertion

And it printed: [9, 1].

For a moment my nose flares because I think this is a bad test and itā€™s not my fault. Of course itā€™s not my fault my largest method returns the two digits in one order and the test is expecting them in the other order! The way multiplication works, the order doesnā€™t matter! It should just include [9,1] in that list so my answer will be right! I want to just edit my answer into to the list of acceptable answers.

I want to be clear that at the time of the writing of this sentence I still donā€™t really know whatā€™s wrong with it but I kind of have a hunch. Iā€™m noticing there are actually way more brackets in that array than I was mentally doing anything with. Itā€™s not an array of arrays, itā€™s an array of arrays of arrays! But why? Iā€™m going to just look at it for a moment here:

[
  [
    [3, 3],
    [1, 9]
  ],
  [
    [1, 9],
    [3, 3]
  ]
]

whatā€™s the deal with arrays

So maybe the order of nine and one matters later, but itā€™s not why I failed this test.

The test asserts that this array includes the largest palindromeā€™s factors. The largest value is nine ā€“ I got that part! ā€“ but there are two in-range pairs of numbers that multiply to form nine, and Iā€™m not currently doing anything to group those together. The test is accounting for those two sets of pairs to be grouped in either order, but it wants both. Okay. Now I know.

I made some changes that felt right. I didnā€™t really think a lot so much as I just vibed out to the new A Great Big Pile Of Leaves album (which has played through maybe three times in full as I write this post) and typed stuff.

class PalindromeFactors
  attr_accessor :value, :factors
  def initialize(num1, num2)
    @value = num1 * num2
    # let's wrap our factors array in an envelope array in case there are multiple ways to arrive at this palindrome
    @factors = [[num1, num2]]
  end

  # and make a method to allow these objects to be updated post hoc
  def add_factor(num1, num2)
    @factors << [num1, num2]
  end

end

class Palindromes
  def initialize(options)
    max = options[:max_factor]
    min = 1
    @range = min..max
    # so let's keep track of the factors whose product is a palindrome
    @palindrome_factors = []
  end

  def is_palindrome?(num)
    num.to_s == num.to_s.reverse
  end

  def generate
    @range.each do |num1|
      @range.each do |num2|
        # let's stash this product in a variable because we'll be using it a few times
        product = num1 * num2
        if is_palindrome?(product)
          # let's check if we've already found this palindrome
          already_found = @palindrome_factors.find{ |pf| pf.value == product }
          if already_found
            already_found.add_factor(num1, num2)
          else
            @palindrome_factors << PalindromeFactors.new(num1, num2)
          end
        end
      end
    end
  end

  def largest
    @palindrome_factors.sort_by{ |pf| pf.value }.last
  end

end

third draft

Allow me to be absolutely clear: this still does not pass the tests but Iā€™m starting to feel a momentum and a full glass of milk happiness in my head because mysteries are unraveling before me.

When I go back to CodeRunner, where I used to see merely [9, 1] I now see: [[1, 9], [3, 3], [9, 1]] and I know what to do.

I change lines 10-13 of the previous example to:

def add_factor(num1, num2)
  @factors << [num1, num2] unless @factors.include? [num2, num1]
end

aha

and run the tests and it passes and I should be weeping happily right now.

After passing the first test it only takes about 30 seconds to get the rest to pass. Hereā€™s my final solution on gist. Itā€™s out of the scope of this post.


Later in the day, Carlos remarked that he sometimes leaves his body while doing yoga. I asked if the same is true for programming but I think I already knew how I felt about that.

I find problems like this very satisfying in that same disassociative, mind-clearing way. When I first start, my mind is moving too fast and I make too many assumptions and just start doing things and thatā€™s probably fine because thatā€™s how I find out what shape it is. Iā€™m reminded of this Steven King quote on writing from On Writing (via):

Stories are found things, like fossils in the ground. . . . Stories arenā€™t souvenir tee-shirts or GameBoys. Stories are relics, part of an undiscovered pre-existing world. The writerā€™s job is to use the tools in his or her toolbox to get as much of each one out of the ground intact as possible. Sometimes the fossil you uncover is small; a seashell. Sometimes itā€™s enormous, a Tyrannosaurus Rex with all those gigantic ribs and grinning teeth. Either way, short story or thousand-page whopper of a novel, the techniques of excavation remain basically the same.

No matter how good you are, no matter how much experience you have, itā€™s probably impossible to get the entire fossil out of the ground without a few breaks and losses. To get even most of it, the shovel must give way to more delicate tools: airhose, palm-pick, perhaps even a toothbrush.

Right?? What a beautiful, humble reframing of what makes great creative work: no, youā€™re not some genius coming up with profound, original ideas; youā€™re just digging, and gently, and hoping that if you just keep trying stuff, youā€™ll find something.

blogs... how do they work?

June 18, 2013

Iā€™ve been using this Octopress blog for a couple weeks and Iā€™m compelled to figure out how it works and came to be. Letā€™s spelunk now.

In October 2008, in a blog post called ā€œBlogging Like a Hackerā€ Tom Preston-Werner (GitHub co-founder) announced Jekyll, a new website generator for his personal blog. He sought to answer the question: ā€œWhat would happen if I approached blogging from a software development perspective? What would that look like?ā€ Hereā€™s the wayback machine archive of that post which is remarkable mainly for looking pretty much the same.

A scant two months later, in December 2008, GitHub announced Pages, a new way to host static sites on GitHub, each of which is processed by Jekyll, regardless of whether the programmer took advantage of its features. (Sidebar: it would be fun to work at a company where I could have an idea for a personal project and then find a home for it in a place that others will find and get use from it.)

At that time, Jekyll was at v0.2.1. In order to time travel and try that version of Jekyll on my local machine I ran these commands:

git clone https://github.com/mojombo/jekyll.git
cd jekyll
git checkout v0.2.1
gem build jekyll.gemspec
gem install jekyll-0.2.1.gem
jekyll --version

And got a bunch of error messages. Ok. I donā€™t know whatā€™s up with these. Let me fast-forward to April 2009 when they announced that GitHub pages was upgraded to use Jekyll v0.5.0. The marquee feature of v0.5.0 is a configuration file.

git checkout v0.5.0
gem build jekyll.gemspec
gem install jekyll-0.5.0.gem
jekyll --version
#=> Jekyll 0.5.0

OK nice. Iā€™m close to arriving at a point. Imagine being a programmer wanting to start a blog at this point in time and wanting to write in Markdown or Textile and wanting to manage your source files in Git and compile a static site and deploy it on GitHub and encountering this upon running jekyll --help:


Jekyll is a blog-aware, static site generator.

Basic Command Line Usage:
  jekyll                                                   # . -> ./_site
  jekyll <path to write generated site>                    # . -> <path>
  jekyll <path to source> <path to write generated site>   # <path> -> <path>

  Configuration is read from '<source>/_config.yaml' but can be overriden
  using the following options:

        --auto                       Auto-regenerate
        --no-auto                    No auto-regenerate
        --server [PORT]              Start web server (default port 4000)
        --lsi                        Use LSI for better related posts
        --pygments                   Use pygments to highlight code
        --rdiscount                  Use rdiscount gem for Markdown
        --permalink [TYPE]           Use 'date' (default) for YYYY/MM/DD
        --version                    Display current version

Alright, cool. Yeah. Ok. Wait where do I start?

Real blog agenda confession: I was planning to get stumped here to make a point but actually the README pretty clearly recommends cloning a ā€œproto-site repoā€ at https://github.com/mojombo/tpw and going from there so thatā€™s what Iā€™ll do now and see where this takes me.

git clone https://github.com/mojombo/tpw.git
cd tpw
git checkout b107ffb6e44fe4f2398b219e254426d3ec302142
jekyll --server

(That SHA is the last commit to that repo as of April 2009 and I feel like a time traveler with secret codez).

What this gives you is a blog that looks very much like Preston-Wernerā€™s and a pattern to follow: replace his posts with your posts; replace his name with your name; commit and push. Now you have a stark, white blog just like that cool guy.

Later in 2009, in October, Brandon Mathis released Octopress, a framework for Jekyll. In what must be an homage to that original blog post, its tagline is ā€œA blogging framework for hackersā€. Since then heā€™s built an ecosystem for plugins and themes around this framework. Where Jekyll is ā€œblog awareā€, Octopress is blog obsessed. Where Jekyll gives you just enough to get started, Octopress gives you a super sturdy, robust design and toolset.

Some key differences between Octopress and pure Jekyll

  • When deploying an Octopress blog to GitHub Pages, you compile the static files before pushing; when deploying a pure Jekyll blog to GitHub Pages, you push the uncompiled source files, with unrendered markup files and templates, and it compiles the assets upon receiving the push. If you want to use plugins, Octopress is a better choice because their effects can be wraught during the compilation but not in the post-receive hook (on GitHub anyway; you can set up your own server if you need all that).
  • That also means you only need one branch for a pure Jekyll blog, where you need two (ā€œsourceā€ and ā€œmasterā€) for Octopress.
  • It also means the commit log on your master branch is full of auto-generated, non-semantic commit messages (boo right?)
  • There are way more source files in an Octopress blog, which can feel somewhat constrictive, at least to this young blogger.
  • Octopressā€™s rake preview command watches for changes, including those made to the sass files, and compiles those into CSS. It would be cool if it compiled CoffeeScript too.
  • Octopress has this kind of confusing relationship with Git branches where its root directory stays on branch ā€œsourceā€ and is updated by the blogger, and contains a directory called _deploy which contains a second instance of the same repo, which is meant to stay on branch ā€œmasterā€ and be auto-generated by the framework. Itā€™s a clever solution to the situation constraints but not immediately intuitive or adequately explained (including by me just now, Iā€™m sure).

Because Jekyll is distributed as a gem and has a simpler, smaller file structure and a normal git repo, Iā€™m tempted to suggest itā€™s a better place to start for someone interested in getting their feet wet with this kind of ā€œhackerā€ blogging. Itā€™s easy to discard Preston-Wernerā€™s theme and start from scratch, and if your site is ugly then, as weā€™ve learned, youā€™re in good hacker company.

This is probably more true than ever since, in May 2013, just last month, Jekyll 1.0 was released and with it a magical, long-overdue command: jekyll new which ā€“ you guessed it ā€“ instantiates a plain white blog for you on your filesystem.

Also new is http://jekyllrb.com, some great (and beautifully designed) documentation to reference as you extend your site.

what even is jekyll

The Jekyll program itself is written in Ruby, but you donā€™t need to know Ruby to work with Jekyll. You just need to be okay with the idea of Ruby code generating your blog. In fact, if you go in knowing some Ruby, you might find yourself confused by some things like I was.

Jekyll looks at each markup file (HTML, Markdown, Textile) in your project and looks at the file extension to know how to convert to HTML, if it needs to. Itā€™s smart enough to know that some people use .md and others use .markdown and to just be chill about it. It reads the ā€œYAML frontmatterā€ to look for instructions for what to do with these files, like if it should look like a post, with the date and maybe comments or if itā€™s just some generic page. You can stash arbitrary values in their to use in your layouts too, like putting mood: happy at the top of fun posts and then referencing page.mood in your posts layout.

So letā€™s talk about that templating system briefly. Knowing Jekyll is a Ruby project, and having dabbled with Ruby web development, I made the mistake of assuming Jekyll would follow Ruby conventions that I was familiar with (something like Haml or ERB or Slim), but it kind of doesnā€™t. What it uses is Liquid, a templating system developed by Shopify. Like Jekyll, itā€™s written in Ruby and distributed as a gem, so it bundles along well. Once I adjusted my expectations, I found it easy to work with. When you initialize a new Jekyll site (with jekyll new my_great_blog), it gives you this index.html file to be your barebones homepage:

(note: I think I have to use a GitHub Gist to host that code snippet because if I embed it in this post, Jekyll will interpet the Liquid tags)

Alright so clearly itā€™s mostly HTML, and the file extension is .html, but thereā€™s a lot in there thatā€™s not valid HTML and would confuse your browser if opened directly. Which is fine, because thatā€™s not what you do. This is what a Liquid template looks like. If youā€™re looking for Ruby, youā€™ll be rebuffed by this. I have no idea where endfor comes from and the double curly braces and dot notation are very JavaScript-y. So learn to love Liquid, I guess.

This file is not a complete web page. It has no doctype or <head> or <body> tags. Itā€™s a partial. The file that has the rest of it is in _layouts/default.html and the line layout: default in this file tells Jekyll to compile this, then insert it into that. You can define more layouts but you may not have to. The other layout that comes with Jekyll is _layouts/post.html which is actually also a partial. When you write a blog post, it has layout: post in the YAML, so the compiled post is sent to _layouts/post.html, which has layout: default in the header, so it does a few things then passes the ball along to its final stop. Itā€™s like a cheap Russian nesting doll with only three dolls.

unspelunk

Honestly both are great. Octopress feels like rocket powered training wheels, but thatā€™s a fun visual so

rubĆ­ dos

June 17, 2013

The Ruby Core Team wrote this in October 2011:

Schedule:

  • We continue to provide normal maintenance for 1.8.7 as usual, until June 2012. You can safely assume we provide bugfixes and no incompatibility shall be introduced.

  • After that we stop bugfixes. We still provide security fixes until June 2013, in case you are still using 1.8.7.

  • We will no longer support 1.8.7 in all senses after June 2013.

Itā€™s June 2013.

One of the things that is keeping people using Ruby 1.8.7 must be that it comes with Macs as the default Ruby, and installing newer versions isnā€™t as easy as it could be. Well this is kind of cool:

Ruby developers will go through the process of installing rvm, rbenv, or chruby to manage multiple Ruby versions so this might not immediately affect the work they do on their personal computers but I think itā€™s a huge win because it encourages people to casually try Ruby and have a modern experience, be they newbies or experts in other languages. It also makes it easier to require newer versions of Ruby when releasing RubyGems.

I had this in mind while reading Whatā€™s new in Ruby 2.0 by Gabriel Fortuna, a speakerdeck Iā€™ll embed here:

Fortuna shows off some of the cool new features Ruby 2.0 offers. Some of them have to do with how the interpreter works more efficiently, which honestly goes over my head right now. But Iā€™m pretty interested in new syntactic features like keyword arguments.

Before Ruby 2.0, if you have a method that has several arguments, you just have to remember their order and which means what or wrap them in a hash. With keyword arguments you can label your arguments for greater clarity. This blog post has a great overview.

Another change is ā€œRefinementsā€ which aims to be a more elegant way to modify class behaviors in lieue of monkey patching. You can still crack open and modify classes in crazy ways, but this lets you localize those changes to contexts, for the sake of being a little safe about it.

Iā€™d love to use these features, the others Fortuna covers, and what Iā€™m sure are plenty of more little cool changes. Fortuna mentions that the next major version of Ruby on Rails, Rails 4, is designed for Ruby 2.0. Thatā€™s exciting. I wonder how fast the community will adopt these as the new de facto standard.

random emoji in prompt

June 13, 2013

Edit: This post is kind of sloppy. Please consider reading this later, similar post instead.


So this is fun. Most of us at school have some symbol or emoji in our bash prompts. Iā€™ve had a little piggie emoji for a few weeks which has served me fine but Iā€™d like to introduce someā€¦ chance into my life. I want to have a random emoji in my prompt. Originally I wanted a new icon on a per-terminal-session basis but then I decided I wanted a new one after every command.

Hereā€™s a simple Ruby script to print a random emoji from a nice subset of positive ones (no murder weapons or pills or bills)1:

#!/usr/bin/ruby
# encoding: UTF-8
emoji = %w{šŸ– šŸŠ šŸ— šŸ’¾ šŸ’” ā˜• šŸ† šŸ† šŸ† šŸ† šŸŽˆ šŸ‘¾}
print emoji[rand(emoji.length)]

I have this exact file saved in my home directory. Itā€™s a dotfile (hidden file) because for the most part I donā€™t want to see it. Maybe thereā€™s a better place to put it.

In order to get the output of that script into my prompt, I need to udpate my PS1 bash variable. In order to refresh it after every command I need to do this weird thing Iā€™ve never done before (this goes in my bash profile):

function set_prompt {
  export PS1="[\@] [\W]\n$(~/.emoji.rb)  "
}
export PROMPT_COMMAND=set_prompt

The PROMPT_COMMAND variable can be assigned some shell script code to run before every drawing of the prompt. In this case, itā€™s calling a function called set_prompt, which runs the Ruby program and interpolates its response into the PS1 variable, so itā€™s different each time.

In order for the Ruby script to be executable by other code, we need to adjust its permissions. If you donā€™t do this, you get an error instead of a pig. You can run chmod a+x ~/.emoji.rb.

Iā€™m happy. Iā€™m gonna keep adding / removing / futzing with my emoji set. The code should work with any number of items in there, so I may go wild. The easiest way to get at them on a Mac is, from any text field, the Edit menu, then Special Characters (tip via classmate Samantha Radocchiaā€™s blog).

If you try this and get it working, let me know on twitter at @maxjacobson #sleaze


EDIT on July 4

Actually this code totally sucks. Itā€™s not at all necessary to use PROMPT_COMMAND. You can change this:

function set_prompt {
  export PS1="[\@] [\W]\n$(~/.emoji.rb) "
}
export PROMPT_COMMAND=set_prompt

to:

export PS1="[\@] [\W]\n\$(~/.emoji.rb) "

The only breakthrough I had is that \$(function_name) runs the function over and over where $(function_name) only runs it once. No idea why.

This fixes the bug where the Terminal wasnā€™t remembering my current working directory and auto-cd-ing into it when I open a new tab.

It should also be easier to drop this into your current prompt. Just add \$(~/.emoji.rb) wherever in your PS1 you want it.

  1. Note: Iā€™m painfully aware that most of those emoji are probably not showing up for you in your browser right now. I donā€™t understand what exactly emoji are or how they work enough to try to fix that. If you want to do this you will probably need to re-populate that line with your favorite picks.Ā