Headshot-color me@jbrains.ca Find out where I'm appearing
« Previous 1

libxml2: Can't upgrade it; can't downgrade it

It started simply enough: I wanted to use webrat to write view specs with its Matchers to add some specs to this very weblog. I swear, that’s all I wanted to do.

When I managed to run those specs properly, I’d get this message:

HI. You’re using libxml2 version 2.6.16 which is over 4 years old and has plenty of bugs. We suggest that for maximum HTML/XML parsing pleasure, you upgrade your version of libxml2 and re-install nokogiri. If you like using libxml2 version 2.6.16, but don’t like this warning, please define the constant I_KNOW_I_AM_USING_AN_OLD_AND_BUGGY_VERSION_OF_LIBXML2 before requring nokogiri.

Very well: let me upgrade libxml2. Big mistake.

I tried downloading libxml2 version 2.7, then I went through the usual motions: configure, make, sudo make install.

Then I couldn’t run anything. Sometimes I couldn’t even boot. I kept seeing the wrong architecture message when I tried to run various programs on my MacBook.

I tried deleting libxml from /usr/lib and rebuilding, but then I couldn’t even sudo. I didn’t know what the hell was going on.

Finally, I booted from my backup disk (thank you, SuperDuper!) and copied /usr/lib/libxml* back onto my internal hard disk. I booted from my internal disk and all returned to normal, including the annoying nokogiri message. I suppose I’ll have to live with the message for now.

Still… has anyone successfully upgraded libxml to version 2.7 on Mac OS 10.5.7? I’d like to know.

August 13, 2009 08:00 rails, ruby, mac, adventures in RSpec

Happy New Year

describe "Year 2008" do
    it "should be happy" do
        Date.new(2008, 1, 1).year.should be_happy
    end
end

Best wishes to all my readers for a happy 2008!

January 02, 2008 03:33 ruby, people, adventures in RSpec, emotional health

The electronic to-do list, revisited

Since I have been spec-driving Rails code, and since I have very limited table space at home right now, I have been experimenting with something I’d never liked before: an electronic test and refactoring list. So far, it’s not too bad.

Like many people, I like to avoid keeping lists in my head, since I tend to forget things. Normally, I use an index card and write tests from the top and refactorings from the bottom, crossing each out as I perform them. It works well. So well, in fact, that I generally question anyone who attempts to use an electronic system, rather than a paper system. The idea, of course, is that we tend to fixate on electronic systems, whereas we use paper systems simply and quickly. Using the computer for anything that doesn’t benefit from automation seems counterproductive to me. Still, since we’re low on table space, I’ve had to try something else, and RSpec gives me the opportunity to maintain a test list without having to implement multiple failing tests (or specs) at once.

With RSpec, one can describe a test with prose without implementing it, simply by invoking it without a block.

describe "The thing I'm spec-driving" do
  it "should do something important"
  it "should do something else important"
  it "should do this third, equally important, thing"
end

When it’s time to implement the spec, add the corresponding block. In the meantime, RSpec reports the other specs as “pending”, rather than attempting to execute them. I had never thought it was a good idea, before, but I’ve been trying it recently, and I’m less annoyed by it than I used to be. That might be because I’m more comfortable spec-driving than I was years ago when I started; but it might just be because my personal taste has changed. I can’t say. What I can say is that I haven’t managed to get lost yet, and it takes little extra effort to describe a handful of specs up front. If it starts bothering me, I’ll be sure to describe my experience.

Patching RedCloth: unique footnote hyperlinks

Recently, I integrated Textile into this blog via RedCloth. As I started to write articles in my Adventures in RSpec series, I found I wanted to use footnotes. Since Textile supports them, I figured I was in luck; however, I soon found a hyperlink collision when two fragments of Textile markup appear on the same page, each with the same-numbered footnote. RedCloth simply generates a hyperlink to target fn1 for footnote #1, so if there are two footnote #1s on the same page, they both link to target fn1, making it the equivalent of a race condition.

I looked for guidance to the Textpattern folks. A certain Mary told me that Textile has fixed this problem, but likely RedCloth has not. After some investigation, I agreed that this was the case. I looked through the Textile source, to the extent I can understand PHP, and saw their fix was simple: keep a table of footnote numbers to unique IDs, then use the unique ID in place of the number in the hyperlink and target. I figured that I could do that.

It took a couple of hours, and I’ll spare you the details. Here is what I wrote:

require 'digest/sha1'

