<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Emmanuel Oga's Blog</title>
 <link href="http://emmanueloga.com/atom.xml" rel="self"/>
 <link href="http://emmanueloga.com/"/>
 <updated>2015-02-06T05:25:29+00:00</updated>
 <id>http://emmanueloga.com/</id>
 <author>
   <name>Emmanuel Oga</name>
   <email>emmanueloga@gmail.com</email>
 </author>

 
 <entry>
   <title>Fun with Google's Apps Script! Batch Processing Gmail emails By Host</title>
   <link href="http://emmanueloga.com/2014/03/28/Google-App-Script-Gmail-Cleanup-By-Hosts.html"/>
   <updated>2014-03-28T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2014/03/28/Google-App-Script-Gmail-Cleanup-By-Hosts</id>
   <content type="html">&lt;p&gt;Like everybody that has had the same email acount for a while, I receive
a lot of emails. Most of them are automatic responses or update from
sites like twitter.com, linkedin.com, facebook.com, plus.google.com,
etc.. Others are mailing lists I signed up for and lost interest
in, and so on.&lt;/p&gt;

&lt;p&gt;Sometimes I get tired of the amount of emails to manage, and  I just
want to tell Gmail: &quot;delete all emails coming from &lt;em&gt;host.com&lt;/em&gt;&quot;, for any
number of hosts.&lt;/p&gt;

&lt;p&gt;My email managemenet workflow goes something like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Locate by visual inspection a host I want to delete or archive&lt;/li&gt;
&lt;li&gt;Search &quot;from:host&quot;, mark all emails for deletion&lt;/li&gt;
&lt;li&gt;Delete all marked emails&lt;/li&gt;
&lt;li&gt;Repeat for as many hosts as needed.&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Since it is unlikely Gmail will ever include a feature to automate such
specific workflow, I decided to give Google&#39;s
&lt;a href=&quot;https://developers.google.com/apps-script/&quot;&gt;Apps Script&lt;/a&gt; a try (not to
confuse with &lt;a href=&quot;http://en.wikipedia.org/wiki/AppleScript&quot;&gt;AppleScript&lt;/a&gt; :p).&lt;/p&gt;

&lt;p&gt;I got tired of doing this by hand and I wrote &lt;a href=&quot;https://script.google.com/d/12ONoFC4Cg05GQI1Q1Y8G50AfWk3wvdmkanTryZ6KndbAdt_l7GGYWqBZ/edit?usp=sharing&quot;&gt;a script to automate this task&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Here&#39;s how the resulting Apps Script looks like (you need to be logged into
Gmail for it to work).&lt;/p&gt;

&lt;div class=&quot;align_center&quot; style=&quot;padding: 2em; border: 1px solid #ccc;&quot;&gt;
  &lt;a href=&quot;https://chrome.google.com/webstore/detail/gmail-sweeper/iabmkioocehcfbobkdchdmmidnjjipdn&quot;&gt;
    &lt;img style=&quot;max-width: 85%;&quot; src=&quot;/images/gmail-sweeper.png&quot; title=&quot;Gmail Sweeper&quot; alt=&quot;Gmail Sweeper Screenshot&quot; /&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;&lt;br/&gt;
&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;The script is also able to archive emails coming from a certain host,
and/or mark them as important.&lt;/p&gt;

&lt;p style=&quot;color: red; border: 2px dashed red; padding: 5px; margin: 5px;&quot;&gt;

The standard &lt;strong&gt;disclaimer&lt;/strong&gt; applies: &lt;strong&gt;this script
will erase some of your emails! Normally it should only move emails from
the hosts you select to your Trash folder, but use it at your own
risk!&lt;/strong&gt;
&lt;/p&gt;


&lt;p&gt;&lt;br/&gt;
&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;Developing this script was fun but I found a few caveats because I was
lazy and decided not to use the &lt;a href=&quot;https://developers.google.com/apps-script/guides/ui-service&quot;&gt;ui services&lt;/a&gt;.
Instead, I used the &lt;a href=&quot;https://developers.google.com/apps-script/execution_web_apps&quot;&gt;html services&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Apps Script uses &lt;a href=&quot;https://code.google.com/p/google-caja/&quot;&gt;caja&lt;/a&gt; under the
hood, so a lot of things are not allowed (e.g.: it did not allow me to
add pictures, like a loading gif, or svg, to the page).&lt;/p&gt;

&lt;p&gt;All in all it was a fun experience and I think AppScript is definitely a
very useful tool to have in your toolbox if you use Google products like
Gmail or Spreadsheets.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Graphs are Everywhere! An overview of GraphConnect San Francisco 2013</title>
   <link href="http://emmanueloga.com/2013/10/07/Graphs-are-Everywhere-An-overview-of-GraphConnect-San-Francisco-2013.html"/>
   <updated>2013-10-07T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2013/10/07/Graphs-are-Everywhere-An-overview-of-GraphConnect-San-Francisco-2013</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.neo4j.org/&quot;&gt;Neo4j&lt;/a&gt; is a very cool
&lt;a href=&quot;http://en.wikipedia.org/wiki/Graph_database&quot;&gt;Graph Database&lt;/a&gt;
which sports an embedded mode for Java applications but also an stand-alone
server with a REST API. Drivers are available for
&lt;a href=&quot;http://www.neo4j.org/develop/drivers&quot;&gt;a ton&lt;/a&gt;
of different programming languages.&lt;/p&gt;

&lt;p&gt;The developers of Neo4j organized &lt;a href=&quot;http://www.graphconnect.com/san-francisco/&quot;&gt;GraphConnect&lt;/a&gt;
@ San Francisco and I was lucky enough to be invited!
Hereby I present some of the notes I took.&lt;/p&gt;

&lt;div class=&quot;align_center&quot; style=&quot;padding: 2em;&quot;&gt;
  &lt;img style=&quot;max-width: 85%;&quot; src=&quot;/images/graphc.png&quot; title=&quot;GraphConnect 2013&quot; alt=&quot;GraphConnect 2013&quot; /&gt;
&lt;/div&gt;


&lt;h3&gt;New Opportunities for Connected Data, by &lt;a href=&quot;https://twitter.com/emileifrem&quot;&gt;Emil Eifrem&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;To me, the take away on this keynote was the notion that, in
any given data set, there are relations to be discovered: &quot;There&#39;s a
Graph for That!&quot;. Exploiting this relationships can give a
company an strategic advantage over competitors.&lt;/p&gt;

&lt;p&gt;Emil mentioned a paper published by Gartner:
&lt;a href=&quot;http://www.gartner.com/id=2081316&quot;&gt;The Competitive Dynamics of the Consumer Web: Five Graphs Deliver a Sustainable Advantage&lt;/a&gt;.
Hopefully I&#39;ll get a hold of that paper at some point, sounds like an
interesting read! Many times relationships are not self evident. A question that we can
ask ourselves when observing a given system is: What five graphs
exist here?&lt;/p&gt;

&lt;p&gt;Emil announced a free course on Neo4j will be made available on
&lt;a href=&quot;versal.com&quot;&gt;versal.com&lt;/a&gt;, probably by end of October.&lt;/p&gt;

&lt;p&gt;He finished by demoing a bit the sweet new
&lt;a href=&quot;https://github.com/neo4j/neo4j-browser/&quot;&gt;data browser for Neo4j&lt;/a&gt;, built with
&lt;a href=&quot;angularjs.org&quot;&gt;AngularJS&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;What&#39;s new in Neo4j 2.0, by &lt;a href=&quot;https://twitter.com/akollegger&quot;&gt;Andreas Kollegger&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Labeling is a new feature that replaces the need to assign &lt;code&gt;{ type: &quot;Type&quot; }&lt;/code&gt; properties
on Nodes or create &lt;code&gt;(Node)-[:IS_A]-&gt;(Type)&lt;/code&gt; relationships. Labels
are light weight and shouldn&#39;t be thought of as a rigid type system.
Labels are automatically indexed, so it is efficient to query
for all Nodes with a certain label.&lt;/p&gt;

