Posts Tagged ‘CodeDunce’

Designing a rudimentary XML Service with Ruby (Part 2)

A few days back, I posted on my journey of understanding into the world of Ruby-based XML clients. This post is a continuation of that account.

Re-Arranging the WebEx Class

I figured it wouldn’t be long before I was back at the drawing board on my main architecture, and I was right. The earlier one I described turned out to be over-abstracted and hard to test.

It all started with my feeling that this looks really elegant:

1
events = WebEx.request(Event.list)

But in practice it turns out to be a little strange. “Attendee” and “Event” were two classes with no attributes of their own, and none of my code ever instantiated objects of these classes. These are two pretty obvious signs over an over-abstracted implementation. I’d been thinking that I’d write logic later which would (for example) instantiate objects of the Event class inside Event.list’s processor, but as I got more and more into the implementation, it just didn’t seem like I was going to need to mess with WebEx’s return values as discreetly defined objects. After all, I already had Events and Attendees represented as hashes in an array, which was working just fine for this first use case and the ones I could see on the horizon. Having separate classes for Event and Attendee would give me maximum extensibility, but at the cost of having pieces of overlong, over-organized code with no (current) purpose.

So I moved the Event class’s code into the WebEx class. Same with Attendee — now the WebEx class’s code looks like this:

(Gist of the WebEx class)

As you can see, everything is now an instance method of the WebEx object. This means that the syntax for getting a list of Events is now:

1
2
w = WebEx.new
events = w.request(w.event_list)

This still looks a little weird to me. I had been thinking that I should make WebEx#request into a class method, so as to have:

1
events = WebEx.request(w.event_list)

But that would mean having WebEx.request instantiate and return a new object of the WebEx class. There’s nothing wrong with that, but given the fact that another WebEx object already needs to be created in order to call one of its instance methods (event_list), it felt like a case where two objects of the same class which weren’t being used at all in the same way. Because of that awkwardness, I decided to live with the clunky-but-servicable all-instance-method approach. After all – there’s a good chance that I’ll refactor it yet again as I go… :-p

Testing

I’m embarrassed to not have spotted this earlier: the class as it had been written before was very hard to test for a couple major reasons:

  • There was no way to override the XML attribute of one of the WebExmlObjects being returned by class methods Event.list and Attendee.list_for_meeting
  • The HTTP request happened within the WebEx.request method, making it difficult to stub the HTTP request’s response, which had to happen in order to ensure that calling that method during testing didn’t involve net calls.

I solved each of these easily enough: I abstracted the HTTP request into its own method and I added a “payload” argument to each method that returned a WebExmlObject so that I could override its request XML.

After that, it was time to set up some fixtures. I created directories for “request” and “response” in my fixtures dir and added files containing the well-formed XML samples I got from the WebEx docs. Then I wrote methods for opening/reading each of them in my WebExSpecHelper module (this testing is all in RSpec). Below is a test that ensures that WebEx#request is calling WebEx#request_post:

1
2
3
4
it "should call request_post" do
  @w.should_receive(:request_post).and_return(lst_summary_event_response)
  @w.request(@w.event_list)
end

@w is the instance variable that is created before every spec, and lst_summary_event_response is the name of the spec helper method that returns the fixture of that XML response. There’s no particular reason I called this one as opposed to an attendee-related method – I just needed to assert that the call would happen and then stipulate the response it would give, so any of my helper methods would do.

Here’s that helper method doing what it’s meant to:

1
2
3
4
it "it should return all events if passed a nil time limit" do
  @events = @w.event_list(payload=lst_summary_event_request, time_limit=nil).processor.call(@w.doc)
  @events.length.should be(3)
end

There are three events in the fixture, so the length should be three when nothing is passed to time limit. All the fixture data from WebEx was in the past, so I altered the dates in there to have one event in the past, one in the future, and one in the future at a more distant date. Here’s what happens when you pass a time limit past that first (earlier) future date

1
2
3
4
5
6
it "should return only events happening after the time limit" do
  middle_future_date = "04/02/2012 01:06:49"
  limit = @w.time_from_string(middle_future_date)
  @events = @w.event_list(payload=lst_summary_event_request, time_limit=limit).processor.call(@w.doc)
  @events.length.should be(1)
end

Only one result gets returned, because the fixture only has one event listing which has a start date after the date given.

Next Steps

