Personal

Newness

January 12, 2016 · 2 min read

I said in my previous post that a lot can happen in 2 years.

In that time span I've:

  • Moved to using a MacBook and OSX.

    • OSX being very BSD-like makes it an prime target for web development. It isn't the second class citizen Windows is in the Ruby or Node.js communities.
  • Transitioned away from .NET and don't really miss it. I do randomly play around with .NET core when possible but I haven't actually built anything with it.

    • This was honestly very huge at the time but I still feel I made the right decision. Though Windows 10 is the platform Windows 8 should have been and likely would've kept me on board.
  • Transitioned to PHP and web technologies full bore. I'm no fan of the PHP language but in the era of Visual Studio 2012, a dynamic language that only required refreshing my browser was much faster than waiting on the compile cycle.
  • Drank the vagrant koolaid via PuPHPet.

    • Recreating production hardware isn't too difficult with my ancient DevOps experience.
    • Waiting on the painful commit/push/wait for deployment/refresh cycle to see a change was a huge productivity destroyer.
    • Even developing locally when production PHP versions aren't consistent can be a nightmare. Something like rvm in Ruby comes close but it isn't perfect.
  • Immediately took to PHPStorm as my IDE of choice. JetBrains have done an amazing job and if you've used ReSharper you've only had a taste. I'm no fan of Java but I'll make a concession for tools this good.
  • Wrote a very crude front-end only CMS. When working in only HTML, CSS, and Javascript you really see the separation of client and server very clearly.
  • I jumped in the deep end with tools like gulp, bower and yeoman.

    • This has fueled my desire to be a lot more fluent in Node.js.
    • Frontend development becomes insanely fun because a lot of the tedium melts away if you do it right.
    • This gulp template was extended from this blog post and it's subsequent repository to streamline working on the custom CMS.
    • This yeoman gulp generator looks a little more promising as it seems to serve a similar purpose but feels like less work.
  • I have a Microsoft Lumia 640 and the Windows 10 Mobile OS is one of the best mobile experiences I've used to date. I know I'm biased but it has shaped up really well.
  • My personal laptop is running Windows 10 as well so I haven't abandoned the Windows ecosystem by a long shot, I've just become more of a consumer rather than a developer.

That's really only scratching the surface. It would've been helpful to have blog posts as I moved along but as with most things, life got in the way.

My main goal for the early part of 2016 is to revamp this site and make it the playground I was looking for in 2013. Octopress is really nice but if I upgrade to v3 it's not much more work to migrating away to something like Hexo, Metalsmith, or DocPad.

We be derpin'

January 10, 2016 · 1 min read

A lot can happen in a little over 2 years...

In my last post, I had proposed an attempt to tackle the FizzBuzz problem. PowerShell was done, PHP was barely started but I never pointed to it in a subsequent post or finished what I wanted. The project url has completed and checked solutions for PHP and Node.js. I had mentioned b. F#, Objective-C, CoffeeScript, C/C++, Go, Dart, and Haskell are the planned languages I've mostly touched in passing or know about., as well as C#, Pascal, and Ruby but I may never get to them.

Shortly after that last post, I switched jobs from .NET to web development focusing on PHP with HTML, CSS, and Javascript. That one action shifted much of my focus from most of the languages in that list. With ES6 coming and recently finishing a CodeSchool course in CoffeeScript, the Javascript landscape is looking pretty awesome. Elixir and the Phoenix Framework have recently stood out as upcoming contenders for my mindshare as well.

My last post taught me that while I may know of a language, it doesn't mean I'll have a genuine desire to pursue it. It can also easily become difficult to want to pursue development outside of your day job. Staying current, however, is always worth pursuing. Tooling and efficiency around web development seems to have come a very long way.

To keep this post brief, I plan on making more updates as I feel a lot has changed for me in the past 2 years that I'd still love to share.

Notable Octopress tweaks: Copyright, Tags, & Feed Excerpts

October 28, 2013 · 8 min read

This is almost pointless to mention but the standard templates give you a very specific copyright with respect to atom feeds (Copyright (c) x-y). The file source\_includes\custom\footer.html includes a way of gathering the system time in the form:

Copyright © {{ site.time | date: "%Y" }}

I simply replaced the current hard-coded year with the ruby code above so that when the site is generated, it always gives the current year.

In case any of you are wondering how to insert code blocks with liquid syntax, see this post.

Tags

This is more involved but luckily gist makes it stupid simple to include here. Everything is pretty much a rip off of the category_generator plugin and includes with just minor tweaks to use the tag object.

_config.yml

tag_dir: tags
view raw _config.yml hosted with ❤ by GitHub

plugins/tag_generator.rb (an almost complete copy of category_generator.rb)

# encoding: utf-8
#
# Jekyll tag page generator.
# Completely stolen from the category generator, where I copied the file and replaced text here:
# http://recursive-design.com/projects/jekyll-plugins/
#
# Version: 0.1.4 (201101061053)
#
# Copyright (c) 2010 Dave Perrett, http://recursive-design.com/
# Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
#
# A generator that creates tag pages for jekyll sites.
#
# Included filters :
# - tag_links: Outputs the list of tags as comma-separated <a> links.
# - date_to_html_string: Outputs the post.date as formatted html, with hooks for CSS styling.
#
# Available _config.yml settings :
# - tag_dir: The subfolder to build tag pages in (default is 'tags').
# - tag_title_prefix: The string used before the tag name in the page title (default is
# 'Tag: ').
require 'stringex'
module Jekyll
# The TagIndex class creates a single tag page for the specified tag.
class TagIndex < Page
# Initializes a new TagIndex.
#
# +base+ is the String path to the <source>.
# +tag_dir+ is the String path between <source> and the tag folder.
# +tag+ is the tag currently being processed.
def initialize(site, base, tag_dir, tag)
@site = site
@base = base
@dir = tag_dir
@name = 'index.html'
self.process(@name)
# Read the YAML data from the layout page.
self.read_yaml(File.join(base, '_layouts'), 'tag_index.html')
self.data['tag'] = tag
# Set the title for this page.
title_prefix = site.config['tag_title_prefix'] || 'Tag: '
self.data['title'] = "#{title_prefix}#{tag}"
# Set the meta-description for this page.
meta_description_prefix = site.config['tag_meta_description_prefix'] || 'Tag: '
self.data['description'] = "#{meta_description_prefix}#{tag}"
end
end
# The TagFeed class creates an Atom feed for the specified tag.
class TagFeed < Page
# Initializes a new TagFeed.
#
# +base+ is the String path to the <source>.
# +tag_dir+ is the String path between <source> and the tag folder.
# +tag+ is the tag currently being processed.
def initialize(site, base, tag_dir, tag)
@site = site
@base = base
@dir = tag_dir
@name = 'atom.xml'
self.process(@name)
# Read the YAML data from the layout page.
self.read_yaml(File.join(base, '_includes/custom'), 'tag_feed.xml')
self.data['tag'] = tag
# Set the title for this page.
title_prefix = site.config['tag_title_prefix'] || 'Tag: '
self.data['title'] = "#{title_prefix}#{tag}"
# Set the meta-description for this page.
meta_description_prefix = site.config['tag_meta_description_prefix'] || 'Tag: '
self.data['description'] = "#{meta_description_prefix}#{tag}"
# Set the correct feed URL.
self.data['feed_url'] = "#{tag_dir}/#{name}"
end
end
# The Site class is a built-in Jekyll class with access to global site config information.
class Site
# Creates an instance of TagIndex for each tag page, renders it, and
# writes the output to a file.
#
# +tag_dir+ is the String path to the tag folder.
# +tag+ is the tag currently being processed.
def write_tag_index(tag_dir, tag)
index = TagIndex.new(self, self.source, tag_dir, tag)
index.render(self.layouts, site_payload)
index.write(self.dest)
# Record the fact that this page has been added, otherwise Site::cleanup will remove it.
self.pages << index
# Create an Atom-feed for each index.
feed = TagFeed.new(self, self.source, tag_dir, tag)
feed.render(self.layouts, site_payload)
feed.write(self.dest)
# Record the fact that this page has been added, otherwise Site::cleanup will remove it.
self.pages << feed
end
# Loops through the list of tag pages and processes each one.
def write_tag_indexes
if self.layouts.key? 'tag_index'
dir = self.config['tag_dir'] || 'tags'
self.tags.keys.each do |tag|
self.write_tag_index(File.join(dir, tag.to_url), tag)
end
# Throw an exception if the layout couldn't be found.
else
raise <<-ERR
===============================================
Error for tag_generator.rb plugin
-----------------------------------------------
No 'tag_index.hmtl' in source/_layouts/
Perhaps you haven't installed a theme yet.
===============================================
ERR
end
end
end
# Jekyll hook - the generate method is called by jekyll, and generates all of the tag pages.
class GenerateTags < Generator
safe true
priority :low
def generate(site)
site.write_tag_indexes
end
end
# Adds some extra filters used during the tag creation process.
module Filters
# Outputs a list of tags as comma-separated <a> links. This is used
# to output the tag list for each post on a tag page.
#
# +tags+ is the list of tags to format.
#
# Returns string
#
def tag_links(tags)
tags = tags.sort!.map { |c| tag_link c }
case tags.length
when 0
""
when 1
tags[0].to_s
else
"#{tags[0...-1].join(', ')}, #{tags[-1]}"
end
end
# Outputs a single tag as an <a> link.
#
# +tag+ is a tag string to format as an <a> link
#
# Returns string
#
def tag_link(tag)
dir = @context.registers[:site].config['tag_dir']
"<a class='tag' href='/#{dir}/#{tag.to_url}/'>#{tag}</a>"
end
# Outputs the post.date as formatted html, with hooks for CSS styling.
#
# +date+ is the date object to format as HTML.
#
# Returns string
def date_to_html_string(date)
result = '<span class="month">' + date.strftime('%b').upcase + '</span> '
result += date.strftime('<span class="day">%d</span> ')
result += date.strftime('<span class="year">%Y</span> ')
result
end
end
end