&lt;p&gt;Another new feature is constraints: for instance, we can now
constraint that a given property, like title, should be unique across
nodes.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;CREATE UNIQUE&lt;/code&gt; is going away and will be replaced with &lt;code&gt;MERGE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Many other things mentioned in this talk are well documented in a couple
of blog posts in a much better way than I could do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.neo4j.org/2013/05/new-milestone-release-neo4j-200-m03.html&quot;&gt;New Milestone Release Neo4j 2.0.0-M03&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.neo4j.org/2013/09/neo4j-200m05-released.html&quot;&gt;Neo4j 2.0.0-M05 released&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;DIY Graph Search, by &lt;a href=&quot;https://twitter.com/maxdemarzi&quot;&gt;Max De Marzi&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;Max demoed a &lt;a href=&quot;http://maxdemarzi.com/2013/01/28/facebook-graph-search-with-cypher-and-neo4j/&quot;&gt;search
engine&lt;/a&gt;
accepting natural language queries, similar to Facebook Search.&lt;/p&gt;

&lt;p&gt;He implemented the parser using
&lt;a href=&quot;http://treetop.rubyforge.org/&quot;&gt;treetop&lt;/a&gt;, so not really a full natural
language processor, but it was a nice hack for getting something
working quickly. The app worked by converting human friendly search
patterns to Cyper queries.&lt;/p&gt;

&lt;h3&gt;Graph Adoption at Gamesys, by &lt;a href=&quot;https://twitter.com/tobyorourke&quot;&gt;Toby O&#39;Rourke&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;I was looking forward this talk because I really like both subjects:
Graphs and Video Games! :)&lt;/p&gt;

&lt;p&gt;The talk was about how Neo4j is used on &lt;a href=&quot;http://www.gamesyscorporate.com/&quot;&gt;Gamesys&lt;/a&gt;
to back many of their games.&lt;/p&gt;

&lt;p&gt;An example was how they tracked referral of friends. By visually
plotting the referrals, suspicious activity patterns can be quickly
spotted.&lt;/p&gt;

&lt;p&gt;Graphs can also be used to model game economy. By putting all
monsters, characters, locations and items of an RPG on a Graph, an
analysis can be done showing things like monster that are too easy to
beat or items that are too cheap or too expensive. The talk was a bit
vague though about how to exactly find this things - trade secrets? :).&lt;/p&gt;

&lt;h3&gt;Hacking Health Care with Neo4j, by &lt;a href=&quot;https://twitter.com/fredtrotter&quot;&gt;Fred Trotter&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;docgraph.org&quot;&gt;DocGraph&lt;/a&gt; is a Data Set comprised of fifty million connections that
shows how healthcare providers team to provide care.&lt;/p&gt;

&lt;p&gt;This talk was about were that data came from and what can be done
with it. If working with a big health data set sounds
interesting to you, you should check &lt;a href=&quot;http://docgraph.org/data-and-tools/&quot;&gt;this page&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Designing and Building a Graph Database Application, by &lt;a href=&quot;https://twitter.com/iansrobinson&quot;&gt;Ian Robinson&lt;/a&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;https://www.dropbox.com/s/nqrt3pfln4vhnzm/Designing%20and%20Building%20Graph%20Database%20Application.pdf&quot;&gt;This talk&lt;/a&gt;
was about &lt;a href=&quot;http://stackoverflow.com/questions/4166816/domain-driven-design-vs-model-driven-architecture&quot;&gt;Domain Driven Design&lt;/a&gt;,
how to build an application able to evolve over time, and how to use
Test Driven Development during the process. Not surprisingly, these very
same tools can be used to build any other application!&lt;/p&gt;

&lt;p&gt;The talk showed how to identify the Domain Entities starting from user
Stories to the specification of the Data Model. One big advantage when
using Graph Databases is that the Entities identified during design
phase are often directly translatable to the Nodes and Relationships,
in a lot more straightforward and flexible way than when designing the
schema for a relational database.&lt;/p&gt;

&lt;h3&gt;A Little Graph Theory for the Busy Developer, by &lt;a href=&quot;https://twitter.com/jimwebber&quot;&gt;Jim Webber&lt;/a&gt;&lt;/h3&gt;

&lt;div class=&quot;align_center&quot; style=&quot;padding: 2em;&quot;&gt;
  &lt;img style=&quot;max-width: 85%;&quot; src=&quot;/images/graphs2.jpg&quot; title=&quot;Fancy Graph Theory Explained :)&quot; alt=&quot;Fancy Graph Theory Explained :)&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;The closing talk from Jim Webber was very entertaining and informative!
Some key points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complexity in data management is a function not only of the &lt;strong&gt;size&lt;/strong&gt;, but also of the &lt;strong&gt;connectedness&lt;/strong&gt; and &lt;strong&gt;uniformity&lt;/strong&gt; of the data (people tend to only focus only on size).&lt;/li&gt;
&lt;li&gt;Graph databases leverage the rich theory behind graphs to find the information hidden in the relations of the data.&lt;/li&gt;
&lt;li&gt;Traditional databases, including relational and document oriented databases, &lt;a href=&quot;http://jim.webber.name/2011/04/square-pegs-and-round-holes-in-the-nosql-world/&quot;&gt;imprison&lt;/a&gt; your data.&lt;/li&gt;
&lt;li&gt;In Graph Databases we don&#39;t need to denormalize or lay the data in a special way (e.g. for map-reduce friendliness).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Some algorithms and concepts mentioned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Triadic_closure&quot;&gt;Triadic Closures&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Signed_graph#Social_psychology&quot;&gt;Structural Balance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Weighted_graph#Weighted_graphs_and_networks&quot;&gt;Weighted Graph&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Graph_partitioning&quot;&gt;Graph Partitioning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;A recommended book to dig more into these subjects is
&lt;a href=&quot;http://books.google.com/books?id=atfCl2agdi8C&amp;amp;lpg=PP1&amp;amp;dq=networks%20crowds%20and%20markets&amp;amp;pg=PP1#v=onepage&amp;amp;q=networks%20crowds%20and%20markets&amp;amp;f=false&quot;&gt;Networks, Crowds, and Markets: Reasoning About a Highly Connected
World&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I&#39;m pretty sure this talk also mentioned the
&lt;a href=&quot;http://books.google.com/books?id=AyY1a6-k3PIC&amp;amp;lpg=PA1&amp;amp;dq=NoSQL%20distilled&amp;amp;pg=PT11#v=onepage&amp;amp;q=NoSQL%20distilled&amp;amp;f=false&quot;&gt;NoSQL distilled book&lt;/a&gt;
as a good source of information regarding non relational databases.&lt;/p&gt;

&lt;h4&gt;A Digression on Graphs, Graph Databases and Graph Processing Systems&lt;/h4&gt;

&lt;div class=&quot;align_center&quot; style=&quot;padding: 2em;&quot;&gt;
  &lt;img style=&quot;max-width: 85%;&quot; src=&quot;/images/graphs.jpg&quot; title=&quot;Graphs are everywhere!&quot; alt=&quot;Graphs are Everywhere!&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;There&#39;s a distinction to be made between Graph Compute Engines (which
