My webzone

A place for John Bintz to ramble.

SheevaPlug bootenv, pre- and post-SD card as root

So I remember. Be sure to get the uImage for the kernel at sheeva.with-linux.com. I followed the instructions here to get the OS off the NAND and onto an SD card.

# pre-SD card
bootargs=console=ttyS0,115200 ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs rootdelay=15
bootcmd=nand read.e 0x800000 0x100000 0x400000; bootm 0x800000

# post-SD card
setenv bootargs_console 'console=ttyS0,115200 rootdelay=15'
setenv bootargs_root_nand 'ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs'
setenv bootcmd_nand 'setenv bootargs $(bootargs_console) $(bootargs_root_nand); nand read.e 0x800000 0x100000 0x400000; bootm 0x800000'
setenv bootargs_root_mmc 'root=/dev/mmcblk0p1'
setenv bootcmd_mmc 'setenv bootargs $(bootargs_console) $(bootargs_root_mmc); mmcinit; ext2load mmc 0 0x800000 /boot/uImage; bootm 0x800000'
setenv bootcmd 'run bootcmd_mmc; run bootcmd_nand;'

# if the SD card was uncleanly mounted, you'll end up booting from NAND. Fix it:

# boot to NAND and...
sudo e2fsck /dev/mmcblk0p1
sudo shutdown -r now
# this can probably be automated in some way.

# ...after the move:
Filesystem           1K-blocks      Used Available Use% Mounted on
rootfs                 3811344    696732   2921000  20% /
/dev/root              3811344    696732   2921000  20% /

BAM.

git hooks fun

Doing some work on penchant I learned a few things about git hooks:

  • You can add things to the commit in pre-commit but not commit-msg. By the time you got there, it’s too late.
  • Be sure to always unset (and restore if necessary) GIT_DIR before doing anything else involving other git repos, like running bundle.

Experiment: flay for Cucumber steps

I’m no code metrics freak, but it’s good to check that stuff every once in a while. Cucumber steps tend to get kind of nasty after a while (at least for me), so I’m trying an experiment where I run flay on the steps after a successful run, just to make sure I’m not duplicating too much between step definitions.

Save this to features/support/flay.rb and tweak flay_level to a sane number. 0 is probably not the right setting if you want to keep your sanity.

Railtie that adds to load paths

Have to add paths via a Railtie (not an Engine)? Use config.before_configuration:

module MyCoolGem
  class Railtie < ::Rails::Railtie
    config.before_configuration do |app|
      app.paths['app/helpers'] << File.expand_path('../../../app/helpers', __FILE__)
      app.paths['app/views'] << File.expand_path('../../../app/views', __FILE__)
    end
  end
end

RubyNation notes from talks I went to

JRuby and threading

import java.util.concurrent

service = Executors.new_fixed_thread_pool
service.execute { codes }

service.shutdown
service.await_termination
service.shutdown_now

Experiment: ActiveResource collection classes

Stealing an idea from Backbone.js, I decided to try using a collection class with an ActiveResource model I was working on. The use case was for creating a tree of objects based on an acts_as_tree storage method, where child objects have a parent_id set the same as the parent’s id. Here’s what I originally had:

class Category < ActiveResource::Base
  def self.tree
    @all = all
    @all.each { |node| node.children = [] }

    top_nodes = @all.find_all { |category| category.parent_id == nil }.sort
    top_nodes.each do |node|
      node.children = @all.find_all { |category| category.parent_id == node.id }.sort
    end
    top_nodes.sort
  end
end

Big, long, hard-to-cleanly-test method. Ick. Did this instead:

# simple skeleton to hang more on later
class ActiveResource::Collection < ::Array
  def initialize(models)
    replace(models)
  end
end

class Category < ActiveResource::Base
  def self.tree
    Categories.new(all).tree
  end

  def top_node?
    parent_id == nil
  end
end

class Categories < ActiveResource::Collection
  def top_nodes
    find_all(&:top_node?).sort
  end

  def tree
    top_nodes.collect do |node|
      node.tap { |n| n.children = models.find_all { |model| model.parent_id == node.id }.sort }
    end.sort
  end
end

More lines of code, but no mess in the model itself. I’ll play with the idea and see how well it scales to other situations.

That sense of tmux cameraderie

I’ve switched to tmux and wanted to simplify my life as best as I can when using it, so I tried a few tmux gems to manage configs and decided on teamocil. However, like anything involving a terminal multiplexer, it needs massaging (Teamocil may cause numbness of the extremities.):

# ~/.bash_profile

tmc() {
  tmux has -t $1 && tmux attach -t $1 || tmux new -s $1 "teamocil $1"
}

