<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>The Rubylution</title>
    <link>http://rubylution.ping.de/</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Starts&amp;hellip; Now.</description>
    <item>
      <title>Y-combinator in Ruby with REAL &amp;amp;lambda;!</title>
      <description>&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="comment"&gt;#!/usr/bin/ruby -KU&lt;/span&gt;
&lt;span class="comment"&gt;# -*- coding: utf-8 -*- &lt;/span&gt;

&lt;span class="comment"&gt;# Do &amp;quot;:imap &amp;lt;C-l&amp;gt; &amp;lt;C-k&amp;gt;l*&amp;quot; in vim&lt;/span&gt;

&lt;span class="keyword"&gt;alias&lt;/span&gt; λ &lt;span class="ident"&gt;lambda&lt;/span&gt;

&lt;span class="constant"&gt;Y&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; λ&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  λ&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;}[&lt;/span&gt;
    λ&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;
      λ&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt; &lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt; &lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;

&lt;span class="constant"&gt;Y&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt; λ&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; λ&lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;n&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt; &lt;span class="punct"&gt;:&lt;/span&gt; &lt;span class="ident"&gt;n&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt; &lt;span class="ident"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt; &lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 3628800&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And they say reading ruby-core doesn't pay off! :-)&lt;/p&gt;</description>
      <pubDate>Mon, 08 Oct 2007 19:02:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:66aaf1f9-0b99-4266-8aec-e47b884cdcc9</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/10/08/y-combinator-in-ruby-with-real-lambda</link>
      <category>ruby</category>
      <category>humour</category>
      <category>programming</category>
    </item>
    <item>
      <title>Open Containing Folder in Firefox under Linux</title>
      <description>&lt;p&gt;After Downloading a file in firefox and right-clicking on the filename in the download manager, you can choose the popup menu entry "Open Containing Folder". This should open a filebrowser for the directory this file was saved in. I have to admit, that this never worked for me under Linux, only under MacOS X and under Windows. I assume the reason for this is, that you have a lot of options under Linux, but no general default for a file manager. Firefox did never show a very smart reaction (and only displays an error) if no filebrowser could be found: Perhaps asking me what to do would be a good idea?&lt;/p&gt;

&lt;p&gt;I finally couldn't take it anymore and researched how to configure this feature. I wanted XFCE4's file manager Thunar to be opened, so this is what you have to do: Open the about:config dialog in you location toolbar (or pick it from the Help menu). Now right click onto the configuration entry list, and choose &lt;em&gt;New -&gt; Boolean&lt;/em&gt; from the popup menu. Create the following two entries and set them both to &lt;tt&gt;true&lt;/tt&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
network.protocol-handler.expose.file = true (Boolean)
network.protocol-handler.external.file = true (Boolean)
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now choose &lt;em&gt;New -&gt; String&lt;/em&gt; from the popup menu, and set the value to &lt;tt&gt;thunar&lt;/tt&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;
network.protocol-handler.app.file = thunar (String)
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will start thunar with containing directory (with a file:// url) as an argument. You can as well use nautilus or konqueror or  whatever here. Another possibility is to use &lt;tt&gt;open&lt;/tt&gt;, which would cause firefox itself to open the directory as a file:// url.&lt;/p&gt;

&lt;p&gt;Now type &lt;tt&gt;network.protocol-handler&lt;/tt&gt; into the about:config filter. The resulting filtered list should now include these entries:&lt;/p&gt;

&lt;p&gt;&lt;img src="/files/open-containing-folder.png" alt="Configuration Entries in about:config"/&gt;&lt;/p&gt;

&lt;p&gt;Now try it with a downloaded file, I hope it works for you.&lt;/p&gt;</description>
      <pubDate>Tue, 11 Sep 2007 21:09:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:bb4fdf5f-1ea0-46f9-835a-bb92d3beb063</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/09/11/open-containing-folder-in-firefox-under-linux</link>
      <category>xfce</category>
      <category>linux</category>
      <category>gentoo</category>
      <category>firefox</category>
      <category>xfce4</category>
      <enclosure type="image/png" length="78667" url="http://rubylution.ping.de/files/open-containing-folder.png"/>
    </item>
    <item>
      <title>Automatically changing Background Wallpaper in XFCE4</title>
      <description>&lt;p&gt;I recently switched from the good, old trusty &lt;a href="http://www.windowmaker.info/"&gt;WindowMaker&lt;/a&gt; to &lt;a href="http://www.xfce.org/"&gt;XFCE4&lt;/a&gt; as a window manager/desktop environment.&lt;/p&gt;

&lt;p&gt;Before the switch I used &lt;code&gt;xsetbg&lt;/code&gt; in the crontab to change my background from the standard wallpaper of my theme to another image every hour. Now I configured Desktop Preferences -&gt; Image -&gt; New list to create a list of desktop images to choose from. But how to swtich every hour or at all? &lt;code&gt;xsetbg&lt;/code&gt; stopped to work under XFCE4 for some reason. It's also strange, that you can configure a list in XFCE4, but it is only used once after login in.&lt;/p&gt;

&lt;h5&gt;The solution&lt;/h5&gt;

&lt;p&gt;Put this line into your crontab:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;0 * * * * killall -USR1 xfdesktop&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will reload xfdesktop's configuration and also switch to a new backdrop image. Yeah, it's that easy, but it took me a while to figure it out.&lt;/p&gt;

&lt;p&gt;There is also the &lt;code&gt;xfdesktop -reload&lt;/code&gt; command, but I had some problems to connect to the X server from the crond. Maybe this is caused by my paranoid X configuration, though.&lt;/p&gt;</description>
      <pubDate>Fri, 31 Aug 2007 15:41:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:9b74bf41-071f-4aab-a4eb-30a67f6ac060</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/08/31/automatically-changing-background-wallpaper-in-xfce4</link>
      <category>xfce</category>
      <category>xfce4</category>
      <category>linux</category>
      <category>gentoo</category>
    </item>
    <item>
      <title>Ruby's Operator Precedence: More subtle than you might think</title>
      <description>&lt;p&gt;I just read Rick DeNatale's article about &lt;a href="http://talklikeaduck.denhaven2.com/articles/2007/08/07/ahh-the-subtleties-of-rubys-operator-precedence"&gt;Ruby's Operator Precedence&lt;/a&gt;, in which he mentioned, that Ruby's &lt;i&gt;and&lt;/i&gt; and &lt;i&gt;or&lt;/i&gt; operators have a weaker precedence than &lt;i&gt;&amp;amp;&amp;amp;&lt;/i&gt; and &lt;i&gt;||&lt;/i&gt; (and also weaker than =). This is similar to Perl's &lt;i&gt;and&lt;/i&gt; and &lt;i&gt;or&lt;/i&gt; operators, and the reason why I use the following rules of thumb for the use of the different operators in both languages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use &lt;i&gt;&amp;amp;&amp;amp;&lt;/i&gt; and &lt;i&gt;||&lt;/i&gt; for expressions (especially more complex ones) like &lt;code&gt;a = a &amp;amp;&amp;amp; b || c&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Use &lt;i&gt;and&lt;/i&gt; and &lt;i&gt;or&lt;/i&gt; instead of
&lt;code&gt;if enabled then do_it end&lt;/code&gt; or &lt;code&gt;do_it if enabled&lt;/code&gt; as in &lt;code&gt;enabled and do_it&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Or use &lt;i&gt;and&lt;/i&gt; and &lt;i&gt;or&lt;/i&gt; for very simple expressions as in &lt;code&gt;if a and b then ... end&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Rule 3 exists only, because I think it is slightly more readable to use &lt;i&gt;and&lt;/i&gt; or &lt;i&gt;or&lt;/i&gt; than &lt;i&gt;&amp;amp;&amp;amp;&lt;/i&gt; and &lt;i&gt;||&lt;/i&gt;. This advantage goes pretty much away if you have to start using parentheses to render more complex expressions unambiguous. It could as well be dropped.&lt;/p&gt;

&lt;p&gt;But in Ruby other than in Perl there is another reason for rule 3:&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Ruby's &lt;i&gt;and&lt;/i&gt; and &lt;i&gt;or&lt;/i&gt; operators have the SAME precedence!&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Yeah, you read this right: So, for example, &lt;code&gt;true || true &amp;amp;&amp;amp; false # =&gt; true&lt;/code&gt;,
but &lt;code&gt;true or true and false # =&gt; false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a rather surprising (as in unfortunate) peculiarity of Ruby, and I do not think, that it is a good idea. I guess most people are unaware of this issue, and their code does only work by accident - until it stops doing so for unknown reasons. Matz' rationalisation of this behaviour (somewhere on ruby-talk) was "'and' and 'or' don't have different precedence in English either." It didn't convince me then and doesn't convince me now: We don't program in English, because it is too unprecise. Why burden Ruby with the same problem as well?&lt;/p&gt;</description>
      <pubDate>Wed, 08 Aug 2007 12:25:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:713b0947-e082-447a-bcf5-39c296cc2c83</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/08/08/rubys-operator-precedence-more-subtle-than-you-might-think</link>
      <category>ruby</category>
      <category>perl</category>
    </item>
    <item>
      <title>Feeling at home in Ruby (if you're coming from C)</title>
      <description>&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Fixnum&lt;/span&gt;
  &lt;span class="keyword"&gt;alias&lt;/span&gt; &lt;span class="ident"&gt;__oldref&lt;/span&gt; &lt;span class="punct"&gt;:[]&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;[]&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;obj&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="constant"&gt;Fixnum&lt;/span&gt; &lt;span class="punct"&gt;===&lt;/span&gt; &lt;span class="ident"&gt;obj&lt;/span&gt;
      &lt;span class="ident"&gt;__oldref&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;obj&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="keyword"&gt;else&lt;/span&gt;
      &lt;span class="ident"&gt;obj&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="global"&gt;$0&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="constant"&gt;__FILE__&lt;/span&gt;
  &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 0&lt;/span&gt;
  &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 1&lt;/span&gt;
  &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;7&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;11&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
  &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 5&lt;/span&gt;
  &lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; 5&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 04 Aug 2007 00:13:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:d8234e94-4675-43f3-8bf2-ef272096ceba</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/08/04/feeling-at-home-in-ruby-if-youre-coming-from-c</link>
      <category>ruby</category>
      <category>c</category>
      <category>humour</category>
      <category>programming</category>
    </item>
    <item>
      <title>Bash reacting very sloooow to every command on Windows/Cygwin</title>
      <description>&lt;p&gt;I have just installed an openssh server with &lt;a href="http://www.cygwin.com/"&gt;Cygwin&lt;/a&gt; on my Windows XP, in order to be able to login from some other machine. I followed the following
&lt;a href="http://pigtail.net/LRP/printsrv/cygwin-sshd.html"&gt;tutorial&lt;/a&gt; to configure the service. I was pleasantly surprised, that after mounting my home directory on the mountpoint /home/flori via a smb share, the bash correctly parsed my .bashrc and .bash_profile files in my $HOME.&lt;/p&gt;

&lt;p&gt;Unfortunately after doing this the bash paused for a rather long time after every command I entered. I first suspected some strange DNS timeout to occur, but that wasn't it. Then I noticed that the smbd on my file server was quite busy during all the pauses. I straced the smbd, while this was happening, and figured out the cause of bash's slow response time: The bash tried to check if new mail had arrived in my $MAIL repository to out output the usal "new mail has arrived" message!&lt;/p&gt;

&lt;p&gt;MAIL was set to $HOME/Maildir and the bash searched through my inbox after every command. This is usually unnoticeable under Unixen (be it via NFS or on a local file system), but the smb share took quite some time (many seconds) to do it. This was aggravated by the fact, that the Cygwin bash didn't set MAILCHECK to 60 seconds or more, which caused the delay after &lt;em&gt;every&lt;/em&gt; command. As a simple and radical remedy I just unset the MAIL environment variable, because I never cared much for the new mail message anyway.&lt;/p&gt;</description>
      <pubDate>Wed, 04 Jul 2007 13:57:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:bbd624d1-aba7-450d-8f06-95099303ff57</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/07/04/bash-reacting-very-sloooow-to-every-command-on-windows-cygwin</link>
      <category>windows</category>
      <category>cygwin</category>
      <category>linux</category>
    </item>
    <item>
      <title>Rail On Rails</title>
      <description>&lt;p&gt;I just found this &lt;a href="http://esoteric.voxelperfect.net/wiki/Rail"&gt;link to the rail  programming language &lt;/a&gt;in &lt;a href="http://www.rubyist.net/~matz/20070529.html#p05"&gt;matz' blog&lt;/a&gt;. It has a rather beautiful layout as you can see in the following implementation of the Ackermann function:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_default "&gt;$ 'main' (--)
 \  Read m and n as input. Just one number each for now
  \  Input is in the form &amp;quot;m\rn&amp;quot; where \r is a return character
   \-[Enter m: ]oi(!m!)[\n\]o-[Enter n: ]oii(!n!)[\n\]o-----(n)-(m)-{ackermann}-[): ](n)[,](m)[A(]oooooo--#


$ 'ackermann' (n m -- A(m,n))  A(m,n) = n+1             if m=0
 \                                    = A(m-1,1)        if m&amp;gt;0 and n=0
  \                                   = A(m-1,A(m,n-1)) if m&amp;gt;0 and n&amp;gt;0
   \-(!m!)-(!n!)-\
                 | 
                 /
      /---q(m)0--     
      |
     t^f        f/-(n)1s-(m)-{ackermann}-(m)1s-{ackermann}-#  
     / \-(n)0q--&amp;lt;
     |          t\-1-(m)1s-{ackermann}-#
     \-(n)1a-#&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yeah, it's an esoteric language. Matz sure doesn't joke when he says, that he's a programming language geek. I wonder when the rail hackers will start to code a web framework and call it &lt;strong&gt;Rail On Rails&lt;/strong&gt;?&lt;/p&gt;</description>
      <pubDate>Thu, 07 Jun 2007 01:47:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:50faba4b-1dbb-4c19-8b6d-19d83306d9be</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/06/07/rail-on-rails</link>
      <category>ruby</category>
      <category>humour</category>
      <category>programming</category>
      <category>language</category>
    </item>
    <item>
      <title>Cache as a proxy object</title>
      <description>&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Cache&lt;/span&gt;
  &lt;span class="ident"&gt;instance_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;id&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;&lt;span class="escape"&gt;\A&lt;/span&gt;__&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="keyword"&gt;or&lt;/span&gt; &lt;span class="ident"&gt;undef_method&lt;/span&gt; &lt;span class="ident"&gt;id&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;

  &lt;span class="comment"&gt;# Caches data returned by block, for _duration_ seconds.&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;duration&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;3600&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;block&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@duration&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;duration&lt;/span&gt;
    &lt;span class="attribute"&gt;@block&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;block&lt;/span&gt;
    &lt;span class="ident"&gt;fetch_data&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;fetch_data&lt;/span&gt;
    &lt;span class="attribute"&gt;@data&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="attribute"&gt;@block&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;
    &lt;span class="attribute"&gt;@last_fetch&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="ident"&gt;private&lt;/span&gt; &lt;span class="symbol"&gt;:fetch_data&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;method_missing&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;fetch_data&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="attribute"&gt;@last_fetch&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="attribute"&gt;@duration&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
    &lt;span class="attribute"&gt;@data&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__send__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;id&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;amp;&lt;/span&gt;&lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Mon, 04 Jun 2007 11:12:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:0b5f1b1c-f704-4c73-9d51-93b8bdedc41c</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/06/04/cache-as-a-proxy-object</link>
      <category>ruby</category>
    </item>
    <item>
      <title>I recently lost my hearing</title>
      <description>&lt;p&gt;Yesterday evening I was listening to some music with my ear phones on. Suddenly I lost my hearing on the right ear! This was quite a shocking experience. I felt a prickling sensation in my ear - or was it more like a feeling of fullness? Unfortunately It was also too late to bother a doctor immediately about it.&lt;/p&gt;

&lt;p&gt;First I don't think, that I am much of a hypochondriac, but I started worrying that all my years of listening to &lt;strong&gt;loud&lt;/strong&gt; music had finally caught up to me. Did one of my ear bones break? - No, this couldn't be, because I couldn't hear anything on my right ear. I figured broken bones would make some noise even though not the ones I'd expect to hear. Or did I finally damage my choclea? This would suck, because there is not much one can do to repair it, except using an implant. I sure didn't want one if somehow possible.&lt;/p&gt;

&lt;p&gt;I knew that it would be advisable to see a doctor the next day in case my symptoms were caused by Tinnitus. (I wasn't quite sure if I heard strange sounds in my ear or if it was strange, that I didn't hear anything anymore!) As far as I know as an interested layman, Tinnitus might be caused by impaired blood circulation in the inner ear. It's necessary to do something &lt;em&gt;fast&lt;/em&gt; before irreversible damage is done to the sensory nerve cells in the choclea. I read somewhere on wikipedia, that in case of Tinnitus drugs are given (as pills or via infusion) to get the circulation going again. This has a high probability to stop or reduce the symptoms. Shit, I really didn't look forward to have needles peeked into my veins for the next two weeks.&lt;/p&gt;

&lt;p&gt;In the wikipedia I also stumbled across "impacted cerumen" (yeah, it's ear wax) as a possible cause for hearing loss, and this would be my preferred diagnosis, because it's like putting ear plugs in your ears - except it's not that easy to pull them out again. I also learned that there are genetical differences between most Europeans and Asians concerning cerumen, that cause a different phenotype of cerumen: The cerumen found in most Europeans (or their ears) is much more humid and sticky (like wax), while most Asians have a drier and more solid form like sand. Interesting! The European ear wax is disgusting - is it possible to exchange it for the Asian stuff via gene therapy or something? I sure would want to buy that!&lt;/p&gt;

&lt;p&gt;After googling about cerumen further, I found some pages, that gave the advise to pour warm olive oil into the ear to loosen the plug of ear wax and wash it out with warm water. I immediately tried that. It didn't work. Though it's a nice feeling to have warm oil in your ear - albeit quite messy. OK, maybe my condition wasn't caused by ear wax, or this method didn't quite work as advertised - at least in my case. So I was back to diagnosis again.&lt;/p&gt;

&lt;p&gt;I found a &lt;a href="http://www.jimmyr.com/blog/hearingloss.html"&gt;hearing test in flash&lt;/a&gt; and tried it. First I put on my ear phones and selected a volume that was bearable and tried some of the frequencies. I heard them all, although my ear phones cut of the highest and lowest frequencies, but that was to be expected. This test wasn't that useful, because I still had the impression I only could hear on the left side. I used my volume control on the computer to switch the sound only to the right side: Now I didn't hear a single tone! OK, don't panic! I selected a much higher volume, it must have been 20db louder ore more and tried all the frequencies again. Now I could hear them all, though a bit more silent than on the left ear.&lt;/p&gt;

&lt;p&gt;This result gave me some hope, because I inferred, that my sensory nerve cells in the cochlea must still be working (at least a bit). I've read that it's typical to loose hearing (in the inner ear) in the high frequencies first. The cells that are specialised for those are located on one end of the cochlea, for the middle frequencies in the middle, and for lower frequencies on the other end. So being able to still hear the full spectrum was a good thing. Maybe my problem was located in the middle or outer ear?&lt;/p&gt;

&lt;p&gt;If I wanted to determine from which direction a sound comes in the future, I would need a hearing aid, because it was quite confusing to hear a silent sound on the left side, which was actually a much louder sound on the right side of my head. Hey, it wouldn't be that bad, hearing aids are pretty small these days. Can one plug a digital recorder into them? That way I could finally record anything I hear and never again forget anything. There must be an advantage to carry one, no?&lt;/p&gt;

&lt;p&gt;I continued to surf on the interwebs and found a hearing test, the
&lt;a href="http://www.webster.edu/~davittdc/ear/rinne/rinne.htm"&gt;Rinne Test&lt;/a&gt;, that was invented by Heinrich Adolf Rinne, a German medical doctor. With this test you can figure out if the hearing is impaired because the air conduction of sound through the outer or middle ear doesn't work anymore or if the sensory perception of sound in the inner ear (cochlea) stopped working. It's quite simple: First you strike the tuning fork on a table and set it on the bone behind the ear (bone conduction of the sound), while starting to measure the seconds until you don't hear the fork's sound anymore. Then you hold it in front of the ear (normally you should hear the sound of the fork again) and also measure the time until you don't hear the sound anymore.&lt;/p&gt;

&lt;p&gt;You should always hear the sound much longer in front of your ear compared to the time you could hear it through the bone, because ear form, eardrum, and ear bones work as an amplifier for the tuning fork's sound. If  you don't hear it longer, there must be a problem in your middle or outer ear. If you have problems hearing the sound via bone conduction &lt;em&gt;and&lt;/em&gt; air conduction you might have a problem in the inner ear. By measuring the time you can even compare your hearing ability to other people's ability. This is a simple, but quite fascinating test: Dr. Rinne can be proud on the fact, that he had such a good idea. Unfortunately I couldn't find my tuning forks in the mess at my home.&lt;/p&gt;

&lt;p&gt;The test gave me the idea to tap on the bone on the left and right side of my skull and compare the sounds. I couldn't make out any difference between both sides. The Rinne test would have been better, but I thought perhaps this was a reason to believe that I might suffer from impacted ear wax, although my problems started while I was just listening to music with my ear phones and they came rather suddenly, which is a weird coincidence. With this thought I went to bed.&lt;/p&gt;

&lt;p&gt;The next morning (I still couldn't hear a single tone on my right ear) I visited a otorhinolaryngologist in order to finally find out what was wrong with my hearing. The medic gazed into my ear with an &lt;a href="http://en.wikipedia.org/wiki/Otoscope"&gt;otoscope&lt;/a&gt; and said: It's all full in there! Then he took a strange devise that consisted of a bowl and a tiny showering head and told me to hold the bowl next to my ear and started pouring warm water and foam into my ear, then even more water. Then he asked, if I had signal again. Wow, he's so funny! I could have been deaf! Yeah, I could hear again! Healed! After just 3 minutes...&lt;/p&gt;

&lt;p&gt;The reason for my hearing loss, was impacted cerumen after all. I was really relieved about this solution. I immediately told him about my new knowledge concerning differences of cerumen in Asians and Europeans, but he hadn't heard a word about it, and only said he rarely treats any Asians in these parts of the woods. Why do I always have the impression, that after googling I know more about &lt;em&gt;their&lt;/em&gt; area of expertise than my doctors do? I hope, he doesn't send some Chinese or Vietnamese patient to the university clinic because of dry cerumen, after I told him this new research result. At least I hope, that he googles about it at home! ;)&lt;/p&gt;</description>
      <pubDate>Thu, 31 May 2007 16:45:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:515bbc66-cba1-4d0c-992f-944f7567bc98</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/05/31/i-recently-lost-my-hearing</link>
      <category>medicine</category>
      <category>hearing</category>
      <category>ears</category>
    </item>
    <item>
      <title>Benchmarking: Sorting Arrays in Descending Order</title>
      <description>&lt;p&gt;Recently i wanted to sort an array of array pairs (array.size == 2)
in descending (highest value first) order in Ruby. I wanted to avoid creating a temporary array for this, so at first I used Array#sort with a block.&lt;/p&gt;

&lt;p&gt;Because the sorting would often be called in my algorithm, I wanted to optimize this part of the code a bit.  I started to benchmark in order to verify, that my assumptions are correct.&lt;/p&gt;

&lt;p&gt;This is the setup data for the benchmarks:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;n&lt;/span&gt;   &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;1000&lt;/span&gt;
&lt;span class="ident"&gt;a&lt;/span&gt;   &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1000&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt; &lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1000&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
&lt;span class="ident"&gt;a2&lt;/span&gt;  &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1000&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
&lt;span class="ident"&gt;m&lt;/span&gt;   &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;1000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;array sizes are &lt;em&gt;n&lt;/em&gt;, &lt;em&gt;a&lt;/em&gt; is my array of pairs, &lt;em&gt;a&lt;/em&gt;2 is for comparison only, and I repeat the benchmarked code &lt;em&gt;m&lt;/em&gt;-times. (I also do a full warmup run before that.)&lt;/p&gt;

&lt;p&gt;This was my first stab at the sorting (I don't care about the first value in the pair, BTW):&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;y&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; &amp;quot; 11.62s 0.011618c/s&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This took quite some time. (The first time value is the duration in seconds, the second the calls per second.) I guessed that calling the block ca. &lt;em&gt;n log(n)&lt;/em&gt; times, was the reason for this, so I tried:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;b&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;reverse!&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; &amp;quot;  3.29s 0.003290c/s&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wow! Much better.  This takes ca. &lt;em&gt;k n log(n) + l n&lt;/em&gt; "machine instructions", while &lt;em&gt;l &amp;lt;&amp;lt; k&lt;/em&gt;, so the reverting doesn't matter neither in theory or praxis. This can be shown, by just benchmarking Array#sort:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; &amp;quot;  3.48s 0.003484c/s&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This has essentially the same speed as the benchmark with reverse. Actually it's slower, which means, that I cannot even measure Array#reverse's speed in this benchmark. &lt;/p&gt;

&lt;p&gt;So let's test a2 to find out, how fast comparing Fixnums is compared to the more complex pair Arrays:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;a2&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt; &lt;span class="comment"&gt;# =&amp;gt; &amp;quot;  0.27s 0.000265c/s&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's quite a speedup, so let's try to profit from that:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_Ruby "&gt;a.sort { |x, y| y.last &amp;lt;=&amp;gt; x.last } # =&amp;gt; &amp;quot; 13.97s 0.013968c/s&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hmm, this didn't work out. But why? I remembered that Ruby's sort cheats a bit for immediate values like Fixnum, that's most likely the reason. (But I am to lazy to look it up just now.) Making the sort block more complex than in the first try didn't help either.&lt;/p&gt;

&lt;p&gt;But what can be gained from these examples is that&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;using a complex compare block, leads to a huge slowdown in sorting time and&lt;/li&gt;
&lt;li&gt;comparing more primitive values can be much faster (especially if all of this happens in C).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This convinced me to try Array#sort_by, which I dismissed from the beginning as being too wasteful of memory (and maybe too slow because of this anyway):&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_Ruby "&gt;a.sort_by { |x| -x.last } # =&amp;gt; &amp;quot;  2.77s 0.002766c/s&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;LOL!&lt;/strong&gt; I really should stop making predictions without benchmarking: I almost always guess wrong, if I do it. This is the fastest way to sort &lt;em&gt;a&lt;/em&gt; in descending OR ascending order. Because it combines Ruby's cheating with Fixnums (-x.last) and only calling the { |x| -x.last }-block &lt;em&gt;n&lt;/em&gt;-times instead of calling the more complex one ca. &lt;em&gt;n * log(n)&lt;/em&gt; times.&lt;/p&gt;

&lt;p&gt;On the other hand it's only a good idea to invest much time into figuring out and exploiting implementation details like this, if you need the speed, need it &lt;strong&gt;now&lt;/strong&gt; and on this Ruby implementation. The used implementation could change in the future or the advantages could turn into drawbacks if you run the algorithm on JRuby for example.&lt;/p&gt;

&lt;p&gt;P.S.: &lt;a href="http://rubylution.ping.de/files/pair_sort_bm.rb"&gt;Benchmark code&lt;/a&gt; can be downloaded.&lt;/p&gt;</description>
      <pubDate>Tue, 29 May 2007 18:13:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:6ff12d31-fe69-4974-88c0-f93c754c6aa9</guid>
      <author>flori@ping.de (flori)</author>
      <link>http://rubylution.ping.de/articles/2007/05/29/benchmarking-sorting-arrays-in-descending-order</link>
      <category>ruby</category>
      <category>optimization</category>
      <category>benchmarking</category>
      <enclosure type="application/x-ruby" length="1189" url="http://rubylution.ping.de/files/pair_sort_bm.rb"/>
    </item>
  </channel>
</rss>