are generally used for running offline algorithms over massive amounts of
Nodes), and Graph Databases. These concepts are explained well in the
freely available &lt;a href=&quot;http://graphdatabases.com/&quot;&gt;Graph Databases Book&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Arguably every big player in the web nowadays is using Graphs in one way
or another (a point stressed in Emil&#39;s keynote):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Facebook has the &lt;a href=&quot;https://developers.facebook.com/docs/opengraph/&quot;&gt;Open Graph&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Yahoo&#39;s Marissa Mayer talked about the
&lt;a href=&quot;https://www.youtube.com/watch?v=Zlru1trZ6MI&quot;&gt;Interests Graph&lt;/a&gt;,
although I still have to see what Yahoo is exactly doing to build this
Graph and make use of it.&lt;/li&gt;
&lt;li&gt;LinkedIn has the Connections Graph: there is a tool that allows
you to visualize your own personal
&lt;a href=&quot;http://inmaps.linkedinlabs.com/network&quot;&gt;connections&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Google&#39;s &lt;a href=&quot;http://en.wikipedia.org/wiki/Pagerank&quot;&gt;Page Rank&lt;/a&gt;,
the company&#39;s corner stone algorithm which powers Search,
is based on Graph Theory (and so is
&lt;a href=&quot;http://en.wikipedia.org/wiki/Knowledge_Graph&quot;&gt;Knowledge Graph&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Google has also published the
&lt;a href=&quot;http://googleresearch.blogspot.com/2009/06/large-scale-graph-computing-at-google.html&quot;&gt;Pregel&lt;/a&gt;
paper describing a distributed graph processing system.
Some open source Graph Processing systems, like
&lt;a href=&quot;http://giraph.apache.org/&quot;&gt;Apache Giraph&lt;/a&gt;,
have picked Pregel as the basis for their implementations, but Google
itself has not released an Open Source Graph Database or Graph
Processing Software package yet.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Using AngularJS with a Rails backend</title>
   <link href="http://emmanueloga.com/2013/07/23/Using-AngularJS-with-a-Rails-backend.html"/>
   <updated>2013-07-23T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2013/07/23/Using-AngularJS-with-a-Rails-backend</id>
   <content type="html">&lt;p&gt;I created a sample &lt;a href=&quot;http://angularjs.org&quot;&gt;AngularJS&lt;/a&gt;
&lt;a href=&quot;https://github.com/EmmanuelOga/simple-angular-rails-app/&quot;&gt;app&lt;/a&gt;
which uses &lt;a href=&quot;http://rubyonrails.org/&quot;&gt;rails&lt;/a&gt; as a backend.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://morning-chamber-9005.herokuapp.com/#/&quot;&gt;The running app&lt;/a&gt; on all its glory.&lt;/li&gt;
&lt;li&gt;Github &lt;a href=&quot;https://github.com/EmmanuelOga/simple-angular-rails-app/&quot;&gt;repository&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;While it is possible to include AngularJS as part of the rails assets, I
think it is better to setup the angular code base &lt;strong&gt;on a
standalone folder&lt;/strong&gt;, leaving the rails app as a (more or less)
isolated backend.&lt;/p&gt;

&lt;p&gt;There are several advantages to this setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ability to manage the frontend app using
&lt;a href=&quot;http://yeoman.io/&quot;&gt;Yeoman&lt;/a&gt;
(including &lt;a href=&quot;https://github.com/yeoman/generator-angular#readme&quot;&gt;generators&lt;/a&gt;!).&lt;/li&gt;
&lt;li&gt;No more questions about file layout: use rails layout for rails stuff,
angular-generator layout for angular stuff.&lt;/li&gt;
&lt;li&gt;Easily install external assets via &lt;a href=&quot;http://bower.io/&quot;&gt;bower&lt;/a&gt; (e.g.
angularjs, jquery, twitter bootstrap, underscore, etc.).&lt;/li&gt;
&lt;li&gt;Write client side unit tests and run them with
&lt;a href=&quot;http://karma-runner.github.com&quot;&gt;karma&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Promotes unit-testing the js codebase and removes the temptation of
integration-testing everything: testing with karma is a lot faster
than using capybara or a similar solution.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://livereload.com/&quot;&gt;LiveReload&lt;/a&gt; support for free with yeoman&#39;s
angular generator! (uses websockets, no need to install a browser plugin).&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Yeoman, Bower, Livereload and Karma Runner.&lt;/h2&gt;

&lt;p&gt;I want to stress out the convinience of working on your frontend using
the stack yeoman sets up for you. By keeping the frontend isolated from
the backend you get an amazingly fast development environment and draw a
clear line between backend and frontend (great for making sure you are
writing the right unit/integration tests).
Yeoman sets up the test environment for you using jasmine as the testing
library and karma as the runner. karma is possibly the &lt;a href=&quot;http://www.youtube.com/watch?feature=player_detailpage&amp;amp;v=Mb3_oT8ZreI&amp;amp;t=11&quot;&gt;fastest and most
complete js test runner&lt;/a&gt; out
there. And it is very well integrated with angular.&lt;/p&gt;

&lt;div class=&quot;text-center&quot; &gt;
  &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;//www.youtube.com/embed/Mb3_oT8ZreI&quot; frameborder=&quot;0&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;The experience of coding with Livereload is simply amazing. Immediate
feedback for every little addition you save in your code editor while
you are working, without having to reload the page in the browser!&lt;/p&gt;

&lt;p&gt;True: you can &lt;a href=&quot;https://github.com/guard/guard-livereload&quot;&gt;use livereload with rails&lt;/a&gt; alone, and you
can &lt;a href=&quot;http://dev.af83.com/2013/01/02/managing-rails-assets-with-bower.html&quot;&gt;use bower with rails too&lt;/a&gt;.
But Yeoman&#39;s angular generator sets everything right for you with a
single command.&lt;/p&gt;

&lt;p&gt;Rails was born in the request-response era of the web, and it shows.
Yeoman sets up an environment with defaults that are better suited for
developing web applications.&lt;/p&gt;

&lt;h2&gt;Setting the environment up&lt;/h2&gt;

&lt;p&gt;You&#39;ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ruby 1.9.3 (&lt;a href=&quot;https://rvm.io/&quot;&gt;rvm&lt;/a&gt; recommended for installation)&lt;/li&gt;
&lt;li&gt;node 0.10.13 (&lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt; recommended for installation)&lt;/li&gt;
&lt;li&gt;Two shell sessions!&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Shell session one: the rails backend:&lt;/h3&gt;

&lt;pre&gt;
rvm use 1.9.3
git clone https://github.com/EmmanuelOga/simple-angular-rails-app.git
cd simple-angular-rails-app
bundle install
bundle exec rake db:migrate
bundle exec rails s -p 3000
&lt;/pre&gt;


&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;:  the angular application was generated using these commands.&lt;/p&gt;

&lt;pre&gt;
npm install -g yo generator-angular
mkdir ngapp; cd ngapp
yo angular notes
&lt;/pre&gt;


&lt;h3&gt;Shell session two: a grunt server&lt;/h3&gt;

&lt;pre&gt;
nvm use 0.10.13
cd simple-angular-rails-app/ngapp
npm install -g grunt-cli
npm install
bower install
grunt server # opens a browser window... you are done!
&lt;/pre&gt;


&lt;h2&gt;What&#39;s going on?&lt;/h2&gt;

&lt;p&gt;During development, you need to run both rails and the grunt server. The
grunt server takes care of serving the assets (yes, it can serve
coffeescript if you like that) and doing the live reloads.&lt;/p&gt;

&lt;p&gt;We &lt;strong&gt;simulate&lt;/strong&gt; that the whole environment is a single web application
by running a proxy inside the grunt server. At some point during the
production deploy process we&#39;ll be consolidating the whole angular app
as a set of static assets in rails&#39; public/ folder.&lt;/p&gt;

&lt;p&gt;Here&#39;s a diagram of the stack during development:&lt;/p&gt;

&lt;div class=&quot;text-center&quot; &gt;
  &lt;img src=&quot;https://raw.github.com/EmmanuelOga/simple-angular-rails-app/master/doc/layout.jpg&quot; title=&quot;Application Layout&quot;&gt;
&lt;/div&gt;


&lt;p&gt;Would it make sense to go the extra mile and just host the angular app
and the rails backend as separated processes? It would. But this setup
allows you deploy the whole thing as a single app in the end, and have
everything in a single domain easily.&lt;/p&gt;

&lt;p&gt;The grunt server task
&lt;a href=&quot;http://github.com/EmmanuelOga/simple-angular-rails-app/blob/master/ngapp/Gruntfile.js#L65-L71&quot;&gt;proxies&lt;/a&gt;
any url with path /api to the rails backend on localhost:3000.&lt;/p&gt;

&lt;p&gt;Would &lt;a href=&quot;http://www.sinatrarb.com/&quot;&gt;sinatra&lt;/a&gt; be a better choice for such a
small app? It would... but the whole point of this blog post is to show
a possible way of using angular and rails together. This setup should be
usable if you already have a running rails app and you want to add some
additional single-pagy parts to it.&lt;/p&gt;

&lt;h2&gt;TESTING&lt;/h2&gt;

&lt;p&gt;To run both the backend tests and front end tests, you can run:&lt;/p&gt;

&lt;pre&gt;
rake test PHANTOMJS_BIN=`which phantomjs`
&lt;/pre&gt;


&lt;p&gt;This is done by &lt;a href=&quot;https://github.com/EmmanuelOga/simple-angular-rails-app/blob/master/Rakefile#L8-L10&quot;&gt;reopening rails&#39;s test
task&lt;/a&gt;
and adding a step to run the karma runner. This design is a bit
simplistic but it works. You may want to have something a bit more
elaborate to make it so angular&#39;s tests are run even if rails tests fail
to complete.&lt;/p&gt;

&lt;p&gt;The PHANTOMJS_BIN env var is needed because the project configures karma
to use &lt;a href=&quot;http://www.phantomjs.org&quot;&gt;phantom js&lt;/a&gt;, but it could be changed
to run any other browser.&lt;/p&gt;

&lt;p&gt;karma can be
&lt;a href=&quot;https://github.com/EmmanuelOga/simple-angular-rails-app/blob/master/ngapp/karma.conf.js#L40&quot;&gt;configured&lt;/a&gt;
to watch the tests as opposed to do a single run. You should
deffinitively look into that during development.&lt;/p&gt;

&lt;h2&gt;Deploying&lt;/h2&gt;

&lt;p&gt;If you run &lt;code&gt;grunt build&lt;/code&gt;, grunt will package the whole angular app in a
tidy package on the rails public/ folder. This packaging step could
happen in the server to avoid having to commit the generated assets in
your repository, analogous to how it is done for generating assets with
rails&#39; assets pipeline.&lt;/p&gt;

&lt;h2&gt;XSRF support&lt;/h2&gt;

&lt;p&gt;The rails app sets the XSRF token in the cookies. The cookies are
accessible even when using the proxy because the port is &lt;a href=&quot;http://stackoverflow.com/questions/1612177/are-http-cookies-port-specific&quot;&gt;not taken into
account&lt;/a&gt;
when restricting access to the cookies.&lt;/p&gt;

&lt;p&gt;Check
&lt;a href=&quot;http://github.com/EmmanuelOga/simple-angular-rails-app/blob/master/app/controllers/application_controller.rb&quot;&gt;ApplicationController&lt;/a&gt;
for some notes on the XSRF protection.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Tidying up an rspec suite with helpers</title>
   <link href="http://emmanueloga.com/2012/04/21/Tidying-up-an-rspec-suite-with-some-helpers.html"/>
   <updated>2012-04-21T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2012/04/21/Tidying-up-an-rspec-suite-with-some-helpers</id>
   <content type="html">&lt;h3&gt;Conditionally include Rspec Helpers depending on the kind of described thing.&lt;/h3&gt;

&lt;p&gt;With rpsec you can define helper methods in modules and include them
only in places where it make sense. As an example I use this for specs
related to ActionMailer functionality in rails:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MailSpecHelpers&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MailDeliveries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&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;:subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;deliveries&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=~&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;count&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;deliveries&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;count&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Returns action mailer deliveries filtered by subject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mail_deliveries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;MailDeliveries&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;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MailerSpecHelpers&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# returns an email from the currently described mailer class.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;email_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;described&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;describes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;description&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;described&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# checks that the body of an emails is not blank&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;can_send_an_email_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;email_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tap&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be_blank&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Rspec Config File.&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MailSpecHelpers&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MailerSpecHelpers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:example_group&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:describes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;described&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;described&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionMailer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&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;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;With these helpers in place I can do things like:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;UserMailer&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&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;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;can_send_an_email_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user_greeting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&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;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&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;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:greetings&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;n&quot;&gt;mail_deliveries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Welcome &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first_name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;!&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;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;sends a greeting to the user after activation&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;activate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;greetings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&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;Notice MailerSpecHelpers only gets included in specs that describe
ActionMailer::Base derived classes, but MailSpecHelpers is included
everywhere,  because I only want to check if a mailer works in its own
describe block, but I may check for mail deliveries anywhere in the spec
suite.&lt;/p&gt;

&lt;h3&gt;Formatting expectations to make it easy to read on the spec&lt;/h3&gt;

&lt;p&gt;I have an xml generator class that outputs xml without pretty printing
it. Making the code generate pretty output would be too expensive for my
purposes, but I still would like to present the expected output in a
nicely formatted way on the specs. Here&#39;s what I did:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Rspec&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;CustomStringHelpers&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;LooksLike&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;failure_message&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@me&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;is different than:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@another&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;matches?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;another&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@me&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@another&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;normalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;normalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;another&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@me&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@another&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;normalize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;split&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:strip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;look_like&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;LooksLike&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;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Rspec config file.&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rspec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;CustomStringHelpers&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Specs&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;XMLGeneratorThingie&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:schemer&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;no&quot;&gt;XMLGeneratorThingie&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;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;can add tag attributes to elements&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;schemer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:thing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;mb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tag&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:h1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;perico&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;look_like&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MARKUP&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;      &amp;lt;div itemscope itemtype=&amp;quot;http://schema.org/Thing&amp;quot;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;        &amp;lt;h1 itemprop=&amp;quot;name&amp;quot; class=&amp;quot;perico&amp;quot;&amp;gt;Spatula&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class=&quot;sh&quot;&gt;      &amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;    MARKUP&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&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;Blank space and new lines does not matter on xml and I can strip them from
both strings I&#39;m comparing using the look_like helper. Because I control
the generation of the xml, I know that it will work for all different
outputs my code can generate.&lt;/p&gt;

&lt;h3&gt;Redefining constants quietly to improve speed of the suite&lt;/h3&gt;

&lt;p&gt;I use machinist to instantiate actual db records in numerous
places, which can be expensive. This small method allows me to reduce
the number of record instantiations:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Allows redefinition of constants without warnings.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;redefine_const&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;const_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;remove_const&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;const_name&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;const_set&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;const_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_value&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&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;Usually redefining a constant produces a noisy warning, but with the
redefine_const method I can do that like a ninja:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UserSearch&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;LIMIT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# max users to return per search&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# implementation...&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Specs&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;UserSearch&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Reopening the class and overwriting this would normally be noisy.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Here we are being explicit and no noise is produced.&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;UserSearch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;redefine_const&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:LIMIT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user1&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;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user2&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;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make!&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;UserSearch&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;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;query-less search&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;returns all users with a limit&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;search&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;UserSearch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LIMIT&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&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;Instead of using redefine_const, I could replace the &lt;strong&gt;LIMIT&lt;/strong&gt; constant
with a class-attribute-accessor. But in the example code, LIMIT &lt;em&gt;should&lt;/em&gt;
be &lt;strong&gt;constant&lt;/strong&gt;, something that should not ever change unless I rewrite its
value and redeploy my code. I think is just natural to use a ruby
constant when something is going to be, well..., constant.&lt;/p&gt;

&lt;h2&gt;Logging in users automagically&lt;/h2&gt;

&lt;p&gt;Before putting these helpers in place I had to define the current_user or
admin in each controller spec, and sign in in a before-filter as needed.
Now, all I have to do is include a parameter in the describe block to
acknowledge whether there should be an admin or a user logged in that
context.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ControllerMacros&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sign_in!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;kind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;kind&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:admin&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:admin&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;no&quot;&gt;Admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&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;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sign_in&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:admin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;admin&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:current_user&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;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;make!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sign_in&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# RSpec configuration file&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# So useful: if something goes wrong on the view, the spec run will blow up.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;render_views&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Extend only controller specs&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;extend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ControllerMacros&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:example_group&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;:describes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;described&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;described&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&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;c1&quot;&gt;# Funny flag... but allows me to write symbols instead of hashes.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;treat_symbols_as_metadata_keys_with_true_values&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# enables: describe(SomeController, :logged_in) { ... }&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:logged_in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&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;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sign_in!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&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;c1&quot;&gt;# enables: describe(SomeController, :logged_as =&amp;gt; :admin / :user / etc..) { ... }&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:all&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:logged_as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&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;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sign_in!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&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;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Controller specs&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Admin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Users&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;authorized&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:logged_as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:admin&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;shows a list of users&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;index&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;not authorized&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:logged_as&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;redirects the user to the front page&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Filtering out specs&lt;/h3&gt;

&lt;p&gt;If you run a spec manually, you can use &lt;strong&gt;rspec spec/name_spec.rb:25&lt;/strong&gt; to
only run the spec defined on the line 25. But if you are using a spec
runner like autotest, or your line numbers change all the time because
you keep adding or removing stuff, that can be annoying. Here is how you
define spec filters:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# RSpec configuration file&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;ec2_instance?&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# if you retrieve this url from an EC2 instance (and only then) it&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# returns an instance id, so if this does not fail we know we are&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# running inside EC2&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://169.254.169.254/latest/meta-data/instance-id&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Only run focused specs:&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter_run&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:focus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Yep, if there is nothing filtered, run the whole thing.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;run_all_when_everything_filtered&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Do not run these specs on ec2&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;filter_run_excluding&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:bypass_on_ec2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ec2_instance?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Specs&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;describe&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;does something I&amp;#39;m checking RIGHT NOW.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:focus&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Stuff I&amp;#39;m working on.&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;context&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;when the external user profile is accessible&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:bypass_on_ec2&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;retrieves the file from the server and process it&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;subject&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update_from_server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raise_error&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&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;There are two examples on how to use filtering. First one is simple: I
just add the :focus simple to the block of code I&#39;m currently working
for.&lt;/p&gt;

&lt;p&gt;The second one is a little different. Providing you have a good reason
&lt;em&gt;not&lt;/em&gt; to run some code when you are on an ec2 instance, then you can set
up a block to skip the examples there.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Rails CMS landscape from 10,000ft high</title>
   <link href="http://emmanueloga.com/2012/03/23/Rails-CMS-landscape-from-10-000ft-high.html"/>
   <updated>2012-03-23T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2012/03/23/Rails-CMS-landscape-from-10-000ft-high</id>
   <content type="html">&lt;p&gt;I&#39;m needing a CMS to setup a semi dynamic web site. The features I&#39;m looking for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby 1.9.2 compatible (for use with &lt;a href=&quot;http://devcenter.heroku.com/articles/cedar&quot;&gt;heroku&#39;s cedar stack&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;If it uses Rails, it should be ~&gt; 3.x.&lt;/li&gt;
&lt;li&gt;Backed by a SQL database.&lt;/li&gt;
&lt;li&gt;Easy to use by non developers.&lt;/li&gt;
&lt;li&gt;Easily extensible with custom sections (e.g. adding a product catalogue).&lt;/li&gt;
&lt;li&gt;I should  be able to install, style it (&lt;a href=&quot;http://twitter.github.com/bootstrap/&quot;&gt;bootstrap&lt;/a&gt;) and test it locally in &lt;em&gt;less than 5 minutes&lt;/em&gt; (pretentious, I know).&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I went through each of the options I found really quick, just to have a
feel of each one from 10,000 ft high, so I&#39;m sure I might have judged
some of them unfairly.&lt;/p&gt;

&lt;h2&gt;Radiant&lt;/h2&gt;

&lt;p&gt;According to the Wikipedia article, the first release of
&lt;a href=&quot;Radiant&quot;&gt;http://radiantcms.org/&lt;/a&gt; was 5 years ago, and it is still today
alive and kicking. Unfortunately, it runs on Rails 2.x. I rather not
have to deal with Rails 2.x for a new project if I can avoid it.&lt;/p&gt;

&lt;h2&gt;Refinery&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;http://refinerycms.com/&quot;&gt;Refinery&lt;/a&gt; installation went on pretty
well, but I couldn&#39;t find any sample themes for it.&lt;/p&gt;

&lt;p&gt;Even though Ryan Bates in
&lt;a href=&quot;http://railscasts.com/episodes/332-refinery-cms-basics&quot;&gt;his screencast&lt;/a&gt;
makes styling Refinery look easy as he just pastes some magic CSS code
on application.css.scss, trying to adapt Refinery to use &lt;a href=&quot;http://twitter.github.com/bootstrap/&quot;&gt;bootstrap&lt;/a&gt; is
definitely a lot more involved.&lt;/p&gt;

&lt;p&gt;To be clear, I think if I was creating the styles from scratch then
Refinery would be great for me. The generated html looks pretty sane.
But since I&#39;m constrained to make it work with existing markup (the way
bootstrap wants me to work), I find it a bit difficult to customize.&lt;/p&gt;

&lt;h2&gt;BrowserCMS&lt;/h2&gt;

&lt;p&gt;After installing the &lt;a href=&quot;http://www.browsercms.org/&quot;&gt;browsercms&lt;/a&gt; gem, the
first thing I got with the very first command I run is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;undefined method `load_missing_constant&#39; for module `ActiveSupport::Dependencies&#39; (NameError)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An error so early in the process of installing the app lowered my
confidence on the project... I wasn&#39;t sure I was going to succeed
debugging the problem in just 5 minutes. I may inspect this option
further in the future.&lt;/p&gt;

&lt;h2&gt;Locomotive&lt;/h2&gt;

&lt;p&gt;Since &lt;a href=&quot;http://locomotivecms.com/&quot;&gt;Locomotive&lt;/a&gt; looks pretty cool, I
decided to obviate my decision of using a good&#39;ol SQL database as the
storage and created a free account on mongohq.com.&lt;/p&gt;

&lt;p&gt;I spent a couple of minutes setting up the whole thing just to be confronted
with this after following the site&#39;s instructions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;uninitialized constant CASClient::Tickets::Storage::ActiveRecord (NameError)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The one requirement I did not want to obviate was, again, my 5 minutes
deadline. So I skipped to the next option.&lt;/p&gt;

&lt;h2&gt;Nesta&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://nestacms.com/&quot;&gt;Nesta&lt;/a&gt; just worked. This is a good thing on my
book. Also, it installed only a few gems.&lt;/p&gt;

&lt;p&gt;There are a couple of
&lt;a href=&quot;https://github.com/search?q=nesta-theme&amp;amp;type=Everything&amp;amp;repo=&amp;amp;langOverride=&amp;amp;start_value=1&quot;&gt;ready made themes&lt;/a&gt;. Even a bootstrap one (which did not work too well out of the box, at least with
the demo content... oh well).&lt;/p&gt;

&lt;p&gt;Anyway, this is a very nice CMS for hackers, I can see myself using it on the
future. It is too hardcore to casual users though: you need to create markdown
files manually into the project directory to edit the site.&lt;/p&gt;

&lt;h2&gt;Zena&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://zenadmin.org/&quot;&gt;Zena&lt;/a&gt; looked promising but again it is based on
Rails 2.x and I don&#39;t feel like using Rails 2.x for a new project.&lt;/p&gt;

&lt;h2&gt;adva2&lt;/h2&gt;

&lt;p&gt;I quote the &lt;a href=&quot;https://github.com/svenfuchs/adva-cms2&quot;&gt;adva-cms2&lt;/a&gt; README:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&quot;adva-cms2 is currently in an early developer sneak-peak preview stage.&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Despite the warning I tried it and... I could not make it work. Some
problem with gem dependencies I think.&lt;/p&gt;

&lt;h2&gt;Alchemy&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://alchemy-cms.com/&quot;&gt;Alchemy&lt;/a&gt; installation was &lt;em&gt;almost&lt;/em&gt;
straightforward. I got a couple of errors but I could correct manually
without a lot of hoop-jumping, but once I ran the dashboard I was
overwhelmed by the interface.&lt;/p&gt;

&lt;p&gt;I just wanted to create a single page and test the result. I have the
&lt;em&gt;feeling&lt;/em&gt; this must be a pretty powerful CMS, but since it is difficult
to use even for a seasoned web applications developer -as I am ;)- I&#39;m
guessing not so experienced users will have a hard time with it too.&lt;/p&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;From the whole list of CMS available the most promising ones for my
purposes where Nesta and Refinery. Nesta is a bare-bones, good for
static content, made for hackers CMS. I can see myself using it if I
ever need something slightly more flexible than jekyll for my blog.&lt;/p&gt;