So far, my unit tests have covered very little – basically just the processor portion of a WebExmlObject. For full coverage, I’ll need to test the :x ml attribute which means validating the generated XML against the XML Schema Definitions(XSDs) WebEx provides with their API docs. Ruby doesn’t provide have any all-native tools for doing validation of XML against a given XSD, but the libxml library (which is distributed as a gem and gets its power from C-bindings it compiles at install time) will let you pass in a schema as a string and then validate against it.

Tags: ,

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: ,

Kill tooltips/keep captions in Lightbox

Using Lightbox? Me too. The version I’ve been working with lately is the jQuery-based one by Krewenki. It’s a handy little plugin and seems to have all the basic stuff that you know and love from the older script.aculo.us-based Lightbox.

If you use Lightbox much, you’ll know that you add captions to the large version of your photo by placing the caption information in the title attribute of the link tag you wrap around the thumbnail image. If you want to get fancy with your captions like I did, you’ll want to put some HTML in the title attribute – maybe a title and an unordered list for some bullet points.

But when you hover the thumbnail, you see a nasty-looking tooltip filled with raw HTML. It took me some time to figure out the best way to get rid of the tooltip on hover but replace it in time for the larger version of the picture to be able to see it for the caption. Making the tooltip disappear was trivial, but replacing it turned out to be a bit tricky – each time I clicked, I kept getting blank captions.

Turns out that this is because I was attaching to the onclick event. Onclick fires when both mousedown and mouseup have happened, so the callback happens too late – the link is already loading. When I switched my title replacement event to be mousedown, the caption showed up just fine.

The jQuery snippet below blanks the title attribute on all Lightbox thumbnail links when the cursor enters the link’s space (defined by the dimensions of the thumbnail image) in the mouseenter event, and then replaces it on either mouseleave or mousedown. This injects the title back into the DOM in time for the caption to be used by Lightbox.

At least that’s my theory for why it works. I should probably find some technical backup for this somewhere in the annals of JavaScript, but being as that’s pretty unlikely, I’ll just go ahead and post the working code. Note that unlike some versions of Lightbox out there, Krewenki’s works by having you designate Lightbox elements by placing a “lightbox” class on the anchor, as opposed to setting the anchor’s rel attribute. It could be argued that this is slightly out of spec with how HTML is supposed to work, but it’s a pretty esoteric thing to compare link “relationship” designators with the appropriate semantic space for classes. And anyway, I don’t really care that much… :-p

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Removes title attr on Lightbox thumbnail links
// replaces for caption on mousedown
function killLightboxTooltips () {
  $.each($('.lightbox'), function(i, link) {
    var title = $(link).attr('title');
    $(link).bind("mouseleave mousedown", function () {
      $(this).attr('title', title);
    });
   
    $(link).bind("mouseenter", function () {
      $(this).attr('title', "");
    });
  });
}

Tags:

Forcing browsers to reload CSS

If you manage a decently high-traffic site, you will have run into the problem of needing to force your users’ browsers to reload your CSS files when you’ve made updates to them. I solve this by appending a query string to the end of the stylesheet’s href, so that this

1
<link rel="stylesheet" href="/css/master.css">

Becomes this:

1
<link rel="stylesheet" href="/css/master.css?foo=bar">

This forces the browser to reload the stylesheet because it sees that href and thinks that it’s an asset it doesn’t have cached. When it asks the server for it, the server has nothing it can do with the query, so the query is ignored and the stylesheet is served again.

I got tired of throwing random stuff on the end of the URLs though, so yesterday I wrote a Ruby script to do this for me, throwing a date/time stamp on the end of the href. The real one is customized for my particular site’s setup, but I’ve put the basics below so you can see how I handled it. I’m assuming that you’ve got an ID declared on the link element you want to mess with. Mine is called default-stylesheet.

Checkout the Gist of the script

I have a script like this on my webserver and I run it whenever I do major updates. The real one is augmented to allow you to pass arguments to act on staging or production. There are a million ways to set it up, but the basics above will be present in almost any approach.

Tags: ,

Loving JQuery

As someone involved with a decent amount of Rails programming over the past year, most of my work in Javascript frameworks has centered on Prototype and script.aculo.us. And with good reason — both are enormously capable and, with Prototype at least, extremely well documented. They create beautiful effects and nearly painless AJAX, they integrate really well with Rails, and there’s a wide community of users you can slot yourself right into. I’ve used some other frameworks as well — made interfaces with ExtJS and messed around with MochiKit some — and I’ve discovered that every one of these things (with the possible exception of MochiKit, which seems to be essentially abandonware at this point) has a specific niche to fill.