class UniqueFootnoteIdGeneratingRedCloth < RedCloth
  def initialize(markup)
    @footnote_ids_by_number = {}
    super(markup)
  end

  def next_footnote_id
    # SHA1 isn't significant; I just figured it'd make a good unique ID
    Digest::SHA1.hexdigest(rand(2**64).to_s)
  end

  def to_html(*rules)
    self.scan( /\b\[([0-9]+?)\](\s)?/ ) do |match|
      @footnote_ids_by_number[$1] = next_footnote_id
    end
    
    super
  end
  
  private

  def footnote_ref(text)
    text.gsub!( /\b\[([0-9]+?)\](\s)?/ ) do |match|
      "<sup><a href=\"#fn#{@footnote_ids_by_number[$1]}\">#{$1}</a></sup>#{$2}"
    end
  end

  def textile_fn_( tag, num, atts, cite, content )
    atts << " id=\"fn#{ @footnote_ids_by_number[num] }\""
    content = "<sup>#{ num }</sup> #{ content }"
    atts = shelve( atts ) if atts
    "\t<p#{ atts }>#{ content }</p>"
  end
end

I ended up copy/pasting more code than I wanted to, so I’ll have to submit something to why for his perusal. Perhaps this will make it into a future version of RedCloth.

August 26, 2007 04:20 rails, ruby, design, adventures in RSpec

Live Preview with RSpec on Rails

Today I’m waiting at Così Cafe for our train to Washington DC for Agile 2007, so it’s time to add the next part of the “preview” feature. I have an internet connection, so I can afford to be a little more aggressive with the story I tackle next, because Google knows all. I think I’ll try to build the real-time preview I imagined earlier this morning. Now I don’t think I can spec-drive the real-time aspect of the preview, but I can certainly spec-drive showing the preview in a nearby window while I’m typing in the posting content text area. To get a sense for how that would look, I do some quick UI design.

In order to make room, I shrink the “content” text area and put the live preview, as it’s called, below it. This looks reasonable to me. In the process, I make one design decision: the <div> that contains the live preview text has the ID content-live-preview, which I’ll need to spec-drive the RJS I’ll have to write.

Speaking of spec-driving RJS, I have no idea how to do that, so I need to read a little about that before I get started.

Unfortunately, after reading Rails Recipes, I’m convinced that I need to implement this first before I can learn how to spec-drive it for next time. I find this happens a lot with Rails: it’s almost too simple. I paste an implementation into my view and inspect it manually. When I do that, it becomes clear that I need an action to handle the live preview, so although I didn’t drive the controller behavior with an automated test or spec, I’m certain I need something. Now I think I can spec-drive the controller behavior. Since this is familiar territory, this should go smoothly. Let’s see.

According to Rails Recipes_, all I need to do in my action is render the default template without a layout, which means I will need to move the live preview markup to a new @livepreview.rhtml@ template. I’ll do that first, to make sure it will be wired together properly.

After a few false starts, I have these specs:

describe "Live Preview for weblog postings" do
  it "should have a section to display the live preview" do
    assigns[:posting] = Posting.new(:content => "Some @textile@ content.")
    render "/postings/live_preview"
    
    response.should have_tag("div#content-live-preview")
  end
  
  it "should be able to handle nil content" do
    assigns[:posting] = Posting.new(:content => nil)
    render "/postings/live_preview"
    
    response.should have_tag("div#content-live-preview")
  end
end

This is the live_preview.rhtml template:

<div id="content-live-preview" class="entry">
	<%= textilize(@posting.content) if @posting.content %>
</div>

That decidedly doesn’t work. When I consult Rails Recipes, I realize I should display the request parameter posting[content] and not the Ruby object @posting.content. For this, I need to learn how to stub the request parameters in the view. Evidently this is as simple as assigning to a params Hash. I fix the specs to match this new information.

describe "Live Preview for weblog postings" do
  it "should have a section to display the live preview" do
    params[:posting] = { :content => "Some @textile@ content." }
    render "/postings/live_preview"
    
    response.should have_tag("div#content-live-preview")
  end
  
  it "should be able to handle nil content" do
    params[:posting] = { :content => nil }
    render "/postings/live_preview"
    
    response.should have_tag("div#content-live-preview")
  end
end

I’m on a green bar, but the UI doesn’t work. Firebug tells me that my controller live_preview method works, but the corresponding <div> is not updating. I don’t know how to spec-drive this, so I need to hack for a while. It’s 14.44; let’s see how long I need to hack.

Fortunately, only about five minutes. I had one <div> too many.

After fixing that, and making a few small changes, it looks like I’m done. I would have preferred to spec-drive the observe_field code, but at least I have less untested code than I used to. Now I can remove the preview button and the code that went with it. It served its purpose; now it can go to its rest.

« Previous 1