&lt;p&gt;Refinery CMS looks pretty good, works out of the box and is easy to
manage, but a little hard to style. Right now I&#39;m not sure if it will
work for me, but spending something more than 5 minutes trying to
customize it seems worth the effort in order to avoid creating my
website form scratch.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Net::HTTP not setting cookies... or so it looked like</title>
   <link href="http://emmanueloga.com/2012/02/29/Net-HTTP-not-setting-cookies-or-so-it-looked-like.html"/>
   <updated>2012-02-29T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2012/02/29/Net-HTTP-not-setting-cookies-or-so-it-looked-like</id>
   <content type="html">&lt;p&gt;I was retrieving a web page from a site, but I found out it needed a cookie to
be set in order to work. Otherwise, it was redirecting me to set up my language
of preference. I thought no problem... let&#39;s set up that cookie.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;net/http&amp;#39;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://www.realtor.com/realestateandhomes-detail/3429-W-Lone-Mountain-Rd_North-Las-Vegas_NV_89031_M12163-28068&amp;quot;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;uri&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;URI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTTP&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;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Get&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;n&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request_uri&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;Cookie&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;preference=USA&amp;quot;&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;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&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;Awesome! it worked! Sometimes...&lt;/p&gt;

&lt;p&gt;After a bit of banging my head against the wall I decided to try with a
different version of ruby, 1.9.3.&lt;/p&gt;