source/_includes/archive_post_tags.html

{% capture tag %}{{ post.tags | size }}{% endcapture %}
<div class="row-fluid">
<div class="span1">
<h1 class="date-time"><time datetime="{{ post.date | datetime | date_to_xmlschema }}" pubdate>{{ post.date | date: "<span class='month'>%b</span> <span class='day'>%d</span><span class='year'><!--%Y--></span>"}}</time></h1>
</div>
<div class="span10">
<h1><a href="{{ root_url }}{{ post.url }}">{{post.title}}</a></h1>
</div>
</div>
{% if tag != '0' %}
<div class="row-fluid">
<div class="span1">
</div>
<div class="span10">
<footer class="archive">
<span class="tags">posted in {{ post.tags | tag_links }}</span>
</footer>
</div>
</div>
{% endif %}

source/_includes/custom/tag_feed.xml

---
layout: nil
---
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title type="text" xml:lang="en"><![CDATA[{{ site.title }}]]></title>
<link type="application/atom+xml" href="{{ site.url }}/{{ page.feed_url }}" rel="self"/>
<link type="text" href="{{ site.url }}/"/>
<updated>{{ site.time | date_to_xmlschema }}</updated>
<id>{{ site.url }}/</id>
<author>
<name><![CDATA[{{ site.author | strip_html }}]]></name>
{% if site.email %}<email><![CDATA[{{ site.email }}]]></email>{% endif %}
</author>
<rights>Copyright (c) 2010-{{ site.time | date_to_string | date: "%Y" }} <![CDATA[{{ site.author | strip_html }}]]></rights>
<generator uri="http://octopress.org/">Octopress</generator>
{% for post in site.tags[page.tag] limit: 5 %}
<entry>
<title type="html"><![CDATA[{{ post.title | cdata_escape }}]]></title>
<link href="{{ site.url }}{{ post.url }}"/>
<updated>{{ post.date | date_to_xmlschema }}</updated>
<id>{{ site.url }}{{ post.id }}</id>
{% if post.has_excerpt %}<summary type="html">{{ post.excerpt | xml_escape }}</summary>{% endif %}
<content type="html"><![CDATA[{{ post.content | expand_urls: site.url | markdownify | cdata_escape }}]]></content>
</entry>
{% endfor %}
</feed>
view raw tag_feed.xml hosted with ❤ by GitHub

