<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Alex Kahn Blog</title>
 <link href="http://akahn.net/atom.xml" rel="self" />
 <link href="http://akahn.net/"/>
 <updated>2010-07-27T15:25:44-04:00</updated>
 <id>http://akahn.net</id>
 <author>
   <name>Alex Kahn</name>
   <email>alexanderkahn@gmail.com</email>
 </author>

 
 <entry>
   <title>Gotham Ruby Conference 2010: A Recap</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2010/05/26/gotham-ruby-conference.html" />
   <updated>2010-05-26T00:00:00-04:00</updated>
   <id>http://akahn.net/2010/05/26/gotham-ruby-conference</id>
   <content type="html">&lt;p&gt;Over the weekend I attended the fourth &lt;a href=&quot;http://www.goruco.com/&quot;&gt;Gotham Ruby Conference&lt;/a&gt; (GoRuCo). The conference was well-organized, the content was top-notch and there were tons of great people there.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3306/4629071041_8b0b0c7c36.jpg&quot; alt=&quot;&quot; /&gt;&lt;br /&gt;
&lt;a href=&quot;http://www.flickr.com/photos/sd/&quot;&gt;Photo by sd&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The day opened with a welcome from a Pace University&amp;#8217;s Jonathan Hill. Jonathan, who is assistant dean of Pace&amp;#8217;s Computer Science program, described the longstanding relationship between Pace and the New York Ruby community, pointing out that GoRuCo has been held at Pace since its first year. Pace uses Ruby and Rails extensively in its Computer Science program and, in turn, its graduates often find employment through this community. Jonathan expressed real appreciation for the health and energy of the Ruby community in New York. It was neat to feel this connection and know that Pace was more than just a rented space for the conference.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nick Gauthier&lt;/strong&gt; presented the first talk, Grease Your Suite, on making slow test suites run faster. This talk demonstrated how he improved a test suite in a Rails project from 13 minutes down to under 20 seconds. To do this, Nick used lifo&amp;#8217;s &lt;a href=&quot;http://github.com/lifo/fast_context&quot;&gt;fast_context&lt;/a&gt;, his own &lt;a href=&quot;http://github.com/ngauthier/hydra&quot;&gt;Hydra&lt;/a&gt; for distributing tests across &lt;span class=&quot;caps&quot;&gt;CPU&lt;/span&gt; cores or machines, and Ruby Enterprise Edition for its ability to tune Ruby&amp;#8217;s garbage collection. He also gained speed by mocking PaperClip&amp;#8217;s image manipulation, using fixtures to replace truly-resized images. Nick got further performance by tweaking a journaling setting for the &lt;code&gt;ext4&lt;/code&gt; filesystem (Nick is a staunch Linux-on-the-desktop user), as well as by disabling &lt;code&gt;atime&lt;/code&gt;. Nick noted that the improvements from these tweaks gain as much in speed as running tests on a solid state drive. With such a fast test suite, the Continuous Integration server can return to its true calling&amp;#8212;ensuring a green build in a production-like environment. While I don&amp;#8217;t have any projects that are burdened by tests that take too long, I nonetheless left this talk with strategies to grease my suite. Get all the details in &lt;a href=&quot;http://grease-your-suite.heroku.com/&quot;&gt;Nick&amp;#8217;s slides&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The next talk, by &lt;strong&gt;Aman Gupta&lt;/strong&gt;, was on a new Ruby profiling tool, Memprof. Aman provided a tour of the tools he&amp;#8217;d worked with for profiling Ruby&amp;#8217;s memory use: &lt;code&gt;ObjectSpace.each_object&lt;/code&gt;, gdb.rb, bleak_house, and patching Ruby in order for it to provide heap dumps. These tools are all helpful, he said, but they require writing patching or running special versions of Ruby, or don&amp;#8217;t provide complete enough information on the contents of the objects in memory or their context in code. Memprof, created by Joe Damato with contributions from Aman, solves the above problems: Installing it is simple (&lt;code&gt;gem install memprof&lt;/code&gt;), use is simple (&lt;code&gt;Memprof.dump_all&lt;/code&gt;, for example), it outputs to &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt;, and provides all the necessary information and context about objects in memory, including references between objects. Memprof&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;JSON&lt;/span&gt; output makes it easy to dump its output into a database like MongoDB, which &lt;a href=&quot;http://memprof.com/&quot;&gt;memprof.com&lt;/a&gt; does. Aman&amp;#8217;s talk struck at just the right level: deep enough to keep us interested, but not so deep as to lose the audience. And if you&amp;#8217;ve ever checked out &lt;a href=&quot;http://timetobleed.com/&quot;&gt;Aman and Joe&amp;#8217;s blog&lt;/a&gt; you&amp;#8217;ll know how deep this this rabbit hole goes. My thanks to Aman for that.&lt;/p&gt;
&lt;p&gt;Managing Rubyists, a talk by &lt;strong&gt;Luke Melia&lt;/strong&gt;, was directed at Ruby developers who manage a team. This was the only non-technical talk of the day and it was one of the highlights for me. In the talk, Luke laid out 15 principles or techniques for managers to follow for their team and its members to achieve happiness, motivation, productivity and growth. I was blown away by the care Luke took with this subject and the regard he has for the developers he works with. Luke takes his craft as a manager as seriously as Rubyists take their code. Check out &lt;a href=&quot;http://www.slideshare.net/lukemelia/managing-rubyists-goruco-2010-pdf&quot;&gt;Luke&amp;#8217;s slides and notes&lt;/a&gt; for the details. If you&amp;#8217;re a manager, be sure to check out Luke&amp;#8217;s &lt;a href=&quot;http://www.goodreads.com/review/list/1047137-luke?shelf=goruco-reading-list&quot;&gt;recommended reading&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After lunch, &lt;strong&gt;Chris Williams&lt;/strong&gt; (of JSConf fame) presented Rails Caching à la JavaScript. In his talk, Chris made the case a straightforward approach to working around performance issues with Rails: using page caching to avoid the Rails stack altogether for most requests, and making &lt;span class=&quot;caps&quot;&gt;JSONP&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; requests to retrieve the personalized aspects of a page. Even though this &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt; request is handled by Rails, its rendering overhead is offloaded to the client (Chris recommends &lt;a href=&quot;http://github.com/janl/mustache.js&quot;&gt;mustache.js&lt;/a&gt; for client-side rendering). Despite Chris&amp;#8217; preface that the technique described is not ideal for most Rails applications, the talk drew skepticism and ire from the audience. Nonetheless, the talk was enjoyable, humorous, and made a strong argument for a straightforward caching strategy.&lt;/p&gt;
&lt;p&gt;Next, &lt;strong&gt;Alex MacCaw&lt;/strong&gt; showcased Bowline (pronounced &amp;#8220;bowlin&amp;#8217;&amp;#8221; like &lt;a href=&quot;http://en.wikipedia.org/wiki/Bowline&quot;&gt;the knot&lt;/a&gt;), a new framework for creating cross platform desktop apps using Ruby, JavaScript and WebKit. Alex gave a tour of developing an app with Bowline, showing off its in-memory model layer, &lt;a href=&quot;http://github.com/maccman/supermodel&quot;&gt;SuperModel&lt;/a&gt;, its bindings between Ruby and JavaScript and neat features such as seamless background updates for installed applications and synchronizing data across remote client apps. In all, Bowline looks to be a very ambitious and promising project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paul Dix&lt;/strong&gt;, author of the forthcoming &lt;a href=&quot;http://www.amazon.com/Service-Oriented-Design-Ruby-Rails-Paul/dp/0321659368&quot;&gt;Service Oriented Architecture with Ruby on Rails&lt;/a&gt;, presented on how to create web service clients using ActiveModel to scale an app. This is not scaling an app for traffic, but how to scaling as complexity and team size grow. Paul demonstrated how to leverage ActiveModel to implement client models with validations, dirty tracking, callbacks and even persistence. If you are struggling to deal with complexity in a large application and to abstract components into separate services, Paul offers an excellent approach. Definitely look out for his book this August.&lt;/p&gt;
&lt;p&gt;The last talk of the day, Scaling to Hundreds of Millions of Requests, was presented by &lt;strong&gt;James Golick&lt;/strong&gt;. In this talk, James outlined how he improved performance and scaled a very active &lt;a href=&quot;http://fetlife.com/&quot;&gt;community site&lt;/a&gt;. James shared his experience moving from Amazon EC2 to physical hardware and the immense performance increase this brought. James also went over his trials with MongoDB and using MySQL &amp;#8220;non-relationally&amp;#8221; with &lt;a href=&quot;http://friendlyorm.com/&quot;&gt;Friendly&lt;/a&gt; before finally settling on Cassandra. As James argued in &lt;a href=&quot;http://jamesgolick.com/2010/3/30/what-does-scalable-database-mean.html&quot;&gt;a recent blog post&lt;/a&gt; Cassandra is one of the NoSQL databases that truly scales horizontally. Look for James speaking further on this topic at Railsconf.&lt;/p&gt;
&lt;p&gt;The final hour of the conference comprised of &amp;#8220;Rejectconf,&amp;#8221; a round of lightning talks and a chance to speak for people whose talks weren&amp;#8217;t accepted for the conference program. Some highlights were Pat Nakajima presenting his &lt;a href=&quot;http://bookmarklets.heroku.com/&quot;&gt;Bookmarklet Factory&lt;/a&gt; (&amp;#8220;how to downvote 100 Gizmodo comments&amp;#8221;); Edward Ocampo-Gooding presenting on &lt;a href=&quot;http://www.openottawa.org/&quot;&gt;open data in Ottawa&lt;/a&gt;; Aaron Quint presenting on &lt;a href=&quot;http://github.com/quirkey/jim&quot;&gt;Jim&lt;/a&gt;, a JavaScript manager, bundler and compressor; and Michael Bernstein presenting on &lt;a href=&quot;http://github.com/soveran/ohm&quot;&gt;Ohm&lt;/a&gt;, the Redis object mapper with an &lt;a href=&quot;http://github.com/sinefunc/ohm-contrib&quot;&gt;extensive contrib collection&lt;/a&gt;. Then it was beer time.&lt;/p&gt;
&lt;p&gt;In all it was a great conference. Thanks to the conference organizers and hello to all the folks I met. And hello to all the folks I didn&amp;#8217;t get a chance to meet but wish I had. Keep your eyes peeled on &lt;a href=&quot;http://www.goruco.com/&quot;&gt;the conference site&lt;/a&gt;; videos will be posted in the next two weeks.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Up and Running With LaTeX</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2010/05/13/latex.html" />
   <updated>2010-05-13T00:00:00-04:00</updated>
   <id>http://akahn.net/2010/05/13/latex</id>
   <content type="html">&lt;p&gt;Recently I&amp;#8217;ve had the pleasure of getting acquainted with LaTeX. For those that don&amp;#8217;t know, LaTeX is a typesetting system that turns marked-up text files into precise, readable, print-ready documents. LaTeX is specialized for creating technical documents containing math and equations, but it&amp;#8217;s also well-suited for any structured document. LaTeX is not just the command-line tool for procesing &lt;code&gt;.tex&lt;/code&gt; files, though&amp;#8212;it&amp;#8217;s an entire ecosystem consisting of libraries, packages and tools for myriad purposes. The size of this ecosystem is staggering. At times, it&amp;#8217;s frustrating. But I&amp;#8217;ve grown to appreciate it the more I&amp;#8217;ve learned.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s so great about LaTeX? I love that it demands explicitness. It doesn&amp;#8217;t try to guess what you mean. Want a hyphen? Use -. Want a slightly longer dash, suitable for numerical ranges? That&amp;#8217;s --. Using a dash for punctuation? --- inserts an em dash. The same explicitness applies to quotes. How does LaTeX know what is an opening quote and what is a closing quote? You tell it. Use two backticks (``) for an opening quote and two apostrophes for a closing quote (''). These are two examples of the attention to detail that LaTeX promotes.&lt;/p&gt;
&lt;p&gt;Some things are more automatic. Hyphenation, for example, is handled by LaTeX. And it&amp;#8217;s smart.&lt;sup class=&quot;footnote&quot; id=&quot;fnr1&quot;&gt;&lt;a href=&quot;#fn1&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; The system sometimes misses possible hyphenation points, but it&amp;#8217;s very good at avoiding incorrect hyphenation, such as &amp;#8220;new-spapers.&amp;#8221; It also allows manual control of hyphenation. For example, put &lt;code&gt;\-&lt;/code&gt; in the middle of a word to identify a possible hyphenation point. I also found some of these &lt;a href=&quot;http://www.personal.ceu.hu/tex/breaking.htm&quot;&gt;line breaking commands&lt;/a&gt; helpful.&lt;/p&gt;
&lt;p&gt;LaTeX excels at working with tables, references, bibliographies, footnotes, indexes (and math, of course)&amp;#8212;features whose use ranges from tedious to hellish in word processing software. Perhaps its greatest strength is that unlike word processing software, LaTeX forces authors to focus on the content and structure of a document, rather than its presentation. LaTeX takes care of what it looks like. It&amp;#8217;s the anti-&lt;acronym title=&quot;What You See Is What You Get&quot;&gt;&lt;span class=&quot;caps&quot;&gt;WYSIWYG&lt;/span&gt;&lt;/acronym&gt;.&lt;/p&gt;
&lt;h3&gt;Installing LaTeX&lt;/h3&gt;
&lt;p&gt;The easiest way to get started with LaTeX on Mac OS X is to install &lt;a href=&quot;http://www.tug.org/mactex/2009/&quot;&gt;MacTeX&lt;/a&gt;. Once you have MacTeX installed, take a look in &lt;code&gt;/usr/local/texlive&lt;/code&gt; (MacTeX is a specialized version of the TeX Live distribution) to see what was installed. You&amp;#8217;ll want to add &lt;code&gt;/usr/local/texlive/2009/bin/universal-darwin&lt;/code&gt; to your &lt;code&gt;$PATH&lt;/code&gt;. Also make note of &lt;code&gt;/usr/local/texlive/2009/texmf-local/tex/latex&lt;/code&gt;&amp;#8212;this is where you&amp;#8217;ll install additional LaTeX packages.&lt;/p&gt;
&lt;h3&gt;The Memoir Class&lt;/h3&gt;
&lt;p&gt;You can get far with LaTeX&amp;#8217;s built in document classes: book, report, article, etc. But for my document, I needed a bit more flexibility. I turned to the Memoir document class. The goal of this class is to combine LaTeX&amp;#8217;s built-in book class with some of the more common packages that help customize the design of a document. The result is a large class, but one that offers convenience, since it reduces the need for installing additional packages.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s difficult to summarize what Memoir offers because it does so much. Instead, I&amp;#8217;ll just share my own experience: Memoir made laying out my document a breeze. I continually got the impression that the creators of Memoir had thought of everything. Refer to &lt;a href=&quot;http://mirror.ctan.org/macros/latex/contrib/memoir/memman.pdf&quot;&gt;Memoir&amp;#8217;s exhaustive, 500-page manual&lt;/a&gt; (&lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt;) to learn about what it offers. It&amp;#8217;s epic.&lt;/p&gt;
&lt;p&gt;To install Memoir (or any document class or package), &lt;a href=&quot;http://www.ctan.org/tex-archive/macros/latex/contrib/memoir/&quot; title=&quot;download the memoir document class&quot;&gt;download it from &lt;span class=&quot;caps&quot;&gt;CTAN&lt;/span&gt;&lt;/a&gt;, compile it using the instructions in the &lt;span class=&quot;caps&quot;&gt;README&lt;/span&gt;, and then copy the entire &lt;code&gt;memoir&lt;/code&gt; directory to the installation directory mentioned above. Then, after running &lt;code&gt;texhash&lt;/code&gt;, you should be able to compile documents using the Memoir class.&lt;/p&gt;
&lt;h3&gt;Printing 2-Up&lt;/h3&gt;
&lt;p&gt;The document I was preparing was a long packet of reading. I wanted to print this document with two pages per sheet, as a photocopied packet from a book would be layed out. Although there are ways to bend LaTeX&amp;#8217;s strong desire to print one logical page per physical sheet of paper (among these are &lt;a href=&quot;http://www.ctan.org/tex-archive/macros/latex/contrib/booklet/&quot;&gt;&lt;code&gt;booklet&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://www.ctan.org/tex-archive/macros/latex/contrib/twoup/&quot;&gt;&lt;code&gt;twoup&lt;/code&gt;&lt;/a&gt;), a more prudent alternative is pdfpages. pdfpages is a package for embedding&amp;#8212;you guessed it&amp;#8212;&lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; pages into LaTeX documents. Conveniently, it has the ability to embed multiple pages of a &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; document into a single page of a LaTeX document. The end result: multiple logical pages per physical sheet. After producing a &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; of your original document, create another LaTeX document which embeds the compiled &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt;, manipulating it to render two &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; pages on one LaTeX page. Some code might make this clearer:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;latex&quot;&gt;&lt;span class=&quot;k&quot;&gt;\documentclass&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;[landscape]&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;{&lt;/span&gt;article&lt;span class=&quot;nb&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;\usepackage&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;{&lt;/span&gt;pdfpages&lt;span class=&quot;nb&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;\begin&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;{&lt;/span&gt;document&lt;span class=&quot;nb&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;\includepdf&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;[nup=2x1,pages=-]&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;{&lt;/span&gt;my-document.pdf&lt;span class=&quot;nb&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;\end&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;{&lt;/span&gt;document&lt;span class=&quot;nb&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The document class used here is irrelevant, but it&amp;#8217;s important to set landscape orientation. The interesting line here is the &lt;code&gt;\includepdf&lt;/code&gt; directive. The &lt;code&gt;nup=2x1&lt;/code&gt; tells pdfpages to place two pages from the &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; file side-by-side in our document. &lt;code&gt;pages=-&lt;/code&gt; tells pdfpages to include all pages of the &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; file. When you compile this document, the output contains two logical pages laid out on a landscape-oriented physical sheet.&lt;/p&gt;
&lt;p&gt;For optimal 2-up printing, you&amp;#8217;ll need to adjust your original document&amp;#8217;s margins. LaTeX assumes that you are printing a book, and thus need a large inner margin (where the binding would be) and a smaller outer margin. Memoir makes it easy to override these defaults:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;latex&quot;&gt;&lt;span class=&quot;c&quot;&gt;% Set inner and outer margins to .5 and 1 inch, respectively&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;\setlrmarginsandblock&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;{&lt;/span&gt;.5in&lt;span class=&quot;nb&quot;&gt;}{&lt;/span&gt;1in&lt;span class=&quot;nb&quot;&gt;}{&lt;/span&gt;*&lt;span class=&quot;nb&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;% Set top and bottom margins to .8 inches&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;\setulmarginsandblock&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;{&lt;/span&gt;.8in&lt;span class=&quot;nb&quot;&gt;}{&lt;/span&gt;.8in&lt;span class=&quot;nb&quot;&gt;}{&lt;/span&gt;*&lt;span class=&quot;nb&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;% The {*} parameter tells LaTeX to use the measurements&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;% provided rather than attempt to calculate a ratio&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;pdfpages has numerous options for arranging booklet-style documents, which you can read about in &lt;a href=&quot;http://www.ctan.org/tex-archive/macros/latex/contrib/pdfpages/pdfpages.pdf&quot; title=&quot;pdfpages manual&quot;&gt;its manual&lt;/a&gt; (&lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt;). &lt;a href=&quot;http://www.ctan.org/tex-archive/macros/latex/contrib/pdfpages/&quot; title=&quot;download pdfpages from CTAN&quot;&gt;Get the package here.&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Better Typography&lt;/h3&gt;
&lt;p&gt;One point of frustration I had with LaTeX was its font handling. The routine for preparing a typeface to be used with LaTeX was so elaborate that it scared me away. But then I came across XeLaTeX, a project that brings modern, convenient typography to LaTeX.&lt;/p&gt;
&lt;p&gt;Using XeLaTeX solved two problems for me. One was using Unicode characters in my documents. For some reason, LaTeX doesn&amp;#8217;t support this by default, requiring external packages for this purpose. Using XeLaTeX, it was as simple as using Unicode characters in an &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; document. XeLaTeX also makes it dropdead simple to use any OpenType or TrueType typeface installed on your system. Replacing LaTeX&amp;#8217;s handsome but staid &lt;a href=&quot;http://en.wikipedia.org/wiki/Computer_modern&quot;&gt;Computer Modern&lt;/a&gt; with the dignified, refined &lt;a href=&quot;http://en.wikipedia.org/wiki/Baskerville&quot;&gt;Baskerville&lt;/a&gt; was as simple as &lt;code&gt;\setmainfont[Mapping=tex-text]{Baskerville}&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Editing LaTeX in Vim&lt;/h3&gt;
&lt;p&gt;The &lt;a href=&quot;http://vim-latex.sourceforge.net/&quot;&gt;Latex-Suite&lt;/a&gt; plugin for Vim is a lifesaver. It provides syntax highlighting, folding (handy for hiding sections or chapters you&amp;#8217;re not currently working on) and numerous mappings that I haven&amp;#8217;t taken the time to learn. One exception is the mapping for compiling. To compile your document to &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt;, use &lt;code&gt;,ll&lt;/code&gt;. The compilation log is displayed in a preview window, and any compilation errors pop up in a QuickFix window. To set Latex-Suite to use xelatex to compile your document, add &lt;code&gt;let g:Tex_CompileRule_pdf = 'xelatex -interaction=nonstopmode $*'&lt;/code&gt; to your &lt;code&gt;.vimrc&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Further Reading&lt;/h3&gt;
&lt;p&gt;There&amp;#8217;s a lot more. This post is the tip of the iceberg. If you&amp;#8217;re interested in learning more, here are some resources that might help:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The &lt;a href=&quot;http://en.wikibooks.org/wiki/LaTeX&quot;&gt;LaTeX Wikibook&lt;/a&gt; is a thorough, clear, and well-organized reference guide to LaTeX. I found the sections on formatting and tables particularly helpful.&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.lyx.org/&quot;&gt;LyX&lt;/a&gt; is a &lt;span class=&quot;caps&quot;&gt;WYSIWYM&lt;/span&gt; (&amp;#8220;what you see is what you mean&amp;#8221;) graphical editor for LaTeX. This could be a more approachable entrée into LaTeX for folks that don&amp;#8217;t want to work with plain text.&lt;/li&gt;
	&lt;li&gt;The #latex channel on Freenode has been a helpful and friendly resource. It&amp;#8217;s not just scientists and mathematicians in there.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;footnote&quot; id=&quot;fn1&quot;&gt;&lt;a href=&quot;#fnr1&quot;&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; &lt;a href=&quot;http://tug.org/docs/liang/&quot;&gt;Frank Liang&amp;#8217;s 1983 dissertation&lt;/a&gt; should give you a sense of how much thought and effort has gone into hyphenation in LaTeX.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Notes on Redis: Data Modeling, Hashes, and Namespaces</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2010/03/30/notes-on-redis.html" />
   <updated>2010-03-30T00:00:00-04:00</updated>
   <id>http://akahn.net/2010/03/30/notes-on-redis</id>
   <content type="html">&lt;h3&gt;What is Redis?&lt;/h3&gt;
&lt;p&gt;Redis is a simple database. It stores its data in memory and saves a snapshot to disk in the background periodically. It can be used as a simple key-value store like Memcached, but it also supports more complex data types such as lists, sets, sorted sets and hashes. These will come in handy. Redis is versatile and is used for a plethora of tasks: &lt;a href=&quot;http://github.com/defunkt/resque&quot;&gt;as a job queue&lt;/a&gt;, as a cache store, for &lt;a href=&quot;http://gist.github.com/296921&quot;&gt;tracking downloads of Ruby Gems&lt;/a&gt;,  for &lt;a href=&quot;http://vanity.labnotes.org/&quot;&gt;storing A/B testing results&lt;/a&gt;, and even as the backend for &lt;a href=&quot;http://try.redis-db.com:8082&quot;&gt;a chat server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Redis has been receiving a lot of praise lately and is the subject of lot of excitement online. This praise is deserved – it&amp;#8217;s an excellent piece of software. I&amp;#8217;ve had the pleasure of using Redis recently and here are some of my findings.&lt;/p&gt;
&lt;h3&gt;Our Use Case&lt;/h3&gt;
&lt;p&gt;On &lt;a href=&quot;http://mediafail.com&quot;&gt;mediaFAIL&lt;/a&gt;, we wanted to track how many mentions a fail receives on Twitter. We wanted to show a count of a fail&amp;#8217;s Twitter mentions and roll that number into a fail&amp;#8217;s votes – this feature lies somewhere between &lt;a href=&quot;http://act.ly/&quot;&gt;act.ly&lt;/a&gt; and &lt;a href=&quot;http://tweetmeme.com/&quot;&gt;Tweetmeme&lt;/a&gt;. Couldn&amp;#8217;t we just store each tweet in our &lt;code&gt;votes&lt;/code&gt; table? Perhaps. But this would break our &amp;#8220;user has many fails through votes&amp;#8221; association. How do I store this data in Redis?&lt;/p&gt;
&lt;h3&gt;Data Modeling&lt;/h3&gt;
&lt;p&gt;My first pass at the problem took advantage Redis&amp;#8217;s sets. For each fail that was mentioned on Twitter, I created a set containing the users that mention a fail. So, key &lt;code&gt;fail:1:tweets&lt;/code&gt; contained the set &lt;code&gt;['alexanderkahn', 'levjoy', 'TimKarr']&lt;/code&gt;. Since elements in sets must be unique, I wouldn&amp;#8217;t have to worry about a user making multiple mentions of a fail getting counted more than once. This was an elegant solution: it allowed looking up the number of mentions a fail has received using &lt;code&gt;SLEN&lt;/code&gt; (set length) and retrieving all the Twitter usernames for a fail using &lt;code&gt;SMEMBERS&lt;/code&gt; (set members).&lt;/p&gt;
&lt;p&gt;As I continued work on this feature, I realized that I wanted to link to the specific tweet where a Twitter user mentioned a fail. One way to do that would be to set a string key for each member of a set that corresponds to a member of the &lt;code&gt;tweet:1:tweets&lt;/code&gt; set. So, for the above example, I would also set &lt;code&gt;fail:1:tweet:alexanderkahn&lt;/code&gt; to &amp;#8220;12330508057&amp;#8221;, the tweet ID for my mention of the fail. But this would cause a lot of keys to be created and mean that looking up usernames and tweet IDs for a fail would require a great deal of queries for a popular fail. Thanks to Redis&amp;#8217;s new hash data structure, there was a cleaner way. In a hash, I can store both the username and the tweet ID under the same &lt;code&gt;fail:1:tweets&lt;/code&gt; key. The hash for this key would look like &lt;code&gt;{&quot;alexanderkahn&quot; =&amp;gt; &quot;12330508057&quot;, &quot;levjoy&quot; =&amp;gt; &quot;12330508067&quot;, &quot;TimKarr&quot; =&amp;gt; &quot;12330518057&quot;}&lt;/code&gt;. Since hash keys have to be unique, a Twitter mention can&amp;#8217;t be counted twice, just like with a set. Now I can look up how many mentions a fail has received with &lt;code&gt;HLEN&lt;/code&gt; (hash length) and fetch both usernames an tweet &lt;span class=&quot;caps&quot;&gt;IDS&lt;/span&gt; with one &lt;code&gt;HGETALL&lt;/code&gt; (hash get all) query. Groovy.&lt;/p&gt;
&lt;h3&gt;Redis and Ruby&lt;/h3&gt;
&lt;p&gt;The Ruby library for Redis, written by Ezra Zygmuntowicz, is a pleasure to use. It has certain touches that make it feel like Redis was born for Ruby. One example of this quality is &lt;a href=&quot;http://github.com/ezmobius/redis-rb/blob/master/lib/redis/client.rb#L395-407&quot;&gt;how it handles Redis&amp;#8217;s &lt;code&gt;MULTI&lt;/code&gt;/&lt;code&gt;EXEC&lt;/code&gt; transactions&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;multi&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;bar&amp;#39;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;incr&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;baz&amp;#39;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In the above code, if an exception is raised during the execution of the block, none of the operations inside are committed. This is just a basic transaction like ActiveRecord provides when working with a &lt;span class=&quot;caps&quot;&gt;SQL&lt;/span&gt; database, but is neatly implemented in idiomatic Ruby. The block returns the result of each Redis operation in an array.&lt;/p&gt;
&lt;p&gt;Another nice Ruby touch is the way the library translates a Redis hashes into a Ruby hashes. When retrieving the entire contents of a hash using &lt;code&gt;HGETALL&lt;/code&gt;, rather than returning a flat list (1. key, 2.value, 3. secondkey, 4. secondvalue) as the Redis internal protocol does, the library &lt;a href=&quot;http://github.com/ezmobius/redis-rb/blob/master/lib/redis/client.rb#L72-74&quot;&gt;turns this list into a Ruby hash&lt;/a&gt; using &lt;code&gt;Hash::[]&lt;/code&gt;. I had never run into this way of creating a Ruby hash out of an array, but its use here struck me as clever. Check out &lt;code&gt;ri Hash::[]&lt;/code&gt; for more on this.&lt;/p&gt;
&lt;p&gt;Another good project for working with Redis in Ruby is &lt;a href=&quot;http://github.com/defunkt/redis-namespace&quot;&gt;redis-namespace&lt;/a&gt; by Chris Wanstrath. This library helps you compartmentalize your Redis keys to keep different sets of data separate. We&amp;#8217;re using this to keep tweets, described above, separate from our A/B testing data. To use it, you just interact with a &lt;code&gt;Redis::Namespace&lt;/code&gt; object rather than a &lt;code&gt;Redis::Client&lt;/code&gt; object.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;namespaced&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Namespace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:my_feature&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:redis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Interact with namespaced Redis as you would a normal Redis client:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;namespaced&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;namespaced&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;#39;bar&amp;#39;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;namespaced&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;*&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [&amp;#39;foo&amp;#39;]&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# The actual key in Redis is prefixed with our namespace:&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;keys&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;*&amp;quot;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [&amp;#39;my_feature:foo&amp;#39;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Nice of Chris to take care of that for us, no?&lt;/p&gt;
&lt;p&gt;One last note. How am I accessing Redis from within my Rails app? Currently, I&amp;#8217;m taking &lt;a href=&quot;http://github.com/qrush/gemcutter/blob/redis/config/environment.rb#L12&quot;&gt;a page out of Nick Quaranto&amp;#8217;s book&lt;/a&gt; and setting a global variable (in &lt;code&gt;environment.rb&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;vg&quot;&gt;$redis&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Redis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Or a namespaced equivalent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This variable provides access to Redis from anywhere in the application. This is not necessarily the best way, but for now it works. I&amp;#8217;m happy to hear how I could improve upon this.&lt;/p&gt;
&lt;p&gt;If you haven&amp;#8217;t had a chance to explore Redis yet, I recommend doing so. I hope this post helps push you in the right direction. Some handy resources will be the &lt;a href=&quot;http://code.google.com/p/redis/wiki/CommandReference&quot;&gt;Redis command reference&lt;/a&gt;, &lt;a href=&quot;http://masonoise.files.wordpress.com/2010/03/redis-cheatsheet-v1.pdf&quot;&gt;this &lt;span class=&quot;caps&quot;&gt;PDF&lt;/span&gt; cheat sheet&lt;/a&gt;, and following &lt;a href=&quot;http://twitter.com/antirez&quot;&gt;@antirez&lt;/a&gt;, Redis&amp;#8217;s author, on Twitter.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A Sinatra App Wrapping Flickr, Plus HTTP Caching and Heroku</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2010/02/22/sinatra-app-wrapping-flickr-http-caching-heroku.html" />
   <updated>2010-02-22T00:00:00-05:00</updated>
   <id>http://akahn.net/2010/02/22/sinatra-app-wrapping-flickr-http-caching-heroku</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://recent-work.estherswhite.net&quot;&gt;&lt;img src=&quot;/images/recent-work.jpg&quot; title=&quot;Screenshot of Esther S White: Recent Work&quot; alt=&quot;Screenshot of Esther S White: Recent Work&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In the last several months, &lt;a href=&quot;http://www.estherswhite.net&quot;&gt;Esther&lt;/a&gt; has produced a large number of monotype prints at a local printmaking studio. She&amp;#8217;s been sharing her work online by scanning it and posting it to Flickr. Recently she experimented with using Tumblr to create a stylish gallery of this work. But this process &amp;mdash; scanning, adding metadata, uploading to Flickr, followed by posting each piece to Tumblr &amp;mdash; proved to be laborious. So we sought to streamline this workflow, hoping to eliminate a step or two.&lt;/p&gt;
&lt;p&gt;Titles, descriptions, tags and sets are all easy to manage on Flickr. What if there was a way to take advantage of Flickr&amp;#8217;s great management interface, taking images and metadata and putting them on an external site? I took on this problem with a &lt;a href=&quot;http://github.com/akahn/recent-work.estherswhite.net&quot;&gt;Sinatra application that wraps the Flickr &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; in a warm embrace&lt;/a&gt;. The app makes an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; request to Flickr asking for all the images from Esther&amp;#8217;s &lt;a href=&quot;http://www.flickr.com/photos/estherswhite/sets/72157622782141504/&quot;&gt;printmaking photoset&lt;/a&gt; and renders them as thumbnails, each image linking to a page for that image. On the individual image page, the app requests information on an image &amp;ndash; title, description, and the next and previous image &amp;ndash; and displays this information along with a larger image of the piece. Now, Flickr itself is the &lt;span class=&quot;caps&quot;&gt;CMS&lt;/span&gt; and the gallery is just a pretty shell for information already stored on Flickr. No more managing metadata in multiple places. &lt;a href=&quot;http://recent-work.estherswhite.net&quot;&gt;Have a look at the site.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;What about performance? Isn&amp;#8217;t it slow to make an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; request to Flickr for every visit to the site? This is a definite concern: making an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; call to Flickr and then responding takes the application about 500ms &amp;ndash; respectable but not exactly speedy. But the content of the site is basically static. Once an image is uploaded and described on Flickr, it is unlikely to change. This means I can cache the entire page with a gateway cache&lt;sup&gt;1&lt;/sup&gt;. To do this, I set &lt;code&gt;Cache-Control&lt;/code&gt; headers that say that my pages are allowed to be cached for long time, and the cache, Varnish, serves up a static representation of the page that the app produced. Once a page has been requested once, subsequent requests for that page are lightning-fast &amp;ndash; under 100ms. After six hours, the cached representation of the homepage is considered stale, and a new one will be generated. After two days, the cached representation of an individual page is considered stale. This way, updates to the photoset or changes to images do eventually get served to visitors.&lt;/p&gt;
&lt;p&gt;I should note that I&amp;#8217;m hosting this site on Heroku. It&amp;#8217;s been said elsewhere and should perhaps be obvious by now, but I&amp;#8217;ll say it again: Heroku is awesome. &lt;a href=&quot;http://docs.heroku.com/http-caching&quot;&gt;Their use of Varnish&lt;/a&gt; made it so easy to make this gallery app fast. Deploying code with just a &lt;code&gt;git push&lt;/code&gt; is seriously great. I recommend hosting an app on Heroku if you haven&amp;#8217;t before. It&amp;#8217;s easy and, for a simple app like this one, is free.&lt;/p&gt;
&lt;p class=&quot;notes&quot;&gt;1: For more on &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; caching, see Ryan Tomayko&amp;#8217;s excellent article &lt;a href=&quot;http://tomayko.com/writings/things-caches-do&quot;&gt;Things Caches Do&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>FakeWeb and Regular Expressions</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2009/12/16/fakeweb-regular-expressions.html" />
   <updated>2009-12-16T00:00:00-05:00</updated>
   <id>http://akahn.net/2009/12/16/fakeweb-regular-expressions</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://fakeweb.rubyforge.org/&quot;&gt;FakeWeb&lt;/a&gt; is a great way to speed up your tests and remove dependencies on external web services. Using FakeWeb is simple: specify a &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; for FakeWeb to respond to, and give it the response you expect from the request. For example:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;HTTParty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now FakeWeb will prevent your code from making an actual &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; request and instead it will return the response you specified. But what if your application makes requests to URLs with query parameters? It would be tedious to register each &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; with FakeWeb:&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=fakeweb&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=excited+kitten&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=ponies&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Stubbed Google!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Thankfully, FakeWeb has a (slightly underdocumented) solution for this. Instead of passing a string to &lt;code&gt;FakeWeb.register_uri&lt;/code&gt;, pass it a regular expression (using Ruby&amp;#8217;s &lt;code&gt;%r||&lt;/code&gt; syntax to avoid having to escape forward slashes):&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;FakeWeb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;register_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;%r|http://www.google.com/search\?q=|&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;A bunch of results&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;HTTParty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=tunisia&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;A bunch of results&amp;quot;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;HTTParty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.google.com/search?q=vegan+latkes&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; &amp;quot;A bunch of results&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;By registering a regular expression, FakeWeb will respond to any &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; &lt;span class=&quot;caps&quot;&gt;GET&lt;/span&gt; request whose &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt; matches the pattern you&amp;#8217;ve supplied. Your test suite can make requests with all different query parameters without having to register each individual &lt;span class=&quot;caps&quot;&gt;URL&lt;/span&gt;. This feature adds a lot of flexibility to FakeWeb and makes it feasible to stub out your application&amp;#8217;s &lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; requests, even when complex, changing query parameters are involved.&lt;/p&gt;
&lt;p&gt;For a general overview of FakeWeb, as well a some far-less-contrived examples of its use, check out Josh Nichols&amp;#8217; post, &lt;a href=&quot;http://technicalpickles.com/posts/stop-net-http-dead-in-its-tracks-with-fakeweb/&quot;&gt;Stop Net::&lt;span class=&quot;caps&quot;&gt;HTTP&lt;/span&gt; dead in its tracks&lt;/a&gt;. Also check out &lt;a href=&quot;http://github.com/chrisk/fakeweb&quot;&gt;FakeWeb on GitHub&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Pretty Feed Items with Facebook Connect</title>
   <link rel="alternate" type="text/html" href="http://akahn.net//2009/11/06/pretty-feed-items-with-facebook-connect.html" />
   <updated>2009-11-06T00:00:00-05:00</updated>
   <id>http://akahn.net/2009/11/06/pretty-feed-items-with-facebook-connect</id>
   <content type="html">&lt;p&gt;At Free Press, when a user signs a petition or shows support for our issues on one of our sites, we want them to spread the word. We want to make it easy for users to share the story they told, or the petition they signed, and to encourage others to do the same. We usually do this with links to &lt;a href=&quot;http://www.facebook.com/sharer.php?u=http://www.akahn.net/2009/11/06/pretty-feed-items-with-facebook-connect.html&quot;&gt;Facebook&amp;#8217;s &lt;code&gt;sharer.php&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;http://twitter.com/home?status=http://www.akahn.net/2009/11/06/pretty-feed-items-with-facebook-connect.html%20--%20Not%20too%20shabby&quot;&gt;Twitter&amp;#8217;s status parameter&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But &lt;code&gt;sharer.php&lt;/code&gt; left us frustrated with its awkward interface and lack of branding. What about the pretty updates that Facebook applications produce? We wanted a feed item that looked branded, looked good, and compelled a user&amp;#8217;s friends to also take action. This is where Facebook Connect comes in.&lt;/p&gt;
&lt;p&gt;Using Facebook Connect for this task turned out to be simple. Surprisingly simple. Here&amp;#8217;s the routine:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;&lt;a href=&quot;http://www.facebook.com/developers/&quot;&gt;Create a Facebook application&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://wiki.developers.facebook.com/index.php/Cross_Domain_Communication_Channel&quot;&gt;Create a file to allow cross-domain JavaScript communication&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://wiki.developers.facebook.com/index.php/FeatureLoader.js.php&quot;&gt;Include Facebook&amp;#8217;s JavaScript library&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Write some JavaScript&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Steps 1-3 are fairly well documented in the links above. Step 4 is the interesting part. Take a look at the code below.&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AK&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;apiKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&amp;quot;de24e7cfd602218871fc8e30b3dd8a5f&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Facebook Connect is easy!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Updating from akahn.net&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.akahn.net&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;caption&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;So cool!&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;media&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;image&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://akahn.net/images/shoes.jpg&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.akahn.net&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;FB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apiKey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;/xd_comm.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;FB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ensureInit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;FB&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;streamPublish&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;AK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attachment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php/en_US&quot;&gt;&lt;/script&gt;&lt;script type=&quot;text/javascript&quot; src=&quot;/js/facebook.js&quot;&gt;&lt;/script&gt;&lt;p&gt;What&amp;#8217;s going on here? First, I&amp;#8217;m creating an object, &lt;code&gt;AK&lt;/code&gt;, to store the various pieces of data I need. This includes an &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; key, the default message that the user will be posting to their feed, along with some other bits of text, and an image.&lt;/p&gt;
&lt;p&gt;I then get the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; ready, using &lt;a href=&quot;http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Init&quot;&gt;&lt;code&gt;FB.init&lt;/code&gt;&lt;/a&gt;, specifying my &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; key and the location of my cross-domain communication file.&lt;/p&gt;
&lt;p&gt;Then I make sure that the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; has finished loading, using &lt;a href=&quot;http://wiki.developers.facebook.com/index.php/JS_API_M_FB.Bootstrap.EnsureInit&quot;&gt;&lt;code&gt;FB.ensureInit&lt;/code&gt;&lt;/a&gt;. I pass in a function, to be executed once the &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; has finished loading.&lt;/p&gt;
&lt;p&gt;In the function, I call &lt;a href=&quot;http://wiki.developers.facebook.com/index.php/FB.Connect.streamPublish&quot;&gt;&lt;code&gt;FB.Connect.streamPublish&lt;/code&gt;&lt;/a&gt;. I pass in the message and the attachment object that I defined earlier. If the user is logged in on Facebook, they&amp;#8217;re presented with a modal popup inviting them to post to their feed. If not, they&amp;#8217;re prompted to log in before they are invited to create a feed item. Try it out below:&lt;/p&gt;
&lt;p class=&quot;connect&quot;&gt;&lt;a class=&quot;connect&quot; href=&quot;http://www.facebook.com/sharer.php?u=http://akahn.net/2009/11/06/pretty-feed-items-with-facebook-connect.html&quot;&gt;Post to my Facebook wall!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And that&amp;#8217;s it! It takes a lot of setup just to make one little call to &lt;code&gt;FB.Connect.streamPublish&lt;/code&gt;. But the smooth user experience and the customized, pretty feed item make it all worthwhile.&lt;/p&gt;</content>
 </entry>
 
 
</feed>