&lt;p&gt;Locally I was using ree-1.8.7-2011.12, and on the c.i. server ruby-1.8.7-p352.&lt;/p&gt;

&lt;p&gt;So what was the difference? &lt;a href=&quot;https://github.com/ruby/ruby/blob/v1_9_3_rc1/lib/net/http.rb#L1864&quot;&gt;Check it out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Turns out 1.9.3 sets a default user agent. Even though it should be optional,
looks like some servers do not look at the cookies header if the user
agent is not set.&lt;/p&gt;

&lt;p&gt;The takeaway: if you are setting cookies on your request, make sure the
user agent is being set too:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;User-Agent&amp;#39;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;MyCoolUserAgentString&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>VIM config snippets</title>
   <link href="http://emmanueloga.com/2011/11/28/a-small-vim-config-tip.html"/>
   <updated>2011-11-28T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2011/11/28/a-small-vim-config-tip</id>
   <content type="html">&lt;p&gt;There are lots of things you can do to better organize your vim
configuration, starting with using
&lt;a href=&quot;http://www.vim.org/scripts/script.php?script_id=2332&quot;&gt;pathogen&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Apart from using pathogen, what I like to do is &lt;em&gt;having small snippets
of configuration on separate files&lt;/em&gt; to tweak specific things. Here&#39;s &lt;a href=&quot;https://github.com/EmmanuelOga/vimrc/blob/master/vimrc&quot;&gt;my
.vimrc&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;&lt;span class=&quot;c&quot;&gt;&amp;quot; Setup for pathogen.&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; pathogen#runtime_append_all_bundles&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;call&lt;/span&gt; pathogen#&lt;span class=&quot;k&quot;&gt;helptags&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;&amp;quot; Load additional plugin configurations and stuff&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; rc &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; split&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;globpath&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&amp;amp;&lt;span class=&quot;nb&quot;&gt;rtp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;rc/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  execute &lt;span class=&quot;s2&quot;&gt;&amp;quot;source&amp;quot;&lt;/span&gt; rc
&lt;span class=&quot;k&quot;&gt;endfor&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;First part is the setup for pathogen. The second part is what I&#39;m
talking about, I go through every file in my
&lt;a href=&quot;https://github.com/EmmanuelOga/vimrc/tree/master/rc&quot;&gt;.vim/rc&lt;/a&gt; directory
and load every snippet of that folder.&lt;/p&gt;