But for the most part, what all these things have in common is that they seem to have been created with web application interface development in mind. They’re not all that well suited to the set of one-off needs that crop up with general forms and lead generation tools on your average small site, but a lot of people end up using them for that anyway because they remove some of the tedium from JS. Numerous blog posts have been written about the phenomenon of people including the entirety of Prototype just to make tiny, “DHTML” DOM manipulation a little less painful, which makes no sense. Just suck it up and use JS for real. It’s not that hard.

There are some tasks that fall in between though — they’re more than trivial with bare JavaScript, but loading the entirety of a framework like Prototype is kind of like using a chainsaw to trim hedges. It’ll work, but it will be heavy and imprecise, and you may find yourself regretting all the extra work later. You still need a tool though, so what’s the solution?

A smaller, more task-oriented framework. This week, I decided that I’m a fan of JQuery. Here are the two examples from this work week that sold me:

Cycle

The Cycle plugin makes it dead simple to create a slideshow effect.

It supports pause-on-hover, auto-stop, auto-fit, before/after callbacks, click triggers and many transition effects including fade, shuffle, scroll, turn and zoom. It also allows you to define and run your own custom transitions. In addition, it supports, but does not require, the Metadata Plugin and the Easing Plugin.

The basic way it works is that you put together a div filled with the objects you want to cycle, usually other divs containing, say, an image and a caption. Once you’ve got your structure set up, you call cycle with one line, which it’s good to place at the bottom of your HTML so you’ll know all your pictures have loaded:

1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>
  <span class="ta">&lt;script</span> <span class="an">type</span>=<span class="s"><span class="dl">&quot;</span><span class="k">text/javascript</span><span class="dl">&quot;</span></span> <span class="an">charset</span>=<span class="s"><span class="dl">&quot;</span><span class="k">utf-8</span><span class="dl">&quot;</span></span><span class="ta">&gt;</span><tt>
</tt>    $('#mydiv').cycle();<tt>
</tt>  <span class="ta">&lt;/script&gt;</span><tt>
</tt>

You can add all kinds of options in the call to cycle, but the bare effect itself is pretty pleasing and is frequently exactly what a developer is looking for.

UI.Datepicker

UI.Datepicker is part of the JQuery UI library. You can think of UI as being script.aculo.us to JQuery’s Prototype — it’s built on top of the JQuery core and provides visual effects like fade, appear/disappear, window shade, shrink, grow, etc. It also contains all the drag/drop-oriented stuff you might need, as well as several other “widgets” and interaction pieces.

Datepicker is a widget that provides a calendar. When a user clicks on a form text field which has been tied to a Datepicker object, a calendar appears. The user navigates the calendar and chooses a date, which is then inserted into the text field. Again, the implementation code is short:

You could one-line this at the bottom of your page as well if you wanted (as with cycle above), but using JQuery’s $(document).ready() enables you to ensure that the code won’t try to execute before the page is loaded, so you can keep code you might use a bunch (like a standard calendar widget) outside your HTML file in a central spot.

1<tt>
</tt>2<tt>
</tt>3<tt>
</tt>4<tt>
</tt><strong>5</strong><tt>
</tt>
  <span class="ta">&lt;script</span> <span class="an">type</span>=<span class="s"><span class="dl">&quot;</span><span class="k">text/javascript</span><span class="dl">&quot;</span></span> <span class="an">charset</span>=<span class="s"><span class="dl">&quot;</span><span class="k">utf-8</span><span class="dl">&quot;</span></span><span class="ta">&gt;</span><tt>
</tt>   $(document).ready(function(){<tt>
</tt>     $('#date').datepicker({dateFormat:'yy-mm-dd'});<tt>
</tt>   });<tt>
</tt>  <span class="ta">&lt;/script&gt;</span><tt>
</tt>

One thing I love about the JQuery UI site: you get to build your own download — i.e., you can select the pieces of code you need by feature and have the file built with just that code. Among JavaScript frameworks, I believe this may be unique to JQuery, and it makes a serious difference in the file size.

I believe that this attitude — favoring modular code, giving you only what you need so you don’t end up with page bloat — probably drives a lot of JQuery’s adoption in smaller-need situations like the ones I’m describing here. But JQuery is also the native JS framework for both Drupal and WordPress. I haven’t messed with MooTools or Dojo yet, but I think of them as being in a similar class to JQuery, and I think JQuery definitely has the momentum to draw in more converts the same way I was: dead-simple use, only-what-you-need philosophy of code distribution, pervasive understanding of the bandwidth challengers front-end web developers face.

Tags: ,