tag:pragdevnotes.com,2008:/ruby Ruby - Pragmatic Development Notes 2011-05-07T12:40:11Z Enki Boško Ivanišević bosko.ivanisevic@gmail.com tag:pragdevnotes.com,2008:Post/16 2011-05-07T06:40:00Z 2011-05-07T12:40:11Z dep_walker Gem <p>Common problem that Ruby developers face on Windows is missing dll message box that appears when they try to use gem that has extension library. Usually these Gems are packed with pre-built binary<br /> extensions for windows and, even though, installation passes without any error or warning, when they try to use them they realize that dll these Gems depend on are missing on the system.</p> <p>Maybe most common Gem for which this happens is sqlite3, Ruby binding for the SQlite3 embedded database. If sqlite3.dll is missing from the system, after installation of sqlite3 Gem any attempt to use it causes following message box to appear.</p> <p><img src="/images/dep_walker/missing_dll_msg_box.png" alt="" /></p> <p>If two versions of a required dll exist on the system Gem might use the wrong one and strange crashes can appear.</p> <p>These errors are not limited to the Gems that have pre-built binary extensions but can also happen if extension library was built with the <a href="http://www.rubyinstaller.org">RubyInstaller&#8217;s</a> <a href="http://www.rubyinstaller.org/add-ons/devkit">DevKit</a>. If development files (header and library files) needed for the extension library to be built exist on the system while target dll is missing gem usage<br /> will cause the same message box to appear.</p> <p>Frequently novice Ruby users on Windows ask question on mailing lists why Gem is not working even if it was installed without any error. That&#8217;s why I made dep_walker, small utility Gem, that can be used to check whether all dependencies for extension libraries used by installed Gem(s) are met or not. Source of the Gem can be found on <a href="http://github.com/bosko/dep_walker">GitHub</a>.</p> <p>Usage is very simple. If you want to check all installed Gems just invoke dep_walker with the &#8216;-a&#8217; switch.</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">dep_walker -a<tt> </tt></pre></td> </tr></table> <p>And for particular gem swith &#8216;-c&#8217; can be used.</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">dep_walker -c sqlite3<tt> </tt></pre></td> </tr></table> <p>More verbose output is obtained via &#8216;-t&#8217; and colour with &#8216;&#8212;color&#8217; swith. Happy dependencies walking!</p> tag:pragdevnotes.com,2008:Post/15 2010-10-31T13:54:59Z 2010-10-31T20:54:58Z Using Selenium with Cucumber through Webrat or Capybara. Which one to choose? <h2>Introduction</h2> <p>Testing is (or should be) important part of every software development. Over time various testing strategies and supporting tools and frameworks have been developed. Regarding Web development biggest advance has been made in Behavior Driven Development. Consequently many tools for <span class="caps">BDD</span> are published and used.</p> <p><a href="http://www.rubyonrails.org">Ruby on Rails</a> framework had great built-in support for testing from the very beginning. As it usually happens, lot of specialised testing tools appeared aside of it and among all of them my favourites are <a href="http://rspec.info">RSpec</a> and <a href="http://github.com/aslakhellesoy/cucumber/wiki">Cucumber</a>. The first one for unit and the second for functional tests. Both of them are well integrated with Ruby on Rails and are very easy to set up and start with. Moreover there is no need to use real browsers which results in fast tests execution. Perfect way for <span class="caps">BDD</span>.</p> <p>But what if you have to perform functional tests on non Ruby on Rails applications or your application relies heavily on JavaScript (no matter in which framework it is written)? Luckily Cucumber can be used in that case too. Since Cucumber supports Rails out of the box there is basically no need for some special configuration. On the other hand if a real browser must be used in tests, or functional testing must be done outside of the Rails environment setting up Cucumber can be little tricky but still simple enough. In this article I will focus on this scenario &#8211; <i>testing non Rails applications with <a href="http://github.com/aslakhellesoy/cucumber/wiki">Cucumber</a> and <a href="http://seleniumhq.org">Selenium</a></i>.</p> <p>Using Selenium in Cucumber tests is done through <a href="http://github.com/brynary/webrat/wiki">Webrat</a> or <a href="http://github.com/jnicklas/capybara">Capybara</a>. First we must set up complete environment, and in the first step all necessary gems must be installed:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">gem install launchy<tt> </tt>gem install rspec<tt> </tt>gem install cucumber<tt> </tt>gem install webrat<tt> </tt>gem install capybara --pre<tt> </tt>gem install selenium-client<tt> </tt>gem install selenium-webdriver<tt> </tt></pre></td> </tr></table> <p><i>Option &#8212;pre is used to install Capybara 0.4.0 rc</i></p> <p><b>Important notice for MS Windows users: Webrat depends on Json gem which installs binaries compiled against <a href="http://www.rubyinstaller.org">Rubyinstaller</a> Ruby 1.8.x version. If you are using 1.9.2 Ruby you must uninstall Json gem and install it again but with <code>--platform=ruby</code> option:</b></p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">gem uninstall json<tt> </tt>gem install json --platform=ruby<tt> </tt></pre></td> </tr></table> <p>Since article focuses on the functional testing outside of Rails we should manually create folder structure that Cucumber expects.</p> <pre> tests |- features |- support |- step_definitions </pre> <p>All <code>.feature</code> files go in the <code>features</code> folder. In the <code>support</code> folder <code>env.rb</code> file should be created and within it all set up must be made. Finally steps are implemented in Ruby files in <code>step_definitions</code> folder.</p> <h2>Webrat</h2> <p><a href="http://github.com/brynary/webrat/wiki">Webrat</a> controls Selenium through Selenium RC (remote control) and selenium-client gem. In order to use Selenium through Webrat put following code in your <code>env.rb</code>:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt>15<tt> </tt>16<tt> </tt>17<tt> </tt>18<tt> </tt>19<tt> </tt><strong>20</strong><tt> </tt>21<tt> </tt>22<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">require <span class="s"><span class="dl">'</span><span class="k">cucumber/formatter/unicode</span><span class="dl">'</span></span><tt> </tt><tt> </tt>require <span class="s"><span class="dl">'</span><span class="k">webrat</span><span class="dl">'</span></span><tt> </tt>require <span class="s"><span class="dl">'</span><span class="k">webrat/core/matchers</span><span class="dl">'</span></span><tt> </tt><tt> </tt><span class="co">Webrat</span>.configure <span class="r">do</span> |config|<tt> </tt> config.mode = <span class="sy">:selenium</span><tt> </tt> config.application_framework = <span class="sy">:external</span><tt> </tt> config.selenium_server_address = <span class="s"><span class="dl">'</span><span class="k">127.0.0.1</span><span class="dl">'</span></span><tt> </tt> <span class="r">if</span> <span class="co">RbConfig</span>::<span class="co">CONFIG</span>[<span class="s"><span class="dl">'</span><span class="k">host_os</span><span class="dl">'</span></span>] =~ <span class="rx"><span class="dl">/</span><span class="k">mingw|mswin</span><span class="dl">/</span></span><tt> </tt> config.selenium_browser_startup_timeout = <span class="i">60</span><tt> </tt> config.application_address = <span class="s"><span class="dl">'</span><span class="k">localhost</span><span class="dl">'</span></span><tt> </tt> config.application_port = <span class="s"><span class="dl">'</span><span class="k">3000</span><span class="dl">'</span></span><tt> </tt><span class="r">end</span><tt> </tt><tt> </tt><span class="co">World</span> <span class="r">do</span><tt> </tt> session = <span class="co">Webrat</span>::<span class="co">Session</span>.new<tt> </tt> session.extend(<span class="co">Webrat</span>::<span class="co">Methods</span>)<tt> </tt> session.extend(<span class="co">Webrat</span>::<span class="co">Selenium</span>::<span class="co">Methods</span>)<tt> </tt> session.extend(<span class="co">Webrat</span>::<span class="co">Selenium</span>::<span class="co">Matchers</span>)<tt> </tt> session<tt> </tt><span class="r">end</span><tt> </tt></pre></td> </tr></table> <p>That&#8217;s all if you are running Linux based system. <i>On Windows a little bit more effort must be made. </i>First of all, Webrat usess 0.0.0.0 IP address when it starts Selenium and MS Windows does not like it at all. Secondly it uses <code>/dev/null</code> stream which is not available on MS Windows. Patch is already submitted and you can follow a ticket at <a href="https://webrat.lighthouseapp.com/projects/10503/tickets/387-tiny-patch-for-work-with-selenium-on-windows#ticket-387-2">Webrat Lighthouse</a>. But until fix is accepted and new version is released, you can take a patch from <a href="http://gist.github.com/584005">Github gitst</a> and apply it to Webrat sources.</p> <script src="http://gist.github.com/584005.js?file=0001-Fix-using-Selenium-on-mingw-based-Ruby-on-Windows.patch"></script><p>Besides this patch few more things must be done. Line:</i></p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">config.selenium_server_address = <span class="s"><span class="dl">'</span><span class="k">127.0.0.1</span><span class="dl">'</span></span><tt> </tt> <span class="r">if</span> <span class="co">RbConfig</span>::<span class="co">CONFIG</span>[<span class="s"><span class="dl">'</span><span class="k">host_os</span><span class="dl">'</span></span>] =~ <span class="rx"><span class="dl">/</span><span class="k">mingw|mswin</span><span class="dl">/</span></span><tt> </tt></pre></td> </tr></table> <p>must be added to the <code>config</code> block as is already shown in the above snippet. Unfortunately selenium-client gem does not recognize <a href="http://www.rubyinstaller.org">Rubyinstaller</a> since it is built using MinGW tools. Therefore one more tiny patch must be made in the <code>selenium-client-1.2.18/lib/nautilus/shell.rb</code> file. Function <code>windows?</code> must be replaced with:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">def</span> <span class="fu">windows?</span><tt> </tt> ::<span class="co">RbConfig</span>::<span class="co">CONFIG</span>[<span class="s"><span class="dl">'</span><span class="k">host_os</span><span class="dl">'</span></span>] =~ <span class="rx"><span class="dl">/</span><span class="k">mswin|mingw</span><span class="dl">/</span></span><tt> </tt><span class="r">end</span> <tt> </tt></pre></td> </tr></table> <p>You are ready for application testing. By default Selenium will use Firefox and if you want to use other browser (in the example Internet Explorer is set) add following line to <code>config</code> block:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">config.selenium_browser_key = <span class="s"><span class="dl">'</span><span class="k">*iexplore</span><span class="dl">'</span></span> <tt> </tt></pre></td> </tr></table> <h2>Capybara</h2> <p>Although <a href="http://github.com/jnicklas/capybara">Capybara</a> can use Selenium RC, it primarily uses Selenium WebDriver which is still in beta phase but is working good. Since we already installed all necessary gems we can go on with configuring our testing environment. File <code>env.rb</code> should look like this:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">require <span class="s"><span class="dl">'</span><span class="k">rbconfig</span><span class="dl">'</span></span><tt> </tt>require <span class="s"><span class="dl">'</span><span class="k">cucumber/formatter/unicode</span><span class="dl">'</span></span><tt> </tt><tt> </tt>require <span class="s"><span class="dl">'</span><span class="k">capybara</span><span class="dl">'</span></span><tt> </tt>require <span class="s"><span class="dl">'</span><span class="k">capybara/dsl</span><span class="dl">'</span></span><tt> </tt>require <span class="s"><span class="dl">&quot;</span><span class="k">capybara/cucumber</span><span class="dl">&quot;</span></span><tt> </tt><tt> </tt><span class="co">Capybara</span>.default_driver = <span class="sy">:selenium</span><tt> </tt><span class="co">Capybara</span>.app_host = <span class="s"><span class="dl">&quot;</span><span class="k">http://127.0.0.1:8000/</span><span class="dl">&quot;</span></span><tt> </tt><span class="co">Capybara</span>.register_driver <span class="sy">:selenium</span> <span class="r">do</span> |app|<tt> </tt> <span class="co">Capybara</span>::<span class="co">Driver</span>::<span class="co">Selenium</span>.new(app, <span class="sy">:browser</span> =&gt; <span class="sy">:firefox</span>)<tt> </tt><span class="r">end</span><tt> </tt><tt> </tt>World(<span class="co">Capybara</span>)<tt> </tt></pre></td> </tr></table> <p>Setting up Capybara is definitely much easier. But on MS Windows systems, if you want to use Internet Explorer, you still have to patch sources. Authors are already <a href="http://groups.google.com/group/webdriver/browse_thread/thread/a8ed4ce6f98e8322">notified about required patch</a> and I believe that new version of <code>selenium-webdriver</code> gem will be released with it. In the meantime you just have to change definition of <code>initialize</code> method in <code>selenium-webdriver-0.0.28/lib/selenium/webdriver/ie/bridge.rb</code> from:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">def</span> <span class="fu">initialize</span>()<tt> </tt></pre></td> </tr></table> <p>to</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">def</span> <span class="fu">initialize</span>(opts = {})<tt> </tt></pre></td> </tr></table> <p>Changing browser is as easy as changing <code>:firefox</code> to <code>:ie</code> or <code>:chrome</code>. Instead of <code>:firefox</code> you can also use <code>:ff</code> and for Internet Explorer <code>:internet_explorer</code>. One more notice about differences if you are switching from Webrat to Capybara. Capybara will reset session after each step. If you do not want that (for example you log in to your application in the first scenario, and do not want to repeat it in each succeeding one) just add:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="co">After</span> <span class="r">do</span><tt> </tt><span class="r">end</span><tt> </tt></pre></td> </tr></table> <p>in <code>env.rb</code> file.</p> <p>With Capybara you are not limited to Selenium WebDriver. If you want to use Selenium RC you just need to configure it in <code>env.rb</code> file:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt>15<tt> </tt>16<tt> </tt>17<tt> </tt>18<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">require <span class="s"><span class="dl">'</span><span class="k">rbconfig</span><span class="dl">'</span></span><tt> </tt>require <span class="s"><span class="dl">'</span><span class="k">cucumber/formatter/unicode</span><span class="dl">'</span></span><tt> </tt><tt> </tt>require <span class="s"><span class="dl">'</span><span class="k">capybara</span><span class="dl">'</span></span><tt> </tt>require <span class="s"><span class="dl">'</span><span class="k">capybara/dsl</span><span class="dl">'</span></span><tt> </tt>require <span class="s"><span class="dl">&quot;</span><span class="k">capybara/cucumber</span><span class="dl">&quot;</span></span><tt> </tt><tt> </tt><span class="co">Capybara</span>.default_driver = <span class="sy">:selenium</span><tt> </tt><span class="co">Capybara</span>.app_host = <span class="s"><span class="dl">&quot;</span><span class="k">http://127.0.0.1:9000/</span><span class="dl">&quot;</span></span><tt> </tt><span class="co">Capybara</span>.register_driver <span class="sy">:selenium</span> <span class="r">do</span> |app|<tt> </tt> <span class="c"># This way we are using Selenium-RC</span><tt> </tt> <span class="co">Capybara</span>::<span class="co">Driver</span>::<span class="co">Selenium</span>.new(app,<tt> </tt> <span class="sy">:browser</span> =&gt; <span class="sy">:remote</span>,<tt> </tt> <span class="sy">:url</span> =&gt; <span class="s"><span class="dl">&quot;</span><span class="k">http://127.0.0.1:4444/wd/hub</span><span class="dl">&quot;</span></span>,<tt> </tt> <span class="sy">:desired_capabilities</span> =&gt; <span class="sy">:internet_explorer</span>)<tt> </tt><span class="r">end</span><tt> </tt><tt> </tt>World(<span class="co">Capybara</span>)<tt> </tt></pre></td> </tr></table> <h2>Conclusion</h2> <p>Both gems for running Selenium as a base for functional tests &#8211; Webrat and Capybara are easy to use. Although Webrat needs more patching to work under Windows it has one advantage. It can be used with <a href="http://mechanize.rubyforge.org/mechanize/">Mechanize</a> if you do not need real browser and you still want to test non Rails application. But as much as it is advantage for &#8220;classic&#8221; Web application Mechanize cannot interpret JavaScript. So if you want to include JavaScript testing you either have to use real browser or switch to Capybara.</p> <p>Capybara, on the other hand, needs significantly less patching on MS Windows systems and it cannot use Mechanize as far as I know. But, from my point of view, it is easier to use then Webrat. Currently it cannot use Mechanize, but it can use <a href="http://github.com/langalex/culerity/">Culerity</a> and <a href="http://celerity.rubyforge.org/">Celerity</a> for JavaScript testing. Moreover <a href="http://github.com/smparkes/capybara-envjs">capybara-envjs driver</a> can be used to interpret JavaScript outside of the browser.</p> <p>Although I&#8217;m still not sure which one is better to use, I switched from Webrat to Capybara and I think that tests that use Selenium WebDriver are running faster. There is an <a href="http://groups.google.com/group/ruby-capybara/browse_thread/thread/4bcc26a9cfa20ef2">initiative for merging</a> these projects into one but I do not know if it will happen and when. I would like to hear what you think. What is your choice: Webrat or Capybara?</p> tag:pragdevnotes.com,2008:Post/14 2010-10-03T13:33:56Z 2010-10-03T20:31:26Z ActiveRecord SchemaDumper and MySQL problem <p>After finishing first version of <a href="http://github.com/bosko/rmre">Rmre</a> and issuing fix gem dependency in version 0.0.2, I got an idea for additional functionality. Why not use Rmre for dumping complete schema with all foreign keys data? What would be possible scenario for using this, one might ask? We have possibility to create ActiveRecord models in order to move to Ruby on Rails where main premise is to keep logic out of database and maintain it in application. Therefore we do not need foreign keys since we already have constraints defined in models.</p> <p>But what if you cannot move to Ruby on Rails and you only have to change <span class="caps">DBE</span>, i.e. instead of MS <span class="caps">SQL</span> you must use Oracle? In that case you still have to work with legacy database from <span class="caps">PHP</span> or Hibernate in Java and &#8220;<em>only</em>&#8221; thing you have to do is to make create script for all tables but for another <span class="caps">DBE</span>. When database has hundreds of tables with lots of relations this can turn into nightmare, especially if you have to maintain both versions.</p> <p>Rmre should simplify this. First you use Rmre to dump schema to some file and later you can use ActiveRecord&#8217;s capabilities to load it on different <span class="caps">DBE</span>. Since loading schema in ActiveRecord is <span class="caps">DBE</span> agnostic it should correctly create tables, indices and foreign keys on any database engine. That&#8217;s theory and, as usual, practice is a little bit different. On a very first step I&#8217;ve faced problem in MySQL database.</p> <p>Let&#8217;s examine database with just a two tables &#8211; <code>city</code> and <code>country</code>. Create script would look like (example from <a href="http://dev.mysql.com/doc/sakila/en/sakila.html">Sakila</a> database):</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt>15<tt> </tt>16<tt> </tt>17<tt> </tt>18<tt> </tt>19<tt> </tt><strong>20</strong><tt> </tt>21<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">CREATE</span> <span class="r">TABLE</span> <span class="">city</span> (<tt> </tt> <span class="">city_id</span> <span class="pt">SMALLINT</span> <span class="pt">UNSIGNED</span> <span class="r">NOT</span> <span class="pc">NULL</span> <span class="di">AUTO_INCREMENT</span>,<tt> </tt> <span class="">city</span> <span class="pt">VARCHAR</span>(<span class="i">50</span>) <span class="r">NOT</span> <span class="pc">NULL</span>,<tt> </tt> <span class="">country_id</span> <span class="pt">SMALLINT</span> <span class="pt">UNSIGNED</span> <span class="r">NOT</span> <span class="pc">NULL</span>,<tt> </tt> <span class="">last_update</span> <span class="pt">TIMESTAMP</span> <span class="r">NOT</span> <span class="pc">NULL</span> <span class="di">DEFAULT</span> <tt> </tt> <span class="">CURRENT_TIMESTAMP</span> <span class="r">ON</span> <span class="r">UPDATE</span> <span class="">CURRENT_TIMESTAMP</span>,<tt> </tt> <span class="r">PRIMARY</span> <span class="r">KEY</span> (<span class="">city_id</span>),<tt> </tt> <span class="r">KEY</span> <span class="">idx_fk_country_id</span> (<span class="">country_id</span>),<tt> </tt> <span class="">CONSTRAINT</span> <span class="s"><span class="dl">`</span><span class="k">fk_city_country</span><span class="dl">`</span></span> <tt> </tt> <span class="">FOREIGN</span> <span class="r">KEY</span> (<span class="">country_id</span>)<tt> </tt> <span class="">REFERENCES</span> <span class="">country</span> (<span class="">country_id</span>)<tt> </tt> <span class="r">ON</span> <span class="r">DELETE</span> <span class="">RESTRICT</span> <span class="r">ON</span> <span class="r">UPDATE</span> <span class="">CASCADE</span><tt> </tt>) <span class="r">ENGINE</span>=<span class="">InnoDB</span> <span class="di">DEFAULT</span> <span class="di">CHARSET</span>=<span class="">utf8</span>;<tt> </tt><tt> </tt><span class="r">CREATE</span> <span class="r">TABLE</span> <span class="">country</span> (<tt> </tt> <span class="">country_id</span> <span class="pt">SMALLINT</span> <span class="pt">UNSIGNED</span> <span class="r">NOT</span> <span class="pc">NULL</span> <span class="di">AUTO_INCREMENT</span>,<tt> </tt> <span class="">country</span> <span class="pt">VARCHAR</span>(<span class="i">50</span>) <span class="r">NOT</span> <span class="pc">NULL</span>,<tt> </tt> <span class="">last_update</span> <span class="pt">TIMESTAMP</span> <span class="r">NOT</span> <span class="pc">NULL</span> <span class="di">DEFAULT</span> <span class="">CURRENT_TIMESTAMP</span><tt> </tt> <span class="r">ON</span> <span class="r">UPDATE</span> <span class="">CURRENT_TIMESTAMP</span>,<tt> </tt> <span class="r">PRIMARY</span> <span class="r">KEY</span> (<span class="">country_id</span>)<tt> </tt>) <span class="r">ENGINE</span>=<span class="">InnoDB</span> <span class="di">DEFAULT</span> <span class="di">CHARSET</span>=<span class="">utf8</span>;<tt> </tt></pre></td> </tr></table> <p>As can be seen from above script table <code>city</code> has foreign key on table <code>country</code>. Now let&#8217;s see what is result of a dump:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt>15<tt> </tt>16<tt> </tt>17<tt> </tt>18<tt> </tt>19<tt> </tt><strong>20</strong><tt> </tt>21<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="co">ActiveRecord</span>::<span class="co">Schema</span>.define(<span class="sy">:version</span> =&gt; <span class="i">0</span>) <span class="r">do</span><tt> </tt><tt> </tt> create_table <span class="s"><span class="dl">&quot;</span><span class="k">actor</span><span class="dl">&quot;</span></span>, <span class="sy">:primary_key</span> =&gt; <span class="s"><span class="dl">&quot;</span><span class="k">actor_id</span><span class="dl">&quot;</span></span>, <span class="sy">:force</span> =&gt; <span class="pc">true</span> <span class="r">do</span> |t|<tt> </tt> create_table <span class="s"><span class="dl">&quot;</span><span class="k">city</span><span class="dl">&quot;</span></span>, <span class="sy">:primary_key</span> =&gt; <span class="s"><span class="dl">&quot;</span><span class="k">city_id</span><span class="dl">&quot;</span></span>, <span class="sy">:force</span> =&gt; <span class="pc">true</span> <span class="r">do</span> |t|<tt> </tt> t.string <span class="s"><span class="dl">&quot;</span><span class="k">city</span><span class="dl">&quot;</span></span>, <span class="sy">:limit</span> =&gt; <span class="i">50</span>, <span class="sy">:null</span> =&gt; <span class="pc">false</span><tt> </tt> t.integer <span class="s"><span class="dl">&quot;</span><span class="k">country_id</span><span class="dl">&quot;</span></span>, <span class="sy">:limit</span> =&gt; <span class="i">2</span>, <span class="sy">:null</span> =&gt; <span class="pc">false</span><tt> </tt> t.timestamp <span class="s"><span class="dl">&quot;</span><span class="k">last_update</span><span class="dl">&quot;</span></span>, <span class="sy">:null</span> =&gt; <span class="pc">false</span><tt> </tt> <span class="r">end</span><tt> </tt><tt> </tt> add_index <span class="s"><span class="dl">&quot;</span><span class="k">city</span><span class="dl">&quot;</span></span>, [<span class="s"><span class="dl">&quot;</span><span class="k">country_id</span><span class="dl">&quot;</span></span>], <span class="sy">:name</span> =&gt; <span class="s"><span class="dl">&quot;</span><span class="k">idx_fk_country_id</span><span class="dl">&quot;</span></span><tt> </tt><tt> </tt> create_table <span class="s"><span class="dl">&quot;</span><span class="k">country</span><span class="dl">&quot;</span></span>, <span class="sy">:primary_key</span> =&gt; <span class="s"><span class="dl">&quot;</span><span class="k">country_id</span><span class="dl">&quot;</span></span>, <span class="sy">:force</span> =&gt; <span class="pc">true</span> <span class="r">do</span> |t|<tt> </tt> t.string <span class="s"><span class="dl">&quot;</span><span class="k">country</span><span class="dl">&quot;</span></span>, <span class="sy">:limit</span> =&gt; <span class="i">50</span>, <span class="sy">:null</span> =&gt; <span class="pc">false</span><tt> </tt> t.timestamp <span class="s"><span class="dl">&quot;</span><span class="k">last_update</span><span class="dl">&quot;</span></span>, <span class="sy">:null</span> =&gt; <span class="pc">false</span><tt> </tt> <span class="r">end</span><tt> </tt> <tt> </tt> execute <span class="s"><span class="dl">&quot;</span><span class="k">ALTER TABLE city<tt> </tt> ADD CONSTRAINT fk_city_country<tt> </tt> FOREIGN KEY (country_id)<tt> </tt> REFERENCES country(country_id)</span><span class="dl">&quot;</span></span><tt> </tt><span class="r">end</span><tt> </tt></pre></td> </tr></table> <p>At the first glance this looks good but unfortunately doesn&#8217;t work. Problem is that loading this schema through ActiveRecord will create columns <code>city_id</code> in table <code>city</code> and <code>country_id</code> in table <code>country</code> as <code>integer</code> type but column <code>country_id</code> in table <code>city</code> is created as <code>smallint</code>. Defining constraint on columns which are not of same type is not allowed so last statement for altering table fails. At the moment I have no idea how to fix this and any suggestion is very welcome. I still have to check what happens on other DBEs: PostgreSQL, Oracle and MS <span class="caps">SQL</span>.</p> tag:pragdevnotes.com,2008:Post/13 2010-09-30T13:50:23Z 2010-09-30T20:50:23Z RMRE - rails models reverse engineering gem <p>Very often I have to work on databases which do not follow ActiveRecord convention and making ActiveRecord models, if number of tables is large, is very slow and boring task. In order to speed up and simplify it I&#8217;ve created <a href="http://github.com/bosko/rmre">Rmre gem</a>. Gem is quite simple yet you might find it useful if you want to create fixtures, migrations or simply port application to Ruby on Rails.</p> <p>So how it works? For each table in the database, gem creates model. Name of the model is created using Rails <code>classify</code> method. Moreover, if table&#8217;s primary key is not column named &#8220;id&#8221; gem sets primary key by adding <code>set_primary_key "primaryKeyColumnName"</code> line to the model. In addition for MySQL, PostgreSQL, Oracle or MS <span class="caps">SQL</span> foreign keys are analyzed and for each constraint gem generates <code>belongs_to</code> or <code>has_many</code> lines. Here is model created for table <em>store</em> in <a href="http://dev.mysql.com/doc/sakila/en/sakila.html">Sakila</a> MySQL test database:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><span class="r">class</span> <span class="cl">Store</span> &lt; <span class="co">ActiveRecord</span>::<span class="co">Base</span><tt> </tt> set_primary_key <span class="sy">:store_id</span><tt> </tt> set_table_name <span class="s"><span class="dl">'</span><span class="k">store</span><span class="dl">'</span></span><tt> </tt> has_many <span class="sy">:customers</span>, <span class="sy">:class_name</span> =&gt; <span class="s"><span class="dl">'</span><span class="k">Customer</span><span class="dl">'</span></span><tt> </tt> has_many <span class="sy">:inventories</span>, <span class="sy">:class_name</span> =&gt; <span class="s"><span class="dl">'</span><span class="k">Inventory</span><span class="dl">'</span></span><tt> </tt> has_many <span class="sy">:staffs</span>, <span class="sy">:class_name</span> =&gt; <span class="s"><span class="dl">'</span><span class="k">Staff</span><span class="dl">'</span></span><tt> </tt> belongs_to <span class="sy">:address</span>, <span class="sy">:class_name</span> =&gt; <span class="s"><span class="dl">'</span><span class="k">Addres</span><span class="dl">'</span></span>, <span class="sy">:foreign_key</span> =&gt; <span class="sy">:address_id</span><tt> </tt> belongs_to <span class="sy">:staff</span>, <span class="sy">:class_name</span> =&gt; <span class="s"><span class="dl">'</span><span class="k">Staff</span><span class="dl">'</span></span>, <span class="sy">:foreign_key</span> =&gt; <span class="sy">:manager_staff_id</span><tt> </tt><span class="r">end</span><tt> </tt></pre></td> </tr></table> tag:pragdevnotes.com,2008:Post/12 2010-08-19T06:22:33Z 2010-08-19T13:20:38Z Ruby 1.9.2 on Windows - coming soon <p>I guess all Ruby and Windows users will be happy to hear that <a href="http://rubyinstaller.org/">RubyInstaller</a> team is about to release Ruby 1.9.2p0 very soon. See details in <a href="http://groups.google.com/group/rubyinstaller/browse_thread/thread/a9b1149f9ee77a72">this thread</a>. It will take some time to update documentation so be patient and keep an eye on the project home page.</p> tag:pragdevnotes.com,2008:Post/10 2010-02-18T22:34:00Z 2010-02-18T19:34:17Z Ruby, Rails and MS SQL server <p>Setting up Rails and Ruby to use MS <span class="caps">SQL</span> server was always painful task. Fortunately things have changed &#8211; a lot! With new <a href="http://github.com/rails-sqlserver/2000-2005-adapter">Rails <span class="caps">SQL</span> Server 2000, 2005 and 2008 Adapter</a> and Christian Werner&#8217;s <a href="http://www.ch-werner.de/rubyodbc">ruby-odbc gem</a> you can do it in a few minutes.</p> <p>If you want to use these gems on Windows grab Ruby installation from <a href="http://www.rubyinstaller.org">RubyInstaller</a> site and be sure to install <a href="http://rubyforge.org/frs/download.php/66888/devkit-3.4.5r3-20091110.7z">DevKit</a> prior to installing ruby-odbc.</p> <p>Versions of ruby-odbc before 0.9999 do not work on mingw based (RubyInstaller) Ruby. Luckily author was very fast and made new version very quickly after I sent him a patch. Thanks Christian!</p> <p>Both gems work well on Ruby 1.8.6 and 1.9.1 Ruby versions on Windows with old ActiveRecords, but I hope rails adapter will be ported to ActiveRecords 3 soon.</p> tag:pragdevnotes.com,2008:Post/9 2010-01-27T00:06:00Z 2010-01-26T21:06:37Z RStreamTuner in action <p>Friend of mine criticised me why I didn&#8217;t put some screenshots on <a href="http://github.com/bosko/rstreamtuner">project page</a>. Since I couldn&#8217;t find a way to do it there I&#8217;ve decided to put some screenshots here, so here they are.</p> <div id="gallery"> <ul> <li> <a href="/images/rst-screenshots/rst_xiph.png" title="RST Xiph plugin."> <img src="/images/rst-screenshots/rst_xiph_thumb.png" width="170" height="95" alt="" /> </a> </li> <li> <a href="/images/rst-screenshots/rst_search.png" title="RST SHOUTcast search in action."> <img src="/images/rst-screenshots/rst_search.png" width="170" height="95" alt="" /> </a> </li> <li> <a href="/images/rst-screenshots/rst_preferences.png" title="RST plugin preferences."> <img src="/images/rst-screenshots/rst_preferences.png" width="125" height="95" alt="" /> </a> </li> </ul> </div> tag:pragdevnotes.com,2008:Post/8 2010-01-22T13:51:01Z 2010-01-22T20:51:01Z RStreamTuner - new streaming directories browser <p>I like to listen various Internet radio stations while I work. My favourite application was <a href="http://www.nongnu.org/streamtuner">streamtuner</a> mostly because it had support for SHOUTcast. Unluckily new SHOUTcast design cannot be handled by <strong>streamtuner</strong> and future development on this application is stopped. In other words there is a little chance for streamtuner to be upgraded so I&#8217;ve decided to make my own streaming directories browser &#8211; <a href="http://github.com/bosko/rstreamtuner" title="Ruby Stream Tuner">RStreamTuner</a>.</p> <p>As usual developing in Ruby was real pleasure and only doubt was what to use for <span class="caps">GUI</span> part. I&#8217;ve started with Ruby/Tk and left it very quickly due to very poor documentation (and probably lack of Tcl knowledge). I had to find replacement and my primary goal was to find library that works equally well on Linux and Windows. WxWidgets with WxRuby gem was my final choice. Although <strong>RStreamTuner</strong> is still in early development phase it is quite usable. At the moment it supports SHOUTcast and Xiph directories, but I plan to add more as soon as I find good one. Good candidate could be Live365 but they&#8217;ve made their pages quite hard to parse so I&#8217;ll probably leave it for later.</p> <p>Once I reach beta version, making support for new streaming directories will be quite easy and will require implementation of just a few methods. As a matter of act it is already so simple but I&#8217;m not satisfied with the code and will change it once I find a little bit more time. Code is quite rough (I had little time to make <strong>RStreamTuner</strong> and was eager to get working version as soon as possible). Besides I want to write detailed instructions how to add support for new directories. Anyway if you like to listen Internet radion stations and like Ruby clone <a href="http://github.com/bosko/rstreamtuner">RStreamTuner</a>. Of course if you have suggestions do not hasitate to drop me a note and if you make support for new streaming directory just send me a pull request and I&#8217;ll try to grab it as soon as possible.</p> tag:pragdevnotes.com,2008:Post/7 2010-01-22T13:49:24Z 2010-01-22T20:49:24Z No Rip on Windows <p>Unfortunately author of Rip has decided to completely leave MS Windows aside. For details you can see this <a href="http://groups.google.com/group/rip-rb/browse_thread/thread/41150e41fa3aa15e">thread</a></p> tag:pragdevnotes.com,2008:Post/6 2009-10-28T05:39:28Z 2009-10-28T11:39:28Z Rip for Windows <p>When I first found a post about <a href="http://hellorip.com/">Rip</a> I was eager to try it. Since most of the time I work on MS Windows platform it was natural to try it there, but Rip concept is Linux oriented and it couldn&#8217;t be installed and used on Windows. Going back to the old, good Linux gave me a feeling what Rip is and how it works, and I&#8217;ve decided to try to fix it as soon as I find some spare time. Additional motivation was a fact that <a href="http://rubyinstaller.org/">Ruby installer for windows</a> RC1 is about to be released and that&#8217;s one more project that I participate in, from time to time.</p> <p>So here it is. If you are willing to try Rip on Windows just <a href="http://pragdevnotes.com/rip-0.0.5.gem">download</a> gem and install it. Rip is in development alpha state, therefore this Windows version can be marked as development pre-alpha.</p> <p>Although Rip environments can be created, deleted and gems can be installed, there are features that do not work. Complete Windows specific code is on <a href="http://github.com/bosko/rip/tree/win-tmp">my fork on Github</a>. A reason why I wanted to put this version available so early is mostly the same as you can see on the Rip homepage &#8211; need for suggestions, ideas, patches and tests.</p> <p>Here comes short explanation of Windows specific part. Rip on Linux uses symbolic link that points to the active environment. Unfortunately such a feature is not available on Windows. Although on Vista and Windows 7 mklink can be used, this command requires administrative privileges. It can be disabled through Local Security Policy settings, but that would be too much work just to get Rip working on Windows. Therefore I&#8217;ve decided to alter environment variables when Rip environment is created or changed.</p> <p>This approach has its own drawbacks. If user has more command prompts opened at the same time and Rip environment is changed in one of them, this change will not be visible in others. Cause of this is in the way command prompt is implemented. Namely it doesn&#8217;t handle WM_SETTINGCHANGE broadcast message. I really do not understand why MS developers didn&#8217;t implement this.</p> <p>Main consequence of such command prompt implementation on Windows is that Rip has to change environment variables in two stages. First stage changes environment for command prompt where Rip command is executed. This change is done by calling batch file where variables are set. The second stage changes values in the registry. Variables are set in a user part of registry (HKEY_CURRENT_USER\Environment) and broadcast message is sent so other applications (such as Explorer) can update their environment which causes newly opened command prompts to pick up new environment.</p> <p>At the end what are problems you could expect if you install Rip. I haven&#8217;t tested all Rip commands mostly because I was focused on basic functionality &#8211; Rip installation, creating and switching between Rip environments and installing packages in active one. Most likely some of commands will fail. In addition gems that have to build shared libraries will fail even if you have <a href="http://www.rubyinstaller.org/addons.html">RubyInstaller DevKit</a> installed. Moreover even if gem has binaries built for mingw32, Rip will invoke build procedure and will report that gem is not correctly installed and you will not be able to uninstall it from Rip environment later. Actually such gem is installed and can be used. One such example is Luis Lavena&#8217;s <a href="http://github.com/luislavena/win32console">win32console</a> gem. Even if build fails and Rip reports that gem is not correctly installed all necessary files are actually present in Rip environment and you will be able to run <a href="http://github.com/luislavena/win32console/tree/master/test/">tests</a>.</p> <p>I&#8217;m still trying to find out how to determine whether gem needs to be built or it already has binaries. As soon as I find out this I&#8217;ll fix this part too. That&#8217;s all for now and happy Ripping.</p> tag:pragdevnotes.com,2008:Post/4 2009-06-04T07:22:25Z 2009-06-04T14:22:25Z Splitting Ruby Array <p>Recently I had to process arrays of data with more than thousand of members but requirement was not to process them one by one. Instead I had to split array into chunks and to process each of sub-arrays separately. I&#8217;ve found one definition of chunk method within comments on this <a href="http://snippets.dzone.com/posts/show/3486">post</a> and I&#8217;m including it here. This method splits array in given number of sub-arrays and I needed a version that will split array in the sub-arrays that have predefined size (ok, I know I could simply calculate a number of chunks by dividing total number of elements by required number of elements, but I just wanted one method that&#8217;ll do all that for me). So I wrote chunk_max_num method. If maximum number of elements per array is zero or negative it will return original array and for all other cases it will return array which has arrays of given size as members.</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt>15<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">require <span class="s"><span class="dl">'</span><span class="k">enumerator</span><span class="dl">'</span></span><tt> </tt><tt> </tt><span class="r">class</span> <span class="cl">Array</span><tt> </tt> <span class="r">def</span> <span class="fu">chunk_max_num</span>(max_num)<tt> </tt> <span class="r">return</span> slice(<span class="i">0</span>...length) <span class="r">unless</span> max_num &gt; <span class="i">0</span><tt> </tt> quot, mod = length.divmod(max_num)<tt> </tt> quot += <span class="i">1</span> <span class="r">if</span> mod &gt; <span class="i">0</span><tt> </tt> (<span class="i">0</span>..quot).map {|i| i*max_num}.enum_cons(<span class="i">2</span>).map {|a,b| slice(a...b)}<tt> </tt> <span class="r">end</span><tt> </tt> <tt> </tt> <span class="r">def</span> <span class="fu">chunk</span>(pieces)<tt> </tt> q,r = length.divmod(pieces)<tt> </tt> (<span class="i">0</span>..pieces).map {|i| i * q + [r,i].min}.enum_cons(<span class="i">2</span>).map {|a,b| slice(a...b)}<tt> </tt> <span class="r">end</span><tt> </tt><span class="r">end</span><tt> </tt></pre></td> </tr></table> tag:pragdevnotes.com,2008:Post/3 2009-05-20T03:35:54Z 2009-05-20T10:35:54Z Easy Emacs <h3>First step</h3> <p>In my <a href="http://pragmaticdevnotes.wordpress.com">previous articles</a> I wrote a lot about Emacs, its customization and adjusting it for Ruby and Ruby on Rails development. Although these articles give detailed instructions how to set everything up, following all steps are somewhat cumbersome and require quite a lot of work.</p> <p>Fortunately there is a solution. Just clone <a href="http://github.com/technomancy/emacs-starter-kit/tree/master">Emacs starter kit</a> from Github and you will be able to develop Ruby and RoR applications in Emacs in just a few simple steps. Emacs starter kit uses <a href="http://tromey.com/elpa/">Elpa</a> packaging and is very easy to configure. But let&#8217;s start from the beginning.</p> <p>Clone <a href="http://github.com/technomancy/emacs-starter-kit/tree/master">Emacs starter kit</a> with <a href="http://git-scm.com/">Git</a>, to your <strong>empty</strong> .emacs.d directory. Be sure that init.el file is in .emacs.d folder. If you do not use Git (do you realize what you are missing?) you can get archived sources if you press <em>download</em> button on Emacs starter kit page on Github. Unpack archive to the .emacs.d and be sure that init.el is in .emacs.d folder.</p> <p>Emacs starter kit has some packages that are still not in Elpa but you&#8217;ll have to install additional packages required for Ruby and RoR. Let&#8217;s do it now:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">M-x package-list-packages<tt> </tt></pre></td> </tr></table> <p>New buffer with list of available packages will open and you can select those you want to install. If you plan to use Emacs for Ruby and RoR you&#8217;ll definitely need <em>Rinari</em>. It will install all dependent packages.</p> <p>There are few other that might come in handy like css-mode, javascript or yasnippet but you can always add them later. If you install yasnippet you should probably need <a href="http://github.com/eschulte/yasnippets-rails/tree/master">yasnippets-rails</a>, but more about that later. Installing packages is very easy. Just place cursor on the package line and press &#8216;i&#8217;. When you are finished with selection press &#8216;x&#8217; and packages will be installed. At any time you can press &#8216;h&#8217; to get quick help for Elpa packaging system. In order to uninstall package you have to press &#8216;d&#8217; (and &#8216;x&#8217; after that).</p> <h3>Further customization</h3> <p>When you are done with packages installation just restart Emacs and you are ready to continue work in your favorite language &#8211; Ruby and framework &#8211; Ruby on Rails :) But what if you want to adjust some settings or keep some of those you set according to my previous articles? Luckily that is easy to do, too.</p> <p>First create sub-directory in .emacs.d directory with your user name on the system you are using. Put your .el files there and Emacs starter kit will load them automatically during Emacs start up. If you have changed color theme and you&#8217;ve used theme from color-theme library put color-theme-library.el in this folder and add, for example, line</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">(color-theme-deep-blue)<tt> </tt></pre></td> </tr></table> <p>to any of .el files in this folder. I keep all my additional settings in customization.el file.</p> <p>I already mentioned yasnippet and yasnippets-rails packages. Simplest way to install yasnippet library is from Elpa system following above mentioned procedure. Unfortunately yasnippets-rails cannot be installed that way so you should clone it from the Github:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">git clone git://github.com/eschulte/yasnippets-rails.git<tt> </tt></pre></td> </tr></table> <p>Directory yasnippets-rails should be in the directory with your user name under .emacs.d. Add following lines to your customization.el file:</p><table class="CodeRay"><tr> <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre>1<tt> </tt>2<tt> </tt>3<tt> </tt>4<tt> </tt>5<tt> </tt>6<tt> </tt>7<tt> </tt>8<tt> </tt>9<tt> </tt><strong>10</strong><tt> </tt>11<tt> </tt>12<tt> </tt>13<tt> </tt>14<tt> </tt>15<tt> </tt>16<tt> </tt>17<tt> </tt>18<tt> </tt>19<tt> </tt><strong>20</strong><tt> </tt>21<tt> </tt></pre></td> <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }">(add-to-list 'load-path <tt> </tt> (concat dotfiles-dir &quot;/&lt;user-name&gt;/yasnippets-rails&quot;))<tt> </tt><tt> </tt>(add-hook 'ruby-mode-hook ; or rails-minor-mode-hook ?<tt> </tt> '(lambda ()<tt> </tt> (make-variable-buffer-local 'yas/trigger-key)<tt> </tt> (setq yas/trigger-key [tab])))<tt> </tt><tt> </tt>(require 'yasnippet)<tt> </tt>(add-to-list 'yas/extra-mode-hooks<tt> </tt> 'ruby-mode-hook)<tt> </tt><tt> </tt>(yas/initialize)<tt> </tt>(setq yas/window-system-popup-function 'yas/x-popup-menu-for-template)<tt> </tt>(yas/load-directory (concat dotfiles-dir &quot;/&lt;user-name&gt;/yasnippet/snippets&quot;))<tt> </tt><tt> </tt>(yas/load-directory <tt> </tt> (concat <tt> </tt> dotfiles-dir &quot;/&lt;user-name&gt;/yasnippets-rails/rails-snippets/&quot;))<tt> </tt><tt> </tt>(make-variable-buffer-local 'yas/trigger-key)<tt> </tt></pre></td> </tr></table> <p>and you will be ready for using new snippets during development.</p> <h3>Final word</h3> <p>My previous articles were based on Rails reloaded package for RoR development in Emacs. It is good library and if you like fancy <span class="caps">GUI</span> things you can still use it. There is a <a href="http://github.com/dima-exe/emacs-rails-reloaded/tree/master">new version</a> on Github.</p> <p>Still, I would recommend trying Rinari that is a package from Elpa. It doesn&#8217;t have any <span class="caps">GUI</span> features but once your fingers &#8220;learn&#8221; all shortcuts your RoR development will be much easier and faster.</p> tag:pragdevnotes.com,2008:Post/2 2009-05-19T07:18:00Z 2009-05-19T10:18:04Z PDN powered by RoR <p>It has been a few months since my last post on the old <a href="http://pragmaticdevnotes.wordpress.com">blog</a> powered by <a href="http://www.wordpress.org">Wordpress</a>. All this time I was searching for a blog engine made in <a href="http://www.rubyonrails.org">Ruby on Rails</a>. It was not easy to decide what to use. I&#8217;ve tested <a href="http://www.mephistoblog.com">Mephisto</a>, <a href="http://wiki.github.com/fdv/typo">Typo</a>, <a href="http://radiantcms.org/">Radiant</a>, <a href="http://simplelog.net/">Simplelog</a> and several others I cannot remember now. All of them really have a lot of features, but for my needs they are way too complex. What I was searching for is some simple application that I can easily tweak and adjust to my needs. I was about to move to <a href="http://www.mephistoblog.com">Mephisto</a> or <a href="http://simplelog.net/">Simplelog</a> when I found <a href="http://www.enkiblog.com">Enki</a>.</p> <p>As soon as I&#8217;ve looked into the code I knew that it is the <em>one</em>. Simple, lightweight blogging engine without fancy stuff that I&#8217;ll rarely use, yet with all features I need for my own blog. Moreover <a href="http://github.com/xaviershay/enki/tree">Enki&#8217;s source</a> is on Github and it was easy to make a fork and start to work on my own version. So I did it. I must say it can be used just as it is, but I wanted to give it a new &#8220;look and feel&#8221;, so I&#8217;ve started with changes on a style sheet and didn&#8217;t stop there.</p> <p>Enki handles comments in a very flexible way. In order to post a comment only name and text of a comment must be filled. On the other hand, if commenter wants to give a little bit more data he can use <a href="http://openidexplained.com/">OpenID</a> authentication. Nowadays with all those spammers around, this was not good enough for me. I didn&#8217;t want blog overloaded with bunch of stupid messages so I&#8217;ve decided to change comments handling a little bit.</p> <p>There are lot of ways to protect a blog from spam. You can forbid posting comment without authorization. That way everyone must register before he is allowed to post a comment. That&#8217;s too much work for commenter and, frankly speaking, for me too. I wanted to make commenting as simple as possible, still under decent level of control. In order to accomplish it I could use <a href="http://http://recaptcha.net/">reCAPTCHA</a> or <a href="http://akismet.com/">Akismet</a>. Both of them are quite good, but I&#8217;ve decided to use Akismet. It leaves commenter same level of simplicity as in the original Enki source but every comment must pass spam filter. So I&#8217;ve dropped OpenID authentication, downloaded <a href="http://soakedandsoaped.com/files/akismet.rb">akismet.rb</a>, adjusted comments controller and fixed tests. It was quite simple and easy.</p> <p>And here it is up and running.</p> <p>Finally few thoughts about Enki. Although it can be used out of the box, I think very few users will actually install it that way. But if you are RoR fan, and you like to work in Ruby and Ruby on Rails this is the right choice for you. Code is readable and easy to change. It is not over-engineered except in one part &#8211; gems. Enki requires cucumber which, on the other hand, requires rspec, rspec-rails, webrat and, optionally, term-ansicolor, nokogiri, builder and few others. For my mind it is a little overhead for such a simple project, but it is definitely neglectable comparing to other good sides of Enki. Lack of support for images uploading might be a limitation in Enki&#8217;s usability, but author wanted to keep it simple so this shouldn&#8217;t stop you from using it. At the end if you like Ruby on Rails it will be a fun implementing support for it, isn&#8217;t it? Go ahead, grab <a href="http://github.com/technoweenie/attachment_fu/tree/master">attachment_fu</a> or <a href="http://www.thoughtbot.com/projects/paperclip">paperclip</a> and do it.</p>