&lt;p&gt;A fun thing to try is to &lt;em&gt;make every snippet &quot;self contained&quot;&lt;/em&gt;. That
way, if someone browsing your config thinks the thing you are setting up
there is cool, all he has to do is copy that single file to get
the specific piece of functionality.&lt;/p&gt;

&lt;p&gt;BTW, since I use gvim most of the time, on the
&lt;a href=&quot;https://github.com/EmmanuelOga/vimrc/blob/master/gvimrc&quot;&gt;.gvimrc&lt;/a&gt; I
just source the .vimrc, plus a few GUI tweaks (removing toolbars, menus,
etc).&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-vim&quot; data-lang=&quot;vim&quot;&gt;source &lt;span class=&quot;p&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/.vim/&lt;/span&gt;vimrc
&lt;span class=&quot;c&quot;&gt;&amp;quot; ... some gui settings.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>Beer Drinking Contest: Ruby versus Lua. Fight!</title>
   <link href="http://emmanueloga.com/2011/07/29/drinking-contest.html"/>
   <updated>2011-07-29T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2011/07/29/drinking-contest</id>
   <content type="html">&lt;p&gt;Grab a &lt;a href=&quot;https://gist.github.com/1113413&quot;&gt;gist&lt;/a&gt;. You probably already
know what&#39;s the &lt;a href=&quot;http://www.99-bottles-of-beer.net/lyrics.html&quot;&gt;output&lt;/a&gt; of these programs.&lt;/p&gt;

&lt;h3&gt;Ruby&lt;/h3&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Crowd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&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;:bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;drink&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Take one down and pass it around.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drink&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy_more&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;Go to the store and buy some more.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;sing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;     &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; on the wall, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Bottles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Struct&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;:qty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;drink&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;buy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;No more bottles of beer&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; bottle&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;s&amp;#39;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; of beer&amp;quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Crowd&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;no&quot;&gt;Bottles&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;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tap&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;crowd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;times&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crowd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drink&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crowd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;crowd&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buy_more&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sing&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Lua&lt;/h3&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Crowd&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;n&quot;&gt;Crowd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drink&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Take one down and pass it around.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drink&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Crowd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buymore&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Go to the store and buy some more.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Crowd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sing&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;tostring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; on the wall, &amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;tostring&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;.&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bottles&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;n&quot;&gt;Bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__index&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bottles&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drink&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buy&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;amount&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Bottles&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__tostring&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;No more bottles of beer&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; bottle&amp;quot;&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;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;#39;&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;s&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; of beer&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crowd&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;setmetatable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bottles&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;setmetatable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;qty&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Bottles&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;n&quot;&gt;__index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Crowd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;crowd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crowd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;drink&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;crowd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buymore&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;():&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Let the games begin!&lt;/h3&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#/usr/bin/env sh&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Baseline echo&amp;#39;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; i in &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..20..1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;A long line with a number: $i&amp;quot;&lt;/span&gt; &amp;gt; /dev/null &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# real  0m0.001s user   0m0.000s sys    0m0.000s&lt;/span&gt;

lua -v
&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; i in &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..20..1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; lua beer.lua &amp;gt; /dev/null &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# real  0m0.054s user   0m0.000s sys    0m0.007s&lt;/span&gt;

luajit-2.0.0-beta6 -v
&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; i in &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..20..1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; luajit-2.0.0-beta6 beer.lua &amp;gt; /dev/null &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# LuaJIT 2.0.0-beta6 -- Copyright (C) 2005-2011 Mike Pall. http://luajit.org/&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# real  0m0.041s user   0m0.000s sys    0m0.007s&lt;/span&gt;

rvm 1.9.2 &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;ruby -v
&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; i in &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..20..1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; rvm 1.9.2 &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;ruby beer.rb &amp;gt; /dev/null &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-linux]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# real  0m17.076s user  0m12.116s sys   0m3.323s&lt;/span&gt;

rvm jruby &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;jruby -v
&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; i in &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..20..1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; rvm jruby &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;jruby beer.rb &amp;gt; /dev/null &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# jruby 1.6.2 (ruby-1.8.7-p330) (2011-05-23 e2ea975) (OpenJDK 64-Bit Server VM 1.6.0_22) [linux-amd64-java]&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# real  1m35.087s user  2m21.537s sys   0m7.226s&lt;/span&gt;

rvm ree ruby -v
&lt;span class=&quot;nb&quot;&gt;time &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; i in &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0..20..1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; rvm ree &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;ruby beer.rb &amp;gt; /dev/null &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# ruby 1.8.7 (2011-02-18 patchlevel 334) [x86_64-linux], MBARI 0x6770, Ruby Enterprise Edition 2011.03&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# real  0m18.075s user  0m12.619s sys   0m3.526s&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Conclusions&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;I don&#39;t give any chance to the jit capable interpreters to work their magic.&lt;/li&gt;
&lt;li&gt;I&#39;m &quot;measuring&quot; the system&#39;s I/O too even when I&#39;m directing the output to /dev/null, get over it.&lt;/li&gt;
&lt;li&gt;Lua, including its start-up time, is FAST!. Also, object oriented programming
in lua is flexible, simple and nice.&lt;/li&gt;
&lt;li&gt;Rails does not scale.&lt;/li&gt;
&lt;li&gt;I want a beer.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Taming a Capybara</title>
   <link href="http://emmanueloga.com/2011/07/26/taming-a-capybara.html"/>
   <updated>2011-07-26T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2011/07/26/taming-a-capybara</id>
   <content type="html">&lt;div class=&quot;align_center&quot;&gt;
  &lt;img src=&quot;/images/capybara.jpg&quot; title=&quot;Rude Capybara&quot; alt=&quot;Rude Capybara&quot;/&gt;
  &lt;br/&gt;
  &lt;a href=&quot;http://raxdakkar.com/2009/06/28/capybara-as-a-pet-i-want-one/&quot;&gt;
    &lt;small&gt;photo from raxdakkar.com&lt;/small&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;&lt;br/&gt;&lt;/p&gt;

&lt;p&gt;Running acceptance tests in our rails 3 application turned out to be non
trivial, even though there are excellent tools out there, and they keep
getting better.&lt;/p&gt;