source/_includes/post/tags.html

{% capture tag %}{% if post %}{{ post.tags | tag_links | size }}{% else %}{{ page.tags | tag_links | size }}{% endif %}{% endcapture %}
{% unless tag == '0' %}
{% if post %}
{% for tag in post.tags %}
<a class="tag" href="{{ root_url }}/{{ site.tag_dir }}/{{ tag | to_url }}/"><span class="badge">{{ tag }}</span></a>
{% endfor %}
{% else %}
{% for tag in page.tags %}
<a class="tag" href="{{ root_url }}/{{ site.tag_dir }}/{{ tag | to_url }}/"><span class="badge">{{ tag }}</span></a>
{% endfor %}
{% endif %}
{% endunless %}
view raw tags.html hosted with ❤ by GitHub

source/_layouts/tag_index.html

---
layout: page
footer: false
---
<div id="blog-archives" class="tag">
{% for post in site.tags[page.tag] %}
{% capture this_year %}{{ post.date | date: "%Y" }}{% endcapture %}
<div class="row-fluid">
<div class="span1">
{% capture this_year %}{{ post.date | date: "%Y" }}{% endcapture %}
{% unless year == this_year %}
{% assign year = this_year %}
<h2>{{ year }}</h2>
{% endunless %}
</div>
<div class="span11">
<article>
{% include archive_post_tags.html %}
</article>
</div>
</div>
{% endfor %}
</div>
view raw tag_index.html hosted with ❤ by GitHub

Feed excerpts

The following goes on line 23 in my atom.xml file, or right before the content tag. A better alternative would be to detect an excerpt and only display that or the content, not both.

{% if post.has_excerpt %}<summary type="html">{{ post.excerpt | xml_escape }}</summary>{% endif %}

Octopress site generation on Windows 8.1

October 24, 2013 · 1 min read

Install RailsInstaller from here. I use the version with Rails 3.2.

libcurl

  • Download the latest "Win32 - Generic" libcurl with SSL development release from here (this is the last entry as of 10/23/2013).
  • Unpack the zip file.
  • Copy curl.exe, libcurl.dll and libidn-11.dll to C:\RailsInstaller\bin.
    The reason I copy curl to test the program. It verifies the files are in the expected path and has an added bonus of making sure all the dll dependencies are present. This is how I figured out libidn-11.dll was necessary to include.

SSL certificate setup

  • Download cacert.pem.
  • Place file in C:\RailsInstaller as cacert.pem.
  • Set an Environment Variable in Control Panel with the Variable name: SSL_CERT_FILE and Variable value: C:\RailsInstaller\cacert.pem.
  • To temporarily set the variable for this command prompt session, use set SSL_CERT_FILE=C:\RailsInstaller\cacert.pem.

My blog's notable Octopress tweaks

July 11, 2013 · 1 min read

My plan is for this post to serve as an index to the upcoming posts. Unlike the ASP.NET MVC posts that fizzled (sorry), I need to chronicle these changes in the event I need to dissect them again.

Here's the collection in no particular order:

  • Copyright date - This one is simple and almost not worth noting. I use a copyright date range of [start year]-[current year] and this post simply explains the what and why.
  • Tag generator - Octopress will not support tags. Tag index pages are trivial to implement but I'm also starting to agree with the premise that one taxonomy should really be enough.
  • Feed excerpts - These aren't generally created to my knowledge, or specifically the summary section. The general way to create excerpts is a little awkward but smart.
  • Google Form notification full service sample taken from here.
  • (Upcoming) Category & Tag index generators for the primary /categories/ /tags/ directory. WordPress didn't have this either but it would be a good idea to list all of them in one place.

One thing in the FAQ that particularly bit me during the WordPress conversion was Using Non-ASCII Characters In Your Blog. Most conversion posts cover this but I'm in the habit of always having this as part of my environment just in case.

The primary reason for my approach so far was to be a close representation as possible of the WordPress site to combat 301 redirect woes. Tags will eventually disappear I think but I like the exercise of making sure they're around in full. The platform seems to support "something" so it's fun to see how far I can go with it.