<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Runtime Revolution Blog</title>
    <description>Knowledge and news from us to you.</description>
    <link>http://www.runtime-revolution.com/runtime/blog/</link>
    <item>
      <title>PS2Format gem, batch transfers made easy</title>
      <description>&lt;p&gt;Usually whenever in your project you get involved with payments, you want an easy way to make multiple bank related transfers. This was the reason behind the creation of the &lt;strong&gt;PS2Format&lt;/strong&gt; gem.&lt;/p&gt;

&lt;h3&gt;What is a PS2 file?&lt;/h3&gt;

&lt;p&gt;PS2 is a file format used to make batch transfer payments and supported by portuguese banks. It provides you with a wide variety of account transfers, allowing you to send them in a batch style and be executed by your bank.&lt;/p&gt;

&lt;h3&gt;And what&amp;#39;s on it?&lt;/h3&gt;

&lt;p&gt;The file is composed by three section: header, operations and footer. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The header provides the information about who is sending the file and general information about the operations. You need to provide a valid NIB and a valid operation type. Regarding the operation type, there is a &lt;a href='https://github.com/runtimerevolution/ps2_format/blob/master/lib/PS2Format/operation_type.rb' target='_blank'&gt;wide range&lt;/a&gt; of operations that can be performed for both incomes and expenses, ranging from payroll to telecomunication payments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can provide multiple operations to be performed within the same file. Like on the header, you provide a NIB, in this case for the &amp;quot;client&amp;quot; bank account, and an operation type. You also need to provide the operation amount and the company&amp;#39;s reference, if the operation is an income.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The final section of the file is the footer which acts like a summary for the whole file, containing the total number of operations and its total amount.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;So, how can I create an PS2 file?&lt;/h3&gt;

&lt;p&gt;Let&amp;#39;s try to create a file for handling a company&amp;#39;s payroll.&lt;/p&gt;

&lt;p&gt;We first create a new batch transfer object which will implicitly create the file&amp;#39;s header:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;ps2_file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;PS2Format:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;BatchTransfer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;ordering_nib:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;123456789012345678901&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;operation_type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;PS2:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;OperationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;expense&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;payroll&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now we need to add the actual operations, one for each company&amp;#39;s employee:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1
2&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;ps2_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;add_operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;amount:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;nib:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;003503730000539151280&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;operation_type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;PS2:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;OperationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;expense&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;payroll&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;processing_date:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;today&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="vg"&gt;ps2_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;add_operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;amount:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;nib:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;003503730000539151280&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;operation_type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;PS2:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;OperationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;expense&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;payroll&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;processing_date:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Date&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;today&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You can always check if your batch is valid...&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;ps2_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;and check for the errors, if used in a Rails context...&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;ps2_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;errors&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;After all operations are correctly added you can save the batch in the form of a file:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;ps2_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;save&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;payroll.ps2&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;or send it to a stream:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;ps2_file&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;marshall&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;stream&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This simple API gives you the ability to generate files of financial operations for portuguese banks. After this you only need to send it to your bank. Different banks have different ways to do it, so, you must follow their instructions.&lt;/p&gt;

&lt;h3&gt;More Information&lt;/h3&gt;

&lt;p&gt;If you need more information you are welcome to check the &lt;a href='https://github.com/runtimerevolution/ps2_format/blob/master/README.md' target='_blank'&gt;README&lt;/a&gt; file in our &lt;a href='https://github.com/runtimerevolution/ps2_format' target='_blank'&gt;Github Repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;What&amp;#39;s Next&lt;/h3&gt;

&lt;p&gt;Currently, there is a new format for financial transfers, &lt;a href='http://www.bportugal.pt/en-US/pagamentos/SEPA/Pages/inicio.aspx' target='_blank'&gt;SEPA&lt;/a&gt;. With SEPA is now easier to make tranfers to foregner banks within the eurozone. This is the evolution of the PS2 format and can also be a new challenge to the Runtime Revolution team, a SEPA gem. You just have to wait and see.&lt;/p&gt;

&lt;p&gt;PS2Format gem was built by the &lt;a href='http://www.runtime-revolution.com' target='_blank'&gt;Runtime Revolution&lt;/a&gt; team. Find us on &lt;a href='https://twitter.com/RuntimeRev' target='_blank'&gt;Twitter&lt;/a&gt; if you have questions, ideas, grab the source code, fork and contribute on &lt;a href='https://github.com/runtimerevolution/ps2_format' target='_blank'&gt;GitHub&lt;/a&gt; right now! Keep an eye on our page and if you have new ideas let us know.&lt;/p&gt;

