bdunagan
fill the void

Ruby Tip: Sort a hash recursively

A while ago, I found a great Stackoverflow answer for sorting a hash in Ruby:

class Hash
  def sorted_hash(&block)
    self.class[sort(&block)]
  end
end

But recently, I wanted to take it a bit further and recursively sort all the hashes in an object, even if they are inside of an array. Here is a snippet to do that:

class Hash
  def sorted_hash(&block)
    self.class[
      self.each do |k,v|
        self[k] = v.sorted_hash(&block) if v.class == Hash
        self[k] = v.collect {|a| a.sorted_hash(&block)} if v.class == Array
      end.sort(&block)]
  end
end

Ruby Tip: 1.8.7 and 1.9.2, Side by Side

Recently, I needed to run rake test on a Ruby gem with both Ruby 1.8.7 and 1.9.2. I wanted to figure out why Travis CI was failing for the gem. Not a problem with rvm, even on Lion (10.7).

To install a version of Ruby, use rvm install:

[~]$ export CC=/usr/bin/gcc-4.2 # Use this for Lion
[~]$ rvm install 1.8.7

You can check that it’s installed with rvm list:

[~]$ rvm list
rvm rubies

=> ruby-1.8.7-p352 [ x86_64 ]
   ruby-1.9.2-p290 [ x86_64 ]

To use Ruby 1.8.7 for the Terminal session, use rvm use:

[~]$ rvm use 1.8.7

Seriously, use rvm. It’s awesome.


Searching GitHub Wikis with Gollum

Over a year ago, GitHub updated their wiki system to be powered by git. It was an awesome upgrade. Now I can check out a wiki, just like source code, and edit it in TextMate, just like source code. Really, really nice…except I can’t search.

Luckily, GitHub released Gollum. Gollum is a local version of their wiki software, wrapped up in a Ruby gem. It supports the same interactions that you get on a GitHub wiki. And, it supports search.

To set up Gollum, just open Terminal and follow the instructions below, using @mojombo’s jekyll as an example project.

# Install the gem. I'm using 1.3.1 with Ruby 1.9.2 (290).
gem install gollum

# Go to a GitHub wiki checkout.
git clone git://github.com/mojombo/jekyll.wiki.git wiki

# Install RedCloth to handle Jekyll's Textfile format.
gem install RedCloth

# Start Gollum.
cd path/to/wiki
gollum

Gollum is now running at http://localhost:4567/. You should see the search bar at the top. Here are two screenshots comparing Gollum to GitHub:


Still, remembering to run gollum and open localhost:4567 is a bit of a pain.

Enter Pow

With 37 Signals’ Pow web server, you always reach your wiki locally at http://wiki.dev/. Pow is ridiculously nice for keeping long-running Rails and Rack process running in the background. After I installed Pow using their awesome one-line instructions (curl get.pow.cx | sh), I used these instructions to integrate Gollum:

First, add config.ru to the base of your wiki repo with the following text. (Use the jekyll wiki repo from above. No need to commit the file. Just add it to .gitignore.)

# Copied from bin/gollum
require "gollum/frontend/app"

Precious::App.set(:gollum_path, File.dirname(__FILE__))
Precious::App.set(:wiki_options, {})
run Precious::App

Next, symlink the project, so that Pow knows about it. (Any folder name is fine, but “wiki” is simpler.)

cd ~/.pow
ln -s path/to/jekyll/wiki

Finally, touch tmp/restart.txt to tell Pow to restart. (I’d add tmp/ to .gitignore as well.)

cd path/to/jekyll/wiki
mkdir tmp
touch tmp/restart.txt

Contrary to the linked post, I didn’t need to add anything to /etc/hosts. Pow just worked. Gollum 1.3.1 is fine, despite the comments in this ServerFault post. Just open http://wiki.dev.

Add a sidebar

A brilliant addition to Gollum is sidebar support. I committed _Sidebar.mediawiki to the wiki repo, and Gollum began displaying it next to each page. The sidebar is a really easy way to add a set of useful links to all pages.

Only commits count

Keep in mind that if changes aren’t committed, Gollum doesn’t see them. For example, I added _Sidebar.mediawiki to the repo folder and refreshed the browser page. No sidebar. Took me a bit to realize Gollum still didn’t see it. You have to commit changes for them to exist to Gollum.

HTML sanitization

