Jed Schneider is a Ruby and Rails software developer for the Medical University of South Carolina. He was a pro cyclist at one time, now he just rides for fun.
crashland, again.
I ran my first half marathon today, a trail run, at one of our local trails systems in Columbia: Harbison State Forest. After a pretty terrible week, I had a hard time honoring this commitment I had made to run this race. I was single parenting it most the week (at least grandma was here) as Theresa was in MA seeing our newest niece and nephew (twins) born to her twin sister Rosemary. Then the day after Theresa gets home sleep deprived as hell, our house is broken into, all our jewelry stolen, most of our electronics. We've been dealing with that, and trying to anchor our side door which was kicked off its hinges, while trying to figure out all that was taken. My training consisted of writing code and a 45 min run Wed morning. Sweet.
It was the inaugural event and part of the Xterra series of races. I did a lot of things right, I think, and several things I wish I hadn't done. As it turns out, I got 7th or 8th, because the first group of 7 or so took a wrong turn and only did about half the race. Some of the guys in that group are locals so I don't think they even had an excuse for not turning on the hardest 5 miles of the course but I guess part of racing is reading the map.
I wore my Merrell Trail Gloves, with the awesome socks Samantha gave me after my last trail run like 4 years ago when i got wicked blisters, and body glide on the feet.
I still got wicked blisters.
When I got home Theresa informed me that body glide is for your underarms and stuff, but still use Vaseline on your feet. I won't wear those Merrell's again, at least at Harbison. Its way too rocky, like big chuck gravel roads in sections (even thought its trail, not road), so no matter how you place your feet, its gonna hurt. I'm starting to wonder if runners have as many shoes as mountain bikers have tires. If so, the cost savings of running over cycling just got a lot narrower. So, the last 5 miles, I felt every rock on my blisters, it was pretty intense and I ended up walking several downhills and really rocky sections, just to give my feet a break. It is so humid here, I was totally wet when i got done, shoes like i ran in the river, wet, so I'm not sure there is a solution to keep the feet dry and blister free. So, that was a major error on my part and cost me twenty minutes I think.
What I did do well is fuel and pace. I definately wanted to run faster, but I knew that the heat would kill me if I ran any bit too hard. I also had a fair bit of fuel and water, enough so that I was still comfortable after the race, not hungry at all. I had about as much as I would have for an equal time in a mountain bike race: 2 packages of Clif Blocks, a gu, and about 2.5 -3 bottles of water. Seems like a lot for running, but it seemed to work out.
It was also interesting to run out there, since I have ridden my mountain bike there a fair bit, I thought it was interesting to note that at some points I was surprised how fast I seemed to get to parts of the trail, and at other times surprised that what I felt was a really boring part of the trail was quite fun to run. I'm also painfully aware that in running, the downhills are not free, like they are on a bike. You pay everywhere, dearly.
So, i finished in 2:12 and some change, 22 min off the wining pace. I feel with better planning on the feet issue, i was easily capable of my aimed goal of1:45 to 1:50. Had those dudes not gotten lost, however, I would have been looking at winning times around 1:30 instead of the winning time of 1:49. But, today, just getting through the race was my only concern. I knew it was in my ability to do it, but just barely. My legs were totally spent at 1:30 in, so I gotta get faster, so I'm done before my legs are.
Also, the swag was swag. They give out good stuff and nice shirts at running races.
I have been reading and working with RSpec 2 fairly heavily over the last week. I though I would try to share some of the things I have gleaned from the documentation on the relishapp site. As I have gone through the examples, it really makes me think differently about how I write my specs.
As informative as that documentation is, I often forget exactly where I see something implemented so I thought I would share some of that here:
some rspec options I like in .rspec
--color -f d
Implicit Subject as passed in from the describe call:
describe 7 do
it {should == 7}
end
But this seems pretty limited, consider that this doesn’t work because it needs an explicit subject. consider a custom class:
class MyClass
attr_accessor :name
def initialize(options)
@name = options[:name]
end
end
# errors out
describe MyClass.new(:name => "Jed") do
its(:name) {should == "Jed"} #=> also, notice the property spec is very nice
end
# this works
describe MyClass do
subject { MyClass.new(:name => "Jed") } #=> explicit subject
its(:name) {should == "Jed"}
end
so we need to pass a variable to the block. Check out the spec syntax for verifying the attribute on the subject, very cool.
jed = MyClass.new(:name => "Jed")
describe jed do
it {should be_a_kind_of MyClass}
its(:name) {should == "Jed"}
endbut the printout is ugly
#<MyClass:0x101329720>
should be a kind of MyClass
name
should == "Jed"so, we should add a to_s method to our class
class MyClass
def to_s
[self.class, "with the name", name].join(" ")
end
endwhich gives a better printout
MyClass with the name Jed
should be a kind of MyClass
name
should == "Jed"Specify seems to exist to support a context that is not as simple as required for the ‘its’ helper. In particular, it seems helpful with the method requires parameters.
class MyClass
def foo(arg)
"foo #{arg}"
end
end
describe MyClass do
subject { MyClass.new(:name => "Jed") }
specify { subject.should be } #=> implicit truthiness
specify { subject.foo("bar").should == "foo bar" }
specify { subject.foo("bar").should be "foo bar" } #=> fails on string equality
endActually this is a really great example from the documentation. I have been using the let structure to replace instance variables in setup blocks. I would use it like this:
describe "something" do
let(:myvar) {"myvar"}
specify { myvar.should be_a_kind_of String }
endinstead of:
describe "something" do
before(:each){@myvar = "myvar"}
specify { @myvar.should be_a_kind_of String }
endShared contexts allow you to share specs across classes or modules. It is a nice way to group specs that belong to an interface-like abstraction. For this example its probably not so simple to create something that is contrived so I will use one from an actual code example.
shared_examples_for "a property" do
subject { Hash.new().extend described_class} #=> Hash.new().extend BasicProperty
it {should respond_to(:name, :nightly_rate) }
it { should respond_to(:nightly_rate).with(1).argument }
it { should respond_to(:nightly_rate).with(0).arguments }
end
describe BasicProperty do
it_behaves_like "a property"
end
describe SeasonalProperty do
it_behaves_like "a property"
end
If anyone else has some interesting uses with the ‘newer’ RSpec, please leave a comment. I’m interested in what others think.
edit:
@frose asked: how is this different than overloading in C++? http://twitter.com/froese/status/11778256189526016
admittedly, I don't know C++ but I'm pretty sure this is different because:
One thing that often comes up in building rails apps is a way to manage somewhat static data in a meaningful way that also feels less icky than hardcoding a static map of key value pairs inside a dependent model. An example would be a list of county codes, the US states, or a semi-static list of options that users may need to choose, may change, but is probably not worth creating a workflow for user editable content. Inspired by a stackoverflow question, I thought I might explain one solution I have used.
First you have some semi-static data you want to load in a consistent format into the database, meaning, the id's are always the same:
In this case I have a fixture file of change reasons that dependent apps expect to know that an address change has an id of 27. There may in the future be more change reasons, but it happens so rarely that we don't need an admin interface to create one change reason a year.
I create a model that uses this data:
So, then I can load them into the database with a rake task, before testing, before ci, or called in your deployment recipe.
special thanks to Jason Dew for introducing me to this technique.
Columbia Residents,
I've been working on getting applications deployed via Warbler and Tomcat and one of the annoying features is the loss of logging to application specific log files when being deployed without any extra setup. It also turns out that besides me not getting warbler apps to deploy on Tomcat 5.x, the procedure for setting logging up is markedly different than on Tomcat 7. So, since I was able to get the apps running on 7, I went about figuring out how to get the application specific logging setup there also. So, I am assuming many things, in part:
Why would I go through configuration hell to setup Tomcat, you say? I can think of no reason that satisfies this answer, but if you are like me, the less you have to deal with adding something 'new' to the system the better off you are. This is a perfect way to be able to work in a reasonable development paradigm (aka Ruby and Rails) and still be able to use the existing infrastructure (java web application servers) with management being less concerned about supporting something 'new'. Also, jRuby is quite performant, and the one click upload deployment strategy of Tomcat is sure nice (or scp your war into the webapps dir).
The rest of this guide is a rough outline of how to get Tomcat 7, Warbler, jRuby, and app specific logging with log4j all working together.
I have always wanted to to something 'real' with sinatra and over the last week there have been two opportunities to do so. The first app was a simple web service app that I was witness to and only helped with some of the debugging. Today, however, I was able to write my first real-world app that exists in three files (4 if you count the Gemfile for bundler).
We've been having some problems with Tomcat at work so are logging the threads every so often and it was a pain sending this stuff around via email. So I decided that it would be a nice little app. I called it 'tidy cat' because we're capturing thread dumps from Tomcat.
I learnt some nifty things, and some disappointing things, mainly, that class instance variables are not passed from route to route. So, here it is, a nifty little app that goes onto a remote server and pulls down a file to view via web browser.