&lt;p&gt;If you find this interesting, or at least useful, please &lt;a href='https://github.com/runtimerevolution/' target='_blank'&gt;check out other Runtime Revolution&amp;#39;s Open-Source Projects&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Wed, 15 Jul 2015 16:59:00 +0000</pubDate>
      <link>http://www.runtime-revolution.com/runtime/blog/ps2-gem</link>
      <guid>http://www.runtime-revolution.com/runtime/blog/ps2-gem</guid>
    </item>
    <item>
      <title>Citizenship - simple yet useful validation of Portuguese cards and more</title>
      <description>&lt;p&gt;Citizenship is a simple gem that allows validation of Portuguese documents or common identifiers, such as citizen card numbers, bank account numbers (NIB), fiscal numbers (NIF) and more.&lt;/p&gt;

&lt;p&gt;As most of these IDs have some kind of checksum, Citizenship calculates and verifies them accordingly. We also provide some convenient methods for validating local phone numbers and email addresses.&lt;/p&gt;

&lt;h3&gt;What is this useful for?&lt;/h3&gt;

&lt;p&gt;Many applications, Rails based or not, have user related fields (e.g. portuguese related card ID&amp;#39;s). So you&amp;#39;ll need for sure to validate those before doing real stuff with them.&lt;/p&gt;

&lt;p&gt;Currently, it validates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NIB (i.e. banking account number)&lt;/li&gt;
&lt;li&gt;NIF (i.e. fiscal number)&lt;/li&gt;
&lt;li&gt;local phone numbers&lt;/li&gt;
&lt;li&gt;identification card (&amp;quot;bilhete de identidade&amp;quot;)&lt;/li&gt;
&lt;li&gt;citizen card (&amp;quot;cartão do cidadão&amp;quot;)&lt;/li&gt;
&lt;li&gt;zip code&lt;/li&gt;
&lt;li&gt;e-mail &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;How does validation work?&lt;/h3&gt;

&lt;p&gt;Sometimes, when your application cannot check these identifiers (e.g. ID, phone, ...) against real databases, you have to fallback to other strategies. A very simple validation may be restricted to a &amp;quot;syntax validation&amp;quot;: &amp;quot;if it&amp;#39;s a phone number it is supposed to only have digits, and possibly a leading plus sign&amp;quot;.&lt;/p&gt;

&lt;p&gt;Citizen related ID&amp;#39;s (e.g. fiscal number, citizen/identification card ID) and bank related identifiers implement checksum/control digits in order to reduce the probability of error whenever using them and provide a basic and minimum validation algorithm.&lt;/p&gt;

&lt;p&gt;The checksum/control digits may be part of the ID itself (e.g. NIF, NIB) or may be complementary, as happens with old Portuguese identification cards.&lt;/p&gt;

&lt;h3&gt;How can you use it?&lt;/h3&gt;

&lt;p&gt;It&amp;#39;s dead simple.&lt;/p&gt;

&lt;p&gt;For convenience, we provide bang methods &amp;quot;!&amp;quot;, which either return the value or raise an exception, and question mark methods &amp;quot;?&amp;quot; which either return true or false, depending on validation.&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1
2&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Citizenship&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid_nif?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;123456789&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# returns true&lt;/span&gt;
&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Citizenship&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;valid_identification_card!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;156 944 8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;8&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# returns &amp;#39;156 944 8&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;Integration with Rails&lt;/h3&gt;

&lt;p&gt;Although you can use this gem outside of Rails context, of course it supports Rails by adding some useful ActiveModel validators.&lt;br&gt;
It&amp;#39;s quite easy. To validate an attribute &amp;quot;fiscal_number&amp;quot; which is supposed to be a valid NIF (fiscal number), you would do something like this:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1
2
3
4&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:fiscal_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;nif&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;.&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;More Information&lt;/h3&gt;

&lt;p&gt;For more information about how to use the Citizenship Gem please look at the &lt;a href='https://github.com/runtimerevolution/citizenship/blob/master/README.md' target='_blank'&gt;README&lt;/a&gt; file on the &lt;a href='https://github.com/runtimerevolution/citizenship/' target='_blank'&gt;Github Repository&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;What&amp;#39;s Next&lt;/h3&gt;

&lt;p&gt;Currently, as of v1.0.0, the zip codes validation is based only on a regex pattern match. That may fit some simple purposes but is not very accurate indeed.&lt;/p&gt;

&lt;p&gt;We will be integrating a full &amp;quot;database&amp;quot; of valid zip codes (easily obtained at CTT&amp;#39;s web site - Portuguese postals).&lt;/p&gt;

&lt;p&gt;We may add IBAN validation and extend currently features beyond Portuguese borders, allowing validation for assets used in other european countries.&lt;/p&gt;

&lt;p&gt;Citizenship was built by the Runtime Revolution team. Find us on &lt;a href='https://twitter.com/RuntimeRev' target='_blank'&gt;Twitter&lt;/a&gt; if you have questions, ideas, grab the source code, fork and contribute on &lt;a href='https://github.com/runtimerevolution/citizenship' target='_blank'&gt;GitHub&lt;/a&gt; right now! Keep an eye on our page and if you have new ideas let us know.&lt;/p&gt;

&lt;p&gt;If you find this interesting, or at least useful, please &lt;a href='https://github.com/runtimerevolution/' target='_blank'&gt;check out other Runtime Revolution&amp;#39;s Open-Source Projects&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Mon, 01 Jun 2015 00:00:00 +0000</pubDate>
      <link>http://www.runtime-revolution.com/runtime/blog/citizenship-simple-yet-useful-validation-of-portuguese-cards-and-more</link>
      <guid>http://www.runtime-revolution.com/runtime/blog/citizenship-simple-yet-useful-validation-of-portuguese-cards-and-more</guid>
    </item>
    <item>
      <title>Capybara: emulating mobile browsers with chromedriver</title>
      <description>&lt;p&gt;In a recent project update where we have done some changes to our responsive site, we broke the native datepicker feature that we use when the browser is a smartphone.&lt;/p&gt;

&lt;p&gt;To help avoid this kind of situation, we decided to research for a solution that would allow us to create tests for mobile browsers specific features that we have on the site.&lt;/p&gt;

&lt;p&gt;Since we use capybara to do these tests, our first trial was to check if we could do this with the driver we were currently using, &lt;a href='https://github.com/teampoltergeist/poltergeist' target='_blank'&gt;poltergeist&lt;/a&gt;. &lt;br&gt;
After some investigation we found out that although we could resize the browser and change the User Agent, it didn&amp;#39;t supported native datepickers.&lt;/p&gt;

&lt;p&gt;Then we checked &lt;a href='https://github.com/thoughtbot/capybara-webkit' target='_blank'&gt;capybara-webkit&lt;/a&gt;, but rapidly came to the same conclusion.&lt;/p&gt;

&lt;p&gt;It was after it that we came across &lt;a href='https://sites.google.com/a/chromium.org/chromedriver/' target='_blank'&gt;chromedriver&lt;/a&gt;, Google Chrome driver for selenium. In a &lt;a href='https://groups.google.com/forum/#!topic/chromedriver-users/VxfqQfpYq7E' target='_blank'&gt;recent update&lt;/a&gt; to the driver, they added support to use the &lt;a href='https://developer.chrome.com/devtools/docs/device-mode' target='_blank'&gt;mobile emulator&lt;/a&gt; present in Google Chrome dev tools that supports among other things, native datepickers.&lt;/p&gt;

&lt;p&gt;This allowed us to create the tests for the specific features that we needed without having to create more complex setups, like using selenium &lt;a href='http://ios-driver.github.io/ios-driver' target='_blank'&gt;ios-driver&lt;/a&gt; or &lt;a href='http://selendroid.io' target='_blank'&gt;selendroid&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To run it in headless mode in an ubuntu machine, first you need to be sure you have the following dependencies installed on your system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Xvfb:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;xvfb&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Google Chrome (&lt;a href='http://www.howopensource.com/2011/10/install-google-chrome-in-ubuntu-11-10-11-04-10-10-10-04/' target='_blank'&gt;source&lt;/a&gt;):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Gets the repository key&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;O&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;https:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="vg"&gt;dl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;google&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;linux&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;linux_signing_key&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Set the repository:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;sh&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;echo &amp;quot;deb http://dl.google.com/linux/chrome/deb/ stable main&amp;quot; &amp;gt;&amp;gt; /etc/apt/sources.list.d/google-chrome.list&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;update&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install the stable version&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;get&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;google&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;chrome&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;stable&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To install the chromedriver&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Download the latest version of chrome driver from &lt;a href='http://chromedriver.storage.googleapis.com/index.html' target='_blank'&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E.g: &lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;wget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;http:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="vg"&gt;chromedriver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;storage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;googleapis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mf"&gt;2.12&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;chromedriver_linux64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;zip&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unzip it to /usr/local/bin&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E.g: &lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;unzip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;chromedriver_linux64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;zip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="vg"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;bin&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Update the chromedriver file permissions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;E.g: &lt;/li&gt;
&lt;/ul&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;chmod&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="il"&gt;0755&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="vg"&gt;chromedriver&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ensure you have the headless and the selenium-webdriver gems on your gemfile:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1
2&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;gem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;selenium-webdriver&amp;#39;&lt;/span&gt;
&lt;span class="vg"&gt;gem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;headless&amp;#39;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Add the following to your /spec/rails_helper.rb file:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="vg"&gt;require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;headless&amp;#39;&lt;/span&gt;

&lt;span class="vg"&gt;headless&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;Headless&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;new&lt;/span&gt;
&lt;span class="vg"&gt;headless&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;start&lt;/span&gt;

&lt;span class="vg"&gt;at_exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;do&lt;/span&gt;
&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;headless&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;destroy&lt;/span&gt;
&lt;span class="vg"&gt;end&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;

&lt;span class="vg"&gt;Capybara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;register_driver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;apple_iphone_5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="vg"&gt;app&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="vg"&gt;mobile_emulation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;deviceName&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Apple iPhone 5&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="vg"&gt;capabilities&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;Selenium:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nl"&gt;WebDriver:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nl"&gt;Remote:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;Capabilities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="c1"&gt;&amp;#39;chromeOptions&amp;#39; =&amp;gt; {&amp;#39;mobileEmulation&amp;#39; =&amp;gt; mobile_emulation})&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;Capybara:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="nl"&gt;Selenium:&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;Driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vg"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;browser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;desired_capabilities&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="vg"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;then, on the tests where you want to run with the mobile browser:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1
2
3
4
5
6
7&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="vg"&gt;before&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;each&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vg"&gt;Capybara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;current_driver&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;apple_iphone_5&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="vg"&gt;end&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="vg"&gt;after&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="vg"&gt;each&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="vg"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="vg"&gt;Capybara&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vg"&gt;use_default_driver&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="vg"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Hope this helps you start using selenium with chromedriver.&lt;/p&gt;

&lt;p&gt;More details and settings in &lt;a href='https://github.com/jnicklas/capybara' target='_blank'&gt;Capybara Github&lt;/a&gt;, &lt;a href='https://github.com/leonid-shevtsov/headless' target='_blank'&gt;Headeless Github&lt;/a&gt; and &lt;a href='https://sites.google.com/a/chromium.org/chromedriver/mobile-emulation' target='_blank'&gt;Chromedriver mobile emulation page&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Fri, 21 Nov 2014 20:38:08 +0000</pubDate>
      <link>http://www.runtime-revolution.com/runtime/blog/capybara-emulating-mobile-browsers-with-chromedriver</link>
      <guid>http://www.runtime-revolution.com/runtime/blog/capybara-emulating-mobile-browsers-with-chromedriver</guid>
    </item>
    <item>
      <title>Metaprogramming in Ruby - Part I</title>
      <description>&lt;p&gt;Here at Runtime Revolution we love Ruby. We love it for several reasons but one of the traits we most cherish is it&amp;#39;s metaprogramming capabilities.  &lt;/p&gt;

&lt;p&gt;In this series of posts, I&amp;#39;ll introduce and explain the concept, make a tour of Ruby&amp;#39;s metaprogramming infrastructure and explore some common metaprogramming techniques.&lt;/p&gt;

&lt;h2&gt;What is metaprogramming?&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Metaprogramming is the process by which a program manipulates other programs or itself.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Although the concept may be somehow strange to some developers, metaprogramming is something that has presence on the daily life of a software maker. Maybe some examples of every day typical metaprogramming products will shed some light on it&amp;#39;s ubiquity:&lt;/p&gt;

&lt;h3&gt;Lexical analyzer generators&lt;/h3&gt;

&lt;p&gt;Lexical analysis consists on translating an expression into a list of it&amp;#39;s representative tokens. This is the first stage of interpreting or compiling your favorite programming language source code files. &lt;/p&gt;

&lt;p&gt;Lexical analyzer generators are applications that given a set of scanning rules, produce a lexer. Hence they are software applications that write other software applications given that a lexical analyzer generator output is a lexer (a.k.a. Scanner or Tokenizer).&lt;/p&gt;

&lt;h3&gt;Interpreters/Compilers&lt;/h3&gt;

&lt;p&gt;Interpreters or compilers are canonical examples of the use of metaprogramming. Both receive a representation of a set of instructions and produce some other representation of the same set of instruction but as another software program. In the case of &lt;a href='http://en.wikipedia.org/wiki/Ruby_MRI' target='_blank'&gt;MRI&lt;/a&gt; 1.8.7 or lesser, your Ruby source code will turn out to be interpreted and executed by C code (for 1.9 and beyond, things are &lt;a href='http://www.youtube.com/watch?v=NG8goJpbKk0&amp;feature=player_detailpage#t=445s' target='_blank'&gt;slightly different&lt;/a&gt;). In the case of JRuby, a Ruby implementation for the Java Virtual Machine, at a given point, your code will run as JVM&amp;#39;s byte code and possibly just-in-time compiled to machine code. In both cases we have a program that writes (manipulates) another program.&lt;/p&gt;

&lt;h3&gt;C++ Templates&lt;/h3&gt;

&lt;p&gt;C++ templates are probably the most typical example of a subset of metaprogramming unsurprisingly called Template metaprogramming. With C++ templates you write code which in turn will be pre-processed to standard C/C++ source code that will be merged with the rest of the code base and subject to the regular compilation step. &lt;/p&gt;

&lt;h3&gt;Most software written in &amp;quot;dynamic&amp;quot; languages&lt;/h3&gt;

&lt;p&gt;Most software written in Ruby, Lisp, Python, Smalltalk, and other languages able to alter the program at runtime. This is usually referred as dynamic metaprogramming.&lt;/p&gt;

&lt;p&gt;This is true even for the most unaware of developers, since in these environments, even if the developers don&amp;#39;t actively use metaprogramming features, most libraries and even core language constructs use them. For instance, in the case of Ruby, metaprogramming is present at various levels of the Ruby ecosystem. It&amp;#39;s is massively employed in Ruby on Rails but also in Ruby itself. e.g. the &lt;a href='http://apidock.com/ruby/Module/attr_accessor' target='_blank'&gt;attr_acessor&lt;/a&gt; method.&lt;/p&gt;

&lt;h2&gt;What is dynamic metaprogramming?&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Dynamic metaprogramming is the process by which a program manipulates itself at runtime.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The first three examples above illustrate a metaprogramming pattern where the resulting program lives on a separated runtime of it&amp;#39;s producer. A compiled program, for instance, not only runs on a different runtime but typically is a loose representation of your original implementation, where many of your origin language concepts and constructs (e.g.: scopes, classes, etc.) don&amp;#39;t even exist. &lt;/p&gt;

&lt;p&gt;This is not the case with dynamic metaprogramming. With dynamic metaprogramming you manipulate your program, on the fly, within the same context. We may think of languages with support for dynamic metaprogramming as languages that have a built-in API to themselves.&lt;/p&gt;

&lt;h2&gt;Why dynamic  metaprogramming?&lt;/h2&gt;

&lt;p&gt;Why dynamic metaprogramming? It&amp;#39;s not that we don&amp;#39;t already have our share of concepts, methodologies, paradigms and techniques that we need to throw one more for software developers to wrap their heads around. What&amp;#39;s the gain?&lt;/p&gt;

&lt;h3&gt;Provide an elegant and powerful way to handle cross application concerns&lt;/h3&gt;

&lt;p&gt;Since using metaprogramming features allows you to write code that deeply interacts and changes code yet to be written by another developer, it&amp;#39;s a very convenient way to address cross-application concerns and develop in a very generic fashion. This in turn is one of the features needed to be able to create high level libraries that correctly interact with application code. At this point you&amp;#39;re able to write libraries that handle functional (instead of technical) issues, resulting in effective code reuse at a very high level.&lt;/p&gt;

&lt;p&gt;In the end, this allows for some very efficient transfer of complexity from application developer to framework/library developer, benefiting an entire language ecosystem. &lt;/p&gt;

&lt;h3&gt;Dynamic code generation is superior to static code generation&lt;/h3&gt;

&lt;p&gt;UI Generation libraries provide a good showcase for the above statement. With more      static languages (e.g. C/C++) every take on UI generation was made  by  generating code. This would often result in marginal gains of productivity simply   because that customization of generated code would invalidate recreation of the     UI code. Regenerating would mean crushing any customization made before hand.   This is not an issue with dynamic code generation.&lt;/p&gt;

&lt;h3&gt;Easy internal DSL development&lt;/h3&gt;

&lt;p&gt;Dynamic metaprogramming features are very useful for creating &lt;a href='http://martinfowler.com/bliki/DomainSpecificLanguage.html' target='_blank'&gt;internal DSLs&lt;/a&gt;. That means you can create a very high level of abstraction for a particular problem, high enough for someone with a functional knowledge of a given domain to be able to use your (mini) language without general programming knowledge. Even if creating a DSL is not desirable, metaprogramming features, when used properly, are useful in creating very high level APIs.&lt;/p&gt;

&lt;h2&gt;Ruby&amp;#39;s metaprogramming infrastructure&lt;/h2&gt;

&lt;p&gt;Ruby has a very complete metaprogramming infrastructure, some of the most relevant components are:  &lt;/p&gt;

&lt;h3&gt;Strong introspective abilities&lt;/h3&gt;

&lt;p&gt;Type introspection is the ability that a program has to examine it&amp;#39;s own types.&lt;br&gt;
it enables the  creation of further metaprogramming infrastructure. Ruby&amp;#39;s  introspection is deeply embedded in it&amp;#39;s object model , thus creating a very intuitive API.&lt;/p&gt;

&lt;h3&gt;Runtime creation of core language constructs&lt;/h3&gt;

&lt;p&gt;In Ruby, you can create most of the core language constructs at runtime. This means you can create new classes and methods (or even remove existing methods). Changing existing classes is also possible (this is usually refered to as Open Classes), even core classes.&lt;/p&gt;

&lt;h3&gt;Other features useful for metaprogramming&lt;/h3&gt;

&lt;p&gt;Ruby has several other features useful for metaprogramming, such as Metaclasses, Hook Methods (method_missing, included, inherited, etc. ), Closures and methods as first level citizens, and many others. &lt;/p&gt;

&lt;p&gt;We will delve into this topics on the next series of this post which will have a much more hands-on approach. I promise :).&lt;/p&gt;

&lt;p&gt;Meanwhile, if you want to learn a bit more about metaprogramming in Ruby, check out the excellent &lt;a href='http://pragprog.com/book/ppmetr/metaprogramming-ruby' target='_blank'&gt;Metaprogramming Ruby&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Tue, 16 Jul 2013 00:00:00 +0000</pubDate>
      <link>http://www.runtime-revolution.com/runtime/blog/metaprogramming-in-ruby</link>
      <guid>http://www.runtime-revolution.com/runtime/blog/metaprogramming-in-ruby</guid>
    </item>
    <item>
      <title>Our new Rails Gem - Survey</title>
      <description>&lt;p&gt;Survey is a Rails Engine that brings quizzes, surveys and contests into your Rails application. Survey was initially extracted from a real application that includes contests and quizzes.&lt;br&gt;
While we were building two of our latest client projects we found the need to have a reusable and generic way to integrate questionnaires, surveys and competitions into different application use cases. &lt;/p&gt;

&lt;p&gt;Ever had the feeling you were creating something that already exists over and over again? In this case we did, so we extracted Survey from those projects. Like most good development shops we are both producers and consumers of open source, and we also love to write it in order to deliver nicer software quickly.&lt;/p&gt;

&lt;p&gt;We wrote Survey because none of the existing gems did what we needed. Some of them are developer oriented, and had to be configured with &lt;em&gt;YML&lt;/em&gt; files or in code, but we needed something backed by models that our end users could directly manage in the application&amp;#39;s back-office.&lt;/p&gt;

&lt;h3&gt;How does it work?&lt;/h3&gt;

&lt;p&gt;Survey is organized as a typical questionnaire domain. On the top of the hierarchy we have the Survey class itself, with associated questions. Answers are related to surveys via Attempts, to model that more than one attempt is possible in some scenarios. The correct answer to a question is modeled via an Option class that relates Questions and Answers, allowing for different relations other than correctness in some custom scenarios. Depending on what you are dealing with you can assign a correct answer to the question and decide if the answers are valued with weights or not. In this model, Attempt objects have a collection of answers made by the participants. We wanted the model to be flexible enough that it can be linked with an existing object model and interact with it without imposing too much constraints.&lt;/p&gt;

&lt;p&gt;The following UML diagram will tell you the infrastructure:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://karmasites.s3.amazonaws.com.s3.amazonaws.com/system/cms/attachments/files/000/000/012/original/survey_uml.jpg" alt="survey diagram"&gt;&lt;/p&gt;

&lt;h3&gt;How can you use it?&lt;/h3&gt;

&lt;p&gt;So what kind of stuff can you make with survey? How can it make creating surveys easier ? Let’s begin:&lt;br&gt;
&lt;em&gt;Dealing with models&lt;/em&gt; - The easy way to create a relation between your target model (let’s say for example, model User) and Survey is to use the has_surveys ActiveRecord::Extension. Just that! Now the User will have a connection to Survey model and every user has a maximum number of attempts and a history log from the Survey Perspective. Survey will also track every new attempt to submit surveys, or deny it if the user already raise the maximum number of attempts to answer it.&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1
2
3&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;has_surveys&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Ok, now our User class has a valid relationship with Survey. We can keep moving forward and think how we would create a sample survey:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt; 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# Let&amp;#39;s build our own survey&lt;/span&gt;
&lt;span class="n"&gt;my_survey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;survey&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Star Wars Quiz&amp;quot;&lt;/span&gt; 
  &lt;span class="n"&gt;survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;The following questions are related with first movie of Star Wars&amp;quot;&lt;/span&gt;
  &lt;span class="n"&gt;survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempts_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
  &lt;span class="n"&gt;survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Let&amp;#39;s add some questions and options&lt;/span&gt;
&lt;span class="n"&gt;question_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;How many droids help Luke in the first movie?&amp;#39;&lt;/span&gt;
  &lt;span class="c1"&gt;# by default when we don&amp;#39;t specify the weight of a option&lt;/span&gt;
  &lt;span class="c1"&gt;# its value is equal to one&lt;/span&gt;
  &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;1 droid&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="ss"&gt;:correct&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2 droids&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:correct&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;3 droids&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:correct&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;question_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Who is the evil guy?&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
    &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Darth Vader&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:weight&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Obi Wan&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;     &lt;span class="ss"&gt;:weight&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Option&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:text&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Jabba&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="ss"&gt;:weight&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;my_survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;question_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;question_2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;my_survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save!&lt;/span&gt;

&lt;span class="c1"&gt;# Let&amp;#39;s answer it with User 1&lt;/span&gt;
&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Attempt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:survey&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_survey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:participant&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;answer_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:option&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;question_1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;answer_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:option&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;question_2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;answers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;answer_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answer_2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;
&lt;span class="c1"&gt;# Let&amp;#39;s answer it with User 2&lt;/span&gt;
&lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Attempt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:survey&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;my_survey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:participant&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;user_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;answer_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:option&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;question_1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;answer_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Answer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:option&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;question_2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;answers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;answer_1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;answer_2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;

&lt;span class="c1"&gt;# Let&amp;#39;s pull some metrics&lt;/span&gt;

&lt;span class="n"&gt;survey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;active&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;

&lt;span class="c1"&gt;# select all the attempts from this survey&lt;/span&gt;
&lt;span class="n"&gt;survey_answers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attempts&lt;/span&gt;

&lt;span class="c1"&gt;# check the highest score for user 2&lt;/span&gt;
&lt;span class="n"&gt;user_2_highest_score&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;survey_answers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;for_participant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;high_score&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;user_2_highest_score&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;51&lt;/span&gt;

&lt;span class="c1"&gt;#check the highest score made for this survey&lt;/span&gt;
&lt;span class="n"&gt;global_highest_score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;survey_answers&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;high_score&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;global_highest_score&lt;/span&gt;
&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;101&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;One great thing to do is to use the data collected by the survey and create metrics with it. For example you can see how many users already spent their valid number of attempts or for example, see how many correct answers the user has, make a sum of answer weights, or something else entirely. You can define your own strategies to collect metrics around the user&amp;#39;s answers. Also, any model, not only the User model, can respond to surveys. &lt;/p&gt;

&lt;h2&gt;Scaffold framework integration&lt;/h2&gt;

&lt;p&gt;Survey offers you a basic structure of different controllers and views that can be generated using a Rails generator. If you are using RailsAdmin or ActiveAdmin templates are included to make building backoffice pages for Survey easy. Depending on your needs, you can use one of the following rake tasks.&lt;/p&gt;

&lt;p&gt;For ActiveAdmin:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;rails generate survey active_admin
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;If you want a traditional rails controller you can execute the following rake task with a namespace contests (this variable is optional):&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;Rails generate survey plain namespace:contests
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;These generators will make building your Survey backoffice easier.&lt;/p&gt;

&lt;h3&gt;What is it good for?&lt;/h3&gt;

&lt;p&gt;Survey is a great choice when you have the concept of questionnaire or contest in your domain model. It is also good when you are using RailsAdmin or ActiveAdmin because it has default templates that you can customize according to your needs, in other words you don’t need to make everything from beginning, because Survey takes care of the basics for you.&lt;br&gt;
Survey has the ability to assign different weights to the questionnaire’s questions; this is quite good when you are dealing with tests or feedback surveys.&lt;br&gt;
Survey controls the number of attempts made by each participant. You can define a maximum number of attempts per questionnaire and restrict the submission to those who have a valid number of attempts. Here&amp;#39;s one simple and straightforward way of doing it:&lt;/p&gt;
&lt;div class='highlighttable'&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;1&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Survey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Star Wars Quiz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:attempts_number&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Survey in the general case can be valuable if you want to collect metrics from surveys afterwards. Although, because many times surveys have their particular form and style, also relevant metrics diverge from project to project, so Survey provides the basic data, and you have to use that data to extract your own goals and metrics.&lt;/p&gt;

&lt;h3&gt;More Information&lt;/h3&gt;

&lt;p&gt;For more information about how to use the Survey Gem please visit the &lt;a href='https://github.com/runtimerevolution/survey/blob/master/README.md' target='_blank'&gt;README&lt;/a&gt; file on the Github Repository.&lt;/p&gt;

&lt;h3&gt;What&amp;#39;s Next&lt;/h3&gt;

&lt;p&gt;We wanted to enable end users to create surveys and other questionnaires without constantly depending on developers. Maybe some day Survey will grow, and someone will use it to build other cool open source projects :)&lt;/p&gt;