function _tmc() {
  local IFS=$'\n'
  local cur="$2"
  COMPREPLY=($(compgen -W "$(find ~/.teamocil -type f | sed 's#^.*/\(.*\)\.yml$#\1#' )" -- "${cur}"))
}

complete -F _tmc tmc
# ~/.tmux.conf

set -g base-index 0

Then, don’t use the session key in your configs:

# ~/.teamocil/johnbintz-gh.yml

windows:
  - name: vim
    root: ~/Projects/johnbintz-gh
    splits:
      - cmd: vim
        height: 90
      - cmd: be rake preview
        height: 10

And finally, tmc johnbintz-gh will start or rejoin an exisiting Teamocil-configured session.

I could’ve sworn my terminal management just got easier. Or not. I think hallucination is one of the side effects of Teamocil. (It isn’t.)

Cucumber and Solarized Dark

Solarized Dark for iTerm2 is weird in that the grey used by Cucumber to show where a snippet comes from is nearly invisible. You can either increase the contrast (I set it to about 20%), or export a CUCUMBER_COLORS environment variable so you don’t have to worry about it:

export CUCUMBER_COLORS=comment=cyan

Closing the given body in Rack middleware

Here’s one that was biting my bum: rack-livereload started generating a bunch of thread deadlock errors left and right for users. One commenter on the bug thread mentioned that middleware need to close the body, which I had never heard of before. Turns out it’s not as well-documented a practice that I would have hoped.

It boils down to trying to close the body that you get after you call your app, in case for some reason it passes you an open file handle (which I guess is a thing?)

class MyMiddleware
  def initialize(app)
    @app = app
  end

  def call(env)
    dup._call(env) # <= the thing I thought would fix the deadlocks
  end

  def _call(env)
    [ status, headers, body ] = @app.call(env)

    new_body = []
    body.each { |line| new_body << line }
    body.close if body.respond_to?(:close) # <= the thing I really had to do

    # ...process stuff...

    [ status, headers, new_body ]
  end
end

So this is mainly so I remember to do this from now on, and for anyone else who runs into thread deadlock issues with Rack middleware.

Dawn Dancing


Done in Sketchbook on Android.

RVM, the JSON gem, the @global gemset, and rb_gc bugs

Upon building Ruby 1.9.3-p125 on my Snow Leopard Mac and getting ready to take it for a spin, trying to run anything of note in a Rails app brought the following cryptic error:

[BUG] cross-thread violation on rb_gc()
(null)

Abort trap

Digging into Console.app, the backtrace indicated that the system libruby.1.dylib was being accessed from the C parser in the json gem living in the @global RVM gemset. otool -L confirmed that the parser in the @global gemset was linked against system ruby, not RVM ruby. Installing a new json gem into the current gemset didn’t work, as RVM prefers to use the @global version of the gem over the one in the current gemset, it seems. Deleting the gems from the @global gemset and reinstalling the json gem in the current gemset worked, and I’m sure I could have reinstalled the json gem globally too.

Dependent APIs and expires_in in Cucumber

The setup:

  • Cucumber
  • Capybara
  • capybara-webkit
  • A running Rails API (started up using vegetable_glue)
  • Active Resource for moving objects around

The problem:

A particular dependent API request wasn’t making it back to the app under test nor the browser. The request was actually being proxied through the app, pretty much raw from the API and not re-run through Active Resource before being sent to the browser.

The issue:

An expires_in in the controller method was sending along cache information, causing the stale data to be cached somewhere.

The solution:

In config/environments/cucumber.rb on the API:

module ActionController::ConditionalGet
  def expires_in(*args) ; end
end

Punch them ducks!

The cleanest Bundler env

Running commands in a Bundler-enabled app that has a Git repo attached to it makes running Bundler in subshells a pain. Bundler.with_clean_env gets close, but still leaves enough of Bundler around to be unpleasant. This kills it dead in subshells:

module Bundler
  class << self
    def with_sparkling_clean_env
      oenv = ENV.to_hash

      %w{BUNDLE_GEMFILE RUBYOPT GEM_HOME GIT_DIR GIT_WORK_TREE}.each { |key| ENV.delete(key) }

      yield

      ENV.replace(oenv)
    end
  end
end

falcon patch adventures for ruby 1.9.3

OK, I got the super-cool falcon patch (as it’s known in rvm) working on my Snow Leopard Macs, but had a few issues with it, and not because of the patch itself:

  • For some reason, building any 1.9.3 in rvm on my machines screws up the Makefile and sticks in a circular reference to building the ruby executable (as in, dependency ruby => ruby). Have to always rip out that last line in the Makefile and make ; make install.
  • As rvm so succinctly warned me (I had no idea rvm requirements existed!), GCC & associated bits in the default Snow Leopard XCode release are broken. I was getting segfaults on garbage collection within the cached load path part of the patch, which is where the real speed came from. I installed osx-gcc-installer and removed the rest of XCode, then recompiled and everything worked fine.