&lt;p&gt;We are currently using &lt;a href=&quot;https://github.com/jnicklas/capybara&quot;&gt;capybara&lt;/a&gt;
with the &lt;a href=&quot;https://github.com/thoughtbot/capybara-webkit&quot;&gt;capybara-webkit driver&lt;/a&gt;,
which is great because it runs in headless mode, without annoying
browser windows popping up. I heard the QT download can be pretty big
for mac users though, so have some spare bandwidth around if you have a
mac and are planning to give it a try.&lt;/p&gt;

&lt;p&gt;As we kept adding tests, the size of our &lt;strong&gt;spec/support/capybara.rb&lt;/strong&gt;
file grew with a lot of hacks. Here is an anotated version of that file
and some others related, should it be helpful to anybody out there.
Perhaps somebody will want to comment on better solutions for some of
the nasty hacks.&lt;/p&gt;

&lt;h3&gt;Gemfile&lt;/h3&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:test&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;capybara&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;~&amp;gt; 1.0.0&amp;#39;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# The git version worked better for us at the time we installed it.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;capybara-webkit&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:git&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;git://github.com/thoughtbot/capybara-webkit&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# This is needed by capybara&amp;#39;s save_and_open_page method.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;launchy&amp;#39;&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# This *might* be needed in some setups&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;database_cleaner&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;h3&gt;config/initializers/session_store.rb&lt;/h3&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# We deploy our application to several different subdomains, and we need&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# to configure the domain for cookies in order to avoid the sessions&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# getting mixed.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# But the domain option was messing with capybara browsers&amp;#39; ability to&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# remember cookies, so we just exclude the domain config on the test environment.&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;options&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;ss&quot;&gt;:key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;_our_app_session_&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:domain&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cookies_host&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test?&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;session_store&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:cookie_store&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;spec/spec_helper.rb&lt;/h3&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# .. rspec stuff&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# This is how we load our support files for rspec, this keeps the size of&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# the spec_helper.rb file manageable.&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;__FILE__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;/support/**/*.rb&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;spec/support/capybara.rb&lt;/h3&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;capybara/rails&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;capybara/rspec&amp;#39;&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Setup capybara webkit as the driver for javascript-enabled tests.&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;javascript_driver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:webkit&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# In our setup, for some reason the browsers capybara was driving were&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# not openning the right host:port. Below, we force the correct&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# host:port.&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server_port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7787&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# We have more than one controller inheriting from&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# ActionController::Base, and, in our app, ApplicationController redefines&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# the default_url_options method, so we need to redefine the method for&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# the two classes.&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Listing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;klass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;klass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;class_eval&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;default_url_options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&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;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;127.0.0.1&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;server_port&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Here we do some selective configuration for tests which run with the&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# rack backend and tests which run with the webkit backend.&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;configure&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# In order for the database to have the same data both for the&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# capybara process and the web application process, we need either to&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# disable transactional fixtures (which produces very slow runs),&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# or use the hack you can find below in this file.&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;use_transactional_fixtures&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;

  &lt;span class=&quot;c1&quot;&gt;# Uncomment in case your db gets dirty somehow.&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# DatabaseCleaner.clean_with(:truncation)&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_driver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rack_test&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# With selenium/webkit the host is set automatically if it was nil.&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# config.use_transactional_fixtures = false&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# $use_truncation = true&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# We found Capybara.app_host needs to be nil when using rack backend,&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# but point to 127.0.0.1 when using selenium or webkit.&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;app_host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://127.0.0.1&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# config.use_transactional_fixtures = true&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# config.after :each do&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;#   DatabaseCleaner.clean_with(:truncation) if $use_truncation&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Big Fat Hack (TM) so the ActiveRecord connections are shared across threads.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# This is a variation of a hack you can find all over the web to make&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# capybara usable without having to switch to non transactional&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# fixtures.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# http://groups.google.com/group/ruby-capybara/browse_thread/thread/248e89ae2acbf603/e5da9e9bfac733e0&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:activerecord_connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;retrieve_connection&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;connection&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:activerecord_connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Last but not least, when using capybara-webkit sometimes the response&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# is not available when capybara tries to retrieve the contents of the&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# page. Of all the possible solutions, this was the simplest for us:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# introducing a fixed delay each time something is clicked in the browser.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# https://github.com/thoughtbot/capybara-webkit/issues/111&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Capybara&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Driver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Webkit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Browser&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;alias&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_command&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;command&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;original_command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;click&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Final Thoughts&lt;/h3&gt;

&lt;p&gt;Even though the config above allows our acceptance tests to merrily run,
I&#39;m not completely satisfied with the hoops we needed to jump
in order to get things to work.&lt;/p&gt;

&lt;p&gt;I have the feeling having the acceptance tests completely isolated from
the main application (even in a separate repository) could be a good
thing. In this direction it would be worthy to try and write the
acceptance tests using a tool like &lt;a href=&quot;http://www.phantomjs.org/&quot;&gt;phantomjs&lt;/a&gt;.
I&#39;m not talking about getting a phantomjs driver for capybara, but
directly writing the whole acceptance suite with phantomjs in
javascript.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Downloading and unzipping a file with ruby</title>
   <link href="http://emmanueloga.com/2011/06/21/dowloading-and-unzipping-a-file.html"/>
   <updated>2011-06-21T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2011/06/21/dowloading-and-unzipping-a-file</id>
   <content type="html">&lt;p&gt;Quick! I need to download a zip file from an HTTP server and unzip it!
That&#39;s surely trivial with ruby... is it? &lt;em&gt;Yes, it is&lt;/em&gt;. But! Turns out
there are a bunch of zip handling gems out there, and I had to try a
a couple before arriving to my final solution.&lt;/p&gt;

&lt;p&gt;First, let&#39;s download the file. This particular resource is served via
an HTTP POST method. Yeah, unusual for a zip file.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;net/http&amp;#39;&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;http://someweirdserver.com/a-zip-served-via-POST.zip&amp;quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;data&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;s2&quot;&gt;&amp;quot;some-bizarre-params&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;which-are-needed&amp;quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;zipbytes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Net&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;HTTP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;post_form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;URI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Done. Moving forward, let&#39;s unzip the file. One detail to bear in mind,
I have the zip file as a buffer (a String instance), and I don&#39;t want
to go trough a tempfile to unzip it. The good news is that the
&lt;a href=&quot;http://zipruby.rubyforge.org/&quot;&gt;zipruby&lt;/a&gt; gem can work off buffers.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;zipruby&amp;#39;&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;Zip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Archive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;open_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zipbytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# this is a single file archive, so read the first file&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;zf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;zf&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;unzipped&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# done! do something with the unzipped file.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>Lua's multiple arguments and the "select" function</title>
   <link href="http://emmanueloga.com/2010/12/09/lua-select.html"/>
   <updated>2010-12-09T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2010/12/09/lua-select</id>
   <content type="html">&lt;p&gt;When I first read about lua&#39;s select function I found it a little
confusing.&lt;/p&gt;

&lt;p&gt;According to &lt;a href=&quot;http://www.lua.org/manual/5.1/manual.html#pdf-select&quot;&gt;lua&#39;s manual for version 5.1&lt;/a&gt;,
select behaves as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&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;pre&gt;
If index is a number, returns all arguments after argument number
index.  Otherwise, index must be the string &quot;#&quot;, and select returns
the total number of extra arguments it received.
&lt;/pre&gt;


&lt;p&gt;That wasn&#39;t clear to me at first, but then I remembered lua sports
&lt;em&gt;real&lt;/em&gt; multiple arguments. I remark the word &lt;em&gt;real&lt;/em&gt; because other
languages like ruby don&#39;t really support returning multiple arguments.
In ruby, if a method returns multiple arguments they are automatically
packed into an array. Lua, in the other hand, has built in multiple
arguments, which you can convert into a table if you really need to:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;k&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;multiple_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;kd&quot;&gt;local&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arguments&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;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;-- pack the arguments in a table&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;-- do something --&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;unpack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;-- return multiple arguments from a table (unpack)&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;Remembering the nature of lua&#39;s multiple arguments, and the fact that
multiple arguments are not returned on a lua table dressed as an array,
the description on the manual started to make sense.&lt;/p&gt;

&lt;p&gt;The select function takes as &quot;index&quot; the index of the first argument
that you want to retrieve, and any number of arguments afterward (the
count of arguments starts at 1).&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; 1, 2, 3&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; 2, 3&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; 3&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; NOTHING&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; table&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; nothing&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In the last two examples, the number of variable arguments is just one,
consisting of a single table.&lt;/p&gt;