&lt;p&gt;Survey was built on Rails by the Runtime Revolution team. Find us on &lt;a href='https://twitter.com/RuntimeRev' target='_blank'&gt;Twitter&lt;/a&gt; if you have questions, ideas, and grab the source code on &lt;a href='https://github.com/runtimerevolution/survey' target='_blank'&gt;GitHub&lt;/a&gt; right now! Keep an eye on our Survey Roadmap and if you have new ideas let us know.&lt;/p&gt;

&lt;p&gt;If you find Survey interesting, also &lt;a href='http://runtime-revolution.com/runtime/community' target='_blank'&gt;check out other Runtime Revolution&amp;#39;s Open-Source Projects&lt;/a&gt;.&lt;/p&gt;
</description>
      <pubDate>Tue, 04 Jun 2013 00:00:00 +0000</pubDate>
      <link>http://www.runtime-revolution.com/runtime/blog/introducing-survey</link>
      <guid>http://www.runtime-revolution.com/runtime/blog/introducing-survey</guid>
    </item>
    <item>
      <title>Welcome to Runtime's new Blog</title>
      <description>&lt;p&gt;It is with great pleasure that we welcome you to our new &lt;a href='http://runtime-revolution.com/runtime/blog' target='_blank'&gt;Runtime Revolution Blog&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Here we will be posting about Ruby, Rails, the web and open-source projects. In a way to celebrate our blog birth we will publish a series of posts around our open-source projects and related themes like meta-programming and parallelism.&lt;/p&gt;

&lt;h2&gt;Who are we ?&lt;/h2&gt;

&lt;p&gt;We don&amp;#39;t just create web applications, we also solve problems. At Runtime we write flexible and well designed software to help business develop strategic solutions and launch their concepts in the right way. &lt;/p&gt;

&lt;p&gt;You can follow us &lt;a href='https://twitter.com/RuntimeRev' target='_blank'&gt;@twitter&lt;/a&gt; or fork us &lt;a href='https://github.com/runtimerevolution' target='_blank'&gt;@github&lt;/a&gt;!&lt;/p&gt;
</description>
      <pubDate>Mon, 03 Jun 2013 00:00:00 +0000</pubDate>
      <link>http://www.runtime-revolution.com/runtime/blog/welcome-to-runtime-blog</link>
      <guid>http://www.runtime-revolution.com/runtime/blog/welcome-to-runtime-blog</guid>
    </item>
  </channel>
</rss>
