String interpolation in ruby2c

Eric Hodel | Sat, 04 Mar 2006 07:27:00 GMT

The toolset zenspider and I built into ParseTree for rewriting Ruby’s AST allows us to make features work that otherwise would be very difficult by rewriting them into easier to implement features.

One feature that makes Ruby so clean is string interpolation but currently ruby2c doesn’t support it. In Ruby there are two types of String nodes, a plain :str node ([:str, "mystring"]) for regular strings and a :dstr node that contains all the parts of the dynamic string which the interpreter concatenates ([:dstr, "val: ", [:vcall, :val]]).

Implementing :dstr in a runtime would be too hard to be worthwhile so I used SexpProcessor to rewrite a :dstr into a series of calls to #<< and #to_s that append to the leading :str node.

Now a dynamic string like:

[:dstr,
 "a",
 [:vcall, :x],
 [:str, "b"],
 [:vcall, :y],
 [:str, "c"]]

Gets transformed into this ugly sexp:

s(:call,
  s(:call,
    s(:call,
      s(:call,
        s(:str, "a"),
          :<<,
          s(:arglist,
            s(:call, s(:call, nil, :x, nil), :to_s, nil))),
        :<<,
        s(:arglist,
          s(:call, s(:str, "b"), :to_s, nil))),
      :<<,
      s(:arglist,
        s(:call, s(:call, nil, :y, nil), :to_s, nil))),
    :<<,
    s(:arglist,
      s(:call, s(:str, "c"), :to_s, nil)))

I don’t know about the inside-outness of it though, I may have to fix that.

Posted in , ,

Markov Chain

Eric Hodel | Sun, 26 Feb 2006 00:39:00 GMT

The back of my brain has been wanting a Markov chain based random-text generator for some time. I found some decently explanatory pseudo-code in the Generating Text section of the online Programming Pearls by Jon Bently.

What I really wanted was something that illustrated the concept well so I could tell what it was doing. The perl, python and ruby versions I found weren’t simple enough for me to see that. I also wanted to adjust the amount of state in the chain, but the only implementations that supported that were far too complicated to figure out.

Working from Jon Bently’s pseudo-code I ended up with the following implementation. Read more...

Posted in ,

I was right!

Eric Hodel | Fri, 17 Feb 2006 10:28:00 GMT

Super-easy!

Except that Rubygems has methods that don’t get called when you think they should.

And that there’s a strange bug in RDoc when you run it twice.

Posted in , , ,

httpdump

Eric Hodel | Mon, 23 Jan 2006 07:34:00 GMT

I wrote a nifty little combination of a WEBrick servlet and a ruby-pcap http grabbing example that lets you see the latest HTTP requests that have crossed a network card interface.

All so I can spy on my neighbors (but they can also spy on me).

Posted in , ,

Open-uri makes tests easy

Eric Hodel | Mon, 21 Nov 2005 01:28:00 GMT

Neither of the two Ruby Flickr APIs do what I want. One stomps all over the global namespace (Photo will be a model class, it adds a Photo class at the toplevel) and doesn’t have the photo taken date as one of its properties. The other doesn’t support the search method (you get back an XML blob instead of a collection) or the photo taken date.

Neither has tests, so I wasn’t going to figure out how to add what I wanted to either. Instead, I decided to wrap as much of the API as I needed with something that I could test.

On a whim, I decided to use open-uri instead of Net::HTTP. This made testing super-easy. I don’t have to touch the network at all, other than to get a blob of XML to feed into the test:

class Flickr

  attr_accessor :responses, :uris

  def open(uri)
    @uris << uri
    yield StringIO.new(@responses.shift)
  end

end

class FlickrTest < Test::Unit::TestCase

  def setup
    @flickr = Flickr.new 'API_KEY'
    @flickr.responses = []
    @flickr.uris = []
  end

Then a test simply adds the XML blobs it is supposed to receive from flickr up-front. After performing the request, I assert it attempted to fetch the correct URLs along with the rest of the stuff the method was supposed to do. (Search is paginated, and I wanted to fetch all the photos without making things clumsy for the user.)

  def test_photo_get_info
    @flickr.responses << <<-EOF
...
    EOF

    info = @flickr.photo_get_info :photo_id => 59864477

    assert_equal 1, @flickr.uris.length
    assert_equal 'http://flickr.com/services/rest/...',
                 @flickr.uris.first

    assert_equal Time.at(1131153707), info[:date_taken]
    assert_equal Time.at(1131153708), info[:date_uploaded]
  end

Posted in , ,

Rails Functional TestCase

Eric Hodel | Tue, 18 Oct 2005 07:26:00 GMT

Its a shame that Rails doesn’t define its own Test::Unit::TestCase subclasses. I’ve taken that into my own hands. This one puts Test on the front because that’s the Test::Unit way.

require 'test/unit'

def Object.path2class(klassname)
  klassname.split('::').inject(Object) { |k,n| k.const_get n }
end

class FunctionalTestCase < Test::Unit::TestCase

  def setup
    self.class.name =~ /\ATest(.*)\Z/
    return unless $1
    controller_klass = Object.path2class $1
    @controller = controller_klass.new
    controller_klass.send(:define_method, :rescue_action) { |e| raise e }
    @request = ActionController::TestRequest.new
    @response = ActionController::TestResponse.new

    @deliveries = []
    ActionMailer::Base.deliveries = @deliveries
  end

  def test_stupid
  end

end

Posted in , , ,

Easy model urls for Rails

Eric Hodel | Tue, 18 Oct 2005 07:19:00 GMT

One part url params


class Player < ActiveRecord::Base

  def url_params
    return { :controller => 'players', :action => 'info', :id => username }
  end

end

One part url_for override

class ApplicationController < ActionController::Base

  def url_for(options, *params)
    if options.include? :model then
      options = options.delete(:model).url_params.merge options
    end

    return super(options, *params)
  end

end

[Simplified due to some insight from zenspider]

Then just add :model => AR_object to anything that accepts url params:

<ul>
<% @players.each do |player| -%>
<li><%= link_to player.username, :model => player %>
<% end -%>
</ul>

And ba-bam!

<ul>
<li><a href="/players/info/herbert">herbert</a>
<li><a href="/players/info/joseph">joseph</a>
</ul>

Posted in ,

Older posts: 1 2 3 4