&lt;p&gt;By the way, note another subtlety of lua: if you select more that the
number of arguments available you get &lt;em&gt;absolutely nothing!&lt;/em&gt;. Not even
nil: nothing. If you try to pack NOTHING into a table, you get an empty
table:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&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;k&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)()})&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; 0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Finally, if you pass &quot;#&quot; as index, the function returns a count of the
multiple arguments provided:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-lua&quot; data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;#&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; 0&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;#&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; 1 (single table as argument)&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;#&amp;quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; 3&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;#&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&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;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;--&amp;gt; 4 (a table, 2 numbers, another table)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>Ruby conferences in Brazil and Uruguay</title>
   <link href="http://emmanueloga.com/2010/10/31/rubyconfs!.html"/>
   <updated>2010-10-31T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2010/10/31/rubyconfs!</id>
   <content type="html">&lt;p&gt;This year I could attend both rubyconf Brazil and Uruguay. Both conferences had
great talks and summarizing everything would be overkill, so I&#39;ll instead post
some brief notes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://rubyconf.com.br/&quot; title=&quot;RubyConf Brazil&quot;&gt;RubyConf Brazil&#39;s Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.rubyconf.com.br/en/schedule&quot; title=&quot;RubyConf Brazil&#39;s Schedule&quot;&gt;RubyConf Brazil&#39;s Schedule&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://rubyconfuruguay.org&quot; title=&quot;RubyConf Uruguay&quot;&gt;RubyConf Uruguay&#39;s Site&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://rubyconfuruguay.org/en/agenda&quot; title=&quot;Uruguay Schedule&quot;&gt;RubyConf Uruguay&#39;s Schedule&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;My Notes&lt;/h2&gt;

&lt;h4&gt;Brazil Opening&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://akitaonrails.com/&quot;&gt;Fabio Akita&lt;/a&gt;&#39;s talk was great in motivating the
audience to be more participative in open source projects as a way of
continuously improving as developers.&lt;/p&gt;

&lt;h4&gt;Client side development&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://yehudakatz.com/&quot;&gt;Yehuda Katz&lt;/a&gt; talked about focusing on the client side
of web applications.  Using Ajax techniques is a start but ajax still generates
a lot of latency waiting for server responses. In order to have
&lt;a href=&quot;http://www.sproutcore.com/&quot;&gt;a better client side experience&lt;/a&gt;
techniques like buffered DOM manipulation, object bindings and
event loops on the client side, can help to do as much work on the client as
possible.&lt;/p&gt;

&lt;h4&gt;Rails 3.1&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/josevalim&quot;&gt;José Valim&lt;/a&gt; talked about some great features
that will be packaged on rails 3.1, as better asset packaging (in line with the
functionality provided by the sprockets gems), making rails serve the
stylesheets and javascript and use sass, and general improvements on a lot of
areas (new ActiveRecord&#39;s identity map, better generators, etc.).&lt;/p&gt;

&lt;h4&gt;Rubinius&lt;/h4&gt;

&lt;p&gt;Both &lt;a href=&quot;http://blog.fallingsnow.net/&quot;&gt;Evan Phoenix&lt;/a&gt; in Brazil and &lt;a href=&quot;http://blog.brightredglow.com/&quot;&gt;Brian
Ford&lt;/a&gt; in Uruguay described great features
packed on of &lt;a href=&quot;http://rubini.us/&quot;&gt;rubinius&lt;/a&gt;. Some of the impressive features are
the integrated console and the profiler (both triggable by command line, no
additional gems required). They also talked about the modularity and
extensibility of the tools bundled in the rubinius environment, made evident by
the possibility to implement 3rd party languages (like the
&lt;a href=&quot;http://www.fancy-lang.org/&quot;&gt;fancy programming language&lt;/a&gt;).&lt;/p&gt;

&lt;h4&gt;JRuby&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://blog.headius.com/&quot;&gt;Charles Nutter&lt;/a&gt;
&lt;a href=&quot;http://www.slideshare.net/CharlesNutter/rubyconf-uruguay-2010-jruby&quot;&gt;showcased&lt;/a&gt;
some cool demos on jruby, including live coding a swt GUI from irb, using the
VisualVM profiler to profile some code, running a multithreaded java
environment from the command line using the &lt;a href=&quot;https://github.com/calavera/trinidad&quot;&gt;trinidad
gem&lt;/a&gt;, and a 3D game. He also showed a
demo of the &lt;a href=&quot;mirah.org&quot;&gt;mirah programming language&lt;/a&gt;, which has a syntax
similar to ruby&#39;s but contains type annotations and can produce either java
code or jvm bytecode.&lt;/p&gt;

&lt;h4&gt;Webfinger&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://romeda.org/&quot;&gt;Blaine Cook&lt;/a&gt; talked about
&lt;a href=&quot;http://webfinger.org/&quot;&gt;webfinger&lt;/a&gt;, a solution to provide users with an
identity on the web in such a way they becomes the owners of it (as opposed as
tying the identity on the web to any given service, like twitter, facebook or
linkedin profile names). Slides &lt;a href=&quot;http://lanyrd.com/2010/rubyconf-uruguay/smzm/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;Ruby 1.9.x fibers&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://tenderlovemaking.com/&quot;&gt;Aaron Patterson&lt;/a&gt; gave a talk about scheduling,
fibers and coroutines.&lt;/p&gt;

&lt;h4&gt;OOP and SOLID&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://onestepback.org/&quot;&gt;Jim Weirich&lt;/a&gt; gave a talk about OOP and the
&lt;a href=&quot;http://en.wikipedia.org/wiki/SOLID&quot;&gt;SOLID&lt;/a&gt; principles.&lt;/p&gt;

&lt;h4&gt;Git&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://jointheconversation.org/&quot;&gt;Scott Chacon&lt;/a&gt; gave a tutorial for git,
starting from the fundamentals and the differences with other VCS like rcs or
svn.&lt;/p&gt;

&lt;h4&gt;Clojure&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/fbru02&quot;&gt;Federico Brubacher&lt;/a&gt; talked about
&lt;a href=&quot;http://clojure.org/&quot;&gt;clojure&lt;/a&gt;, a very nice functional programming language for
the jvm, and a great alternative to scala as it is a much more simple language.&lt;/p&gt;

&lt;h4&gt;ActiveRecord and Identity Maps&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://miloops.com/&quot;&gt;Emilio Tagua&lt;/a&gt; talked the addition of an Identity Map to
ActiveRecord to shield great memory and performance savings.&lt;/p&gt;

&lt;h4&gt;Programming patterns&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://nucleartesuji.com/&quot;&gt;Ignacio Facello&lt;/a&gt; talked about patterns for Ruby.&lt;/p&gt;

&lt;h4&gt;Metaprogramming&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://twitter.com/spastorino&quot;&gt;Santiago Pastorino&lt;/a&gt; talked about
&lt;a href=&quot;http://www.slideshare.net/spastorino/metaprogramming-5634072&quot;&gt;metaprogramming&lt;/a&gt;
ruby techniques.&lt;/p&gt;

&lt;h4&gt;Android&lt;/h4&gt;

&lt;p&gt;&lt;a href=&quot;http://www.tbray.org/ongoing/&quot;&gt;Tim Bray&lt;/a&gt; gave a 30 minutes long advertisement
on &lt;a href=&quot;http://www.android.com/&quot;&gt;android&lt;/a&gt;, quickly dismissing ruby as a viable
development option while it was on it. Despite that, android is a great
platform to develop mobile applications.&lt;/p&gt;

&lt;h4&gt;Uruguay Keynote&lt;/h4&gt;

&lt;p&gt;Evan Henshaw-Plath (&lt;a href=&quot;http://twitter.com/rabble&quot;&gt;@rabble&lt;/a&gt;) closed the Uruguay
conference with a great keynote where he talked about the characteristics of
the ruby community.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>See you at rubyconf.br!</title>
   <link href="http://emmanueloga.com/2010/10/24/rubyconf-br.html"/>
   <updated>2010-10-24T00:00:00+00:00</updated>
   <id>http://emmanueloga.com/2010/10/24/rubyconf-br</id>
   <content type="html">&lt;p&gt;Tomorrow I&#39;m travelling to Sao Pablo, Brazil, to attend my first
&lt;a href=&quot;http://rubyconf.com.br/&quot; title=&quot;RubyConf Brazil&quot;&gt;http://rubyconf.com.br/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Exiting times! See you there?&lt;/p&gt;
</content>
 </entry>
 

</feed>