How much of an improvement for me? 3 RSpec runs of a big app went from 2:40.742s (1.9.2-p290 with load patch) to 1:48.104s (1.9.3-p0 with falcon patch). A 33% speed increase. Sweet.

JavaScript in my jQuery: Objects as data containers

Sometimes you have to pass in options to jQuery functions like this:

$('div').animate({
  height: '300px',
  opacity: 0.75,
});

This:

{
  height: '300px',
  opacity: 0.75
}

is the most basic form of an Object. Objects have two things: properties and methods. When you attach other things to an object, like the String 300px or the Number 0.75, you’re creating properties.

Methods are Functions attached to an object. When you extend jQuery.fn with your own jQuery actions, you’re creating a new method:

$.fn.makeAllTranslucent = function() {
  $(this).animate({
    height: '300px',
    opacity: 0.75
  });

  return this;
};

// now you have a shortcut!
$('div').makeAllTranslucent();

You can add and change properties on an object after-the-fact, too:

var properties = { height: "300px" };
if confirm("Want them translucent?") {
  properties.opacity = 0.75;
}

// pass the object in as the first parameter
$('div').animate(properties);

Because of the way JavaScript is designed, everything is an object: the one you created with {curly: 'brackets'}, $.fn, standalone Functions, everything. This lets developers do some very clever things with JavaScript.

JavaScript in my jQuery: the magic $(this)

Say you’re looping over some elements on the page:

<div>One</div>
<div>Two</div>
<div>Three</div>

<script type="text/javascript">
$('div').each(function() {
  $(this).addClass('unvisited');
});
</script>

Within the anonymous function:

function() {
  $(this).addClass('unvisited');
}

this becomes each jQuery object found in $('div') in turn. But how?

That this normally means the object running the current code:

// create a class constructor
function Cat(name) {
  this.name = name;
}

// add a method to the object
Cat.prototype.hiss = function() {
  return this.name + " is hissing at you!";
}

// instantiate a Cat
var myCat = new Cat("Fluffy");

// work with our cat
console.log(myCat.name); // => Fluffy
console.log(myCat.hiss()); // => Fluffy is hissing at you!

But JavaScript lets you change this to whatever object you want using Function#apply:

function Dog(name) {
  this.name = name;
}

var dog = new Dog("Bruiser");

// Cat.prototype.hiss is an object of type Function
console.log(Cat.prototype.hiss.apply(dog)); // => Bruiser is hissing at you!

jQuery does this with the jQuery.fn#each method when looping over things like DOM elements. this becomes a jQuery object for each DOM node in turn:

$('div').each(function() {
  // the first run through, `this` is $('div:eq(0)')
  console.log($('div:eq(0)').attr('class')); // => ''
  console.log($('div:eq(1)').attr('class')); // => ''

  $(this).addClass('uninvited');
  console.log($('div:eq(0)').attr('class')); // => 'uninvited'
  console.log($('div:eq(1)').attr('class')); // => ''
});

For polyglots: This is very similar in concept to how instance_eval can be used in Ruby:

code = lambda { puts @name }

class Dog
  def initialize(name) ; @name = name ; end
end

my_dog = Dog.new("Bruiser")

my_dog.instance_eval(&code) #=> "Bruiser"

JavaScript in my jQuery: $(document).ready()

In jQuery, you normally write code like this to do something after the whole page loads:

<script type="text/javascript">
  // the long way...
  $(document).ready(function() {
    $('#login-box').show('slow');
  });

  // the short way...
  $(function() {
    $('#login-box').show('slow');
  });
</script>

There’s two things going on here:

  • You’re attaching an event handler to a thing that fires an event. Specifically, the event that fires when all the parts of your Web page have finished loading and that the document is ready.
  • That event handler:
  function() {
    $('#login-box').show('slow');
  }
  

is what’s known as an anonymous function. Normally functions get names:

  function doSomething() {
    $('#login-box').show('slow');
  }
  

But, you can also create a function that doesn’t have a name…it’s anonymous. You use these a lot in jQuery. They come in pretty handy and have a lot of interesting properties.

Cucumber, Capybara, and Rails Asset Pipeline in debug mode

Because who wants to recompile all their assets on each run?

features/support/env.rb

Capybara.server_port = 3001
Capybara.app_host = "http://localhost:3001"

ActionController::Base.asset_host = Capybara.app_host

config/environments/cucumber.rb

config.assets.enabled = true
config.assets.debug = true

You’re welcome.