GitHub spells this out in its gollum readme (https://github.com/github/gollum), but it’s worth reiterating. Gollum sanitizes the input with @rgrove’s sanitize gem, removing any malformed HTML or security issues like custom CSS. This sanitization converts <div style="color:red;">red</div> into <div>red</div>.

To change that setting locally, just find lib/gollum/sanitization.rb and add 'style' to the end of the ATTRIBUTES list. Your local version will use the custom CSS, and the GitHub version will silently strip it out.

MediaWiki supported

I switched to a GitHub wiki from a MediaWiki instance. Converting was easy: click Edit for each page, save the contents as Page.mediawiki, repeat, push to GitHub. Done.

GitHub is able to render MediaWiki markup due to @nricciar’s handy WikiCloth Ruby gem. The latest release is 0.7.0, but it has a couple issues. I submitted a couple fixes in a pull request today, and @nricciar already merged them into master. To use the latest WikiCloth sources as a gem for Gollum, follow these steps:

# Remove existing version.
gem uninstall wikicloth

# Fetch the sources from GitHub.
git clone git://github.com/nricciar/wikicloth.git

# Build master and install that gem.
cd wikicloth
gem build wikicloth.gemspec
gem install wikicloth-0.7.0.gem

# Restart Gollum with Pow.
cd path/to/wiki
touch tmp/restart.txt

GitHub Wiki Search

Of course, GitHub will add searching on the website eventually. They’re prodigious coders, and Issues already has search. I’m sure they’re getting to it. Until then, just open http://wiki.dev/ and search.


Logging slow queries in MySQL

It’s straight-forward to log slow queries in MySQL both on your local machine and on an Amazon AWS RDS instance. I’ll walk through both, although MySQL has good documentation on slow query log and log destinations.

Local MySQL

There are many blog posts about enabling slow query logging to a file within the MySQL data folder, but very few point out that, for files outside that folder, you have to manually create the log file and set its permissions correctly with touch and chown.

# Run in Terminal.
sudo touch /var/log/mysql.slow.queries.log
sudo chown mysql:mysql /var/log/mysql.slow.queries.log

# Insert the following into /etc/my.cnf.
[mysqld]
# log_slow_queries is deprecated
# log_output = FILE (use 'TABLE' if you prefer accessing slow queries through the mysql.slow_log table)
slow_query_log = 1
slow_query_log_file = /var/log/mysql.slow.queries.log
long_query_time = 1
min_examined_row_limit = 100
log_queries_not_using_indexes

# Reboot mysqld.

Amazon RDS

AWS does not allow shell access, so there is no way to read a local log file. Instead, RDS logs the output (log_output = TABLE) to the built-in table: mysql.slow_log. Here are the RDS command line instructions for setting up the parameter group, modified from Inventables’ excellent write-up.

# Create a test parameter group for slow query logging.
rds-create-db-parameter-group --db-parameter-group-name test-group --engine MySQL5.1 --description "Test group"

# Modify the parameter group to support UTF8 and slow query logging.
rds-modify-db-parameter-group test-group \
    --parameters="name=character_set_server, value=utf8, method=immediate" \
    --parameters="name=character_set_client, value=utf8, method=immediate" \
    --parameters="name=character_set_results,value=utf8,method=immediate" \
    --parameters="name=collation_server, value=utf8_unicode_ci, method=immediate" \
    --parameters="name=collation_connection, value=utf8_unicode_ci, method=immediate" \
    --parameters="name=slow_query_log, value=ON, method=immediate" \
    --parameters="name=long_query_time, value=1, method=immediate" \
    --parameters="name=min_examined_row_limit,value=100,method=immediate"

# Modify the EC2 instance and reboot it.
rds-modify-db-instance rds-db --db-parameter-group-name test-group
rds-reboot-db-instance rds-db

# Connect to the RDS instance after it's rebooted, execute 2s query, and check the table.
select * from mysql.slow_log \G
# Rotate the log out of the table with this command. It will move the queries to mysql.slow_log_backup.
\u mysql
call rds_rotate_slow_log

Rails Tip: Logger in Rake

Here are a couple lines of Ruby to bring Logger into rake tasks. I use them for logging cron jobs that are Rails rake tasks. I tried this post, but it didn’t get me all the way.

# Used with Rails 2.3.4
RAILS_DEFAULT_LOGGER = Logger.new(STDOUT)
RAILS_DEFAULT_LOGGER.level = Logger::INFO
def logger
  Rails.logger
end