Posts Tagged ‘Ruby’

Designing a Rudimentary XML Service with Ruby

1
events = WebEx.request(Event.list)

That felt the most natural to me. The idea is that you have a WebEx class that’s basically responsible for initiating the connection and handling the boilerplate security stuff that’s going to be at the top of any XML API request. The question then became how to structure the Event class so that it could do two things at once: pass in the XML for the request and process the XML from the response.

WebExmlObject and its Subclasses

I decided to define a WebExmlObject class with “xml” and “processor” attributes:

1
2
3
class WebExmlObject
  attr_accessor :xml, :processor
end

Then I could define subclasses for each of the major types of objects I’d be pulling from WebEx (Attendee and Event, to start). For right now, it doesn’t matter that the subclasses themselves don’t define any new attributes or instance methods – it’s worth it to me to do it this way because I believe that they probably will have to in the future. And in any case, I’m a sucker for aesthetics and simplicity, and I wanted the readability and elegance you get from the class method approach I outlined above. Here’s the Event class and its single class method:

(Event class Gist)

Notice that this method is basically in two halves: the first half creates the XML and the second creates the processor as a Proc object. After creating the XML (using the super-handy Builder library), I create a new Event object and load the XML into it. Then I create a Proc and set it to the event object’s :processor attribute. The processor assumes one argument will be passed to it – the XML response as a REXML document – and it returns an array of hashes, each one representing an event. Only the stuff I care about is in each event hash, an easily extendable list represented by the event_keys variable.

The WebEx Class

Next up is the implementation of the request part. The WebEx class has two instance methods: request and response. Request takes a WebExmlObject, adds its XML in as the body of the request, makes the request, parses the response, and returns an object of class WebEx. Response holds the response header. Here’s the full implementation of the class:

(WebEx class Gist)

Putting it Together

I’m still working on the integration part of this, but it’s happening in Sinatra, so I can easily show the short piece that renders the form:

1
2
3
4
5
6
7
8
9
get '/online_demo' do
  events = WebEx.request(Event.list)
  if events.response['result'] == "SUCCESS"
    @events = events.body
    erb :online_demo
  else
    LOGGER.warn('No meetings appear to be available at this time')
  end
end

It’s obviously still a work in progress, but you can see how the XML-to-object abstraction feels pretty well hidden, and the class structure provides the level of elegance and terseness that I was hoping for. If you’re unfamiliar with the way Sinatra works, the above is called when an HTTP GET request is made to the URL “<WEBROOT>/online_demo”. Once the request is made and parsed into the events variable, I create the @events instance variable to hold the actual events array. The last thing I do is call the ERb template “online_demo”. Instance variables created in this block are available to the template in much the same way as the controller/view relationship works in Rails. The view is responsible for iterating over the array and inserting the proper attributes into the proper places:

1
2
3
4
5
6
7
<label for="demo_startdate">Choose a demo date:</label>
  <select name="sessionKey" id="demo-startdate">
    <option value="">Please select</option>
    <% @events.each do |event| %>
      <option value="<%= event['sessionKey'] %>"><%= event['startDate'] %></option>
    <% end %>
  </select>

I’ll post more about this as I move forward, just to document the process of learning how to structure this stuff. I’m still not entirely satisfied with the semantics of the WebEx class’s methods – especially since calling request will set up your object with the data you need and response only gives you access to the header of the response. I pacify myself by reasoning that since one is a class method and one is an instance method, there’s no philosophical/structural problem, but something about it still bugs me.

Big thanks to bona fide code wizard Collin VanDyck for suggestions in this process – as always, I’m proud to be able to call CCV my homie.

Tags: ,

Profile your Rails RSpec and find your slow tests fast

Long-as-hell Ruby on Rails RSpec test running times are making you ask “what the deuce?” Specs are taking way too long to run, but the prospect of looking through them all one at a time to find offending external dependencies, net calls that should be mocked, etc is driving you to drink. You just want a read-out of the tests that are taking the longest so you can refactor ASAP.

Sound familiar?

I was in this boat until I found out about the profiling command:

1
$>spec spec -f profile

The double “spec” here can be a bit confusing. The first is the command, and the second is the directory (RAILS_ROOT/spec) that you’re running it on. The -f is the format flag. You can see a list of all formats with:

1
$>spec --help

Basically you’re just passing the “profile” argument to the formatting command. It gives you a readout of the 10 most time-intensive specs at the top and then a nicely verbose list of all pending and failed tests. Using this list, I was able to go straight to the most obnoxious offenders and eliminate the external dependencies (these specs happened to be fetching feeds) that were slowing my test suite down. In less than 15 minutes, I had chopped my execution time down to 10% of what it was before I started.

Huzzah!

Autotester and GrowlGlue – an adventurer is me!

Setting up autotest earlier today was kind of an annoying, semi-humbling experience. A few things that people should know to save themselves some trouble:

  • Everyone calls it autotest, but it’s actually ZenTest that you need to install. ZenTest is a larger testing package, of which autotest is merely one part.
  • Autotest runs as a separate process (which you should background — the ‘&’ is your friend!) and watches your Rails dir after you have it turned on. This last bit took me some time to figure out, as the otherwise excellent RSpec Peepcode screencast completely glosses over this point. I kept waiting for the magic to happen when I hit “save” in TextMate, but I didn’t have the process running from the command line. Magic doesn’t work. I should stop expecting it to.
  • Do yourself a favor and vastly simplify your autotest–>Growl connection by using Collin VanDyck’s GrowlGlue gem as the basis for your .autotest config file.

As of right now, I’m sitting here with just the basic GG config. I’m sure I’ll expand/customize tomorrow, but I’m just happy for now that I was able to get a working setup with just one line of code, as the normal way to get the connection going involves a decent amount of crap. After you get that going, GrowlGlue lets you set up all sorts of customization of the notifications — including custom messages, custom notification icons, and even speaking your test results through OS X’s built-in text-to-speech support — in nice, neat Ruby statements.

It’s nice to have something get in my face about my tests, and it’s also nice to have something that automatically makes you want to get your tests passing and running faster. Autotest provides you with the nagging voice that says “get your tests running right, holmes!” It’s good to strike this longstanding to-do off my list.

Late update: Turns out that running autotest in the background isn’t really ideal since you might sometimes want to cancel a running suite or check out the time elapsed since you started a given test set. What I’m looking for now is a way to see how long it takes any individual test to run so that I can find the offenders that are kicking up the aggregate time.

Tags: , ,