<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>H3RALD - Tag 'ruby' (RSS Feed)</title>
    <language>en-us</language>
    <lastBuildDate>Fri, 03 Sep 2010 17:45:00 -0000</lastBuildDate>
    <ttl>40</ttl>
    <link>http://www.h3rald.com</link>
    <description/>
    <item>
      <title>Glyph 0.4.0 Released</title>
      <description>
		&lt;div class="section"&gt;
&lt;p&gt;This new release of Glyph introduces an unusually large number of features, improvements and bugfixes. Not so much in terms of new macros maybe (no index or bibliography support for now, but it will come, don&amp;#8217;t worry!), but rather&amp;#8230; pretty much everything else!&lt;/p&gt;

&lt;div class="section"&gt;
&lt;h3 id="h_1"&gt;Web Output&lt;/h3&gt;
&lt;p&gt;By far the biggest feature of this release is support for multi-file output, i.e. the possibility to transform your book into a web site. You&amp;#8217;ve asked for it, I needed it too, and now it&amp;#8217;s finally here.&lt;/p&gt;
&lt;p&gt;An example? Sure. Take the &lt;a href="http://github.com/downloads/h3rald/glyph/glyph.pdf"&gt;Glyph Book&lt;/a&gt; (now a 98-page &lt;span class="caps"&gt;PDF&lt;/span&gt; file) for instance. My only regret was that a long &lt;span class="caps"&gt;PDF&lt;/span&gt; is quite heavy to digest and peruse, especially if you&amp;#8217;re in a hurry. It would be so much nice to have it available online, in chunks of more manageable size.&lt;/p&gt;
&lt;p&gt;Well, &lt;a href="/glyph/book/"&gt;here it is&lt;/a&gt;. That&amp;#8217;s the very same document, split in several &lt;span class="caps"&gt;HTML&lt;/span&gt; files with a custom layout that matches this site&amp;#8217;s. The good news is that you can do it too:&lt;/p&gt;
	
&lt;div class="code"&gt;
&lt;pre&gt;
&lt;code&gt;
section[
  @title[This title is compulsory]
  @id[random_section]	
  @src[topic_file.glyph]
]
&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;
	&lt;p&gt;Note the &lt;code&gt;@src&lt;/code&gt; attribute? It basically includes the specified topic file. So by creating a &lt;code&gt;document.glyph&lt;/code&gt; file like &lt;a href="http://github.com/h3rald/glyph/blob/master/book/document.glyph"&gt;this&lt;/a&gt;, you can create a tidy table of contents (not a single &lt;code&gt;include&lt;/code&gt; macro) &lt;em&gt;and&lt;/em&gt; get a website for free. Glyph, as usual, takes care of anything for you, especially links between topics. Just link away like you did so far, nothing changes from previous versions, it will just work as expected (&lt;a href="/glyph/book/compiling/compiling.html#web_output"&gt;read more&lt;/a&gt;).&lt;/p&gt;

&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_2"&gt;HTML5 Output&lt;/h3&gt;
&lt;p&gt;Compared to Web output, HTML5 support was trivial and only took a few hours to implement and test. You can now produce single-file HTML5-compliant documents (&lt;code&gt;html5&lt;/code&gt; output format) or even HTML5-compliant web sites (&lt;code&gt;web5&lt;/code&gt; output). Just using &lt;code&gt;section&lt;/code&gt; tags instead of &lt;code&gt;div&lt;/code&gt; tags made it worth it.&lt;/p&gt;
&lt;p&gt;Of course, the default &lt;span class="caps"&gt;CSS&lt;/span&gt; files have been updated to be compatible with HTML5 output too.&lt;/p&gt;

&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_3"&gt;Project Statistics&lt;/h3&gt;
&lt;p&gt;Anoher big thing was a shiny new command, &lt;code&gt;glyph stats&lt;/code&gt;, which brings &amp;#8212; guess &amp;#8212; stats. No more chasing after bookmark references, just type &lt;code&gt;glyph stats --bookmark=#web_output&lt;/code&gt; and you&amp;#8217;ll know where the &lt;code&gt;#web_output&lt;/code&gt; bookmark was defined &lt;em&gt;and&lt;/em&gt; what links to it. Similar stats are available for:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;macros&lt;/li&gt;
	&lt;li&gt;links&lt;/li&gt;
	&lt;li&gt;files&lt;/li&gt;
	&lt;li&gt;snippets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;glyph stats -m&lt;/code&gt; tells me that I used 3236 macro instances throughout the Glyph book. Just so you know.&lt;/p&gt;

&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_4"&gt;Custom tasks and commands&lt;/h3&gt;
&lt;p&gt;&amp;#8220;Glyph is extensible&amp;#8221;, &amp;#8220;Glyph lets you create your own macros&amp;#8221;, &amp;#8230;great, but kinda limited right? No more. Glyph now lets you create &lt;em&gt;custom Rake tasks&lt;/em&gt; and even &lt;em&gt;custom commands&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Have a look at &lt;a href="/glyph/book/extending/commands_tasks.html"&gt;this page&lt;/a&gt; for more information on what you can do and how. You can now extend Glyph in any way you like (including adding custom output formats) without having to touch its core, just do it &lt;em&gt;within your own project&lt;/em&gt;.&lt;/p&gt;

&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_5"&gt;wkhtmltopdf&lt;/h3&gt;
&lt;p&gt;Last but not least, you no longer need Prince &lt;span class="caps"&gt;XML&lt;/span&gt; to produce &lt;span class="caps"&gt;PDF&lt;/span&gt; file. Granted, Prince is awesome and the &lt;span class="caps"&gt;PDF&lt;/span&gt; it produces are very, very nice&amp;#8230; but if you want to produce PDFs commercially and want to same some money, you can now use &lt;a href="http://code.google.com/p/wkhtmltopdf/"&gt;wkhtmltopdf&lt;/a&gt;: it&amp;#8217;s &lt;em&gt;free&lt;/em&gt; and &lt;em&gt;open source&lt;/em&gt;, and it keeps getting better and better.&lt;/p&gt;

&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_6"&gt;...and more to come!&lt;/h3&gt;
&lt;p&gt;After this release I&amp;#8217;m going to take a small break from Glyph. Nothing major, I just want to redesign my site (again) and find the time to write a proper Glyph tutorial. This doesn&amp;#8217;t mean that development will be halted or anything, just that it will take a few months for Glyph 0.5.0 to come out.&lt;/p&gt;
&lt;p&gt;Meanwhile, there may be bugfix releases (depends how many bugs turn up). It would be a good time to come out of the closet and propose/vote on new &lt;a href="http://github.com/h3rald/glyph/issues"&gt;features&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Hope you enjoy using Glyph 0.4.0, and if you need anything or feel social, remember that the doors of the &lt;a href="http://groups.google.com/group/glyph-framework"&gt;Glyph User Group&lt;/a&gt; are always open!&lt;/p&gt;

&lt;/div&gt;

&lt;/div&gt;</description>
      <pubDate>Fri, 03 Sep 2010 17:45:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/glyph-040-released/</guid>
      <link>http://www.h3rald.com/articles/glyph-040-released/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/glyph-040-released/#comments</comments>
      <category>glyph</category>
      <category>ruby</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Book Review: Distributed Programming with Ruby</title>
      <description>
		&lt;div class="section"&gt;
&lt;p&gt;Back when I read &#8225;&#8225;&#8225;&#8225;&#8225;PLACEHOLDER&#164;1&#8225;&#8225;&#8225;&#8225;&#8225; for the first time, I distinctly remember a short reference to &lt;a href="http://ruby-doc.org/stdlib/libdoc/drb/rdoc/index.html"&gt;DRb&lt;/a&gt;, the &lt;strong&gt;D&lt;/strong&gt;istributed &lt;strong&gt;R&lt;/strong&gt;u&lt;strong&gt;b&lt;/strong&gt;y library included in the Standard Library.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;Cool!&amp;#8221;&lt;/em&gt;  &amp;#8212; I thought&lt;/p&gt;
&lt;p&gt;&amp;#8230;and that was pretty much it. The documentation for DRb was pretty much nonexistent (at the time), I didn&amp;#8217;t need it, so I pretty much forgot about it altogether until this book came out.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.informit.com/store/product.aspx?isbn=0321638360"&gt;&lt;em&gt;Distributed Programming with Ruby&lt;/em&gt;&lt;/a&gt; fills a very particular niche of the Ruby programming world: &lt;em&gt;distributed&lt;/em&gt; programming. Moreover, this book is somehow &lt;em&gt;justified&lt;/em&gt; by the scarce documentation on the subject:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Although these libraries [DRb and rinda] have been included with Ruby for many years now, they have received little or no attention (or documentation). This has led to a lot of &lt;span class="caps"&gt;FUD&lt;/span&gt;&lt;br /&gt;
(fear, uncertainty, and doubt) about what these libraries can and cannot do, and when they are appropriate to use (if at all).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p style="padding-left:5em;"&gt;&amp;#8212; Mark Bates, &lt;em&gt;Distributed Programming with Ruby&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But there&amp;#8217;s more. This book gives the reader a complete overview of what&amp;#8217;s out there, in the Ruby world, to support distributed programming. This includes quite a few gems and libraries besides the ones provided in the standard library.&lt;/p&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_1"&gt;Overview&lt;/h3&gt;
&lt;img alt="-" src="/img/pictures/distributed-programming-with-ruby.jpg" style="float:right;" /&gt;
	&lt;p&gt;The book is organized into four parts, each dealing with a particular set of Ruby libraries related to distributed programming.&lt;/p&gt;
&lt;p&gt;The author, &lt;a href="http://www.metabates.com/"&gt;Mark Bates&lt;/a&gt;, does a good job maintaining a sort of continuity in the examples throughout the book: you&amp;#8217;ll get accustomed to a &lt;em&gt;Logger&lt;/em&gt; class of some kind being punctually re-implemented more or less once per chapter, using a different library.&lt;/p&gt;
&lt;p&gt;Additionally, the libraries described in the book are ordered by &amp;#8220;reverse preference&amp;#8221; in each part of the book, so normally the libraries described later on in a part fix some of the shortcomings of the preceding ones.&lt;/p&gt;


	
	&lt;div class="section"&gt;
&lt;h4 id="h_2"&gt;Part I: Standard Library&lt;/h4&gt;
&lt;p&gt;This part is the most important of all: it gives you the very basics about Distributed Programming and it describes the &amp;#8220;building blocks&amp;#8221; (&lt;a href="http://ruby-doc.org/stdlib/libdoc/drb/rdoc/index.html"&gt;DRb&lt;/a&gt; and &lt;a href="http://ruby-doc.org/stdlib/libdoc/rinda/rdoc/index.html"&gt;Rinda&lt;/a&gt;) used in nearly all the other libraries described in the book. If you want you can skip some chapters in the other parts of the book, but make sure this part is crystal clear in your head before proceeding any further.&lt;/p&gt;

&lt;/div&gt;	
	
	&lt;div class="section"&gt;
&lt;h4 id="h_3"&gt;Part II: Third-Party Frameworks and Libraries&lt;/h4&gt;
&lt;p&gt;If you read part I, you&amp;#8217;re probably a bit disappointed by DRb and Rinda and the amount of code you have to write to make simple things work in a distributed environment. The good news is that there are some Ruby gems out there that can make life simpler:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://seattlerb.rubyforge.org/RingyDingy/"&gt;RingyDingy&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://rufy.com/starfish/doc/"&gt;Starfish&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/markbates/distribunaut"&gt;Distribunaut&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/mperham/politics"&gt;Politics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;	
	
	&lt;div class="section"&gt;
&lt;h4 id="h_4"&gt;Part III: Distributed Message Queues&lt;/h4&gt;
&lt;p&gt;In this part, the author introduces more in detail the concept of distribute message queues, and also the technologies and protocols available not only in the Ruby world but elsewhere. It focuses on two libraries:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://rubyforge.org/projects/starling/"&gt;Starling&lt;/a&gt;, originally used by Twitter.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/tmm1/amqp"&gt;&lt;span class="caps"&gt;AMQP&lt;/span&gt;&lt;/a&gt;, an implementation of the &lt;a href="http://www.amqp.org/"&gt;&lt;span class="caps"&gt;AMQP&lt;/span&gt;&lt;/a&gt; protocol in Ruby, that can be used in conjunction with &lt;a href="http://www.rabbitmq.com/"&gt;RabbitMQ&lt;/a&gt;, an Erlang-based messaging system.&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;	
	
	&lt;div class="section"&gt;
&lt;h4 id="h_5"&gt;Part IV: Distributed Programming with Ruby on Rails&lt;/h4&gt;
&lt;p&gt;The book ends somewhat abruptly with this last part that deals with distributed programming in the Rails world. It feels a bit like a last-minute addendum that I would have left for an appendix, nevertheless it briefly introduces &lt;a href="http://backgroundrb.rubyforge.org/"&gt;BackgrounDRb&lt;/a&gt; and &lt;a href="http://github.com/tobi/delayed_job"&gt;Delayed Job&lt;/a&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;/div&gt;

&lt;div class="section"&gt;
&lt;h3 id="h_6"&gt;Technical Analysis&lt;/h3&gt;
&lt;p&gt;Unlike other technical books, this one can (must?) be read sequentially. Generally each chapter focuses on a library, describes how to install it and use it, and highlights its pros and cons. Typically, the &amp;#8220;cons&amp;#8221; are solved in the following chapter by another library, and so on&amp;#8230;&lt;/p&gt;
&lt;p&gt;The book is not meant to contain a full technical reference of each library, and it&amp;#8217;s quite short (256 pages), so you really get the most out of it if you read it all, from start to finish. I didn&amp;#8217;t realize there were so many different libraries in this particular niche of Ruby programming, and Mark does a good job demistifying some of them.&lt;/p&gt;
&lt;p&gt;One thing that really struck me out of this book is the focus on gems. We&amp;#8217;re not talking about &lt;em&gt;mainstream&lt;/em&gt; frameworks like Rails or Merb here, but rather of some rather specialized, smaller libraries that fullfill very specific tasks. Personally, I don&amp;#8217;t remember any other Ruby book doing this in the same way, and I was quite happy about it.&lt;/p&gt;
&lt;p&gt;On the other hand, gems are a double-edged sword: while some of them are really cool and well-maintained, others may disappear tomorrow with no prior notice. I was actually very surprised to see even some of the &lt;em&gt;quirks&lt;/em&gt; of these gems documented in the book:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;p91&lt;/strong&gt;: &lt;em&gt;&amp;#8220;Notice that we added client { } to the bottom of the server file. The reason for this appears to be a bug or flaw in the Starfish architecture.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Really? Hasn&amp;#8217;t it be fixed now? Apparently not, that&amp;#8217;s the way it works, so no, you can&amp;#8217;t blame the author of the book for this.&lt;/p&gt;

	&lt;div class="section"&gt;
&lt;h4 id="h_7"&gt;Formatting and Readability&lt;/h4&gt;
&lt;p&gt;As I pointed out earlier, this book is somehow meant to be read sequentially, and Mark does a good job making sure you don&amp;#8217;t get bored. Chapters and sections are quite short and there&amp;#8217;s a good text/code ratio: the examples are short and clear, and you don&amp;#8217;t have to try them out yourself, because most of the time the author does it for you. It&amp;#8217;s not infrequent for the author to tell you to run &amp;#8220;wrong&amp;#8221; code, but that&amp;#8217;s a great way to show you how to do the right thing right afterwards.&lt;/p&gt;
&lt;p&gt;Sidebars and boxes are used properly and they do provide actual value-added content: some information on a non-Ruby technology, some tips and tricks on how to run things smoothly, etc. On the other hand, one thing I couldn&amp;#8217;t stand were the &lt;em&gt;endnotes&lt;/em&gt;. I must say I don&amp;#8217;t like endnotes at the best of times, but when they are pointless I just can&amp;#8217;t suffer them. Each chapter has its own fair share of endnotes, but unfortunately most of them are just URLs to Wikipedia pages or RubyForce/GitHub projects: I would have preferred the URLs inline with the rest of the text, but that&amp;#8217;s just me.&lt;/p&gt;

&lt;/div&gt;
	&lt;div class="section"&gt;
&lt;h4 id="h_8"&gt;Style and Contents&lt;/h4&gt;
&lt;p&gt;Mark has a nice, informal writing style. Exactly what you expect from a programming book nowadays, even if sometimes it feels a bit too informal:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;p86&lt;/strong&gt;: &lt;em&gt;&amp;#8220;I think I understand what Eric means by all that. However, that is as deep as the documentation goes on the subject. I have not been able to test what I think he means, so I won&amp;#8217;t make any grand promises about what the library can and cannot do in regards to expiring/renewing registrations.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Although this is not something you&amp;#8217;d see in a professional book everyday, it definitely helps to connect with the reader: Mark is one of us after all, even if he happens to have created quite a few &lt;a href="http://github.com/markbates"&gt;interesting projects&lt;/a&gt;, like the Mack framework, the Distribunaut library (which is also mentioned in his book, but in a very impartial way) and Configatron. From his book you understand that he&amp;#8217;s neither one of those rockstar developers nor one of those famous authors who just writes books for a living: he&amp;#8217;s a competent programmer who knows quite a bit about a particular, but relevant, niche of Ruby programming.&lt;/p&gt;

&lt;/div&gt;

&lt;/div&gt;

&lt;div class="section"&gt;
&lt;h3 id="h_9"&gt;Final Thoughts&lt;/h3&gt;
&lt;p&gt;This is one of those books I&amp;#8217;d like to see a second edition of. Partly because there are some relatively new gems which have been left out (&lt;a href="http://github.com/kwi/BrB"&gt;BrB&lt;/a&gt;, for example), partly because this is a rather hot topic at the moment, and different solutions are popping out at a rather extreme rate.&lt;/p&gt;
&lt;p&gt;The decision to write about mainly about gems was bold but necessary, and I&amp;#8217;d really like to see more authors doing that, but with extra care. From reading this book, you understand that there&amp;#8217;s no &lt;em&gt;silver bullet&lt;/em&gt; when it comes to Distributed Programming, but rather different tools to do different jobs.&lt;/p&gt;
&lt;p&gt;The thing I missed the most? A proper conclusion to the book. You&amp;#8217;re left with two chapter about Rails-specific libraries which could have easily become appendixes, and nothing else. I would have liked a sort of &amp;#8220;summing up&amp;#8221; end chapter (re-)highlighting the pros and cons of each library and a sort of feature matrix.&lt;/p&gt;
&lt;p&gt;Nevertheless, it was well worth my time and it proved to be a very good resource to get started in writing distributed Ruby programs.&lt;/p&gt;

&lt;/div&gt;

&lt;/div&gt;</description>
      <pubDate>Tue, 22 Jun 2010 11:30:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/distributed-programming-with-ruby-review/</guid>
      <link>http://www.h3rald.com/articles/distributed-programming-with-ruby-review/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/distributed-programming-with-ruby-review/#comments</comments>
      <category>review</category>
      <category>books</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Glyph 0.3.0 Released</title>
      <description>
		&lt;div class="section"&gt;
&lt;p&gt;The third release of &lt;a href="/glyph/"&gt;Glyph&lt;/a&gt; is out!&lt;/p&gt; 

&lt;p&gt;For those checking it out for the first time, Glyph is a &lt;em&gt;Rapid Document Authoring Framework&lt;/em&gt; focused on extensibility and content reuse. For an example of what Glyph can do, have a look at Glyph's &lt;a href="http://github.com/h3rald/glyph/raw/master/book/output/pdf/glyph.pdf"&gt;free PDF book&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This release brings more stability to Glyph, more speed, and features affecting Glyph's core functionality. As a consequence, some &lt;a href="http://github.com/h3rald/glyph/issues/closed#issue/121"&gt;incompatibilities&lt;/a&gt; had to be introduced &amp;ndash; but after all, better now than later.&lt;/p&gt; 

&lt;div class="section"&gt;
&lt;h3 id="h_1"&gt;New parser and performance improvements&lt;/h3&gt;
&lt;p&gt;This release's big news is the brand new &lt;a href="http://yardoc.org/docs/h3rald-glyph/glyph/parser"&gt;Glyph Parser&lt;/a&gt;. Until this release, Glyph relied on the awesome &lt;a href="http://treetop.rubyforge.org/"&gt;Treetop&lt;/a&gt; library for parsing Glyph language. Treetop is great when it comes to creating language parsers effortlessly, but it can add quite a bit of an overhead especially when using &lt;a href="http://groups.google.com/group/treetop-dev/browse_thread/thread/15ff7659b2efbeed"&gt;dot star&lt;/a&gt; patterns.&lt;/p&gt;

	&lt;p&gt;So I ran a few benchmarks and in the end decided to write my very own (first!) parser from scratch using just the &lt;a href="http://ruby-doc.org/core/classes/StringScanner.html"&gt;StringScanner&lt;/a&gt; class, which is part of Ruby Standard Library. It took me a bit to get used to it, but in the end I managed to create something able to produce an Abstract Syntax Tree exactly the way I wanted.&lt;/p&gt;

	&lt;p&gt;After adding the new parser, Glyph became significantly faster. This doesn't mean it's as fast as, say, RedCloth, but I it can be used to process long books in just a few &lt;em&gt;seconds&lt;/em&gt; rather than &lt;em&gt;minutes&lt;/em&gt;.&lt;/p&gt;

&lt;/div&gt;

&lt;div class="section"&gt;
&lt;h3 id="h_2"&gt;Macro Attributes&lt;/h3&gt;
&lt;p&gt;Glyph now supports named attributes as well as positional parameters. This is particularly handy when you want to create macros with a lot of optional arguments: in this case, positional parameters are not great. As a result, for example, the &lt;code&gt;section&lt;/code&gt; macro now takes an optional &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt; attributes, rather than two parameters&lt;/p&gt;
	
	&lt;p&gt;Attributes look like macros, but they all start with a &lt;code&gt;@&lt;/code&gt; character. For example, see the the following image, showing this very section:&lt;/p&gt;
	
	&lt;img alt="-" src="/img/pictures/updated_glyph_syntax.png" /&gt;

&lt;/div&gt;

&lt;div class="section"&gt;
&lt;h3 id="h_3"&gt;Full XML support&lt;/h3&gt;
&lt;p&gt;Once macro attributes became available at parser level, having Glyph to produce arbitrary XML code became extremely easy. By default, now if Glyph doesn't find a macro it assumes you're inputting an XML tag of some kind, so you can write:&lt;/p&gt;

	&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;p[This is a paragraph with some em[emphasized] text.]
img[
  @alt[Glyph Code]
  @width[50%]
  @height[50%]
  @src[glyph_code.png]
]&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


	&lt;p&gt;And get the following HTML code back:&lt;/p&gt;
	
	&lt;div class="CodeRay"&gt;
  &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="ta"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;This is a paragraph with some &lt;span class="ta"&gt;&amp;lt;em&amp;gt;&lt;/span&gt;emphasized&lt;span class="ta"&gt;&amp;lt;/em&amp;gt;&lt;/span&gt; text.&lt;span class="ta"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="ta"&gt;&amp;lt;img&lt;/span&gt; 
  &lt;span class="an"&gt;alt&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Glyph Code&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="an"&gt;width&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;50%&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="an"&gt;height&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;60%&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="an"&gt;src&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;glyph_code.png&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;  
&lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/div&gt;


  &lt;p&gt;...and none of the macros used in the previosu Glyph code snippet are actually defined in Glyph. Among other things, this means that &lt;em&gt;you don't have to&lt;/em&gt; use Textile or Markup within your Glyph code unless you absolutely need to (e.g. for lists, which would be a bit verbose to create using just Glyph markup).&lt;/p&gt;

&lt;/div&gt;

&lt;div class="section"&gt;
&lt;h3 id="h_4"&gt;Improved &lt;code&gt;include&lt;/code&gt; macro and "safe mode"&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;include&lt;/code&gt; macro now &lt;em&gt;must&lt;/em&gt; take an path to a file relative to the &lt;code&gt;text/&lt;/code&gt; directory of your project, &lt;em&gt;or&lt;/em&gt; it can also be used to include (and &lt;em&gt;evaluate&lt;/em&gt;) ruby code within your &lt;code&gt;lib/&lt;/code&gt; directory. Moreover, you can now use the &lt;code&gt;include&lt;/code&gt; macro even when compiling single Glyph files.&lt;/p&gt;

	&lt;p&gt;Now, while evaluating Ruby code in an external file can be quite handy, is also quite insecure. For this reason, it is now possible to use Glyph programmatically in "safe mode", thereby forbidding the usage of certain &lt;em&gt;unsafe&lt;/em&gt; macros.&lt;/p&gt;

&lt;/div&gt;

&lt;div class="section"&gt;
&lt;h3 id="h_5"&gt;What's next?&lt;/h3&gt;
&lt;p&gt;Sooner or later I'll have to implement support for generating multiple files in output. This would make it possible to make the  &lt;a href="http://github.com/h3rald/glyph/raw/master/book/output/pdf/glyph.pdf"&gt;Glyph book&lt;/a&gt; available online as a collection of separate HTML file, for example, or, later on, maybe even compiled into a (ugh!) CHM file.&lt;/p&gt;

	&lt;p&gt;Additionally, HTML5 support is also on the horizon: given the current Glyph architecture, it will be relatively easy to have Glyph macros to produce HTML5 code instead of XHTML. LaTeX support, on the other hand, is a completely different game, mainly because I'm not familiar with it, so if anyone feels creative and would like an easier way to produce reusable LaTeX code, &lt;a href="http://github.com/h3rald/glyph/"&gt;get forking&lt;/a&gt; and contact me!&lt;/p&gt;

&lt;/div&gt;

&lt;/div&gt;</description>
      <pubDate>Sun, 13 Jun 2010 12:10:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/glyph-030-released/</guid>
      <link>http://www.h3rald.com/articles/glyph-030-released/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/glyph-030-released/#comments</comments>
      <category>glyph</category>
      <category>ruby</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Glyph 0.2.0 Released</title>
      <description>
		&lt;div class="section"&gt;
&lt;p&gt;I am very pleased to announce the second release of the &lt;a href="/glyph/"&gt;Glyph Document Authoring Framework&lt;/a&gt;. For those who don&amp;#8217;t know, Glyph is a pure-Ruby, extensible solution to author documents like books or articles using a simple, fully-customizable markup language.&lt;/p&gt;
&lt;p&gt;Since the &lt;a href="/articles/introducing-glyph/"&gt;first release&lt;/a&gt;, came out, last month, a lot happened. Plenty of bugs were fixed and new features implemented, as shown by the &lt;a href="http://github.com/h3rald/glyph/blob/master/CHANGELOG.textile"&gt;changelog&lt;/a&gt;. Here&amp;#8217;s a brief rundown of the most notable changes.&lt;/p&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_1"&gt;What Glyph code looks like&lt;/h3&gt;
&lt;p&gt;Earlier this week I &lt;a href="http://blog.h3rald.com/making-a-custom-vim-syntax-file"&gt;blogged&lt;/a&gt; about my new &lt;a href="http://github.com/h3rald/stash/blob/master/.vim/syntax/glyph.vim"&gt;Glyph vim syntax file&lt;/a&gt;. I&amp;#8217;ve been using it for a while, and all I can say is that it really helps! Here&amp;#8217;s what it looks like:&lt;/p&gt;
&lt;p&gt;&lt;img alt="-" src="/img/pictures/glyph_syntax.png" /&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m sorry for the Emacs and TextMate folks, but I only use Vim, so I only made a Vim syntax file. Anyhow, Glyph grammar is very simple, so rolling out your own syntax file for your favorite editor shouldn&amp;#8217;t be too hard.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_2"&gt;Notable features&lt;/h3&gt;
&lt;div class="section"&gt;
&lt;h4 id="h_3"&gt;Single-file compilation&lt;/h4&gt;
&lt;p&gt;Perhaps the most life-changing feature in this release is the possibility of compiling a single Glyph source file into an &lt;span class="caps"&gt;HTML&lt;/span&gt; or &lt;span class="caps"&gt;PDF&lt;/span&gt; file. This means you no longer need to create a full-blown project for writing a short article: just create a file anywhere and run &lt;code&gt;glyph compile filename.glyph&lt;/code&gt;on it!&lt;/p&gt;
&lt;p&gt;The good thing is that with this new release you can also define snippets, configuration settings, and even macros right into your Glyph files, so you can do almost anything without having to create a project or fiddle with &lt;span class="caps"&gt;YAML&lt;/span&gt; files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h4 id="h_4"&gt;Programmatic usage&lt;/h4&gt;
&lt;p&gt;The second most notable feature is the possibility to use Glyph as a Ruby library, i.e. as you&amp;#8217;d use a filter like RedCloth or MarkDown. Additionally, it is also possible to compile single files programmatically, so you can, for example, create &lt;span class="caps"&gt;PDF&lt;/span&gt; files for your articles from the same source file. Don&amp;#8217;t believe me? Feel free to click the &lt;em&gt;Download &lt;span class="caps"&gt;PDF&lt;/span&gt;&lt;/em&gt; and &lt;em&gt;View Source&lt;/em&gt; links on this very page to see for yourself&amp;#8230;&lt;/p&gt;
&lt;p&gt;For those of you using the awesome &lt;a href="http://nanoc.stoneship.org"&gt;nanoc&lt;/a&gt; static site generator, here&amp;#8217;s a few source files you may want to take a look at:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/h3rald/h3rald/blob/master/lib/glyph-data.rb"&gt;lib/glyph-data.rb&lt;/a&gt; &amp;#8212; How to update configuration settings.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/h3rald/h3rald/blob/master/lib/glyph-filter.rb"&gt;lib/glyph-data.rb&lt;/a&gt; &amp;#8212;  a simple Glyph filter.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://github.com/h3rald/h3rald/blob/master/Rules"&gt;Rules&lt;/a&gt; &amp;#8212; a rule using the &lt;code&gt;Glyph#compile&lt;/code&gt; method to generate &lt;span class="caps"&gt;PDF&lt;/span&gt; files.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h4 id="h_5"&gt;Auto-regeneration&lt;/h4&gt;
&lt;p&gt;Another very interesting feature is the possibility to auto-regenerate your output files automatically whenever a source file is changed. Just run &lt;code&gt;glyph compile --auto&lt;/code&gt; and you&amp;#8217;re away. I&amp;#8217;d like to thank &lt;a href="http://koraktor.github.com"&gt;Sebastian Staudt&lt;/a&gt; for proposing, implementing, and testing this feature.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h4 id="h_6"&gt;Conditional macros&lt;/h4&gt;
&lt;p&gt;Finally, although it may worry some, I added the possibility to evaluate conditional expressions directly in Glyph. The syntax is a bit verbose due to the extreme simplicity of Glyph parser, but it does the job:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;?[and[
    eq[$[document.output]|pdf]|
    eq[$[tools.pdf_generator]|prince]
    ]|
  style[pagination.css]]&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The snippet above can be used to include the &lt;code&gt;pagination.css&lt;/code&gt; stylesheet only when generating a &lt;span class="caps"&gt;PDF&lt;/span&gt; file with Prince &lt;span class="caps"&gt;XML&lt;/span&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section"&gt;
&lt;h3 id="h_7"&gt;What&amp;#8217;s next?&lt;/h3&gt;
&lt;p&gt;Release 0.3.0 is currently being planned, and so are its &lt;a href="http://github.com/h3rald/glyph/issues"&gt;features&lt;/a&gt;. For now, I&amp;#8217;d like to thank the following individuals for contributing to Glyph:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.jabbslad.com"&gt;Jamie Atkinson&lt;/a&gt; (Jabbslad), for spotting and fixing some bugs and providing feedback.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://koraktor.github.com"&gt;Sebastian Staudt&lt;/a&gt; (koraktor), for spotting and fixing some bugs, proposing and implementing new features.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In particular, Sebastian is working on &lt;a href="http://wiki.github.com/h3rald/glyph/feature-bibliography-support"&gt;bibliogaphy support&lt;/a&gt; for Glyph, looking forward to it!&lt;/p&gt;
&lt;p&gt;Although still in its infancy, Glyph is becoming more and more usable everyday. If you are interested, you can contribute in many different ways to the project, such as:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;By participating to discussions on the &lt;a href="http://groups.google.com/group/glyph-framework"&gt;user group&lt;/a&gt; (it&amp;#8217;s a bit quiet of there for now&amp;#8230;)&lt;/li&gt;
	&lt;li&gt;By spreading the word on Twitter, on your blog, or wherever you like.&lt;/li&gt;
	&lt;li&gt;By installing it, using it, reporting bugs and proposing new features (it&amp;#8217;s just a &lt;code&gt;gem install glyph&lt;/code&gt; away!).&lt;/li&gt;
	&lt;li&gt;By actually contributing to its development (it&amp;#8217;s &lt;a href="http://wiki.github.com/h3rald/glyph/contribution-guidelines"&gt;easy&lt;/a&gt;!).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, if you don&amp;#8217;t like coding:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;feedback on the current documentation and on the &lt;a href="http://github.com/h3rald/glyph/raw/master/book/output/pdf/glyph.pdf"&gt;Glyph book&lt;/a&gt; is appreciated&lt;/li&gt;
	&lt;li&gt;if you are good with &lt;span class="caps"&gt;CSS&lt;/span&gt;, I&amp;#8217;m looking for some nice new &lt;span class="caps"&gt;CSS&lt;/span&gt; styles to include in the standard Glyph distribution.&lt;/li&gt;
	&lt;li&gt;if you&amp;#8217;re good with graphics, Glyph needs a good-looking logo&amp;#8230;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Any form of contribution will be credited in some way, e.g. by links and tweets.&lt;/p&gt;
&lt;/div&gt;

&lt;/div&gt;</description>
      <pubDate>Sun, 09 May 2010 15:00:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/glyph-020-released/</guid>
      <link>http://www.h3rald.com/articles/glyph-020-released/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/glyph-020-released/#comments</comments>
      <category>glyph</category>
      <category>ruby</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Introducing Glyph</title>
      <description>&lt;p&gt;I&amp;#8217;ve been writing technical documents for a living for the past four years, and I can tell you: there is no easy way to go about it.&lt;/p&gt;
&lt;p&gt;For example, you can use:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;a Word Processor&lt;/strong&gt; like MS Word, for example &amp;#8212; anyone can do that, right? Sure, but no, thanks: I strongly believe that Word Processors should not be used for writing technical documents as I firmly don&amp;#8217;t believe GUIs are suitable for doing this at a professional level.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;a Document Authoring Software&lt;/strong&gt; like Adobe Framemaker, Robohelp, etc. Still GUIs, only more complicated to use.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;XML&lt;/span&gt;, like &lt;span class="caps"&gt;DITA&lt;/span&gt; or DocBook, or other markups&lt;/strong&gt;, like ReStructuredText. Better, but still not easily extensible and flexible enough.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;your company&amp;#8217;s tools&lt;/strong&gt;, if you have them. That&amp;#8217;s great if they are usable enough and the result makes your boss happy.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;LaTeX&lt;/strong&gt;, and that&amp;#8217;s probably your best option, if you know what you&amp;#8217;re doing.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;XHTML&lt;/span&gt; and CSS3&lt;/strong&gt;, in conjunction with a &lt;span class="caps"&gt;PDF&lt;/span&gt; renderer like &lt;a href="http://www.princexml.com/"&gt;Prince &lt;span class="caps"&gt;XML&lt;/span&gt;&lt;/a&gt; &amp;#8212; that&amp;#8217;s great if you know &lt;span class="caps"&gt;HTML&lt;/span&gt; and &lt;span class="caps"&gt;CSS&lt;/span&gt;, and you don&amp;#8217;t mind hand-crafting the structure of the document.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Lightweight markups&lt;/h3&gt;
&lt;p&gt;I love Textile and Markdown. When people aren&amp;#8217;t looking, I even use them at work to generate &lt;span class="caps"&gt;HTML&lt;/span&gt; code, because it&amp;#8217;s just so much faster. Textile in particular can be used as a drop-in replacement for &lt;span class="caps"&gt;HTML&lt;/span&gt; (and a bit of LaTeX, too), as it can produce most inline &lt;span class="caps"&gt;HTML&lt;/span&gt; tags effortlessly and some block-level tags, too.&lt;/p&gt;
&lt;p&gt;For things like &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; tags and &lt;code&gt;&amp;lt;tables&amp;gt;&lt;/code&gt; though, Textile is not the best thing in the world, so you normally end up falling back to &lt;span class="caps"&gt;HTML&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Another &amp;#8220;problem&amp;#8221; is that &lt;strong&gt;Textile&lt;/strong&gt; or other similar lightweight markups cannot be extended easily, simply because they were not meant to be extended in the first place.&lt;/p&gt;
&lt;p&gt;Moreover, if you are producing a book, Textile can&amp;#8217;t help you if you want to generate things like a Table of Contents automatically or validate links: those things are simply not part of Textile&amp;#8217;s job.&lt;/p&gt;
&lt;h3&gt;How Glyph can help&lt;/h3&gt;
&lt;p style="float:right;"&gt;&lt;img src="/img/pictures/glyph.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;There are a few projects on the Internet that tackle structured document generation. One of them is &lt;a href="http://github.com/fnando/kitabu"&gt;Kitabu&lt;/a&gt;, which looks promising and is able to produce pretty documents using Textile and Prince for &lt;span class="caps"&gt;PDF&lt;/span&gt; rendering&amp;#8230; but again, it&amp;#8217;s not extensible because it relies too much on Textile and Markdown.&lt;/p&gt;
&lt;p&gt;&lt;a href="/glyph/"&gt;Glyph&lt;/a&gt; is different. For one, it is much younger than any other, therefore it is most likely full of bugs.&lt;/p&gt;
&lt;p&gt;Jokes aside, Glyph follows a much more radical approach, which consists in using a &lt;em&gt;macro language&lt;/em&gt; on top of Textile or Markdown. The good thing about it is that this macro language is very simple to learn and &amp;#8212; most importantly &amp;#8212; very easy to extend.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;section[header[Something about Glyph]
You can use Glyph macros in conjunction
 with _Textile_ or _Markdown_ to
produce HTML files effortlessly.
  section[header[What about PDFs?|pdf]
Once you have a single, well-formatted HTML 
file, converting it to PDF is
extremely easy with a 3rd-party 
renderer like =&amp;gt;[http://www.princexml.com|Prince].
  ]   
]
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Which translates to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;div class=&amp;quot;section&amp;quot;&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;
  &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;h2 id=&amp;quot;h_1&amp;quot;&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;Something about Glyph&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/h2&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;
  &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;p&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;You can use Glyph macros in conjunction with 
     &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;em&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;Textile&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/em&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt; or &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;em&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;Markdown&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/em&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt; to
     produce HTML files effortlessly.&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/p&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;
  &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;div class=&amp;quot;section&amp;quot;&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;
   &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;h3 id=&amp;quot;pdf&amp;quot;&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;What about PDFs?&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/h3&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;
   &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;p&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;Once you have a single, well-formatted HTML 
      file, converting it to PDF is
      extremely easy with a 3rd-party renderer 
      like &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;a href=&amp;quot;http://www.princexml.com&amp;quot;&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;Prince&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/a&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;.&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/p&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;
  &lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/div&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;
&lt;span class="ni"&gt;&amp;amp;lt;&lt;/span&gt;/div&lt;span class="ni"&gt;&amp;amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Glyph macros can be used to:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Generate block-level &lt;span class="caps"&gt;HTML&lt;/span&gt; tags not commonly managed by lightweight markups, like &lt;code&gt;head&lt;/code&gt;, &lt;code&gt;body&lt;/code&gt;, &lt;code&gt;div&lt;/code&gt; and &lt;code&gt;table&lt;/code&gt;.&lt;/li&gt;
	&lt;li&gt;Create and validate internal and external links.&lt;/li&gt;
	&lt;li&gt;Include and validate images and figures.&lt;/li&gt;
	&lt;li&gt;Automatically determine header levels based on the document structure.&lt;/li&gt;
	&lt;li&gt;Automatically generate a Table of Contents based on the document structure.&lt;/li&gt;
	&lt;li&gt;Store common snippets of text in a single &lt;span class="caps"&gt;YAML&lt;/span&gt; file and use them anywhere in your document, as many times as you need.&lt;/li&gt;
	&lt;li&gt;Store configuration settings in a &lt;span class="caps"&gt;YAML&lt;/span&gt; file and use them anywhere in your document, as many times as you need.&lt;/li&gt;
	&lt;li&gt;Evaluate Ruby code within your document.&lt;/li&gt;
	&lt;li&gt;Call macros from other macros (including snippets), carefully avoiding mutual calls.&lt;/li&gt;
	&lt;li&gt;Include text files in other text files.&lt;/li&gt;
	&lt;li&gt;Include the contents of configuration settings (author, title) in the document.&lt;/li&gt;
	&lt;li&gt;Filter input explicitly or implicitly, based on file extensions when including files.&lt;/li&gt;
	&lt;li&gt;Manage comments and todo items.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An example Glyph project? Sure, Glyph&amp;#8217;s own guide (&lt;a href="http://github.com/h3rald/glyph/tree/master/book/"&gt;source&lt;/a&gt; &amp;#8212; &lt;a href="http://github.com/h3rald/glyph/tree/master/book/output/pdf/"&gt;&lt;span class="caps"&gt;PDF&lt;/span&gt; output&lt;/a&gt;).&lt;/p&gt;
&lt;h3&gt;Technical Details&lt;/h3&gt;
&lt;p&gt;Glyph is built on top of the following Ruby Gems:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://github.com/davetron5000/gli"&gt;gli&lt;/a&gt; &amp;#8212; For the high-level command line interface.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://rake.rubyforge.org/"&gt;rake&lt;/a&gt; &amp;#8212; For the mid-level interdependent task layer.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://treetop.rubyforge.org/"&gt;treetop&lt;/a&gt; &amp;#8212; For parsing Glyph Language, whose grammar is &lt;a href="http://github.com/h3rald/glyph/blob/master/lib/glyph/glyph_language.treetop"&gt;ridiculously simple&lt;/a&gt;, but it seems to work so far.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://rubyforge.org/projects/extlib/"&gt;extlib&lt;/a&gt; &amp;#8212; Because I can&amp;#8217;t leave without it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Disclaimer&lt;/h3&gt;
&lt;p&gt;Glyph is &lt;strong&gt;alpha software&lt;/strong&gt; (hence the 0.1.0 version number) &amp;#8212; handle with care and be aware that &lt;em&gt;everything&lt;/em&gt; could change tomorrow. If you want to keep up-to-date and/or provide feedback, feel free to join &lt;a href="http://groups.google.com/group/glyph-framework"&gt;Glyph&amp;#8217;s User Group&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;For more information&amp;#8230;&lt;/h3&gt;
&lt;p&gt;&amp;#8230;head over to &lt;a href="/glyph/"&gt;Glyph&amp;#8217;s homepage&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Fri, 09 Apr 2010 17:30:39 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/introducing-glyph/</guid>
      <link>http://www.h3rald.com/articles/introducing-glyph/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/introducing-glyph/#comments</comments>
      <category>glyph</category>
      <category>ruby</category>
      <category>frameworks</category>
      <category>writing</category>
    </item>
    <item>
      <title>Book Review: Refactoring - Ruby Edition</title>
      <description>&lt;p&gt;Refactoring, like testing, is an activity that should be very familiar to all programmers, especially Rubyists. Actually, programs written in Ruby don&amp;#8217;t need as many refactorings as, say, Java programs. However Rubyists are traditionally more &lt;span class="caps"&gt;TDD&lt;/span&gt; oriented and they like writing clear and elegant code.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.informit.com/store/product.aspx?isbn=0321603508"&gt;Refactoring: Ruby Edition&lt;/a&gt; is actually a rewrite of the more revolutionary &amp;#8212; at the time &amp;#8212; &lt;a href="http://www.informit.com/store/product.aspx?isbn=0201485672"&gt;Refactoring: Improving the Design of Existing Code&lt;/a&gt;, written by Martin Fowler &amp;amp; others to teach Java programmers about refactoring. Jay Fields and others decided to &lt;em&gt;port&lt;/em&gt; this historical title to Ruby to fill a gap: there was no authoritative book about refactoring for this language, so what&amp;#8217;s better than translating the Bible on the subject?&lt;/p&gt;
&lt;p&gt;If you already own the Java book you shouldn&amp;#8217;t buy this one. This is not my personal opinion (I never read the original), it&amp;#8217;s actually written in the Preface of the book itself. I really like honest authors, and luckily this seems to have become a trend, lately: programmers don&amp;#8217;t like reading bullshit after all. By the authors&amp;#8217; own admission, this book contains roughly the same material and the same examples of the original Java book, plus some slightly more Ruby-specific content.&lt;/p&gt;
&lt;h3&gt;Getting started&lt;/h3&gt;
&lt;p style="float:right;"&gt;&lt;img src="/img/pictures/refactoring-ruby-ed.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The first chapter, &lt;em&gt;Refactoring, a first example&lt;/em&gt;, is not a first chapter. Well, it is in a literal sense, but it doesn&amp;#8217;t look like one: no theory, no padding, you&amp;#8217;re immediately thrown in the middle of the battle, dealing with a small program in desperate need of refactoring. It literally contains quite a lot of code: the same program is rewritten over and over with changes in bold to teach you what refactoring means. The most intimidating thing is reading names of refactoring techniques capitalized and used in a natural way, like if the reader was supposed to know them already. In all fairness though, they are self-explanatory most of the time, e.g. &lt;em&gt;Replace Array with Object&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What makes this chapter even more unusual is the clever usage of white space: &lt;em&gt;before&lt;/em&gt; and &lt;em&gt;after&lt;/em&gt; code snippets are shown on separate page, which makes it much more immediate to see the changes in code (but it won&amp;#8217;t work very well if you bought the ebook instead of the hardback).&lt;/p&gt;
&lt;p&gt;By contrast, the second chapter &lt;em&gt;Principles in Refactoring&lt;/em&gt; is all about theory: it should have been the first chapter, but it&amp;#8217;s better this way. Here you&amp;#8217;ll learn the basics: a bit of history, when to refactor and when not to, and so on. I bet it was taken almost verbatim from the Java book; see for example: &lt;em&gt;&amp;#8220;[&amp;#8230;] If your building APIs for outsid consumption, as &lt;strong&gt;Sun&lt;/strong&gt; does [&amp;#8230;]&amp;#8221;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Chapter 3, &lt;em&gt;Bad Smells in Code&lt;/em&gt;, is probably the most important and useful chapter in the entire book. It&amp;#8217;s somethig you should read over and over until you can spot a code smell right after coding.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;You should use this chapter and the table on the inside back cover as a way to give you inspiration whn you&amp;#8217;re not sure what refactorings to do.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Precisely what you have to do. Except that there is no table on the inside back cover, so I guess &lt;a href="http://docs.google.com/viewer?url=http://www.industriallogic.com/papers/smellstorefactorings.pdf"&gt;this one&lt;/a&gt; will have to do. Pity.&lt;/p&gt;
&lt;p&gt;Chapter 4, &lt;em&gt;Building Tests&lt;/em&gt;, is the usual, compulsory chapter about unit testing, i.e. the usual intro to Test::Unit. As I said, it&amp;#8217;s essential for the book to make sense, but you can safely skip it if you know how to test already.&lt;/p&gt;
&lt;p&gt;Finally, chapter 5 (&lt;em&gt;Toward a Catalog of Refactoring&lt;/em&gt;) is a 2.5 page intro to the bulk of the book, nothing more than glue to ease the transition. I would have removed it completely, but that&amp;#8217;s because I&amp;#8217;m a merciless technical writer I guess.&lt;/p&gt;
&lt;h3&gt;Diving in&lt;/h3&gt;
&lt;p&gt;From chapter 6 onwards, specific refactoring techniques are described. Each chapter starts with a brief overview of the following sections (which should have been a list, but I&amp;#8217;m just being pedantic now), so you know what to expect.&lt;/p&gt;
&lt;p&gt;Each technique described has a very meaningful and immediate name that reflects its purpose, like Extract Method or Split Temporary Variable. A code example introduces the code smell and the proposed refactoring, followed by a &lt;em&gt;Mechanics&lt;/em&gt; section with a list of actions to perform and an explanatory &lt;em&gt;Motivation&lt;/em&gt; section.&lt;/p&gt;
&lt;p&gt;Tipically, each refactoring has its own, self-contained code snippets. Depending on the complexity of the refactoring technique examined, the authors may spend half to five or six pages just to show all code iterations to get to the result. When things get too complicated, &lt;span class="caps"&gt;UML&lt;/span&gt; diagrams are used to make the technique easier to understand, but only when it&amp;#8217;s strictly necessary.&lt;/p&gt;
&lt;p&gt;Even if the original techniques were though for Java, the authors (in particlar Jay Fields, I guess) do a great job making sure that the Ruby code doensn&amp;#8217;t look like Java code in disguise: the result of the refactoring always follows Ruby&amp;#8217;s philosophy and idioms. I particularly liked the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Replace Dynamic Receptor with Dynamic Method Definition (Chapter 6), a nice example of metaprogramming.&lt;/li&gt;
	&lt;li&gt;Decompose Conditional/Recompose Conditional (Chapter 9), very useful and very common&lt;/li&gt;
	&lt;li&gt;Replace Nested Conditional with Guard Clause (Chapter 9), another way to deal with a very common problem with conditionals&lt;/li&gt;
	&lt;li&gt;Extract Module (Chapter 11), very Rubyesque way to tidy up busy classes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This doesn&amp;#8217;t mean that &lt;em&gt;every&lt;/em&gt; refactoring described in the book is a programmer&amp;#8217;s epiphany, some of the techniques are indeed pretty obvious and some portion of code in need of refactoring indeed smell very, very bad! E.g.:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Inline Class (Chapter 7): Who on Earth would ever create a class containing a single method returning a telephone number?&lt;/li&gt;
	&lt;li&gt;Replace Magic Number with Symbolic Constant (Chapter 8): Why would you use integers for constants? Didn&amp;#8217;t Matz give us Symbols to avoid just that?&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;The big picture&lt;/h3&gt;
&lt;p&gt;By the end of chapter 11 you should be familiar with nearly all the best possible way to get rid of code smells. That&amp;#8217;s all good, but what happens if &lt;em&gt;the entire program&lt;/em&gt; stinks? Chapter 12 (&lt;em&gt;Big Refactorings&lt;/em&gt;) claims to have some answers to some common pitfalls. The techniques defined in this chapter are by no means sufficient to solve all problems caused by bad design, but they can help especially to rewrite legacy code, or programs developed by Ruby newbies:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Tease Apart Inheritance&lt;/li&gt;
	&lt;li&gt;Convert procedural design to objects&lt;/li&gt;
	&lt;li&gt;Separate domain from presentation&lt;/li&gt;
	&lt;li&gt;Extract hierarchy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They are basically all about reducing bloat and unnecessary complexity, and &amp;#8212; to me, that is &amp;#8212; they all sounded pretty obvious. &lt;em&gt;Of course&lt;/em&gt; I&amp;#8217;m going to separate domain from presentation! Didn&amp;#8217;t Rails teach us anything at all? I must say I was somehow disappointed by this chapter. I was going to bet there was something slightly more advanced, maybe something about replacing traditional object instantiation with an internal &lt;span class="caps"&gt;DSL&lt;/span&gt;? Nope, sorry.&lt;/p&gt;
&lt;p&gt;Chapter 13, on the other hand, is an excellent conclusion to the book: it really helps the reader to understand when to refactor and how to do so, depending on the situation.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This and &lt;a href="http://www.h3rald.com/articles/design-patterns-in-ruby-review/"&gt;Design Patterns in Ruby&lt;/a&gt; are now my favorite Ruby books. I believe they complete each other: Russ Olsen&amp;#8217;s book is more about designing your programs properly from the start, while &lt;em&gt;Refactoring: Ruby Edition&lt;/em&gt; can help to make things better at a lower level. &lt;br /&gt;
Ruby developers don&amp;#8217;t need to refactor as much as Java developers, mainly because of Ruby itself, nevertheless, this is an excellent read for anyone who wants to get serious about programming in Ruby, and is determined to do so by following the Ruby Way.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll definitely keep this book near me when I&amp;#8217;m coding: I do believe it is much more helpful when you start using it as a reference, when you already read about all the refactoring techniques and want to put them in practice. Also, I&amp;#8217;ll probably re-read chapter 3 on a regular basis, to get accustomed to recognize code smells, and deal with them accordingly.&lt;/p&gt;</description>
      <pubDate>Fri, 22 Jan 2010 14:40:36 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/refactoring-ruby-edition-review/</guid>
      <link>http://www.h3rald.com/articles/refactoring-ruby-edition-review/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/refactoring-ruby-edition-review/#comments</comments>
      <category>ruby</category>
      <category>books</category>
      <category>review</category>
    </item>
    <item>
      <title>Book Review: The Merb Way</title>
      <description>&lt;p&gt;When I first picked up this book I was surprised by its length. Somehow, after reading &lt;a href="/articles/the-rails-way-review"&gt;The Rails Way&lt;/a&gt;, I got stuck in my mind that &lt;a href="http://my.safaribooksonline.com/9780321601636"&gt;The Merb Way&lt;/a&gt; had to be almost equally voluminous. Instead, this book is about 300 page long, roughly as long as the sum of the chapters devoted to &lt;em&gt;ActiveRecord&lt;/em&gt; in Obie Fernandez&amp;#8217;s acclaimed Rails bible.&lt;/p&gt;
&lt;p&gt;Apparently it only takes 300 pages to describe a web framework nowadays! I couldn&amp;#8217;t help but feeling a bit skeptical at first. Even in the foreword, Obie Fernandez presents the book &amp;ndash; and the whole &lt;a href="http://www.merbivore.com"&gt;Merb&lt;/a&gt; framework &amp;ndash; with some initial skepticism: isn&amp;#8217;t Ruby on Rails enough? Why do we need yet another Ruby web framework? And above all, seeing that Merb is going to eventually be &lt;a href="http://weblog.rubyonrails.org/2008/12/23/merb-gets-merged-into-rails-3"&gt;merged into Rails 3&lt;/a&gt;, why on Earth do we need a book about Merb, &lt;em&gt;now&lt;/em&gt;?&lt;/p&gt;
&lt;p&gt;Needless to say, Foy Savas proved that both Merb and its book cannot be dismissed just like that.&lt;/p&gt;
&lt;h3&gt;Getting started&lt;/h3&gt;
&lt;p style="float:right;"&gt;&lt;img src="/img/pictures/therailsway.jpg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The book starts with the original &lt;a href="http://pastie.org/14416"&gt;Merb Pastie&lt;/a&gt;, a single page of Ruby code able to sort out &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests, dispatch them to the appropriate controllers and render a web page. This piece of code is enough to convey what Merb is: a new breed of web framework, almost as simple as it can get but very poweful and flexible at the same time.&lt;/p&gt;
&lt;p&gt;As you start diving in through the first chapter, you realize you&amp;#8217;re reading about a &lt;em&gt;Hacker&amp;#8217;s Web Framework&lt;/em&gt;. That&amp;#8217;s precisely what Merb is: a very versatile tool to get the job done, in the simplest way possible. Similarly, &lt;em&gt;The Merb Way&lt;/em&gt; immediately feels like a &lt;em&gt;Hacker&amp;#8217;s Handbook&lt;/em&gt; rather than an ordinary guide on how to develop web applications. You won&amp;#8217;t learn what &lt;span class="caps"&gt;MVC&lt;/span&gt; is by reading this book, and don&amp;#8217;t expect to be taught what a &lt;em&gt;mixin&lt;/em&gt; is; you are reading a book about a Ruby web framework that was born after the &lt;em&gt;Rails Revolution&lt;/em&gt;, so it is safe (for the author) to assume that:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You know the Ruby programming language&lt;/li&gt;
	&lt;li&gt;You know what Ruby on Rails is and you tried it out, at the very least&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first few chapters are about the core functionalities provided by an an &lt;span class="caps"&gt;MVC&lt;/span&gt; framework: after a comprehensive first chapter about Merb&amp;#8217;s fundamentals (from the layout of a Merb application to an overview of Merb internals) you are quite abruptly &amp;#8220;introduced&amp;#8221; to routing, controllers, views and models. These chapters do not aim to provide a comprehensive description of each component, they simply tell you: &lt;em&gt;here&amp;#8217;s how Merb does this&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Out of the first five chapters, favorite is definitely the one about &lt;em&gt;Models&lt;/em&gt;. Although Merb is &lt;span class="caps"&gt;ORM&lt;/span&gt;-agnostic, DataMapper is the &lt;em&gt;de facto standard&lt;/em&gt; for Merb applications, and it fully embrace the framework&amp;#8217;s design and extreme flexibility without being &lt;em&gt;in the way&lt;/em&gt; of your code.&lt;br /&gt;
Foy does an excellent job in this chapter by strategically describing DataMapper&amp;#8217;s code from the top to the very bottom, from the highest abstractions to raw &lt;span class="caps"&gt;SQL&lt;/span&gt; code, using a plethora of snippets taken from the actual Merb code.&lt;/p&gt;
&lt;h3&gt;It&amp;#8217;s about how Merb works, not how to work with Merb&lt;/h3&gt;
&lt;p&gt;After reading the &lt;em&gt;Models&lt;/em&gt; chapter I decided to go back and re-examine the previous chapters. I didn&amp;#8217;t notice until then, but the author sneakily &lt;em&gt;smuggled&lt;/em&gt; a consistent amount of Merb source code into this book. This is rather unusual for books about web frameworks: they normally tell you how to use the framework, not how it was built! While this can be disappointing for people used to read Rails books, it came as a very pleasant surprise to me.&lt;/p&gt;
&lt;p&gt;About 40-50% of this entire book (and I&amp;#8217;m not exaggerating) is Ruby source code. In a good way, it feels like a collection of strategically-positioned code snippets glued together with explanations of the most tricky bits and digressions on how the framework was &lt;em&gt;designed&lt;/em&gt;. In other words, it probably contains just enough text to make sure that the average reader understands the code, but remember that the &lt;em&gt;average reader&lt;/em&gt; of this book must know Ruby failry well.&lt;/p&gt;
&lt;p&gt;There is no pointless prose in this book, no explanations of obvious methods, no fancy words, no useless boasting on how cool the framework is: just an objective description of how Merb works and of the key design decisions behind it. If I may, the only thing that doesn&amp;#8217;t feel quite right with this book is its title: &lt;em&gt;Merb Internals&lt;/em&gt; would have been a better choice. Once you realize this, the book suddenly makes sense, and can even make you a better Ruby programmer.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The Merb Way&lt;/em&gt; does an excellent job in describing how to design a web framework, or any real-world Ruby application for that matter. It teaches you that modularity is the key to flexibility by showing how the Merb stack is organized. Sure, it doesn&amp;#8217;t teach you how to create a blog in five minutes, but perhaps a thorough explanation of how anthentication is implemented (Chapter 9) will actually be useful in two months time, when you&amp;#8217;ll have to create your own Merb plugin from scratch.&lt;/p&gt;
&lt;h3&gt;Some constructive criticism&lt;/h3&gt;
&lt;p&gt;The idea behind this book is clever but a bit dangerous. I flipped through the pages in front of my wife and asked her what was wrong with it. &lt;em&gt;&amp;#8220;There&amp;#8217;s too much code!&amp;#8221;&lt;/em&gt; she said, without hesitation. Precisely.&lt;/p&gt;
&lt;p&gt;It is damn good Ruby code, but sometimes you wish there was more text describing how to use it in practice. Or maybe some code examples on &lt;em&gt;using&lt;/em&gt; the framework on a real-world application. Not a chance. Of all that holy code, there&amp;#8217;s not much featuring something other than Merb itself. Basically the exact opposite of all the other books about Rails or other web frameworks!&lt;/p&gt;
&lt;p&gt;Even accepting the fact that you are not reading a book about developing web applications, there are two more things which could be improved:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Merb&amp;#8217;s design is very intriguing, and you grasp the essentials by reading this book, but a few diagrams here and there and more in-depth digressions on the subjects would have been nice.&lt;/li&gt;
	&lt;li&gt;Besides DataMapper, what I really wanted to read about were Slices and Parts &amp;ndash; unfortunately the chapters about them are far too short and shallow. The reasoning behind this is that &lt;em&gt;their future may be uncertain&lt;/em&gt; due to the Rails 3 merge. Pity.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The death of Merb has been greatly exaggerated. Too bad I &lt;a href="/articles/take-back-your-site-with-nanoc/"&gt;gave up web frameworks altogether&lt;/a&gt; for my site, because after reading this book I would have gone for Merb &lt;em&gt;today&lt;/em&gt; rather than waiting to see the wonders of Rails 3 &lt;em&gt;tomorrow&lt;/em&gt;. Even a book with this title could have been written in a very different way, I would still recommend it if you want to become a better Ruby programmer by learning from the best: Merb code really stands out, even compared to Rails, and Foy Savas does a great job presenting and describing it.&lt;/p&gt;</description>
      <pubDate>Tue, 17 Nov 2009 10:15:36 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/the-merb-way-review/</guid>
      <link>http://www.h3rald.com/articles/the-merb-way-review/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/the-merb-way-review/#comments</comments>
      <category>ruby</category>
      <category>books</category>
      <category>review</category>
    </item>
    <item>
      <title>Take back your site, with nanoc!</title>
      <description>&lt;p&gt;Back in 2004, when I bought the h3rald.com domain, this site was static. At the time I hardly knew &lt;span class="caps"&gt;HTML&lt;/span&gt; and &lt;span class="caps"&gt;CSS&lt;/span&gt;, nevermind server-side languages, so I remember creating a &lt;em&gt;pseudo-template&lt;/em&gt; for the web site layout and using it whenever I wanted to create a new page, to preserve the overall look-and-feel. This was a crude and inefficient strategy, of course: whenever I changed the layout I had to replicate the change in all the pages of the site &amp;ndash; the whole eight of them.&lt;/p&gt;
&lt;p&gt;Five years later, after rebuilding this web site &lt;a href="/h3rald/"&gt;seven times&lt;/a&gt; using different backends (&lt;span class="caps"&gt;PHP&lt;/span&gt; + CakePHP, Ruby + Rails + Typo, etc.), I decided to make it static again, this time with a twist. It all started when I read a &lt;a href="http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html"&gt;post&lt;/a&gt; by Tom Preston-Warner (&lt;a href="http://www.github.com"&gt;GitHub&lt;/a&gt; co-founder) that I finally decided to give it a try. Today, the 8th release of this web site is 100% static: if you load any page, there&amp;#8217;s no server-side interpretation going on, you&amp;#8217;re just browsing a plain &lt;span class="caps"&gt;HTML&lt;/span&gt; page, at most with a few &lt;span class="caps"&gt;AJAX&lt;/span&gt; calls. But let&amp;#8217;s start from the beginning&amp;#8230;&lt;/p&gt;
&lt;h3&gt;Why I don&amp;#8217;t need a blog platform&lt;/h3&gt;
&lt;p&gt;There&amp;#8217;s nothing inherently wrong with blog platforms like Wordpress: they allow &lt;em&gt;anyone&lt;/em&gt; to publish content on the web using a user-friendly administration area. They were built with one thing in mind: make publishing content on the web something as simple as possible, even for people who don&amp;#8217;t know anything about &lt;span class="caps"&gt;HTML&lt;/span&gt;, let alone server-side scripting.&lt;/p&gt;
&lt;p&gt;What about people who &lt;em&gt;do&lt;/em&gt; know about web development though? Do they still need a blog platform? Depends. If you are comfortable with editing files using a text editor, if you enjoy using the command-line on a daily basis, if you like programming and &lt;em&gt;hacking&lt;/em&gt; a little bit, if you don&amp;#8217;t really care about fancy and user-friendly administration backends&amp;#8230; &lt;em&gt;then you probably don&amp;#8217;t&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;All you need is a system to transform a bunch of source files into a web site. The good news is that such system exists &amp;ndash; and you&amp;#8217;re also spoiled for choices!&lt;/p&gt;
&lt;h3&gt;Introducing site compilers&lt;/h3&gt;
&lt;p&gt;The first &lt;em&gt;site compiler&lt;/em&gt; I discovered was &lt;a href="http://webby.rubyforge.org/"&gt;Webby&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[&amp;#8230;] Webby works by combining the contents of a page with a layout to produce &lt;span class="caps"&gt;HTML&lt;/span&gt;. The layout contains everything common to all the pages &amp;mdash; &lt;span class="caps"&gt;HTML&lt;/span&gt; headers, navigation menu, footer, etc. &amp;mdash; and the page contains just the information for that page. You can use your favorite markup language to write your pages; Webby supports quite a few.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There are quite a few applications like Webby, such as:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://nanoc.stoneship.org/"&gt;nanoc&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://snk.tuxfamily.org/lib/rassmalog/doc/guide.html"&gt;Rassmalog&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.jekyllrb.com/"&gt;Jeckyll&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://webgen.rubyforge.org/"&gt;WebGen&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://rog.rubyforge.org/"&gt;Rog&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://rote.rubyforge.org/"&gt;Rote&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://hobix.com/"&gt;Hobix&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://rakeweb.rubyforge.org/wiki/wiki.pl"&gt;RakeWeb&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.apeth.com/RubyFrontierDocs/default.html"&gt;RubyFrontier&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://staticmatic.rubyforge.org/"&gt;StaticMatic&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://staticweb.rubyforge.org/"&gt;StaticWeb&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.zenspider.com/ZSS/Products/ZenWeb/"&gt;ZenWeb&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://yurtcms.roberthahn.ca/"&gt;YurtCMS&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://nanoblogger.sourceforge.net/"&gt;NanoBlogger&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are probably even more, with different features, but they all try to solve the same problem: provide a way to generate static web sites in an automated way.&lt;/p&gt;
&lt;p&gt;I spent some time reading about each one of them, &lt;a href="http://github.com/h3rald/h3rald/issues/closed#issue/1"&gt;evaluating the pros and cons&lt;/a&gt; and in the end I decided to go for &lt;a href="http://nanoc.stoneship.org/"&gt;nanoc&lt;/a&gt;, simply because it was the only one that seemed to fit all my needs.&lt;/p&gt;
&lt;h3&gt;A quick overview of nanoc&lt;/h3&gt;
&lt;p&gt;nanoc is a nifty tool written in Ruby suitable for &lt;em&gt;[&amp;#8230;] building small to medium-sized websites&lt;/em&gt;. In other words, anything which doesn&amp;#8217;t involve some fancy user interaction. For what concerns blogs, the only user interaction is &lt;em&gt;comments&lt;/em&gt; &amp;ndash; but that&amp;#8217;s fine, because there&amp;#8217;s more than one web service for that, such as &lt;a href="http://disqus.com/"&gt;Disqus&lt;/a&gt; or &lt;a href="http://intensedebate.com/"&gt;IntenseDebate&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Some details on the project&lt;/h4&gt;
&lt;p&gt;Compared to the alternatives, nanoc is one of the most mature and most maintained, having hit just a few weeks ago its 3.0 release. Its creator, Denis Defreyne, uses it for his own &lt;a href="http://stoneship.org/"&gt;web site&lt;/a&gt; and is involved with the project on a daily basis, both coding and offering support to nanoc users like myself who regularly ask questions on the &lt;a href="http://groups.google.com/group/nanoc"&gt;nanoc user group&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Denis also seems very concerned about keeping documentation up-to-date &amp;ndash; something that really impressed me from a technical writer&amp;#8217;s point of view. The &lt;a href="http://nanoc.stoneship.org/tutorial/"&gt;tutorial&lt;/a&gt; he put together will get you started in no time, and the &lt;a href="http://nanoc.stoneship.org/manual/"&gt;manual&lt;/a&gt; will explain everything else you may possibly want to know. When release 3.0 came out he even put together a &lt;a href="http://nanoc.stoneship.org/migrating/"&gt;migration guide&lt;/a&gt;. If this is still not enough and you don&amp;#8217;t mind spending some time extending the system, nanoc&amp;#8217;s &lt;a href="http://nanoc.stoneship.org/doc/3.0.0/"&gt;RDoc documentation&lt;/a&gt; is very comprehensive compared to other Ruby projects.&lt;/p&gt;
&lt;h4&gt;Sites, Items and data sources&lt;/h4&gt;
&lt;p style="float:right;"&gt;&lt;img src="/img/pictures/nanoc-structure.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;nanoc ships with a really neat command line tool that can do most of the work for you. &lt;code&gt;Nanoc3 create_site h3rald&lt;/code&gt; will create a new web site in a folder called h3rald. The contents of this folder are laid out according to a particular logic (&lt;em&gt;convention over configuration&lt;/em&gt;, remember?) So:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;content&lt;/strong&gt; &amp;ndash; your articles, pages, stylesheets, images, &amp;#8230;all the site content and assets.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;layouts&lt;/strong&gt; &amp;ndash; the site layouts (and partial layouts)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;lib&lt;/strong&gt; &amp;ndash; place your custom ruby code and vendor libraries here&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;output&lt;/strong&gt; &amp;ndash; your &amp;#8220;compiled&amp;#8221; site, ready to be deployed&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;config.yaml&lt;/strong&gt; &amp;ndash; your site&amp;#8217;s configuration file. The only one (and it&amp;#8217;s just a few lines)&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Rakefile&lt;/strong&gt; &amp;ndash; place any custom Rake task here&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Rules&lt;/strong&gt; &amp;ndash; defines the rules for compilation, layout and routing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#8217;s the default &lt;code&gt;config.yaml&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;data_sources&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; 
&lt;span class="p-Indicator"&gt;-&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;items_root&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;/&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;layouts_root&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;/&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;type&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;filesystem_compact&lt;/span&gt;
  &lt;span class="l-Scalar-Plain"&gt;output_dir&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;output&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;A &lt;em&gt;data source&lt;/em&gt; in nanoc defines where data is retrieved from to create the web site. By default, the &lt;a href="http://nanoc.stoneship.org/doc/3.0.0/Nanoc3/DataSources/FilesystemCompact.html"&gt;filesystem_compact&lt;/a&gt; data source requires that you create two files in the /content folder for each article or page of your web page:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;One containing the actual content of the page&lt;/li&gt;
	&lt;li&gt;Another for the page&amp;#8217;s arbitrary metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By personal preference, I chose the &lt;a href="http://nanoc.stoneship.org/doc/3.0/Nanoc3/DataSources/FilesystemCombined.html"&gt;filesystem_combined&lt;/a&gt; data source, which allows you to combine the content and the metadata of a page in a single file.&lt;/p&gt;
&lt;p&gt;The source code for this very article, for example, starts like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;-----
type: article
tags:
- website
- ruby
- programming
- writing
date: 2009-09-15 13:32:51.049000 +02:00
permalink: take-back-your-site-with-nanoc
title: &amp;quot;Take back your site, with nanoc!&amp;quot;
toc: true
-----
Back in 2004, when I bought the h3rald.com domain, this site was static. At the time I hardly 
knew HTML and CSS, nevermind server-side languages, so I remember creating a _pseudo-template_ for
 the web site layout and using it whenever I wanted to create a new page, to preserve the overall look-and-feel. 
This was a crude and inefficient strategy, of course: whenever I changed the layout I had to replicate the change
 in all the pages of the site &amp;amp;ndash; the whole eight of them.
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;At run time, the content goes through a Textile filter and the metadata is used in layouts, to generate tag links automatically, for example.&lt;/p&gt;
&lt;h4&gt;Layouts, filters, and helpers&lt;/h4&gt;
&lt;p&gt;Layouts in nanoc are similar to layouts and views in Rails, but much simpler. The same applies to helpers. Here&amp;#8217;s a snippet from my &lt;a href="http://github.com/h3rald/h3rald/tree/master/layouts/default.erb"&gt;default layout&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;        &amp;lt;div id=&amp;quot;container&amp;quot;&amp;gt;
          &amp;lt;!-- CONTENT START --&amp;gt;
          &amp;lt;div id=&amp;quot;content&amp;quot; class=&amp;quot;clearfix&amp;lt;%= (@item[:permalink] == &amp;#39;home&amp;#39;) ? &amp;#39; home&amp;#39; : &amp;#39; standard&amp;#39; %&amp;gt;&amp;quot;&amp;gt;
            &amp;lt;h2&amp;gt;&amp;lt;%= @item[:title] %&amp;gt;&amp;lt;/h2&amp;gt;
            &amp;lt;%   case @item[:type]
                when &amp;#39;article&amp;#39; then%&amp;gt;
                &amp;lt;div id=&amp;quot;content-header&amp;quot;&amp;gt;
                  &amp;lt;%= render &amp;#39;article_meta&amp;#39;, :article =&amp;gt; @item %&amp;gt;
                &amp;lt;/div&amp;gt;
              &amp;lt;% end %&amp;gt;
              &amp;lt;hr /&amp;gt;
              &amp;lt;div id=&amp;quot;content-body&amp;quot;&amp;gt;
                &amp;lt;%= yield %&amp;gt;
              &amp;lt;/div&amp;gt;
              &amp;lt;div id=&amp;quot;content-footer&amp;quot;&amp;gt;
                &amp;lt;div class=&amp;quot;share&amp;quot;&amp;gt;
                  &amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;http://w.sharethis.com/button/sharethis.js#publisher=6e34d60c-b14e-4c19-9b2f-7c35a9f0ab09&amp;amp;amp;type=website&amp;amp;amp;linkfg=%23a4282d&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
                  &amp;lt;% if @item[:feed] then %&amp;gt;
                  &amp;lt;a href=&amp;quot;&amp;lt;% @item[:feed_url] || @item[:feed]+&amp;quot;rss/&amp;quot; %&amp;gt;&amp;quot; type=&amp;quot;application/rss+xml&amp;quot; rel=&amp;quot;alternate&amp;quot;&amp;gt;&amp;lt;img src=&amp;quot;/images/theme/feed-icon-14x14.png&amp;quot; alt=&amp;quot;#&amp;quot;/&amp;gt;H3RALD - &amp;lt;%= @item[:feed_title]%&amp;gt;&amp;lt;/a&amp;gt;
                  &amp;lt;% end %&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;%= render &amp;#39;article_buttons&amp;#39; if @item[:type] == &amp;#39;article&amp;#39; %&amp;gt;
              &amp;lt;/div&amp;gt;
            &amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This source code snippet shows quite a few features of nanoc&amp;#8217;s layouts:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You can access the metadata of the page which is being rendered using the &lt;code&gt;@item&lt;/code&gt;, so &lt;code&gt;@item[:title]&lt;/code&gt; returns the page&amp;#8217;s title, for example.&lt;/li&gt;
	&lt;li&gt;Layouts can be nested, and behave like Rails&amp;#8217;s partials. The &lt;code&gt;render&lt;/code&gt; takes a string parameter (the name of the layout to render) and an optional hash parameter to pass variables to the layout.&lt;/li&gt;
	&lt;li&gt;The &lt;code&gt;yield&lt;/code&gt; method is used to include the content of a page.&lt;/li&gt;
	&lt;li&gt;Layouts support any kind of filter, like &lt;span class="caps"&gt;ERB&lt;/span&gt; for example. Go crazy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Helpers can be used in layouts to perform common tasks, like creating links, feeds, navigation elements and so on. Check the &lt;a href="http://nanoc.stoneship.org/doc/3.0.0/"&gt;source code docs&lt;/a&gt; for more info, and of course feel free to create your own as you see fit.&lt;/p&gt;
&lt;p&gt;Finally, filters are used to filter content markup. nanoc ships with &lt;a href="http://nanoc.stoneship.org/manual/#list-of-built-in-filters"&gt;almost everything you need&lt;/a&gt;, from Textile to Haml to RDoc, but nobody forbids you to create your own, and it&amp;#8217;s dead easy.&lt;/p&gt;
&lt;h4&gt;Rules and tasks&lt;/h4&gt;
&lt;p&gt;While tasks (as in Rake tasks) do not constitute a huge part of nanoc (but as usual, you may need to create your own to perform custom operations), Rules became, as of version 3, one of the key concepts to grasp in order to make everything work. Rules are stored in the &lt;code&gt;Rules&lt;/code&gt; file of your nanoc site, they can be used to:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Define routes, i.e. where pages are deployed in the output folder.&lt;/li&gt;
	&lt;li&gt;Define how pages are compiled, which filters to apply to a particular set of pages, which layouts to use, etc.&lt;/li&gt;
	&lt;li&gt;Define how layout are handled, which filters to apply to a particular layout, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find more information in the &lt;a href="http://nanoc.stoneship.org/manual/#rules"&gt;manual&lt;/a&gt;, along with other important information, but for now, let&amp;#8217;s say you should be familiar with &lt;em&gt;most&lt;/em&gt; of nanoc&amp;#8217;s jargon and how it works. Let&amp;#8217;s see what you can do with it, in practice.&lt;/p&gt;
&lt;h3&gt;Migrating from your blog platform&lt;/h3&gt;
&lt;p&gt;As of version 7, h3rald.com has been powered by the &lt;a href="http://www.typosphere.org"&gt;Typo&lt;/a&gt; blog platform. If you are not familiar with it, let&amp;#8217;s just say it&amp;#8217;s a sort of Wordpress built on top of Rails: database backend, pretty admin front-end, tags, comments, and all sort of things a blog may need. While Typo is pleasant enough to use, it has all the inherent disadvantages of any other similar platform:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;It relies on a database&lt;/li&gt;
	&lt;li&gt;It relies on server-side scripting to render pages&lt;/li&gt;
	&lt;li&gt;It uses a complex caching mechanism to produce, ultimately, semi-static pages&lt;/li&gt;
	&lt;li&gt;It may be subject to exploits, attacks, high server loads, and similar&lt;/li&gt;
	&lt;li&gt;You can&amp;#8217;t really customize it beyond a certain point&lt;/li&gt;
	&lt;li&gt;You have to upgrade your backend frequently, and often is not as painless as you may expect&lt;/li&gt;
	&lt;li&gt;You can&amp;#8217;t use versioning tools like git for your content, as it&amp;#8217;s stored in a database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#8217;m not claiming that nanoc is blogging&amp;#8217;s silver bullet (it was not created for that), but for sure:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;It &lt;em&gt;does not&lt;/em&gt; rely on a database&lt;/li&gt;
	&lt;li&gt;It &lt;em&gt;does not&lt;/em&gt; rely on server-side scripting to render pages (not in real-time, anyway)&lt;/li&gt;
	&lt;li&gt;It &lt;em&gt;does not&lt;/em&gt; need a complex caching mechanism simply because it produces static pages&lt;/li&gt;
	&lt;li&gt;It is definitely less prone to nasty things&lt;/li&gt;
	&lt;li&gt;It&amp;#8217;s extremely flexible and hackable with very little effort&lt;/li&gt;
	&lt;li&gt;You don&amp;#8217;t have to upgrade all the time, but it is &lt;em&gt;really&lt;/em&gt; painless if you decide to&lt;/li&gt;
	&lt;li&gt;You can use git and similar: your content is in plain old text files&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rants are beside the point, suffice to say I recently convinced myself that switching from Typo to nanoc was a &lt;em&gt;good thing&lt;/em&gt;, so let&amp;#8217;s see how it worked out.&lt;/p&gt;
&lt;h4&gt;Posts, pages and comments&lt;/h4&gt;
&lt;p&gt;Out of Typo&amp;#8217;s MySQL database, I just wanted to get the following data:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Pages and posts&lt;/li&gt;
	&lt;li&gt;Tags&lt;/li&gt;
	&lt;li&gt;Comments&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Following the approach used by &lt;a href="http://github.com/mojombo/jekyll"&gt;Jekyll&lt;/a&gt;, I decided to use the simple and powerful &lt;a href="http://sequel.rubyforge.org/"&gt;Sequel&lt;/a&gt; gem. I&amp;#8217;m sorry to disappoint you, but the whole migration process can be summarize with the following Rake task:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:migrate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:usr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:pwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:host&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Please provide :db, :usr, :pass&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:db&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:usr&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:pwd&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Sequel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mysql&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:db&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:usr&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:password&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:pwd&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:host&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:host&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;localhost&amp;#39;&lt;/span&gt;
    &lt;span class="c1"&gt;# Remove all existing pages!&lt;/span&gt;
    &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;content&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rmtree&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exist?&lt;/span&gt;
    &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkpath&lt;/span&gt;
    &lt;span class="c1"&gt;# Prepare page data&lt;/span&gt;
    &lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:contents&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;state = &amp;#39;published&amp;#39; || type = &amp;#39;Page&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; 
    &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;total_tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Migrating [&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]: &amp;#39;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;...&amp;quot;&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;tags&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_tags&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:keywords&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;comments&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_comments&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;permalink&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:permalink&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;type&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;downcase&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;date&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:published_at&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;toc&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
      &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;filters_pre&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extension&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_filter&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:text_filter_id&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;convert_code_blocks&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:body&lt;/span&gt;&lt;span class="o"&gt;]+&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:extended&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;
      &lt;span class="n"&gt;write_page&lt;/span&gt; &lt;span class="n"&gt;meta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;extension&lt;/span&gt;
      &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;That&amp;#8217;s it. Well, almost: you can find the &lt;code&gt;get_comments&lt;/code&gt;, &lt;code&gt;get_tags&lt;/code&gt; and &lt;code&gt;get_filter&lt;/code&gt; methods in a separate &lt;a href="http://github.com/h3rald/h3rald/tree/master/lib/utils.rb"&gt;utility file&lt;/a&gt;. Nothing special really, just a few convenience methods wrapping queries or simply processing data. Note how all information, including tags and legacy comments, is saved in each page&amp;#8217;s metadata. The &lt;code&gt;write_page&lt;/code&gt; method simply creates a file in the &lt;code&gt;/contents&lt;/code&gt; folder.&lt;/p&gt;
&lt;h4&gt;Filters and highlighters&lt;/h4&gt;
&lt;p&gt;On my old site, I used mainly Textile and Markdown to write posts. However, some of my really old articles used BBCode, whose corresponding filter is not available in nanoc. No worries, I soon found out that creating a new nanoc filter came down to this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;bb-ruby&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BbcodeFilter&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Nanoc3&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Filter&lt;/span&gt;
  &lt;span class="n"&gt;identifier&lt;/span&gt; &lt;span class="ss"&gt;:bbcode&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bbcode_to_html&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Yes, that&amp;#8217;s it. Granted, the &lt;code&gt;bb-ruby&lt;/code&gt; gem does all the work, but notice how easy it is to just plug in new Ruby code into nanoc&amp;#8217;s architecture!&lt;/p&gt;
&lt;p&gt;The next big challange was code highlighting. After a quick research, I found at least a half dozen of possible solutions to highlight source code. Some were javascript based, others were based on a server-side language like &lt;span class="caps"&gt;PHP&lt;/span&gt;, Ruby or Python. Again, I looked at Jekyll for inspiration and discovered they integrated the &lt;a href="http://www.pygments.org"&gt;Pygments&lt;/a&gt; &lt;em&gt;Python&lt;/em&gt; library. Why use a Python library for code highlighting in a Ruby-based project? Because there&amp;#8217;s nothing to stop you (if you can run Python on your server, that is), because it looks very neat and because it supports a lot of different programming languages.&lt;/p&gt;
&lt;p&gt;Lazy as I am, I more or less dropped &lt;a href="http://github.com/h3rald/h3rald/blob/master/lib/albino.rb"&gt;Chris Wanstrath&amp;#8217;s Ruby wrapper&lt;/a&gt; into my &lt;code&gt;/lib&lt;/code&gt; folder (I just used Open3 instead of Open4 for Windows compatibility), and monkey-patched nanoc&amp;#8217;s filtering helper as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Nanoc3::Helpers::Filtering&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;highlight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;syntax&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Seamlessly ripped off from the filter method...&lt;/span&gt;
    &lt;span class="c1"&gt;# Capture block&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;capture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Reconvert &lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gsub!&lt;/span&gt; &lt;span class="sr"&gt;/&amp;lt;%/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
    &lt;span class="c1"&gt;# Filter captured data&lt;/span&gt;
    &lt;span class="n"&gt;filtered_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;notextile&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="no"&gt;Albino&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;syntax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;/notextile&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; 
    &lt;span class="c1"&gt;# Append filtered data to buffer&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;_erbout&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;filtered_data&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Nanoc3&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Helpers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Filtering&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;There you go, another thing sorted.&lt;/p&gt;
&lt;h4&gt;Tags and Feeds&lt;/h4&gt;
&lt;p&gt;Adding tagging support was a tiny bit more tricky. nanoc supports content tagging out-of-the-box though metadata and a simple helper, but I wanted to create tag pages (with feeds). Nothing too difficult though, it all came down to a simple Rake task:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:tags&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Nanoc3&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_data&lt;/span&gt;
    &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Pathname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;content/tags&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rmtree&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exist?&lt;/span&gt;
    &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkpath&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="c1"&gt;# Collect tag and page data&lt;/span&gt;
    &lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:tags&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
      &lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:tags&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
          &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;]+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
          &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="c1"&gt;# Write pages&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each_pair&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;write_tag_page&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;
      &lt;span class="n"&gt;write_tag_feed_page&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;RSS&amp;#39;&lt;/span&gt;
      &lt;span class="n"&gt;write_tag_feed_page&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Atom&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Again, you can find all the other simple utility methods in my &lt;a href="http://github.com/h3rald/h3rald/tree/master/lib/utils.rb"&gt;utility file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When it came to feeds, I decided to create a new method for the Blogging helper to create &lt;span class="caps"&gt;RSS&lt;/span&gt; feeds, although nanoc does come with an Atom feed generator:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rss_feed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;builder&amp;#39;&lt;/span&gt;
    &lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;time&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;prepare_feed&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
    &lt;span class="c1"&gt;# Create builder&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;
    &lt;span class="n"&gt;xml&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Builder&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;XmlMarkup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:target&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:indent&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Build feed&lt;/span&gt;
    &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instruct!&lt;/span&gt;
    &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rss&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:version&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;2.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="vi"&gt;@item&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;language&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;en-us&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastBuildDate&lt;/span&gt; &lt;span class="vi"&gt;@item&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:last&lt;/span&gt;&lt;span class="o"&gt;][&lt;/span&gt;&lt;span class="ss"&gt;:date&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;rfc822&lt;/span&gt;
        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ttl&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;40&amp;#39;&lt;/span&gt;
        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="vi"&gt;@site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:base_url&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;
        &lt;span class="vi"&gt;@item&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:articles&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
          &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="vi"&gt;@item&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:content_proc&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pubDate&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:date&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;rfc822&lt;/span&gt;
            &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;guid&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="vi"&gt;@site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:author_email&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;comments&lt;/span&gt; &lt;span class="n"&gt;url_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;#comments&amp;#39;&lt;/span&gt;
            &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:tags&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
              &lt;span class="n"&gt;xml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;category&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
            &lt;span class="k"&gt;end&lt;/span&gt;
          &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="n"&gt;buffer&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Nothing too daunting, once you get used to Ruby&amp;#8217;s &lt;span class="caps"&gt;XML&lt;/span&gt; builder. I followed a similar approach for my &lt;a href="/archives"&gt;monthly archives&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;3rd-party services&lt;/h4&gt;
&lt;p&gt;Finally, the interactive bits. I basically turned to third-party services and a bit of jQuery for everything which required user-interaction or pulling data from other web sites. Here&amp;#8217;s a list of services and APIs I currently use:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://intensedebate.com/"&gt;IntenseDebate&lt;/a&gt;, for comments.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://code.google.com/apis/ajaxsearch/web.html"&gt;Google &lt;span class="caps"&gt;AJAX&lt;/span&gt; Search &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt; for internal site-wide search.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://apiwiki.twitter.com/"&gt;Twitter &lt;span class="caps"&gt;JSON&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt; to fetch tweets.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://delicious.com/help/json"&gt;Delicious &lt;span class="caps"&gt;JSON&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt; to fetch delicious bookmarks.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.backtype.com/developers"&gt;BackType &lt;span class="caps"&gt;JSON&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt; to fetch comments from other sites.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://develop.github.com/"&gt;GitHub &lt;span class="caps"&gt;JSON&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt; to fetch GitHub commits for most of my &lt;a href="/projects"&gt;projects&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to know how I integrated them, check out my &lt;a href="http://github.com/h3rald/h3rald/tree/master/content/js"&gt;/js folder&lt;/a&gt;, it was very simple, really.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;I was very happy of switching to nanoc. It didn&amp;#8217;t take me long, and I spent most of the time with non-nanoc issues (brushing up jQuery, &lt;span class="caps"&gt;CSS&lt;/span&gt;, graphics, etc.). Of course knowing the Ruby programming language helps, and if you&amp;#8217;re not comfortable with hacking your way a little bit, then maybe it&amp;#8217;s not for you.&lt;/p&gt;
&lt;p style="float:left;"&gt;&lt;img src="/img/pictures/nanoc-compile.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Personally, I&amp;#8217;ve been waiting for something like nanoc for a long time: its simple and yet powerful architecture makes you able to do virtually anything with it. For the first time in a long time, I feel like I&amp;#8217;m in complete control of my web site, I know every bits of it and if I want to change the way it works or looks I only have to touch a few files.&lt;/p&gt;
&lt;p&gt;nanoc&amp;#8217;s metadata is mindblowing for its simplicity and power: although you&amp;#8217;re not dealing with a database, you can query your content in the easiest ways possible. Whenever I needed a way to easily access pages, filter them, add extra logic to them, I just added metadata. If you forget something, you don&amp;#8217;t have to change your database tables, create new relationships or anything of the sort, you simply add metadata to pages.&lt;/p&gt;
&lt;p&gt;Be warned that tweaking nanoc gets addictive very quickly: you soon end up creating silly little tasks for making things just the way you want. For me, adding a new article to my blog now just means this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;$ rake site:article name=take-back-your-site-with-nanoc
$ vim content/articles/take-back-your-site-with-nanoc
... write &amp;amp; close the file ...
$ Nanoc3 compile 
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&amp;#8230;Exactly what I need. Nothing more, nothing less.&lt;/p&gt;</description>
      <pubDate>Tue, 15 Sep 2009 11:32:51 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/take-back-your-site-with-nanoc/</guid>
      <link>http://www.h3rald.com/articles/take-back-your-site-with-nanoc/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/take-back-your-site-with-nanoc/#comments</comments>
      <category>website</category>
      <category>ruby</category>
      <category>programming</category>
      <category>writing</category>
    </item>
    <item>
      <title>Personal Log - June 2009</title>
      <description>&lt;p&gt;Welcome to yet another of my extremely boring, excessively fragmented &lt;a href="/tags/personal_log"&gt;personal log&lt;/a&gt; posts. I&amp;#8217;m seriously thinking of dropping the whole series in favor of more frequent (and shorter) blog posts, starting from next year. This means you&amp;#8217;ll probably have to read &lt;em&gt;another six&lt;/em&gt; of these priceless gems, until december 2009.&lt;br /&gt;
As usual, feel free to skim through as each of the following &lt;em&gt;sections&lt;/em&gt; is almost completely unrelated to the others.&lt;/p&gt;
&lt;h3&gt;H3RALD Web Site v8.0&lt;/h3&gt;
&lt;p&gt;It&amp;#8217;s the time of the year, again. It doesn&amp;#8217;t happen &lt;em&gt;every&lt;/em&gt; year but it&amp;#8217;s definitely a trend (hence the high version number): I&amp;#8217;m going to redesign &amp;amp; redevelop my web site.&lt;/p&gt;
&lt;p&gt;This time is not the usual &amp;#8220;Let&amp;#8217;s pick another language and another framework and start from scratch&amp;#8221;, but a rather more radical shift, and yet at the same time less painful. The idea is to transform H3RALD.com into a 100% static web site, without losing anything in functionality (gaining, if anything!).&lt;/p&gt;
&lt;p&gt;&lt;a href="/http://tom.preston-werner.com/"&gt;Tom Preston-Werner&lt;/a&gt; is definitely &lt;em&gt;not&lt;/em&gt; the first person to &lt;a href="http://tom.preston-werner.com/2008/11/17/blogging-like-a-hacker.html"&gt;blog like a hacker&lt;/a&gt;, and his very own &lt;a href="http://www.jekyllrb.com/"&gt;Jekyll&lt;/a&gt; is definitely not the first static web site generator our there, nevertheless, he inspired me to embrace what seems to be one of the latest trend in developer&amp;#8217;s blogs.&lt;/p&gt;
&lt;p&gt;The idea is simple: turn all the blog posts and pages into static content, and rely on third party web services for things like comments, search etc. For a rather extreme by very interesting example, see &lt;a href="http://tagaholic.me/"&gt;Tagaholic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The advantages of this approach are many:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Free yourself from a database.&lt;/li&gt;
	&lt;li&gt;Free yourself from a resource-hungry, server-side app (&lt;a href="http://wiki.github.com/fdv/typo/"&gt;Typo&lt;/a&gt;, in this case).&lt;/li&gt;
	&lt;li&gt;Increase speed and reliability, without using caching or similar artifacts.&lt;/li&gt;
	&lt;li&gt;Keep everything under version control.&lt;/li&gt;
	&lt;li&gt;Don&amp;#8217;t worry about breaking things when upgrading (even if the static content generator changes, it shouldn&amp;#8217;t really break things).&lt;/li&gt;
	&lt;li&gt;Unleash the power of client-side scripting (namely, JQuery).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For now, I&amp;#8217;m just brainstorming a little bit on &lt;a href="http://github.com/h3rald/h3rald-website/issues"&gt;GitHub&lt;/a&gt;, feel free to participate. The first step is obviously choosing a static content generator, and atm Jekyll seems to be slightly ahead of Webby. Opinions?&lt;/p&gt;
&lt;h3&gt;Glyph&lt;/h3&gt;
&lt;p&gt;Did you ever want to write a short manual or a book, or even a long article? If so, chances are you gave LaTeX a shot and either fully embraced its philosophy or totally refused it. Sadly, I belong to the second category: I believe sequential documents like manuals or books should be easier to create simply by using &lt;span class="caps"&gt;HTML&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Whever I have a chance to actually start working on it, Glyph will become a &lt;em&gt;document authoring framework&lt;/em&gt;, i.e. a way to create visually appealing documents in a simple way. All the ingredients are there, it&amp;#8217;s only necessary to glue them together in a pretty form:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Textile (and &lt;a href="http://redcloth.org/"&gt;RedCloth&lt;/a&gt;) to produce clean &lt;span class="caps"&gt;HTML&lt;/span&gt; code from a human-readable markup&lt;/li&gt;
	&lt;li&gt;CSS3 to specify page rules&lt;/li&gt;
	&lt;li&gt;A few rake scripts to produce a standalone &lt;span class="caps"&gt;HTML&lt;/span&gt; file, &lt;span class="caps"&gt;TOC&lt;/span&gt;, Index etc.&lt;/li&gt;
	&lt;li&gt;An internal &lt;span class="caps"&gt;DSL&lt;/span&gt; for the document structure and metadata&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.liquidmarkup.org/"&gt;Liquid&lt;/a&gt; for control flow, snippets and filters&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.princexml.com/"&gt;PrinceXML&lt;/a&gt; to generate a &lt;span class="caps"&gt;PDF&lt;/span&gt; from &lt;span class="caps"&gt;HTML&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This project is still in planning stage, feel free to have a look at the &lt;a href="http://github.com/h3rald/glyph/issues"&gt;issues/features page&lt;/a&gt; on GitHub. Feedback is appreciated, as usual.&lt;/p&gt;
&lt;h3&gt;Vim files &amp;amp; &lt;em&gt;the Stash&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;If you read the previous two sections of this post, you may have noticed that I&amp;#8217;m growing more and more fond of git (and GitHub). Besides the repositories I already mentioned earlier on, I also created a personal &lt;a href="http://github.com/h3rald/stash"&gt;stash&lt;/a&gt;, which I&amp;#8217;m using mainly to store some of my Linux dotfiles, article drafts and &amp;#8230;Vim customizations.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re looking for a color scheme for Vim, check out my very own &lt;a href="/herald-vim-color-scheme"&gt;herald.vim&lt;/a&gt;, and tell me what you think.&lt;/p&gt;
&lt;h3&gt;Getting ready for the Big Step&lt;/h3&gt;
&lt;p&gt;This will probably be my last post as a free man, as I&amp;#8217;m getting married (civilly) on July 2nd and (religiously) on July 11th. &lt;br /&gt;
Luckily the photographer agreed to give us a CD with all the pictures taken on the big day, with no copyright restrictions attached to it (believe it or not, some photographers don&amp;#8217;t allow you to republish &lt;em&gt;your own&lt;/em&gt; photos unless you ask them first), so I&amp;#8217;ll probably write a long post with pictures when we come back from our (half) honeymoon.&lt;/p&gt;
&lt;p&gt;Everything is pretty much organized. We had troubles with the waistcoats we got from eBay: they were cut almost randomly to &lt;em&gt;resamble&lt;/em&gt; waistcoats, but they weren&amp;#8217;t so we had to re-order another lot of 7 sets (waistcoat, cravat &lt;em&gt;and&lt;/em&gt; shirt this time) from another seller, this time UK-based. I seriously hope to get them in time.&lt;/p&gt;
&lt;p&gt;On the 24th we&amp;#8217;re having a party at our house. If you were invited, feel free to drop by, otherwise be prepared to be thrown out of the window (4th floor) by one of our ushers (Roxanne&amp;#8217;s &lt;em&gt;big&lt;/em&gt; brother). It&amp;#8217;s probalby going to be about 30-40 people in the end, mainly because most of my office can&amp;#8217;t come due to holidays they booked in advance.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s left to do now? Well:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Send the bomboniere over to Ireland&lt;/li&gt;
	&lt;li&gt;Make sure my dad actually ships the 96 specially-bottled bottles of our own wine to uncle John, in Ireland.&lt;/li&gt;
	&lt;li&gt;Make sure uncle John doesn&amp;#8217;t drink all the 96 bottles of wine before the wedding reception.&lt;/li&gt;
	&lt;li&gt;Make sure my best man understood that the speech he has do make &lt;em&gt;must&lt;/em&gt; be in English, at least 3 minutes long and not too offensive to the groom.&lt;/li&gt;
	&lt;li&gt;Pay a huge, colossal heap of money for the whole thing. It&amp;#8217;s going to cost us (and my dad) quite a bit, in the end. But it&amp;#8217;s a once-in-a-lifetime experience, after all (getting totally trashed in a fancy hotel with all your family, including 2nd and 3rd grade cousins).&lt;/li&gt;
&lt;/ul&gt;</description>
      <pubDate>Mon, 29 Jun 2009 00:24:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/log-jun-2009/</guid>
      <link>http://www.h3rald.com/articles/log-jun-2009/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/log-jun-2009/#comments</comments>
      <category>personal_log</category>
      <category>vim</category>
      <category>ruby</category>
      <category>wedding</category>
    </item>
    <item>
      <title>Personal Log - April 2009</title>
      <description>&lt;p&gt;April is tratidionally a rather busy month: Easter, public holidays, and &amp;mdash; always &amp;mdash; some deadline to meet at work. Moreover, my birthday is also in April which makes it even more busy! Let&amp;#8217;s see what happened this year&amp;#8230;h3. Using Ruby in a corporate environment&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been using Ruby at work for a while now. I started off writing some automation script for my own needs, then someone noticed it and asked me if by chance I could develop some scripts for them, for automating part of their own job, and so on. My boss ultimately noticed it, and she liked the idea of me investing a small portion of my time to make other people save huge amount of &lt;em&gt;their&lt;/em&gt; time, so now I am &lt;em&gt;officially&lt;/em&gt; in charge of workflow improvements and automation (it&amp;#8217;s even in my job description!).&lt;/p&gt;
&lt;p&gt;This month a colleague of mine and I had to figure out a way to write some documents &lt;strong&gt;once&lt;/strong&gt; in &lt;span class="caps"&gt;XML&lt;/span&gt; format and then produce different kind of outputs (other &lt;span class="caps"&gt;XML&lt;/span&gt; files, PDFs, etc.) using the &lt;a href="http://dita-ot.sourceforge.net/"&gt;&lt;span class="caps"&gt;DITA&lt;/span&gt; Open Toolkit&lt;/a&gt;. Originally we thought the toolkit would do most of the job, but we soon realized we needed to tweak and change a lot more than what we usually expected.&lt;/p&gt;
&lt;p&gt;We ended up hacking together a &lt;em&gt;system&lt;/em&gt; using:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://office.microsoft.com/en-us/infopath/default.aspx"&gt;Microsoft Infopath&lt;/a&gt; as &lt;span class="caps"&gt;XML&lt;/span&gt; editor for the end users (the company buys it by default, so no worries there)&lt;/li&gt;
	&lt;li&gt;A Ruby program to parse and manipulate the original &lt;span class="caps"&gt;XML&lt;/span&gt; and produce &lt;span class="caps"&gt;DITA&lt;/span&gt;-compatible &lt;span class="caps"&gt;XML&lt;/span&gt; files.&lt;/li&gt;
	&lt;li&gt;Some &lt;a href="http://ant.apache.org/"&gt;Apache Ant&lt;/a&gt; tasks available in the open toolkit to produce an &lt;span class="caps"&gt;XSL&lt;/span&gt;-FO file&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://xmlgraphics.apache.org/fop/"&gt;Apache &lt;span class="caps"&gt;FOP&lt;/span&gt;&lt;/a&gt; to produce the &lt;span class="caps"&gt;PDF&lt;/span&gt; from the &lt;span class="caps"&gt;XSL&lt;/span&gt;-FO file&amp;#8230;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The thing seems to work fine (after a lot of tweaking), and I really enjoyed creating the Ruby program to &lt;em&gt;glue&lt;/em&gt; everything together. I even got a chance to introduce my colleagues to the wonderful world of &lt;a href="http://hobix.com/textile/"&gt;Textile&lt;/a&gt; (they are so happy that they don&amp;#8217;t want to use &lt;span class="caps"&gt;WYSIWYG&lt;/span&gt; editors anymore!).&lt;/p&gt;
&lt;h3&gt;Easter in London&lt;/h3&gt;
&lt;p&gt;As usual, Roxanne and I spent our Easter holidays in London, at her brother&amp;#8217;s place. This year we actually had 9 days to go around &lt;del&gt;squandering money&lt;/del&gt;  spending &lt;em&gt;wisely&lt;/em&gt; in food, books, clothes and entertainment.&lt;/p&gt;
&lt;p&gt;Most notably, I managed to drag Roxanne to &lt;a href="http://www.foyles.co.uk/"&gt;Foyles&lt;/a&gt; and I got myself a copy of &lt;a href="http://www.pragprog.com/the-pragmatic-programmer"&gt;The Pragmatic Programmer&lt;/a&gt;, which I&amp;#8217;m reading avidly. If it was up to me I was going to buy half of the computing section, but Roxanne &lt;em&gt;kindly pointed out&lt;/em&gt; that I could get all of them from Amazon for half the price. &lt;br /&gt;
And she was right: for my birthday I preordered a copy of &lt;a href="http://www.amazon.com/Programming-Language-Pragmatics-Third-Michael/dp/0123745144"&gt;Programming Language Pragmatics, 3rd Ed.&lt;/a&gt;, which should be shipped soon.&lt;/p&gt;
&lt;h3&gt;Wedding planning&lt;/h3&gt;
&lt;p&gt;My spreadsheets for the wedding guests, wedding expenses (!) and &amp;#8230;suit sizes are getting bigger and bigger. We managed to book a lot of flights to Ireland to my parents, us, relatives etc., but there are still quite a few things to do for the wedding. The most urgent thing to do right now is sending the invites: we had them printed with the words &lt;em&gt;&lt;span class="caps"&gt;RSVP&lt;/span&gt; within May&lt;/em&gt; on them, so they &lt;em&gt;have&lt;/em&gt; to be out in one or two weeks at most.&lt;/p&gt;
&lt;p&gt;The other thing which must be sorted soon are the suits. According to English (and Irish) tradition, the groom, the bestman, the father of the groom, the father  of the bride and the ushers have to wear the same type of suit, with minor differences (the color of the waistcoats?). In my case, this means getting 7 (&lt;span class="caps"&gt;SEVEN&lt;/span&gt;) &lt;em&gt;morning suits&lt;/em&gt; off eBay, in the right sizes! Hopefully I&amp;#8217;ll be able to get them by the end of next week (if my bestman manages to let me know his sizes).&lt;/p&gt;
&lt;h3&gt;XBox 360 Gaming&lt;/h3&gt;
&lt;p&gt;Now that our new XBox 360 finally came through, Roxanne and I have a lot of hours of hard core week end gaming ahead of us! This, added to the physiological increase of stress due to the wedding, may result in a temporary slowdown of my coding and writing activities.&lt;br /&gt;
Right now we&amp;#8217;re playing &lt;a href="http://xbox360.ign.com/objects/949/949455.html"&gt;Mirror&amp;#8217;s Edge&lt;/a&gt;, &lt;a href="http://xbox360.ign.com/objects/718/718963.html"&gt;Mass Effect&lt;/a&gt;, and &lt;a href="http://xbox360.ign.com/objects/746/746631.html"&gt;Unreal Tournment &lt;span class="caps"&gt;III&lt;/span&gt;&lt;/a&gt;. The last one was a special surprise present from Roxanne (&lt;em&gt;&amp;#8220;&amp;#8230;so we can kill each other!&amp;#8221;&lt;/em&gt; &amp;mdash; she&amp;#8217;s really lovely at times!).&lt;/p&gt;
&lt;h3&gt;Other tech-related tidbits&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;I can&amp;#8217;t wait to go to the cinema to watch &lt;a href="http://www.imdb.com/title/tt0796366/"&gt;Star Trek XI&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;I started using &lt;a href="http://www.shelfari.com/"&gt;Shelfari&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;I started using &lt;a href="http://start.io"&gt;Star.io&lt;/a&gt; as my personal, bare-bones start page.&lt;/li&gt;
	&lt;li&gt;I recently &lt;a href="http://www.h3rald.com/articles/concatenative-020"&gt;released Concatenative 0.2.0&lt;/a&gt;.&lt;/li&gt;
	&lt;li&gt;I&amp;#8217;m currently evaluating the possibility to create a Ruby-based &lt;em&gt;Document Authoring Framework&lt;/em&gt;. Stay tuned.&lt;/li&gt;
&lt;/ul&gt;</description>
      <pubDate>Tue, 28 Apr 2009 04:11:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/log-apr-2009/</guid>
      <link>http://www.h3rald.com/articles/log-apr-2009/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/log-apr-2009/#comments</comments>
      <category>personal_log</category>
      <category>ruby</category>
      <category>books</category>
      <category>wedding</category>
    </item>
    <item>
      <title>Concatenative 0.2.0 released</title>
      <description>&lt;p&gt;Version 0.2.0. of the &lt;a href="/concatenative"&gt;Concatenative&lt;/a&gt; &lt;span class="caps"&gt;DSL&lt;/span&gt; has been &lt;a href="http://rubyforge.org/frs/?group_id=8068&amp;amp;release_id=33575"&gt;released&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here are some highlights from the changelog:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Implemented new combinators:
	&lt;ul&gt;
		&lt;li&gt;binrec&lt;/li&gt;
		&lt;li&gt;split&lt;/li&gt;
		&lt;li&gt;twodip&lt;/li&gt;
		&lt;li&gt;threedip&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Performance improvements:
	&lt;ul&gt;
		&lt;li&gt;Stack is never copied.&lt;/li&gt;
		&lt;li&gt;No symbol/string conversion when processing words.&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
	&lt;li&gt;Pseudo-namespace support (e.g. :kernel/:while and :math/:factorial)&lt;/li&gt;
	&lt;li&gt;~ and &amp;lt;= operators to unquote and define words, respectively.&lt;/li&gt;
	&lt;li&gt;No more uppercase words!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Oddly enough, I realized that it is possible to defined methods named after reserved words like &amp;#8220;while&amp;#8221; or &amp;#8220;if&amp;#8221;, so now all the concatenative words (combinators) in &lt;code&gt;kernel.rb&lt;/code&gt; are now defined &lt;em&gt;without&lt;/em&gt; a leading undersore. Similarly, there&amp;#8217;s no real need to use &lt;span class="caps"&gt;UPPERCASE&lt;/span&gt; symbols, so as a result, method lookup is significantly faster and will use less resources.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s how the lookup works. Say you have the following program:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:concat&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If &lt;code&gt;:concat&lt;/code&gt; has been defined by the user (&lt;code&gt;:concat &amp;lt;= [...]&lt;/code&gt;), that definition will be used, otherwise the &lt;code&gt;Concatenative::Kernel&lt;/code&gt; combinator &lt;code&gt;concat&lt;/code&gt; will be called. If you want to use the corresponding Ruby method, all you have to do is specifying the arity explicitly using the &lt;code&gt;|&lt;/code&gt; operator.&lt;/p&gt;
&lt;p&gt;To remove any ambiguity, it is now possible to specify the &lt;em&gt;namespace&lt;/em&gt; of a word explicitly, e.g. :kernel/:concat or :ruby/concat. The &lt;code&gt;/&lt;/code&gt; operator simply concatenates the two symbols together (&lt;code&gt;:"kernel/concat"&lt;/code&gt;) and sets the namespace (&lt;code&gt;:kernel&lt;/code&gt;) and name (&lt;code&gt;:concat&lt;/code&gt;) of the new symbol. &lt;code&gt;:kernel&lt;/code&gt; and &lt;code&gt;:ruby&lt;/code&gt; are not meant to be used when defining new words, but you can use anything else you like, for example :math/:factorial or :local/:a, etc.&lt;/p&gt;
&lt;p&gt;As I pointed out in the &lt;a href="/articles/concatenative-programming-in-ruby"&gt;first article&lt;/a&gt; about concatenative, even with the new performance improvement a concatenative program still runs slower than a standard Ruby program, but at least now you won&amp;#8217;t run out of stack space (the &lt;em&gt;Ruby&lt;/em&gt; stack, in this case) too soon.&lt;/p&gt;
&lt;p&gt;If you have any issues to report, feature requests, etc., feel free to use &lt;a href="http://github.com/h3rald/concatenative/issues"&gt;GitHub&lt;/a&gt; to do so.&lt;/p&gt;</description>
      <pubDate>Sun, 19 Apr 2009 07:42:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/concatenative-020/</guid>
      <link>http://www.h3rald.com/articles/concatenative-020/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/concatenative-020/#comments</comments>
      <category>ruby</category>
      <category>concatenative</category>
    </item>
    <item>
      <title>Personal Log - March 2009</title>
      <description>&lt;p&gt;Another month &lt;em&gt;without&lt;/em&gt; the Internet at home. This is getting really annoying, and I decided to change provider, &lt;strong&gt;again&lt;/strong&gt;, hoping that I&amp;#8217;ll eventually get my broadband back, someday. Luckily I can still go online at work, but of course it&amp;#8217;s not the same thing: my time on Twitter and Facebook is now basically limited to weekends only, when Roxanne and I go down to Tuscany to stay with her parents.&lt;/p&gt;
&lt;h3&gt;Concatenative programming&lt;/h3&gt;
&lt;p&gt;For some weird reason I became fond of the &lt;a href="http://en.wikipedia.org/wiki/Concatenative_programming_language"&gt;Concatenative programming paradigm&lt;/a&gt;. I started reading about &lt;a href="http://www.latrobe.edu.au/philosophy/phimvt/joy/j00rat.html"&gt;Joy&lt;/a&gt; and then started to work on a Ruby &lt;span class="caps"&gt;DSL&lt;/span&gt; able to do the similar things: &lt;a href="/concatenative/"&gt;Concatenative&lt;/a&gt;. Another pet project &amp;mdash; as if I didn&amp;#8217;t have enough things to do already!&lt;/p&gt;
&lt;p&gt;Some people seemed pleased about it, especially on &lt;a href="http://www.reddit.com/r/ruby/comments/887kn/concatenative_programming_in_ruby"&gt;Reddit&lt;/a&gt; and &lt;a href="http://dzone.com/links/concatenative_programming_in_ruby.html"&gt;dzone&lt;/a&gt;. The downside of it is that it&amp;#8217;s still fairly slow if compared to Ruby code (which is not exactly fast, either!), so if I had some spare time I should really try to implement it as a C extension, maybe.&lt;/p&gt;
&lt;h3&gt;Learning new programming languages?&lt;/h3&gt;
&lt;p&gt;Incidentally, I&amp;#8217;m still fighting with myself on whether to learn another programming language or not. At this point, learning &lt;a href="http://www.factorcode.org"&gt;Factor&lt;/a&gt; could turn out to be more natural than months ago. However, I would only learn new programming languages as a hobby, as I don&amp;#8217;t need to do so for profit: luckily I&amp;#8217;m still a happy technical writer and I enjoy my job.&lt;/p&gt;
&lt;p&gt;I admit, I&amp;#8217;m still looking for &lt;em&gt;the&lt;/em&gt; perfect programming language which is fun to learn (not easy: fun), elegant, minimalist, fast, general purpose and cross platform (meaning Linux, Windows, and Windows Mobile as well). Of course there is no such thing out there and there will never be, so I&amp;#8217;m still evaluating the current alternatives. Possible candidates are Haskell, Factor, some dialect of Lisp or C. &lt;br /&gt;
Why C? Well, because I didn&amp;#8217;t do much with it since my first year at uni, and it could still be useful to write Ruby extensions or implement something at a lower level. After so much time getting spoiled by high level languages, I kinda miss the low level stuff. Ahhh where are all the pointers gone?!&lt;/p&gt;
&lt;p&gt;On the other hand, I&amp;#8217;m getting married soon, and I should use these months to help my wife-to-be a bit more with wedding planning (see next section). After all, I can always learn a new programming language &lt;em&gt;after&lt;/em&gt; getting married, right? &amp;#8230;&lt;em&gt;right?!&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Wedding planning&lt;/h3&gt;
&lt;p&gt;Roxanne and I are slowly getting more and more things done for the wedding. Every attempt I made to introduce her to &lt;a href="http://en.wikipedia.org/wiki/Getting_things_done"&gt;&lt;span class="caps"&gt;GTD&lt;/span&gt;&lt;/a&gt; failed miserably so far, or better, it worked too well: she is now getting used to make lists and deciding on our &lt;em&gt;next actions&lt;/em&gt; for the weekend. &lt;br /&gt;
This weekend we booked our flights to Ireland, looked at cottages and hotels for the three days after the wedding (not the honeymoon yet, we&amp;#8217;ll have a late honeymoon in autumn), chose the waistcoats for me, my bestman and the ushers, and &amp;#8230;booked the wedding car!&lt;br /&gt;
Now, this turned out to be good fun! Take a look at &lt;a href="http://www.alleventslimos.com/Wedding/rolls_silver_cloud.html"&gt;Ruby&lt;/a&gt; (yes, yes, I know&amp;#8230; ), a Silver Cloud II 1961 Rolls Royce which will be ours for (less than) one day!&lt;/p&gt;
&lt;h3&gt;Other tech-related tidbits&lt;/h3&gt;
&lt;ul&gt;
	&lt;li&gt;I successfully migrated to Ubuntu 9.0.4 Jaunty. Everything works, except the flash plugin for Firefox.&lt;/li&gt;
	&lt;li&gt;I&amp;#8217;m now using TweetDeck as my main Twitter client on both Windows and Linux.&lt;/li&gt;
	&lt;li&gt;I&amp;#8217;m thinking of buying (after the wedding) an Eee PC (no Macs: Ubuntu is sleek and powerful enough &amp;emdash;and free, too).&lt;/li&gt;
	&lt;li&gt;We finally got an XBox 360 from eBay, this time it came through the post.&lt;/li&gt;
	&lt;li&gt;Roxanne is thinking of buying a big &lt;span class="caps"&gt;LCD&lt;/span&gt; TV to go with it &amp;emdash; I&amp;#8217;m politely (and sadly) postponing till after the wedding.&lt;/li&gt;
	&lt;li&gt;After listening a &lt;span class="caps"&gt;FLOSS&lt;/span&gt; Weekly episode featuring it, I think I&amp;#8217;ll get myself an &lt;a href="http://arduino.cc/"&gt;Arduino Board&lt;/a&gt; for my birthday.&lt;/li&gt;
&lt;/ul&gt;</description>
      <pubDate>Mon, 30 Mar 2009 04:04:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/log-mar-2009/</guid>
      <link>http://www.h3rald.com/articles/log-mar-2009/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/log-mar-2009/#comments</comments>
      <category>personal_log</category>
      <category>wedding</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Concatenative programming in Ruby</title>
      <description>&lt;p&gt;A while ago, I sat down examining a few &lt;a href="http://www.h3rald.com/articles/10-programming-languages"&gt;alternative programming languages&lt;/a&gt; I might decide to learn someday. Each of those languages has its own peculiarities, and I didn&amp;#8217;t choose them randomly, I chose them based on their popularity, power, paradigm and how actively they are developed.&lt;/p&gt;
&lt;p&gt;I included &lt;a href="http://factorcode.org/"&gt;Factor&lt;/a&gt; as the only representative for &lt;em&gt;concatenative programming&lt;/em&gt;, an interesting way to write programs, but seldom used in &amp;#8220;recent&amp;#8221; languages (except for Factor and a few others).&lt;/p&gt;
&lt;h3&gt;The Joy of concatenative programming&lt;/h3&gt;
&lt;p&gt;If you have absolutely no clue on what I&amp;#8217;m talking about, you should consider looking at the home page for the &lt;a href="http://www.latrobe.edu.au/philosophy/phimvt/joy.html"&gt;Joy Programming Language&lt;/a&gt;, or maybe just the &lt;a href="http://www.latrobe.edu.au/philosophy/phimvt/joy/j00ovr.html"&gt;overview&lt;/a&gt;: it should be enough to tikle your curiosity.&lt;/p&gt;
&lt;p&gt;Joy is often considered the &lt;em&gt;canonical&lt;/em&gt; concatenative programming language: a basic &amp;mdash;but working&amp;mdash; implementation of a simple programming language to illustrate the fundamentals of concatenative programming. Joy looks like this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;2  3  +  dup  *&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This simple programs computes the sum of 2 and 3, pushes it on the stack, duplicates it (using the &lt;code&gt;dup&lt;/code&gt; combinator) and then multiplies the two values, obtaining 25 as a result.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s slow down a second. Here&amp;#8217;s what happens, exactly:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Element entered &lt;/th&gt;
		&lt;th&gt;Stack contents&lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 2 &lt;/td&gt;
		&lt;td&gt; &lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; 3 &lt;/td&gt;
		&lt;td&gt; [2 3] &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; + &lt;/td&gt;
		&lt;td&gt; &lt;sup class="footnote" id="fnr5"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt; &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; dup &lt;/td&gt;
		&lt;td&gt; [5 5] &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; * &lt;/td&gt;
		&lt;td&gt; &lt;sup class="footnote" id="fnr25"&gt;&lt;a href="#fn25"&gt;25&lt;/a&gt;&lt;/sup&gt; &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Got it? Let&amp;#8217;s take it one step further. When you enter &lt;code&gt;dup&lt;/code&gt; and then &lt;code&gt;*&lt;/code&gt;, you are effectively computing the square of a number, so we can define the function &lt;code&gt;square&lt;/code&gt; simply as:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;square == dup *&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In Ruby, this would be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;square&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What&amp;#8217;s unusual here? &amp;mdash; Simple, there are no &lt;em&gt;variables&lt;/em&gt; involved. Joy doesn&amp;#8217;t need any explicit variable or &lt;em&gt;formal parameters&lt;/em&gt; of any sort.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s more. Take the following code:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[1 2 3 4]  [dup *]  map&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;map&lt;/code&gt; combinator expects a list and a &lt;em&gt;quoted program&lt;/em&gt; (the same one used to compute the square) and produces a new list containing the result of that program applied to each element of the original list. Basically the equivalent of:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Do you notice anything different? &amp;mdash; Yes, Joy doesn&amp;#8217;t need blocks or lambdas either, it uses &lt;em&gt;quoted programs&lt;/em&gt; instead, which are nothing but slightly fancier lists (or arrays, as you like).&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s recap then, Joy doesn&amp;#8217;t need of:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;lambda functions or blocks (quotation does the trick)&lt;/li&gt;
	&lt;li&gt;explicit parameters (everything you need is on the stack)&lt;/li&gt;
	&lt;li&gt;variable assignments (same as above)&lt;/li&gt;
	&lt;li&gt;explicit recursion (provided you can use combinators like linrec, primrec, binrec, etc.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I would consider this one of the best examples of &lt;em&gt;programming minimalism&lt;/em&gt;: an incredibly simple syntax, a very small set of rules, but a good deal of power.&lt;/p&gt;
&lt;h3&gt;Ruby objects on the stack&lt;/h3&gt;
&lt;p&gt;After reading about Joy, I realized that implementing something similar in Ruby would be an interesting mini-project (let&amp;#8217;s say a week of lunch breaks) to understand more about concatenative programming. It would also be pointless, too: a stack-based programming language implemented on top of one of the most high-level programming languages you can find isn&amp;#8217;t going to be fast, is it? Nevertheless, it would still be interesting.&lt;/p&gt;
&lt;p&gt;Ruby offers everything you need to build a Joy-like &lt;span class="caps"&gt;DSL&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You can use arrays as &amp;#8230;arrays, but also as quoted programs, and to model the stack itself.&lt;/li&gt;
	&lt;li&gt;You can use integers, strings, etc. as themselves&lt;/li&gt;
	&lt;li&gt;You can use Symbols as functions (we&amp;#8217;ll get to this in a minute)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you think about the following expression in postfix notation:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;2 2 +&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;We &lt;em&gt;could&lt;/em&gt; translate it into infix notation (&lt;code&gt;2 + 2&lt;/code&gt;), because Ruby supports it, but it&amp;#8217;s not general enough. What you could do is this though:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:+&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Message sending. I can see all the SmallTalk sympathizers drooling already. Well yes, In Ruby, &lt;em&gt;everything&lt;/em&gt; is an object, so &lt;em&gt;everything&lt;/em&gt; has a receiver and maybe some parameters. In other words, every method call can be reduced to the following syntax:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;receiver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this way, it is safe to assume that everything has a receiver, which could be understood as a function parameter, and may have 0 or more parameters. Take the following then:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:+&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It&amp;#8217;s not too different from Joy, and it&amp;#8217;s still Ruby code. All you have to do is use something to do the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Take an array, and examine each item:
	&lt;ul&gt;
		&lt;li&gt;If it&amp;#8217;s an object (non-Symbol), then push it on top of the stack.&lt;/li&gt;
		&lt;li&gt;If it&amp;#8217;s a Symbol, then do something different, i.e.:
		&lt;ul&gt;
			&lt;li&gt;Find its receiver and its parameters and call a method.&lt;/li&gt;
			&lt;li&gt;Manipulate something on the stack.&lt;/li&gt;
		&lt;/ul&gt;&lt;/li&gt;
	&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this case, we have to find :+&amp;#8217;s receiver and its parameter and we&amp;#8217;re sorted.&lt;/p&gt;
&lt;p&gt;Unfortunately Ruby&amp;#8217;s &lt;code&gt;arity&lt;/code&gt; method isn&amp;#8217;t that reliable. For example: &lt;code&gt;"test".instance_method(:sub).arity&lt;/code&gt; returns -1, while it should return &amp;#8220;2&amp;#8221; to be useful. So we have no choice but find a way to pass the method&amp;#8217;s arity explicitly, in some cases.&lt;/p&gt;
&lt;p&gt;For example like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Ciao, Fabio&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="sr"&gt; /Ciao/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Hello&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:sub&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If we define a | operator for the Symbol class, it&amp;#8217;s not too bad after all. It&amp;#8217;s heavy, but in this way we can use &lt;em&gt;any&lt;/em&gt; Ruby method in postfix notation.&lt;/p&gt;
&lt;h3&gt;Introducing the Concatenative Ruby &lt;span class="caps"&gt;DSL&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href="/concatenative"&gt;Concatenative&lt;/a&gt; is a simple Ruby &lt;span class="caps"&gt;DSL&lt;/span&gt; for concatenative programming. You can write concatenative programs inside ordinary Ruby arrays and execute them by calling either &lt;code&gt;Array#execute&lt;/code&gt; or &lt;code&gt;Kernel#concatenate&lt;/code&gt;, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;concatenative&amp;#39;&lt;/span&gt;

&lt;span class="n"&gt;concatenate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:==&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:+&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:dup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:-&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:*&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;:linrec&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This simple program calculates the factorial of 10. As you can see, no matter how unusual it may look, it is perfectly valid Ruby code and it is equivalent to the following Joy code:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;
10 [0 =] [1 +] [dup 1 -] [*] linrec
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Granted, Joy looks better, but that&amp;#8217;s the tradeoff for not writing a parser for Joy syntax, after all. &lt;br /&gt;
Looking at the code above, there are a few things to keep in mind when programming with Concatenative:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You are using Ruby arrays, so you have to use commas, at least&lt;/li&gt;
	&lt;li&gt;functions, operators and combinators (let&amp;#8217;s just call them &lt;em&gt;words&lt;/em&gt;) are available as Ruby symbols&lt;/li&gt;
	&lt;li&gt;The arity of all Ruby infix operators has been already set to &amp;#8220;1&amp;#8221; by concatenative using the &lt;code&gt;set_arity&lt;/code&gt; method (which simply stores the arity of a particular symbol in a constant hash)&lt;/li&gt;
	&lt;li&gt;You can specify explicit arities using the | operator (&lt;code&gt;:gsub|2&lt;/code&gt;, or &lt;code&gt;:join|1&lt;/code&gt;)&lt;/li&gt;
	&lt;li&gt;Unless the arity has been specified, an arity of 0 is assumed.&lt;/li&gt;
	&lt;li&gt;You can define your own concatenative functions using the &lt;code&gt;Symbol#&amp;lt;=&lt;/code&gt; method, which expects a quoted concatenative program.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Performance issues&lt;/h3&gt;
&lt;p&gt;In its current form, Concatenative can be very slow, as show the &amp;#8220;benchmarks&amp;#8221; provided in the /examples folder, especially if you use recursive combinators. This is understandable because everything is implemented in pure Ruby, which is totally unsuitable for low level stuff.&lt;/p&gt;
&lt;p&gt;If you are interested, you are more than welcome to submit patches and suggestions to improve Concatenative&amp;#8217;s performance, or, if you feel brave enough, you could help me create a C extension instead: things would become much faster then.&lt;/p&gt;
&lt;p&gt;At any rate, feel free to play with it. You can get the source from &lt;a href="http://github.com/h3rald/concatenative/tree/master"&gt;GitHub&lt;/a&gt;, you can get the gem from &lt;a href="http://rubyforge.org/projects/concatenative/"&gt;RubyForge&lt;/a&gt; and you can submit ticket through &lt;a href="http://github.com/h3rald/concatenative/issues"&gt;GitHub&lt;/a&gt; as well.&lt;/p&gt;</description>
      <pubDate>Sat, 28 Mar 2009 06:24:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/concatenative-programming-in-ruby/</guid>
      <link>http://www.h3rald.com/articles/concatenative-programming-in-ruby/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/concatenative-programming-in-ruby/#comments</comments>
      <category>ruby</category>
      <category>concatenative</category>
      <category>programming</category>
    </item>
    <item>
      <title>Real-world Rawline usage</title>
      <description>&lt;p&gt;So I finally decided to update &lt;a href="/rawline"&gt;RawLine&lt;/a&gt; last week, and I added a more Readline-like &lt;span class="caps"&gt;API&lt;/span&gt;. When I first started the project, I was determined &lt;em&gt;not&lt;/em&gt; to do that, because the current Readline wrapper shipped with Ruby is not very Ruby-ish: it&amp;#8217;s a wrapper, after all!&lt;/p&gt;
&lt;p&gt;The good thing of having a new &lt;span class="caps"&gt;API&lt;/span&gt; compatible with Readline is that now people can use RawLine in their Readline-powered scripts, with very minor modifications.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s have a look at some examples (they are also shipped with &lt;a href="http://rubyforge.org/projects/rawline"&gt;Rawline v0.3.1&lt;/a&gt;):&lt;br /&gt;
h3. Rush&lt;/p&gt;
&lt;p&gt;&lt;a href="http://rush.heroku.com"&gt;Rush&lt;/a&gt; is an excellent gem which provides a cross-platform shell environment, entirely written in Ruby.&lt;br /&gt;
Being a shell, it obviously uses Readline for tab completion, and that does the job on Linux. On Windows though, things aren&amp;#8217;t that easy:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;text gets garbled if you write long lines&lt;/li&gt;
	&lt;li&gt;you can&amp;#8217;t type certain characters if they use some key modifiers like &lt;RIGHT-ALT&gt;, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;RawLine doesn&amp;#8217;t have these problems (that&amp;#8217;s the very reason why I created it), so here&amp;#8217;s a simple script which launches a Rawline-enabled Rush shell:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rush&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rawline&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RawlineRush&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Rush&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Shell&lt;/span&gt;

	&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
		&lt;span class="no"&gt;Rawline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basic_word_break_characters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt; 
		&lt;span class="no"&gt;Rawline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completion_proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;completion_proc&lt;/span&gt;
		&lt;span class="k"&gt;super&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;

	&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;
		&lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
			&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rawline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;rawline_rush&amp;gt; &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
			&lt;span class="n"&gt;finish&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nil?&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;exit&amp;#39;&lt;/span&gt;
			&lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
			&lt;span class="no"&gt;Rawline&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;HISTORY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
			&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
		&lt;span class="k"&gt;end&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;shell&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RawlineRush&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;What happens here? Nothing much really, all I had to do was:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Derive a new class from Rush::Shell&lt;/li&gt;
	&lt;li&gt;Set &lt;code&gt;Rawline.basic_word_break_characters&lt;/code&gt; to the same value used in the original Rush code&lt;/li&gt;
	&lt;li&gt;Set &lt;code&gt;Rawline.completion_proc&lt;/code&gt; to &lt;em&gt;the same&lt;/em&gt; completion Proc used in the original Rush code&lt;/li&gt;
	&lt;li&gt;Rewrite the original &lt;code&gt;run&lt;/code&gt; replacing &lt;code&gt;Readline&lt;/code&gt; with &lt;code&gt;Rawline&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;And it works as it was intended to, i.e. typing &lt;code&gt;root['b&amp;lt;TAB&amp;gt;&lt;/code&gt; will expand to &lt;code&gt;root['bin/&lt;/code&gt;, etc.&lt;br /&gt;
Note that I didn&amp;#8217;t write the completion Proc from scratch: it was already there.&lt;/p&gt;
&lt;h3&gt;&lt;span class="caps"&gt;IRB&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;After trying out Rush, the next logical step was trying &lt;span class="caps"&gt;IRB&lt;/span&gt; itself: I could never use it properly on Windows, and that was really frustrating.&lt;br /&gt;
After a few minutes trying to figure out how to start &lt;span class="caps"&gt;IRB&lt;/span&gt; programmatically, I quickly came up with a similar example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;irb&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;irb/completion&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rawline&amp;#39;&lt;/span&gt;

&lt;span class="no"&gt;Rawline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basic_word_break_characters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; &lt;/span&gt;&lt;span class="se"&gt;\t\n\&amp;quot;\\&lt;/span&gt;&lt;span class="s2"&gt;&amp;#39;`&amp;gt;&amp;lt;;|&amp;amp;{(&amp;quot;&lt;/span&gt; 
&lt;span class="no"&gt;Rawline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completion_append_character&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;span class="no"&gt;Rawline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completion_proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;IRB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;InputCompletor&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CompletionProc&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RawlineInputMethod&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;IRB&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ReadlineInputMethod&lt;/span&gt;
	&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Rawline&lt;/span&gt;
	&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gets&lt;/span&gt;
		&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@prompt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
			&lt;span class="no"&gt;HISTORY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;empty?&lt;/span&gt;
			&lt;span class="vi"&gt;@line&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="vi"&gt;@line_no&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
		&lt;span class="k"&gt;else&lt;/span&gt;
			&lt;span class="vi"&gt;@eof&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
			&lt;span class="n"&gt;l&lt;/span&gt;
		&lt;span class="k"&gt;end&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;IRB&lt;/span&gt;
	&lt;span class="vi"&gt;@CONF&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:SCRIPT&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RawlineInputMethod&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;IRB&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this case, Rawline is included in the &lt;code&gt;RawlineInputMethod&lt;/code&gt; class, derived from the original &lt;code&gt;ReadlineInputMethod&lt;/code&gt; class, i.e. the class &lt;span class="caps"&gt;IRB&lt;/span&gt; uses to define (guess&amp;#8230;) how to input characters.&lt;br /&gt;
Again, all I had to do was set a few Rawline variables to match the ones used in Readline, and then redefine the function used to get characters. All done.&lt;/p&gt;
&lt;p&gt;It works as expected (only with inline completion, of course): typing &lt;code&gt;"test".ma&amp;lt;TAB&amp;gt;&lt;/code&gt; will give you &lt;code&gt;"test".map&lt;/code&gt;, &lt;code&gt;"test".match&lt;/code&gt;, etc.&lt;/p&gt;
&lt;p&gt;You also get all Rawline key mappings for free (&lt;span class="caps"&gt;CTRL&lt;/span&gt;-K to clear the line, &lt;span class="caps"&gt;CTRL&lt;/span&gt;-U and &lt;span class="caps"&gt;CTRL&lt;/span&gt;-R to undo and redo, etc.), and you can define your own.&lt;/p&gt;</description>
      <pubDate>Sat, 07 Mar 2009 03:54:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/real-world-rawline-usage/</guid>
      <link>http://www.h3rald.com/articles/real-world-rawline-usage/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/real-world-rawline-usage/#comments</comments>
      <category>ruby</category>
      <category>rawline</category>
    </item>
    <item>
      <title>RawLine 0.3.0 released &#8212; now with Readline emulation</title>
      <description>&lt;p&gt;&lt;a href="/rawline"&gt;RawLine&lt;/a&gt; 0.3.0 has been &lt;a href="http://rubyforge.org/projects/rawline"&gt;released&lt;/a&gt;. This new milestones fixes some minor bugs and adds some new functionalities, must notably:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Ruby 1.9 support&lt;/li&gt;
	&lt;li&gt;A filename completion function&lt;/li&gt;
	&lt;li&gt;A new &lt;span class="caps"&gt;API&lt;/span&gt; very similar to the one exposed by the Ruby wrapper for &lt;span class="caps"&gt;GNU&lt;/span&gt; Readline&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of you asked for Readline compatibility/emulation and that was actually not too difficult to implement: all the bricks were already there, I just had to put them together in the right place.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;RawLine&lt;/code&gt; module (you can spell it &amp;#8220;Rawline&amp;#8221; as well, if you wish) now behaves like &lt;code&gt;Readline&lt;/code&gt;. This means that you can now use RawLine like this (taken from examples/readline_emulation.rb):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Rawline&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;*** Readline Emulation Test Shell ***&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; * Press CTRL+X to exit&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; * Press &amp;lt;TAB&amp;gt; for file completion&amp;quot;&lt;/span&gt;

&lt;span class="no"&gt;Rawline&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ctrl_x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Exiting...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chdir&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;..&amp;#39;&lt;/span&gt;

&lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
	&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;You typed: [&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;=&amp;gt; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chomp!&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Basically you get a &lt;code&gt;readline&lt;/code&gt; method, a &lt;code&gt;HISTORY&lt;/code&gt; constant like the one exposed by Readline (Rawline&amp;#8217;s is a RawLine::HistoryBuffer object though &amp;mdash; much more manageable), and a &lt;code&gt;FILENAME_COMPLETION_PROC&lt;/code&gt; constant, which provides basic filename completion. Here it is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;	&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;filename_completion_proc&lt;/span&gt;
			&lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
				&lt;span class="n"&gt;dirs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
					&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@line&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^\/|[a-zA-Z]:\//&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;
				&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="c1"&gt;# starting directory&lt;/span&gt;
					&lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
				&lt;span class="k"&gt;else&lt;/span&gt;
					&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;directory?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
					&lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
				&lt;span class="k"&gt;end&lt;/span&gt;
				&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^\./&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="vi"&gt;@match_hidden_files&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;!~&lt;/span&gt; &lt;span class="sr"&gt;/^\./&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
			&lt;span class="k"&gt;end&lt;/span&gt;
		&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You can find this function as part of the &lt;code&gt;RawLine::Editor&lt;/code&gt; class. The result is not exactly the same Readline, because completion matches are not displayed underneath the line but inline and can be cycled through &amp;mdash; which is one of Readline&amp;#8217;s completion modes anyway.&lt;/p&gt;
&lt;p&gt;A few methods of the &lt;code&gt;RawLine::Editor&lt;/code&gt; class can now be accessed directly from the &lt;code&gt;RawLine&lt;/code&gt; module, like with Readline:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;Rawline.completion_proc&lt;/code&gt; &amp;mdash; the Proc object used for &lt;span class="caps"&gt;TAB&lt;/span&gt; completion (defaults to FILENAME_COMPLETION_PROC).&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.completion_matches&lt;/code&gt; &amp;mdash; an array of completion matches.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.completion_append_char&lt;/code&gt; &amp;mdash; a character to append after a successful completion.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.basic_word_break_characters&lt;/code&gt; &amp;mdash; a String listing all the characters used as word separators.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.completer_word_break_characters&lt;/code&gt; &amp;mdash; same as above.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.library_version&lt;/code&gt; &amp;mdash; the current version of the Rawline library.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.clear_history&lt;/code&gt; &amp;mdash; to clear the current history.&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;Rawline.match_hidden_files&lt;/code&gt; &amp;mdash; whether FILENAME_COMPLETION_PROC matches hidden files and folders or not.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I bet you didn&amp;#8217;t know these methods were even in the Readline wrapper, did you? Probably because of lack of documentation.&lt;br /&gt;
Anyhow, another very important difference beween Rawline and Readline is &lt;code&gt;Rawline.editor&lt;/code&gt;, i.e. the default instance of RawLine::Editor used by the Rawline module itself.&lt;/p&gt;
&lt;p&gt;This makes things easier if you want more control over the line which is being edited and the previously-edited lines. Sure, &lt;code&gt;Readline#completion_proc&lt;/code&gt; exposes the current &lt;em&gt;word&lt;/em&gt; being typed before hitting tab, and so does &lt;code&gt;Rawline#completion_proc&lt;/code&gt; the difference is that if you access &lt;code&gt;Rawline.editor.line&lt;/code&gt; you get a &lt;code&gt;RawLine::Line&lt;/code&gt; object with all the information you could possibly need about the current line: the position of the cursor, the text, the order the characters were entered, etc. etc. &lt;br /&gt;
Now you can imagine why it took me a few minutes to write the &lt;code&gt;filename_completion_proc&lt;/code&gt; method (and why it will take you even less time to write your own similar method if you wanna do something different): you can access not only the last word being typed but also the current &lt;em&gt;and previous&lt;/em&gt; lines (through &lt;code&gt;Rawline.editor.history&lt;/code&gt; or just &lt;code&gt;Rawline::HISTORY&lt;/code&gt;)!&lt;/p&gt;
&lt;p&gt;It must be said, as usual, that Rawline is &lt;em&gt;not&lt;/em&gt; a complete replacement for the Readline library yet (and it will probably never be, as Readline is huge!), but it&amp;#8217;s a good cross-platform, more Ruby-esque alternative to what&amp;#8217;s currently available by the Readline wrapper for Ruby.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not as fast, of course, especially when completing long words, but it&amp;#8217;s quite usable. The following libraries are not required but recommended:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;win32console&lt;/code&gt; (on Windows)&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;termios&lt;/code&gt; (on *nix)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;They basically make Rawline faster. If you don&amp;#8217;t use them, Rawline will fall back on its pure-Ruby implementation to move left and right (i.e. printing backspaces and spaces character codes instead of &lt;span class="caps"&gt;ASCII&lt;/span&gt; escape codes).&lt;/p&gt;
&lt;p&gt;Unfortunately, there&amp;#8217;s no &lt;code&gt;vi_editing_mode&lt;/code&gt; or &lt;code&gt;emacs_editing_mode&lt;/code&gt; yet (for time constraints: they &lt;em&gt;can&lt;/em&gt; be implemented!) but patches are very welcome. Also, if you need more features, all you have to do is ask :-)&lt;/p&gt;
&lt;p&gt;P.S.: Check out the new &lt;a href="/rawline"&gt;Project Page&lt;/a&gt; and especially its Resources section!&lt;/p&gt;</description>
      <pubDate>Sun, 01 Mar 2009 06:47:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/rawline-030/</guid>
      <link>http://www.h3rald.com/articles/rawline-030/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/rawline-030/#comments</comments>
      <category>ruby</category>
      <category>opensource</category>
      <category>rawline</category>
    </item>
    <item>
      <title>Personal Log - February 2009</title>
      <description>&lt;p&gt;This has been a rather busy month, hence the lack of general Internet activity. I really wanted to post some more articles to my site, but for one reason or another I had to procrastinate more and more, and here we are at the end of the month again.&lt;/p&gt;
&lt;h3&gt;Recession time!&lt;/h3&gt;
&lt;p&gt;I&amp;#8217;ve always considered the current economic downturn as something happening &lt;em&gt;somewhere else&lt;/em&gt;: &lt;span class="caps"&gt;USA&lt;/span&gt;, England, Ireland&amp;#8230; but not in Italy, really: our country never boomed, we don&amp;#8217;t go mental with loans and mortgages (or at least we didn&amp;#8217;t use to), so there&amp;#8217;s no real reason for a full-on recession period.&lt;/p&gt;
&lt;p&gt;It turns out I was wrong. Other than the fact that our industries are more or less non-existant or already in debt, I didn&amp;#8217;t consider that:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Italians tend to panic a lot.&lt;/li&gt;
	&lt;li&gt;We have an awful lot of foreign business going on, a lot of multi-national companies opened up through the years lured by cheap workers and acceptable craftmanship.&lt;/li&gt;
	&lt;li&gt;Our government already &lt;del&gt;wastes&lt;/del&gt; invests a lot of money regularly, every year, to fuel a colossal, &lt;a href="http://dictionary.reference.com/browse/nepotistic"&gt;nepotistic&lt;/a&gt;, pointless bureaucratic machine they insist on calling &amp;#8220;State&amp;#8221;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Result: the recession is starting to hit properly over here too. People are saving money, they don&amp;#8217;t go out buying pointless crap, they are scared to ask for a raise at work&amp;#8230; the usual. I work for a foreign company which has been, as were most, forced to save some money to compensate some not-so-good First Quarter&amp;#8217;s revenues. This means less unnecessary expenses, less training, less travelling and less outsourcing, which didn&amp;#8217;t help improving the daily work experiece. Personally, I&amp;#8217;m not that affected by all this, nevertheless it made me bless the day my fianc&#233;e persuaded me to stop uni after my Bachelor&amp;#8217;s Degree to get a very rewarding, not-so-stressful job.&lt;/p&gt;
&lt;h3&gt;No &amp;#8217;Net @ Home&lt;/h3&gt;
&lt;p&gt;The most annoying thing of the month was (and still is) the lack of Internet access at our house. Let&amp;#8217;s do a quick recap:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;After spending one year with Telecom Italia, Roxanne and I decided to change provider to save a bit of money and get more speed.&lt;/li&gt;
	&lt;li&gt;On &lt;em&gt;December 24th&lt;/em&gt; we requested a contract with &lt;a href="http://www.wind.it"&gt;Wind&lt;/a&gt;, after they assured that we&amp;#8217;d have the Internet back on in &lt;em&gt;just a few days, tops&lt;/em&gt;.&lt;/li&gt;
	&lt;li&gt;On &lt;em&gt;January 5th&lt;/em&gt; Telecom disconnected us.&lt;/li&gt;
	&lt;li&gt;On &lt;em&gt;January 12th&lt;/em&gt; Wind sent me a mail telling me that there was going to be a &lt;em&gt;15-day delay&lt;/em&gt; in the activation &amp;mdash; well, at least they told us so! We waited.&lt;/li&gt;
	&lt;li&gt;On &lt;em&gt;February 2nd&lt;/em&gt; I call Wind Customer Care hassling them to get a move on &amp;mdash; just some minor delays, &lt;em&gt;it will only take a few days, tops&lt;/em&gt;. We waited.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Our new Internet line has been &lt;em&gt;in the process of being activated&lt;/em&gt; ever since January 5th. Why? Because being a customer sucks, in Italy, and you can&amp;#8217;t do much about it.&lt;br /&gt;
Let me quote one of the 13 phone calls I made:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&amp;#8230; 5 minutes on hold, stupid music in the background &amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Operator]: Good Evening Sir, I&amp;#8217;m &lt;random name&gt;, how can I help you?&lt;/li&gt;
	&lt;li&gt;[Me]: Hello, I&amp;#8217;m enquiring about the status of my Internet connection: I&amp;#8217;ve been disconnected since the 5th of January&amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Operator]: Phone Number please?&lt;/li&gt;
	&lt;li&gt;[Me]: *** ******&lt;/li&gt;
	&lt;li&gt;&amp;#8230; 2 minutes on old &amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Operator]: Name plase?&lt;/li&gt;
	&lt;li&gt;[Me]: Fabio Cevasco&lt;/li&gt;
	&lt;li&gt;[Operator]: Let me check&amp;#8230;&lt;/li&gt;
	&lt;li&gt;&amp;#8230; 6 minutes on hold, stupid music in the background &amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Me]: Any luck?&lt;/li&gt;
	&lt;li&gt;[Operator]: One moment please&amp;#8230;&lt;/li&gt;
	&lt;li&gt;&amp;#8230; 2 minutes on hold, stupid music in the background &amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Operator]: Sir, it says here that you are &lt;em&gt;in the process of being activated&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;[Me]: (you stupid idiot, I can check that on the Net in less than a minute) Yes, I know what, but why, exactly? It has been over a month&amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Operator]: Let me check&amp;#8230;&lt;/li&gt;
	&lt;li&gt;&amp;#8230; 3 minutes on hold, stupid music in the background &amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Operator]: There are some technical difficulties.&lt;/li&gt;
	&lt;li&gt;[Me]: What kind of technical difficulties?&lt;/li&gt;
	&lt;li&gt;[Operator]: I&amp;#8230; I don&amp;#8217;t think you can understand Sir, it&amp;#8217;s technical&amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Me]: (!!!) I have a degree in IT Engineering, so yes, I think I can understand enough.&lt;/li&gt;
	&lt;li&gt;[Operator]: &amp;#8230;well, there&amp;#8217;s nothing I can do&amp;#8230; it says we&amp;#8217;re in the process of connecting you, it should be just&amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Me]: &amp;#8230;a matter of a couple of days, yes, I know: it has been over a month though!&lt;/li&gt;
	&lt;li&gt;[Operator]: Sir, really, I can&amp;#8217;t really do much about it, you&amp;#8217;ll just have to wait&lt;/li&gt;
	&lt;li&gt;[Me]: Can you let me speak with the Technical Department?&lt;/li&gt;
	&lt;li&gt;[Operator]: No, sir, I can&amp;#8217;t: you see, your &lt;span class="caps"&gt;ADSL&lt;/span&gt; line is not yet activated, they can&amp;#8217;t do anything about it.&lt;/li&gt;
	&lt;li&gt;[Me]: Excuse me, but I&amp;#8217;d like to know what the problem is, and how long it will take to activate the line.&lt;/li&gt;
	&lt;li&gt;[Operator]: Sorry sir, we don&amp;#8217;t have this information, and we can&amp;#8217;t commit to a specific date.&lt;/li&gt;
	&lt;li&gt;[Me]: (!!!) May I speak to someone who knows this? May I speak to your superior?&lt;/li&gt;
	&lt;li&gt;[Operator] No, you can&amp;#8217;t speak to my superior. You&amp;#8217;ll just have to wait, I&amp;#8217;m sorry.&lt;/li&gt;
	&lt;li&gt;[Me]: Well, it has been over a month, and I don&amp;#8217;t know if you realize that you were supposed to connect me in just a few days and&amp;#8230;&lt;/li&gt;
	&lt;li&gt;[Operator]: Thank you for calling sir, have a good day.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That barely conveys the frustration I felt and I&amp;#8217;m still feeling now. I can&amp;#8217;t even sue them: I could get 100 Euro at most after spending at least a couple of thousands in lawyer. So much for the land of sunshine huh?&lt;/p&gt;
&lt;h3&gt;Programming in Ruby, again&lt;/h3&gt;
&lt;p&gt;Some of you may be pleased to know I&amp;#8217;m back coding in Ruby after slacking for months. It&amp;#8217;s just the time of the year, I guess. &lt;br /&gt;
I&amp;#8217;m also evangelizing the language quite a bit at work: after I wrote a few scripts on demand, I slowly lured one of my colleagues to Vim, the Texile markup and then finally the Ruby language. He&amp;#8217;s going through the &lt;a href="http://www.h3rald.com/articles/hlrb-review"&gt;Humble Little Ruby Book&lt;/a&gt; and he&amp;#8217;s loving it, so far. He&amp;#8217;ll hopefully be fully assimilated in a few weeks at most, and after that there will be no going back!&lt;/p&gt;
&lt;p&gt;This inspired me to start a full rewrite of &lt;a href="http://www.h3rald.com/tags/redbook/"&gt;RedBook&lt;/a&gt;, my little Ruby daily logger. It will feature a SQLite backend and Merb&amp;#8217;s Datamapper to take care of the dirty work.&lt;br /&gt;
Unfortunately, even if the new sources are already available on &lt;a href="http://github.com/h3rald/redbook/tree/master"&gt;GitHub&lt;/a&gt;, it will take me approximately a few more weeks to complete all the plugins and more to finish the RDoc documentation and &amp;mdash; hopefully &amp;mdash; a fully-fledged user manual. It&amp;#8217;s &lt;strong&gt;the&lt;/strong&gt; pet project, after all&amp;#8230;&lt;/p&gt;
&lt;p&gt;On the other hand, it will take me considerably less time (a few days?) to release the next version of my &lt;a href="http://www.h3rald.com/tags/rawline"&gt;RawLine&lt;/a&gt; library, featuring:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Ruby 1.9 support&lt;/li&gt;
	&lt;li&gt;A handy little function for filename completion&lt;/li&gt;
	&lt;li&gt;Readline emulation, i.e. just &lt;code&gt;include Rawline&lt;/code&gt; and use it as if it was &lt;span class="caps"&gt;GNU&lt;/span&gt; Readline&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course this doesn&amp;#8217;t mean RawLine is a complete, 100% Ruby port of the &lt;span class="caps"&gt;GNU&lt;/span&gt; Readline library, but it is definitely more Ruby-ish, more cross platform (try using Readline with Ruby on Windows&amp;#8230;), and usable enough for most of the normal things, like:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;tab completion&lt;/li&gt;
	&lt;li&gt;line editing (but no vi or emacs mode yet, sorry)&lt;/li&gt;
	&lt;li&gt;history&lt;/li&gt;
	&lt;li&gt;quick and easy key bindings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once this comes out, I&amp;#8217;ll be implementing features on-demand, as &lt;span class="caps"&gt;GNU&lt;/span&gt; Readline is huge and offers way too many things anyone would ever need. Patches and contributions are of course more than welcome, though.&lt;/p&gt;
&lt;p&gt;For all my open source Ruby projects, after &lt;a href="http://www.h3rald.com/articles/where-does-your-ruby-code-live"&gt;pondering the alternatives&lt;/a&gt;, I decided to go with the following setup:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;My own site for the home pages of the projects&lt;/li&gt;
	&lt;li&gt;RubyForge for gem support and for RDoc documentation&lt;/li&gt;
	&lt;li&gt;GitHub as source code repository&lt;/li&gt;
	&lt;li&gt;LightHouse for issue tracking&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I hope it works out&amp;#8230;&lt;/p&gt;</description>
      <pubDate>Fri, 27 Feb 2009 12:09:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/log-feb-2009/</guid>
      <link>http://www.h3rald.com/articles/log-feb-2009/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/log-feb-2009/#comments</comments>
      <category>personal_log</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Italian translation of Ruby-Lang.org finally available!</title>
      <description>&lt;p&gt;&lt;a href="#italian-version"&gt;[Vai alla versione italiana]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I am very pleased to announce that the official site of the Ruby programming language is now available in Italian:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="www.ruby-lang.org/it/"&gt;www.ruby-lang.org/it/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;In the beginning&amp;#8230;&lt;/h3&gt;
&lt;p&gt;It all started in July 2007, when after a closer look at the site I discovered that apparently it was not available in Italian! How could it be? There were a lot of translations available, such as French, Spanish, Japanese, Korean&amp;#8230; but no Italian. &lt;br /&gt;
I immediately emailed the webmaster and within a few hours &lt;a href="http://curthibbs.wordpress.com/"&gt;Curt Hibbs&lt;/a&gt; (hell yes, &lt;a href="http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html"&gt;that&lt;/a&gt; Curt Hibbs!) mailed me the instructions to get me started:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;[&amp;#8230;] Providing a translation of the Ruby web site would have two parts: 1) the initial translation of the current content, and 2) the ongoing maintenance of the Italian version as new content and news items are added.&lt;/p&gt;
&lt;p&gt;This effort will be much more sustainable over the long term if you put together a team of at least three people who would commit to translating and maintaining the site. [&amp;#8230;]&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;#8230;Why &lt;em&gt;three&lt;/em&gt; people to translate &amp;#8220;a few pages&amp;#8221;? That&amp;#8217;s what bugged me at the time: it honestly seemed just a few days work for one person at most. Later on I understood why.&lt;br /&gt;
I wasn&amp;#8217;t the first to volunteer for the Italian translation, actually: &lt;strong&gt;&lt;a href="http://www.raulparolari.com"&gt;Raul Parolari&lt;/a&gt;&lt;/strong&gt; was indeed the first, but he was waiting for another two team members to start, of course.&lt;/p&gt;
&lt;p&gt;We eventually persuaded Curt that &lt;em&gt;we could handle it&lt;/em&gt; even without a third team member, so we started right away. As a matter of fact, we did manage to translate a lot of stuff within the first week.&lt;/p&gt;
&lt;h3&gt;Translating is easy, right?&lt;/h3&gt;
&lt;p&gt;Translating feels easy when you are mother tongue in the language you&amp;#8217;re translating into (Italian), and you know fairly well the language you&amp;#8217;re translating from (English): it can&amp;#8217;t possibly hard, right? Nah, a piece of cake. &lt;br /&gt;
Most of the time it&amp;#8217;s fairly easy and fast, too, but things can get a bit more complicated when you stumble upon idioms and tech jargon.&lt;/p&gt;
&lt;p&gt;Personlly, I never surf the web in Italian. That&amp;#8217;s a personal choice (I love the English language to an extreme extent), and I&amp;#8217;ve learnt to live with it no matter what people think. I admit that it was hard for me to translate some of the things on the Ruby web site: not because they were hard for me to understand, but because in some cases a translation would simply not do justice to the original text.&lt;/p&gt;
&lt;p&gt;Some of the text may sound weird in Italian, especially in the code examples. In the end we choose to translate every bit of code, e.g. &lt;code&gt;puts sentence&lt;/code&gt; became &lt;code&gt;puts frase&lt;/code&gt; and other equally horrid things. Sometimes I wonder whether we should have just left the original code as it was, but we wanted to make things easier for people who don&amp;#8217;t speak much English at all.&lt;/p&gt;
&lt;h3&gt;Stagnation&lt;/h3&gt;
&lt;p&gt;Things went quite after the initial excitement, I admit. Both Raul and me more or less stopped translating as time went on, and I am truly and deeply sorry for that. You know how it is: you start off really enthusiastic and then you lose interest, you get involved in other projects, work, family, etc. etc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.lipsiasoft.com/"&gt;Davide D&amp;#8217;Agostino&lt;/a&gt;&lt;/strong&gt; came to our rescue in December 2007. He&amp;#8217;s arguably the &amp;#8220;most Italian&amp;#8221; of the group and he came out with some interesting solutions for some particularly difficult bits of the translation. &lt;br /&gt;
Believe it or not, the 80% of the site was translated by the beginning of 2008: only a few bits were left, but then&amp;#8230; erhm, things went quiet again. I put the translation of the site on my todo list, and I knew it was there all along: &amp;#8220;Oh, yes, I should have a look at Ruby-Lang.org again&amp;#8221; I repeated to myself from time to time.&lt;/p&gt;
&lt;p&gt;About two weeks ago I got so pissed off with myself about this that I decided to finally &amp;#8220;get things done&amp;#8221; and translate the few remaining bits, reviewed the lot, got rid of some rough edges, did some minor proofreading and here it is, ready to be browsed by Italians, finally.&lt;/p&gt;
&lt;p&gt;The most ironic thing? It took literally a few hours of &amp;#8220;work&amp;#8221; to sort things out&amp;#8230; but nearly a year to finally find the will to do it.&lt;/p&gt;
&lt;h3&gt;What now?&lt;/h3&gt;
&lt;p&gt;Now the site is live and we&amp;#8217;ll keep it up-to-date from now on. I sincerely hope it will help bringing more and more Italians closer to the Ruby world. I&amp;#8217;m sure there are plenty of people out there who would have done a much better job than we did, and definitely in a much shorter timeframe&amp;#8230; but hey, we finally did it, after all!&lt;/p&gt;
&lt;p&gt;I would like to thank again &lt;strong&gt;&lt;a href="http://www.raulparolari.com"&gt;Raul Parolari&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="http://www.lipsiasoft.com/"&gt;Davide D&amp;#8217;Agostino&lt;/a&gt;&lt;/strong&gt; for helping translating the site: I now finally understand why Curt wanted three people on the translation team!&lt;/p&gt;
&lt;p&gt;One last thing: if you find any mistake (and there are plenty, I&amp;#8217;m sure) or if you have any suggestion to improve the current translation, don&amp;#8217;t hesitate to &lt;a href="/about/"&gt;contact me&lt;/a&gt;: I&amp;#8217;ll try to fix things as soon as possible.&lt;/p&gt;
&lt;p&gt;Enjoy Ruby, now finally &lt;a href="http://www.ruby-lang.org/it/"&gt;in Italian&lt;/a&gt; too!&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a name="italian-version"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;&amp;Egrave; finalmente disponibile la traduzione italiana di Ruby-Lang.org&lt;/h2&gt;
&lt;p&gt;Sono veramente contento di annunciare che il sito ufficiale del linguaggio di programmazione Ruby &#232; ora disponibile anche in Italiano:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="www.ruby-lang.org/it/"&gt;www.ruby-lang.org/it/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;In principio&amp;#8230;&lt;/h3&gt;
&lt;p&gt;Tutto incominci&#242; nel luglio del 2007, quando dopo un&amp;#8217;occhiata pi&#249; da vicino al sito mi accorsi che apparentemente non era disponibile in italiano! Com&amp;#8217;era possibile? Era gi&#224; tradotto in molte lingue tra cui francese, spagnolo, giapponese, coreano&amp;#8230; ma niente italiano.&lt;/p&gt;
&lt;p&gt;Mandai immediatamente un&amp;#8217;email al webmaster, e in poche ore &lt;a href="http://curthibbs.wordpress.com/"&gt;Curt Hibbs&lt;/a&gt; (gi&#224;, proprio &lt;a href="http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html"&gt;quel&lt;/a&gt; Curt Hibbs!) mi invi&#242; le istruzioni su come iniziare a tradurre:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;[&amp;#8230;] La traduzione del sito di Ruby &#232; articolata in due parti: 1) la traduzione iniziale degli attuali contenuti e 2) il continuo aggiornamento della versione italiana ogniqualvolta vengono create nuove pagine.&lt;/p&gt;
&lt;p&gt;Questo sforzo &#232; molto pi&#249; sostenibile nel lungo termine se riesci a mettere insieme una squadra di almeno tre persone dedite a tradurre e ad aggiornare il sito. [&amp;#8230;]&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;#8230;Perch&#232; &lt;em&gt;tre&lt;/em&gt; persone per tradurre &amp;#8220;solo poche pagine&amp;#8221;? Questo quello che mi chiesi in quel momento: sembrava veramente essere una questione di pochi giorni, e sicuramente una persona sarebbe stata pi&#249; che sufficiente. Successivamente capii perch&#232; tre persone erano necessarie.&lt;/p&gt;
&lt;p&gt;Comunque, non ero il primo ad offrirmi volontario per la traduzione italiana: &lt;strong&gt;&lt;a href="http://www.raulparolari.com"&gt;Raul Parolari&lt;/a&gt;&lt;/strong&gt; si era gi&#224; fatto avanti, ma stava ancora aspettando altre due persone per poter iniziare, ovviamente.&lt;/p&gt;
&lt;p&gt;Alla fine, riuscimmo comunque a persuadere Curt che &lt;em&gt;ce la potevamo fare&lt;/em&gt;, anche senza una tersa persona ad aiutarci. Incominciammo a tradurre quindi di buona lena, e di fatto riuscimmo a tradurre molto durante la prima settimana.&lt;/p&gt;
&lt;h3&gt;Tradurre &#232; facile, non &#232; cos&#236;?&lt;/h3&gt;
&lt;p&gt;Tradurre dall&amp;#8217;inglese all&amp;#8217;italiano sembra facile se sei madrelingua e conosci bene l&amp;#8217;inglese: non pu&#242; essere difficile, giusto? Facilissimo, ovvio. &lt;br /&gt;
Per la maggior parte &#232; cos&#236;, di fatto: facile e veloce. Ma le cose tendono a complicarsi un pochettino quando hai a che fare con modi di dire e linguaggio un po&amp;#8217; pi&#249; tecnico.&lt;/p&gt;
&lt;p&gt;Personalmente, non vado mai su siti italiani. &amp;Egrave; una mia scelta personale (mi piace tantissimo la lingua inglese), e ho imparato a non fare caso a quello che gli altri pensano di questa scelta. Devo ammettere che &#232; stato difficile per me tradurre alcune parti del sito di Ruby: non perch&#232; fossero difficili da capire, ma perch&#232; in qualche caso una traduzione non &#232; semplicemente in grado di rendere giustizia al testo originale.&lt;/p&gt;
&lt;p&gt;Alcuni pezzi della traduzione, per questa ragione, potrebbero suonare un po&amp;#8217; strani alle orecchie di Italiani d.o.c., specialmente per quanto riguarda gli esempi di codice. Alla fine abbiamo deciso di tradurre la maggior parte del codice (ove possibile, ovviamente): &lt;code&gt;puts sentence&lt;/code&gt; &#232; quindi diventato &lt;code&gt;puts frase&lt;/code&gt;, e altri simili orrori. Qualche volta mi chiedo se non avessimo fatto meglio a lasciare il codice originale cos&#236; com&amp;#8217;era, ma d&amp;#8217;altra parta abbiamo cercato di fare il possibile per rendere le cose pi&#249; semplici anche per persone che non sanno una parola di inglese.&lt;/p&gt;
&lt;h3&gt;Stagnazione&lt;/h3&gt;
&lt;p&gt;Col tempo, l&amp;#8217;iniziale interesse nella traduzione &#232; andato affievolendosi, lo ammetto. Sia io che Raul abbiamo praticamente interrotto la traduzione ad un certo punto, e mi dispiace veramente tanto. Sapete com&amp;#8217;&#232;: incominci entusiasta e poi piano piano inizi a perdere interesse, ti dedichi ad altri progetti, il lavoro, la famiglia, eccetera.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.lipsiasoft.com/"&gt;Davide D&amp;#8217;Agostino&lt;/a&gt;&lt;/strong&gt; venne in nostro aiuto nel Dicembre 2007. Penso che sia quello &amp;#8220;pi&#249; italiano&amp;#8221; del gruppo, tanto da essere in grado di proporre soluzioni interessanti per alcuni pezzi particolarmente difficili da tradurre. Che ci crediate oppure no, l&amp;#8217;80% del sito era pronto e tradotto all&amp;#8217;inizio del 2008: rimanevano solamente alcune piccole parti ancora da tradurre, e poi&amp;#8230; beh, abbiamo un po&amp;#8217; lasciato perdere, di nuovo. La traduzione del sito era tra le mie cose da fare, c&amp;#8217;&#232; sempre stata: &amp;#8220;S&#236;, certo, &lt;em&gt;dovrei&lt;/em&gt; dare un&amp;#8217;occhiata a Ruby-Lang.org&amp;#8221;&amp;#8230; mi sono ripetuto questa frase periodicamente, senza di fatto fare nulla.&lt;/p&gt;
&lt;p&gt;Poi, finalmente, due settimane fa mi sono deciso a finire il lavoro traducendo le poche pagine rimaste, revisionando il tutto, facendo un po&amp;#8217; di pulizie qua e l&#224;, ed ecco qui: il sito pu&#242; ora essere visitato da tutti gli italiani che lo desiderano.&lt;/p&gt;
&lt;p&gt;La cosa pi&#249; ironica? Sono bastate solo poche oro di &amp;#8220;lavoro&amp;#8221; per mettere le cose a posto, ma quasi un anno per trovare finalmente la forza di volont&#224; per farlo&amp;#8230;&lt;/p&gt;
&lt;h3&gt;E adesso?&lt;/h3&gt;
&lt;p&gt;Ora il sito &#232; accessibile e lo terremo aggiornato d&amp;#8217;ora in avanti. &lt;br /&gt;
Spero sinceramente che possa contribuire ad avvicinare sempre pi&#249; italiani al mondo di Ruby, anche se sono sicuro che ci sono moltissime altre persone l&#224; fuori che avrebbero fatto un lavoro pi&#249; ben fatto del nostro, e sicuramente in tempi molto pi&#249; brevi&amp;#8230; ma dopotutto, alla fine ce l&amp;#8217;abbiamo fatta, no?&lt;/p&gt;
&lt;p&gt;Vorrei spendere ancora due parole per ringraziare nuovamente &lt;strong&gt;&lt;a href="http://www.raulparolari.com"&gt;Raul Parolari&lt;/a&gt;&lt;/strong&gt; e &lt;strong&gt;&lt;a href="http://www.lipsiasoft.com/"&gt;Davide D&amp;#8217;Agostino&lt;/a&gt;&lt;/strong&gt; per avermi aiutato a tradurre questo sito. Finalmente ora capisco perch&#232; Curt voleva tre persone nel gruppo di traduzione!&lt;/p&gt;
&lt;p&gt;Un&amp;#8217;ultima cosa: se qualcuno di voi trova un errore (e ce ne saranno molti, ne sono sicuro), o se ha un suggerimento per migliorare l&amp;#8217;attuale traduzione, pu&#242; &lt;a href="/about/"&gt;contattarmi&lt;/a&gt;: cercher&#242; di correggere il sito quanto prima possibile.&lt;/p&gt;
&lt;p&gt;E ora, divertitevi con Ruby, ora anche &lt;a href="http://www.ruby-lang.org/it/"&gt;in italiano&lt;/a&gt;!&lt;/p&gt;</description>
      <pubDate>Sat, 15 Nov 2008 13:48:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/ruby-lang-italian/</guid>
      <link>http://www.h3rald.com/articles/ruby-lang-italian/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/ruby-lang-italian/#comments</comments>
      <category>ruby</category>
    </item>
    <item>
      <title>Where does your Ruby code live?</title>
      <description>&lt;p&gt;Back when I wrote my &lt;a href="/articles/10-reasons-to-learn-ruby"&gt;10 reasons to learn Ruby&lt;/a&gt; article, I mentioned &lt;a href="http://www.rubygems.org/"&gt;RubyGems&lt;/a&gt; in &lt;em&gt;Reason #1&lt;/em&gt; as one of they key features of the Ruby programming languages.&lt;br /&gt;
Indeed, gems make getting Ruby programs as easy as typing &lt;code&gt;gem install &amp;lt;something&amp;gt;&lt;/code&gt; from the command line. When you want to distribute something new in Ruby, there&amp;#8217;s no need to give people download links, zip files or setup programs, just &lt;a href="http://adam.blog.heroku.com/past/2008/11/2/pony_the_express_way_to_send_email_from_ruby/"&gt;tell them to get the gem&lt;/a&gt;. That&amp;#8217;s perfectly normal, and extremely cool.&lt;/p&gt;
&lt;p&gt;Gems are normally stored on &lt;a href="http://rubyforge.org"&gt;RubyForge&lt;/a&gt;, so all you have to do is uploading your gem there, and it will be available to the rest of the universe. It&amp;#8217;s a nice feeling. I remember when I first uploaded &lt;a href="http://rubyforge.org/projects/rawline/"&gt;RawLine&lt;/a&gt; and then tried &lt;code&gt;gem install rawline&lt;/code&gt; just for the hell of it: it downloaded and installed the gem, as expected.&lt;/p&gt;
&lt;p&gt;Back in the day, if you wanted to find something written in Ruby, all you had to do is search through RubyForge, and you&amp;#8217;d eventually find it, with a bit of luck.&lt;/p&gt;
&lt;h3&gt;Can we just have git, please?&lt;/h3&gt;
&lt;p&gt;RubyForge had, until recently, one major problem: it only allowed &lt;span class="caps"&gt;CVS&lt;/span&gt; and &lt;span class="caps"&gt;SVN&lt;/span&gt; repositories, and you had to make your choice when creating the project, once and for all. So when the cool guys at &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt; rolled out their &lt;em&gt;social code hosting&lt;/em&gt; web site, most of the &lt;em&gt;cr&#233;me de la cr&#233;me&lt;/em&gt; of RubyForge flocked there in mass migration: &lt;a href="http://github.com/rails/rails/tree/master"&gt;Rails&lt;/a&gt;, &lt;a href="http://github.com/wycats/merb-core/tree/master"&gt;Merb&lt;/a&gt;, &lt;a href="http://github.com/dchelimsky/rspec/tree/master"&gt;RSpec&lt;/a&gt;&amp;#8230; you name it.&lt;br /&gt;
Once the big guys made the switch, a lot jumped on the GitHub bandwagon of course. Result: we have a lot of projects still on RubyForge, but quite a few (and important ones) on GitHub.&lt;/p&gt;
&lt;p&gt;Why did people move there? Well, at first it was because they wanted a sleek-looking git host, and RubyForge didn&amp;#8217;t offer git at the time. But &lt;a href="http://drnicwilliams.com/2008/04/08/git-for-rubyforge-accounts/"&gt;git is now available on RubyForge&lt;/a&gt;, so why don&amp;#8217;t people use it? &lt;br /&gt;
I&amp;#8217;d like to know how many people use git on RubyForge. Apparently you can have your old &lt;span class="caps"&gt;SVN&lt;/span&gt; repository manually migrated to git, if you ask nicely (and RubyForge people are very helpful always, anyway). Still, I don&amp;#8217;t think many people use git there, and hardly anyone (if any) moved back from GitHub.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s so special about this new &amp;#8220;social code hosting&amp;#8221; site then? I guess just a few key features:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Fast and reliable git hosting&lt;/li&gt;
	&lt;li&gt;The ability to &amp;#8220;watch&amp;#8221; other people&amp;#8217;s repositories and interact with them &amp;#8220;the git way&amp;#8221;, also by forking.&lt;/li&gt;
	&lt;li&gt;There&amp;#8217;s a whole new and fresh community feeling to it: you can follow people, message them, etc.&lt;/li&gt;
	&lt;li&gt;The interface is much more neat than RubyForge&amp;#8217;s (OK, granted, it doesn&amp;#8217;t take much)&lt;/li&gt;
	&lt;li&gt;Really cool stats and graphs&lt;/li&gt;
	&lt;li&gt;A basic, but functional, wiki&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&amp;#8230;oh, and bug tracking, too!&lt;/h3&gt;
&lt;p&gt;GitHub has no bug tracking features. It tracks an awful lot of stuff about your repositories and people working on them, but &amp;#8220;batteries are sold separately&amp;#8221;. You can get batteries &lt;a href="http://lighthouseapp.com/"&gt;here&lt;/a&gt;, for example. Apparently, GitHub and LightHouse are seamlessly &lt;a href="http://github.com/blog/41-service-integration"&gt;integrated&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So now you can sign up to two cool brand new web applications with neat interfaces instead of sticking with the old-looking RubyForge (which comes with &amp;#8220;batteries included&amp;#8221;, after all). &lt;br /&gt;
Personally &lt;strong&gt;I&amp;#8217;m very confused now&lt;/strong&gt;. Fortunately I don&amp;#8217;t have any extremely cool projects used by thousands of people, so jumping from one source code hosting solution from another is not really an issue for me, but I imagine it would be for others! Correct?&lt;/p&gt;
&lt;p&gt;So, as far as I know, if you are a Rubyist, here&amp;#8217;s what you can do:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Stick with RubyForge: it&amp;#8217;s not so bad after all.&lt;/li&gt;
	&lt;li&gt;Embrace GitHub (and Lighthouse): it&amp;#8217;s extremely nice to use. Some people are not &lt;a href="http://groovie.org/2008/05/06/most-bizarre-git-service-and-other-stupid-rails-powered-businesses"&gt;too convinced&lt;/a&gt; that this is the best choice though.&lt;/li&gt;
	&lt;li&gt;Go for something in between, like &lt;a href="http://www.assembla.com/"&gt;Assembla&lt;/a&gt;, which actually has an &lt;em&gt;impressive&lt;/em&gt; list of features and is powered by Rails too, so you&amp;#8217;ll feel at home. &lt;a href="http://code.google.com/hosting/"&gt;Google Code&lt;/a&gt; used to be another common choice, but sadly they don&amp;#8217;t offer git yet.&lt;/li&gt;
	&lt;li&gt;Do-it-yourself, maybe using something like &lt;a href="http://gitorious.org/"&gt;Gitorius&lt;/a&gt; and some open source bug tracking/project management solution.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So&amp;#8230; what choice did &lt;em&gt;you&lt;/em&gt; make or are you planning to make?&lt;/p&gt;
&lt;h3&gt;Moving houses&lt;/h3&gt;
&lt;p&gt;There&amp;#8217;s one simple issue to consider when moving your code to a new place: what happens to your &lt;em&gt;old&lt;/em&gt; place. If have a relatively popular project, a lot of people may have bookmarked your project page on RubyForge, or the RubyForge subdomain which you may have used as the &amp;#8220;home page&amp;#8221; for your project (in truth, most of the ones who moved away still use it).&lt;/p&gt;
&lt;p&gt;You may setup a redirection to the new home page or put a notice saying that the project moved somewhere else and point visitors to GitHub and LightHouse, or to another web site, if you wish. When &lt;a href="http://weblog.rubyonrails.org/2008/4/11/rails-premieres-on-github"&gt;Rails moved to GitHub&lt;/a&gt;, that wasn&amp;#8217;t much of a problem as Rails has its own web site.&lt;/p&gt;
&lt;p&gt;What may become a problem is your old repository. In Rails&amp;#8217; case, they left the old &lt;span class="caps"&gt;SVN&lt;/span&gt; repository available on sourceforge for a while and then removed it altogether. Other project owners have just abandoned their old repositories, occasionally resulting in &lt;a href="http://webby.rubyforge.org/"&gt;someone else&lt;/a&gt; deciding to leave a note as their &lt;a href="http://webby.rubyforge.org/svn/trunk/"&gt;last &lt;span class="caps"&gt;SVN&lt;/span&gt; commit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These solutions all work (you eventually drive people to the new home of your project), but it&amp;#8217;s not very nice, that&amp;#8217;s all. What happens if someone comes up with something cooler than GitHub? In all honesty, you may end up moving house over and over again.&lt;/p&gt;
&lt;h3&gt;Don&amp;#8217;t forget the gems!&lt;/h3&gt;
&lt;p&gt;One thing I liked about RubyForge, as I wrote at the beginning, was that if you uploaded a gem there, it was immediately available to everyone typing &lt;code&gt;gem install &amp;lt;something&amp;gt;&lt;/code&gt;.  &lt;br /&gt;
Luckily, &lt;a href="http://gems.github.com/list.html"&gt;GitHub supports gems, too&lt;/a&gt;! We&amp;#8217;re saved. The page they put up is &lt;a href="http://gems.github.com/"&gt;utterly awful&lt;/a&gt;, but it does the job: you can have your gems hosted on GitHub.&lt;/p&gt;
&lt;p&gt;Good! So surely I can get Rails now, right? Yup: &lt;code&gt;gem install rails&lt;/code&gt; will get the latest version of Rails for you, straight from GitHub.&lt;/p&gt;
&lt;p&gt;Actually, no. It doesn&amp;#8217;t seem to work that way: sure you can get the latest rails in that way, but it will actually be downloaded from &lt;em&gt;RubyForge&lt;/em&gt; (go check the &lt;a href="http://rubyforge.org/frs/?group_id=307&amp;amp;release_id=27493"&gt;downloads&lt;/a&gt;, you&amp;#8217;ll see it there). &lt;br /&gt;
So even if technically you got Rails, you got it from RubyForge. If you want to get gem from GitHub, you have to add it as gem source first (that&amp;#8217;s an &lt;em&gt;una tantum&lt;/em&gt; operation, luckily): &lt;code&gt;gem sources -a http://gems.github.com&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, yes, you can move to GitHub and you&amp;#8217;ll also get gem support: but please &lt;em&gt;remind the users&lt;/em&gt; that they have to add GitHub as gem source. Or, better, you should always remember to upload your latest gems to GitHub &lt;em&gt;and to RubyForge as well&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;The present&lt;/h3&gt;
&lt;p&gt;To sum up:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If you want, you can stay on RubyForge. It has git, it has gems, it&amp;#8217;s probably not nearly as prettier than competitors and is not as social, but it works.&lt;/li&gt;
	&lt;li&gt;You can opt for GitHub+LightHouse, have a slick interface, plenty of features and your project will be scattered in 2 different places + your home page, and you&amp;#8217;ll also have to keep uploading your gems to RubyForge.&lt;/li&gt;
	&lt;li&gt;At this point, you may even go for something completely different, like Assembla or your own setup, but still upload your gems to RubyForge.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The obvious solutions at this point would be that the folks who craft rubygems (the gem which makes the gems, to be clear) add GitHub as default source. Sure as hell when that happens other people will want that too (hey, I&amp;#8217;ll have gems.h3rald.com setup by then!). Is this the future? I hope not.&lt;/p&gt;
&lt;h3&gt;The future?&lt;/h3&gt;
&lt;p&gt;You know there&amp;#8217;s a domain called &lt;a href="http://www.rubygems.org/"&gt;www.rubygems.org&lt;/a&gt;? It&amp;#8217;s where the gem &lt;em&gt;manuals&lt;/em&gt; are! &lt;br /&gt;
As much as I love documentation, there&amp;#8217;s nothing wrong in moving all those documents and books to something like &lt;em&gt;docs.rubygems.org&lt;/em&gt;, right? &lt;br /&gt;
Then they could make RubyGems.org the &lt;em&gt;only&lt;/em&gt; official gem server and tell people they should upload their gems there if they want to distribute them efficiently (after manual approval, if necessary, like there is on RubyForge).&lt;/p&gt;
&lt;p&gt;In this way:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You wouldn&amp;#8217;t have to upload stuff to RubyForge anymore&lt;/li&gt;
	&lt;li&gt;You could have the clever folks at GitHub to create a simple script to automate the upload&lt;/li&gt;
	&lt;li&gt;You&amp;#8217;d have virtually &lt;em&gt;all&lt;/em&gt; the gems in one place&lt;/li&gt;
	&lt;li&gt;You&amp;#8217;d put a good domain name (currently almost forgotten) to good use&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While they are at it, &lt;strong&gt;the clever folks at RubyGems.org could also setup a &lt;em&gt;proper&lt;/em&gt; gem directory with a &lt;em&gt;proper&lt;/em&gt; search&lt;/strong&gt;. I&amp;#8217;m sure there would be plenty of people who could help, too!&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s not impossible, right? They said that making Rails/Ruby/RSpec documentation more accurate and accessible was impossible, but now there&amp;#8217;s &lt;a href="http://apidock.com/"&gt;APIdock&lt;/a&gt;, correct?&lt;/p&gt;
&lt;p&gt;Personally I&amp;#8217;d like it to be a collaborative effort of the Ruby community (like ruby-lang.org), rather than one private company showing off, but I think everyone will be happy as long as it works.&lt;br /&gt;
I&amp;#8217;m sure people will contribute, I would try at least (after finishing the Italian translation of ruby-lang.org, that is&amp;#8230; erhm, well, that&amp;#8217;s another story&amp;#8230;).&lt;/p&gt;
&lt;p&gt;Thoughts?&lt;/p&gt;</description>
      <pubDate>Sat, 08 Nov 2008 12:34:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/where-does-your-ruby-code-live/</guid>
      <link>http://www.h3rald.com/articles/where-does-your-ruby-code-live/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/where-does-your-ruby-code-live/#comments</comments>
      <category>ruby</category>
      <category>programming</category>
    </item>
    <item>
      <title>Rails-powered Open Source Killer Apps, Anyone?</title>
      <description>&lt;p&gt;Lately I&amp;#8217;ve been meandering around the web to find a good &lt;span class="caps"&gt;CMS&lt;/span&gt; for a family site I&amp;#8217;d like to set up. &lt;br /&gt;
Why a &lt;span class="caps"&gt;CMS&lt;/span&gt;? Well, for a few simple reasons:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;I don&amp;#8217;t have enough free time to fiddle with Rails and make my own (I&amp;#8217;m an &lt;em&gt;Hobbyist Programmer&amp;#8482;&lt;/em&gt;: I code for fun and enlightment, not for money)&lt;/li&gt;
	&lt;li&gt;Even if I had the time, I&amp;#8217;m &lt;em&gt;sure&lt;/em&gt; there are plenty of CMSes out there which suits my needs.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It turns out that reason #2 is not really applicable in this case, especially if we restrict the field to Ruby + Rails/Merb/&amp;lt;insert cool &lt;span class="caps"&gt;DRY&lt;/span&gt; framework here&amp;gt;.h3. Rails-powered CMSes&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Name a Rails-powered &lt;span class="caps"&gt;CMS&lt;/span&gt;, quick!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Easy: &lt;a href="http://radiantcms.org/"&gt;Radiant&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hmm, no. As much as I do like Radiant, it really cannot be considered a general-purpose &lt;span class="caps"&gt;CMS&lt;/span&gt;, can it? When it comes to build nearly-static sites in a clean and neat way I&amp;#8217;d pick it any day, but it lacks quite a lot of community features like comments, ability to create forums, etc. etc. It does, however, support multilingual content in a rudimentary, yet effective way: create each translated page manually and use consistent &lt;span class="caps"&gt;URL&lt;/span&gt; conventions (/en/about, /it/about, etc.).&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not saying that there aren&amp;#8217;t enough CMSes built on Rails, just that there&amp;#8217;s no &amp;#8220;killer app&amp;#8221; in the pack. A &amp;#8220;killer&amp;#8221; &lt;span class="caps"&gt;CMS&lt;/span&gt; would be something as powerful as Drupal, but easier to use and more modular.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s an incomplete list of the Rails CMSes I&amp;#8217;m currently aware of:&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;Name &lt;/th&gt;
		&lt;th&gt;First Impressions/Comments &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://radiantcms.org/"&gt;Radiant&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Mature, suitable for administering static sites &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://www.typosphere.org/"&gt;Typo&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Mature, one of the best blogging engines out there (my opinion is slightly biased though) &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://mephistoblog.com/"&gt;Mephisto&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Mature, blogging engine &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://rubricks.org/index_en.html"&gt;Rubricks&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Under development, basic features if compared to other non-Rails solutions &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://slateinfo.blogs.wvu.edu/"&gt;Slate&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Missing a lot of features if compared to competitors &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://beast.caboo.se"&gt;Beast&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Forum engine, extremely ligtweight &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://www.railfrog.com/"&gt;RailFrog&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Not sure if it&amp;#8217;s still being updated, not so many features &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://zenadmin.org/en"&gt;Zena&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Alpha, looks promising although it doesn&amp;#8217;t offer many features &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://simplelog.net/"&gt;simplelog&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Yet another blogging engine. Simple and easy to use &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://rcms.oopen.de/"&gt;oooopen rcms&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Early development stage (dead?), minimal feature set &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; &lt;a href="http://www.geegocms.com/"&gt;Geego&lt;/a&gt; &lt;/td&gt;
		&lt;td&gt; Multilingual, not so many out-of-the-box features &lt;/td&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;[Psst, if you know any other Rails &lt;span class="caps"&gt;CMS&lt;/span&gt; I missed out, mention it in a comment and I&amp;#8217;ll update this table!]&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Developing Proprietary Web Applications with Rails&lt;/h3&gt;
&lt;p&gt;What&amp;#8217;s wrong with all of these? Normally one of three things: either they are mature, production-ready but focused on only one particular function (blog, forum, etc.), or they are still too new to be used seriously or they are slowly heading towards oblivion.&lt;/p&gt;
&lt;p&gt;What&amp;#8217;s going on here? Rails is a damn fine framework which offers all the modularity and power you need to build sites! Why isn&amp;#8217;t there a fully fledged &lt;span class="caps"&gt;CMS&lt;/span&gt; to rival Drupal? &lt;br /&gt;
I think that part of the problem is that Rails is &lt;em&gt;too&lt;/em&gt; good. &lt;strong&gt;Why build a &lt;span class="caps"&gt;CMS&lt;/span&gt; from scratch when you can develop a web site from scratch much more easily, tailored to your customer?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Rails has been used to build a few &amp;#8220;mainstream&amp;#8221; sites like Twitter (no bashing please!), Basecamp, GitHub and many more. What do these sites have in common? &lt;em&gt;They are not open source&lt;/em&gt;. You cannot deploy your own Twitter on your server (You can with &lt;a href="http://laconi.ca/trac/"&gt;Laconica&lt;/a&gt;, though), you cannot deploy your own Basecamp to your server (you can with &lt;a href="http://www.projectpier.org/"&gt;ProjectPier&lt;/a&gt;, an open source fork of &lt;a href="http://www.activecollab.com/"&gt;ActiveCollab&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;It feels like that even though Rails itself is open source, &lt;strong&gt;there aren&amp;#8217;t that many open source Rails-powered projects after all&lt;/strong&gt;. Maybe there are, but they do not really compare with similar alternatives offered in other languages. This is the reason why, despite its utter ugliness, &lt;span class="caps"&gt;PHP&lt;/span&gt; is still the &lt;em&gt;Open Source King of the Web&lt;/em&gt;, and that&amp;#8217;s very, very sad in my opinion.&lt;/p&gt;
&lt;h3&gt;Dreams on Rails&lt;/h3&gt;
&lt;p&gt;The annoying thing is that Rails &lt;em&gt;is suitable&lt;/em&gt; to build CMSes, and good ones, too! Take Radiant and Typo, for example: they both excel in their own ways, &lt;em&gt;in their own worlds&lt;/em&gt;.&lt;br /&gt;
Theorethically speaking, &lt;strong&gt;there&amp;#8217;s no reason why someone couldn&amp;#8217;t develop a modular system to glue different components together&lt;/strong&gt;: you&amp;#8217;d need common user administration and common workflow, a few hooks, and a solid set of conventions on how to build third-party components.&lt;br /&gt;
Hell guys, the folks at Drupal developed a huge (and successful) product with a million different ways to extend it &lt;em&gt;in &lt;span class="caps"&gt;PHP&lt;/span&gt;&lt;/em&gt;. Even without using &lt;span class="caps"&gt;OOP&lt;/span&gt;! Every damn hook in the core is a &lt;em&gt;function&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;What does it take to do something like this using Rails, o Merb, or whatever else you like? You already have a very solid and consistent framework to build on (Rails), a way to automate tasks (Rake) and a language which lets you do everything you want, in a very elegant and organized way.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Rails lacks successful open source projects, in particular CMSes&lt;/strong&gt;. I wish someone could fix this: not by coding the &lt;em&gt;n^th^&lt;/em&gt; &lt;span class="caps"&gt;CMS&lt;/span&gt; with the only two or three features you need, but by developing an &lt;em&gt;high level application framework&lt;/em&gt; to build complex, dynamic and interactive web sites. Don&amp;#8217;t even develop the whole damn thing: just come up with a set of conventions on how to extend a very basic core, and tell people how they can contribute, or even integrate existing applications into it.&lt;/p&gt;
&lt;p&gt;The community will do the rest, hopefully&amp;#8230; Or maybe are you too busy trying to roll out your newest, closed source startup?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If someone decides to develop such a powerful, high-level framework and is determined to keep it user-friendly and open source, I hereby promise to write the documentation for it&lt;/strong&gt;, articles, and books. And I&amp;#8217;m not kidding.&lt;/p&gt;
&lt;h3&gt;[&lt;span class="caps"&gt;UPDATED&lt;/span&gt;] A Glimpse of Hope&lt;/h3&gt;
&lt;p&gt;A few of the commenters of this article brought up a few interesting points and actually gave me a little bit of hope. &lt;a href="http://salesforceonrails.com/"&gt;Luigi Montanez&lt;/a&gt; pointed out that Rails was built to help developers build web sites. For now, Rails deployment isn&amp;#8217;t as seamless as end users would like it, so there&amp;#8217;s no point creating a killer app for such users if they can&amp;#8217;t even get it to run on their $2/month shared hosting environment.&lt;br /&gt;
Nevertheless, there seems to be at least &lt;em&gt;three&lt;/em&gt; different open source &amp;#8220;social network engines&amp;#8221; powered by Rails:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://portal.insoshi.com/"&gt;Insoshi&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.communityengine.org/"&gt;Community Engine&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://lovdbyless.com/"&gt;Lovd By Less&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are not CMSes &lt;em&gt;in the early 2000&amp;#8217;s sense&lt;/em&gt;, obviously, but they do provide the basis to effectively build a late Web 2.0-ish community web site. Each one of these project seems stable and mature enough to be used in production, but surely not as well-known as many other &lt;span class="caps"&gt;PHP&lt;/span&gt;-based solutions.&lt;/p&gt;
&lt;p&gt;On the other hand, &lt;a href="http://priit.mx.ee/"&gt;Priit Tamboom&lt;/a&gt; mentioned &lt;a href="http://adva-cms.org/"&gt;adva cms&lt;/a&gt;, a project still in alpha stage which aims to be more traditional and site-agnostic:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;[&amp;#8230;] Different from other Rails applications the all-engines approach of adva cms allows you to build your own applications on top of it. It also makes it very flexible and extensible: our plan is to make it possible to only pick those engines/features that you really need for your application and omit the rest. As they are still all designed to work together seemlessly and reuse each others functionality the whole plattform feels much more consistent to a collection of similar but separate Rails applications. [&amp;#8230;]&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This sounds &lt;em&gt;exactly&lt;/em&gt; like what I was hoping would come out from the Rails community: something in between a web development framework and an high-level &lt;span class="caps"&gt;CMS&lt;/span&gt;. &lt;br /&gt;
I&amp;#8217;m definitely going to try it out (it&amp;#8217;s an ideal weekend project) and I&amp;#8217;ll report back once I know more about it.&lt;/p&gt;</description>
      <pubDate>Sun, 02 Nov 2008 09:41:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/rails-os-killer-apps/</guid>
      <link>http://www.h3rald.com/articles/rails-os-killer-apps/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/rails-os-killer-apps/#comments</comments>
      <category>rails</category>
      <category>ruby</category>
      <category>writing</category>
      <category>rant</category>
    </item>
    <item>
      <title>Rails-Doc.org - A First Look</title>
      <description>&lt;p&gt;When you decided to learn Ruby on Rails (if you did, that is), chances are that you bought a book. I did, too, actually: there are a lot of very interesting and fairly comprehensive books out there after all.&lt;/p&gt;
&lt;p&gt;I actually never bought a book to learn &lt;span class="caps"&gt;PHP&lt;/span&gt;, in the past though. Why&amp;#8217;s that? Well, for two simple reasons:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The &lt;a href="http://www.php.net/manual/en/"&gt;&lt;span class="caps"&gt;PHP&lt;/span&gt; manual&lt;/a&gt; can easily be searched and provides enough documentation, in most cases.&lt;/li&gt;
	&lt;li&gt;When the documentation is not enough, there&amp;#8217;s always plenty of comments by experienced developers to save your day.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That being said, &lt;span class="caps"&gt;PHP&lt;/span&gt; is still an awfully disorganized language, but believe it or not, coming from &lt;span class="caps"&gt;PHP&lt;/span&gt; I didn&amp;#8217;t find &lt;a href="http://api.rubyonrails.org/"&gt;Rails documentation&lt;/a&gt; useful enough simply because it didn&amp;#8217;t have these two simple but very powerful features.&lt;/p&gt;
&lt;p&gt;Sure, there&amp;#8217;s the &lt;a href="http://www.railsdocumentation.org/"&gt;Rails Documentation Project&lt;/a&gt; which provides more organized docs, and &lt;a href="http://www.noobkit.com/"&gt;Noobkit&lt;/a&gt; does a nice job with its search-as-you-type feature&amp;#8230; but still is not quite enough: you&amp;#8217;d expect something much better than that for something like Rails!h3. Introducing Rails-Doc.org&lt;/p&gt;
&lt;p style="float:right;"&gt;&lt;img src="/files/railsdoc_logo_sm.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.rails-doc.org"&gt;Rails-Doc.org&lt;/a&gt; focuses on providing a better interface to Rails documentation by offering two key features:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;A powerful, fast and useful document search&lt;/li&gt;
	&lt;li&gt;The possibility to add notes to Rails documentation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When the app went live, I immediately registered (it&amp;#8217;s free of course) and started playing with it&amp;#8230;&lt;/p&gt;
&lt;h4&gt;Search as you type&amp;#8230;&lt;/h4&gt;
&lt;p&gt;The first thing I did was trying the search features, of course. I started typing &amp;#8220;rout&amp;#8221; for Routing, and I was immediately shown a list of matches:&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/rails-doc_search.gif" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;It took a small fraction of a second to load the matches, which makes me think that definitely they have all the names indexed somewhere. Nevertheless, it was a pleasant surprise: normally, these search-as-you-type utilities are not that refined!&lt;/p&gt;
&lt;p&gt;All you need to do is start typing at least three letters, and you get results, if any. &lt;br /&gt;
if you press &lt;span class="caps"&gt;ENTER&lt;/span&gt;, you get automatically redirected to the first result. This can be good, but maybe it would have been nicer to load a &amp;#8220;traditional&amp;#8221; list of results, but it depends on your taste, really.&lt;/p&gt;
&lt;h4&gt;&amp;#8230;or browse through the namespaces&lt;/h4&gt;
&lt;p&gt;Alternatively, it is possible to browse the docs in the more traditional way, i.e. according to their class or module: the &lt;strong&gt;Browse&lt;/strong&gt; page does just that: it lists &lt;em&gt;all&lt;/em&gt; Rails classes and modules, regardless of the nesting. But there&amp;#8217;s more: a little roundy icon precedes each class name, to indicate whether the documentation is present, and to what degree:&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/rails-doc_icons.gif" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;This is an interesting concept: in this way, in theory, people should contribute to the documentation where it&amp;#8217;s more needed.&lt;/p&gt;
&lt;p&gt;Each reference page is very neatly re-formatted: you can hardly imagine it&amp;#8217;s actually the same content included in Rails&amp;#8217; RDoc pages!&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/rails-doc_document.gif" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Finally, another nice addition is the &lt;strong&gt;Related&lt;/strong&gt; column, which lists links to other items which are related to the current topic:&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/rails-doc-related.gif" alt="" /&gt;&lt;/p&gt;
&lt;h3&gt;Contribute, contribute, contribute!&lt;/h3&gt;
&lt;p&gt;You have to register for something, don&amp;#8217;t you? Yes. If you register, you can post notes to any document. Simple enough, all you have to do is to click the &lt;strong&gt;Add Note&lt;/strong&gt; button and a form will slide down for you to fill in:&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/rails-doc_note1.gif" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;As you start typing, you&amp;#8217;ll notice that a preview of the note is displayed instantly: as you can use SimpleMarkup to write notes, exactly like in RDoc, this feature can be very handy:&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/rails-doc_note2.gif" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;What if there&amp;#8217;s no documentation for a particular class or method? You&amp;#8217;ll get a warning like this one:&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/rails-doc_nodoc.gif" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The idea behind this is that, if you provide some useful insights, they&amp;#8217;ll eventually end up in Rails core documentation.&lt;/p&gt;
&lt;h3&gt;An Short Interview with Mikael Roos, from Nodeta&lt;/h3&gt;
&lt;p&gt;Before the application went live, I was lucky enough to get Mikael Roos to answer to some of my questions. Here&amp;#8217;s the full interview&amp;#8230;&lt;/p&gt;
&lt;h4&gt;What are you actually trying to do on Rails-Doc.org?&lt;/h4&gt;
&lt;p&gt;The initial goal of the project is to provide the existing documentation in a more accessible way, most importantly to provide a lightning fast search feature that gives weighted results based on the&lt;br /&gt;
quality and amount of documentation. This we have already accomplished, and all remaining issues are related to browser compatibility. Another initial goal is to present a smooth interface for creating inline notes to&lt;br /&gt;
the documentation so that Rails developers can post notes about certain methods etc. for themselves and others to draw knowledge from.&lt;/p&gt;
&lt;p&gt;Our longer-term goal (N.B. we are an agile project, so long-term means, say, three months) is to provide a way for the active members of the Rails community to improve the existing documentation based on the posted notes&lt;br /&gt;
to create an extended documentation that could optimally even be made in to a patch and would find its way back into the actual Rails source.&lt;/p&gt;
&lt;p&gt;Another clear and obvious goal is to keep improving the service steadily as we progress toward the goals that I mentioned above.&lt;/p&gt;
&lt;h4&gt;Could you spend a few words on the &amp;#8220;development process&amp;#8221; followed by your company to develop this app? Did I read the word &amp;#8220;Scrum&amp;#8221; somewhere? Am I correct?&lt;/h4&gt;
&lt;p&gt;Yes, our development process of choice is Scrum. The core team is only three members, one backend developer, one backed/frontend develope and one frontend developer/UI specialist. I feel the team is optimal in many ways.&lt;br /&gt;
The team also has a few more experienced developers who are primarily active in other projects to ask questions from, one of whom is also the acting product owner on the Rails-doc project (that&amp;#8217;s me!).&lt;/p&gt;
&lt;h4&gt;Did you develop it in three months, or&amp;#8230;?&lt;/h4&gt;
&lt;p&gt;The first release was developed in three &lt;span class="caps"&gt;SPRINTS&lt;/span&gt;, not months &amp;#8211; so what I&amp;#8217;m saying is the first release was developed in five weeks (first sprint was mostly introductory and lasted a week, the next two sprints, first&lt;br /&gt;
development and then stabilization, were two weeks each). However, it is a &lt;span class="caps"&gt;FIRST&lt;/span&gt; &lt;span class="caps"&gt;RELEASE&lt;/span&gt;, which means the app is by all means not complete, but since we make software in a very agile way, it&amp;#8217;a all about &amp;#8220;Ship, ship, ship!&amp;#8221;.&lt;/p&gt;
&lt;h4&gt;What is &lt;a href="http://www.nodeta.fi"&gt;Nodeta&lt;/a&gt;, exactly? My Finnish is a bit rusty nowadays&amp;#8230;&lt;/h4&gt;
&lt;p&gt;Nodeta is a software development company that focuses on web software. We employ a highly agile and effective process. We have worked both on light independent projects and in the environment of large global enterprises.&lt;br /&gt;
There are currently 10 Nodetans.&lt;/p&gt;
&lt;p&gt;Rails-Doc.org is a pilot project for your new shiny app, ApiDock. Is it an open source app?&lt;/p&gt;
&lt;p&gt;Unfortunately, I cannot go into details about APIdoc yet. What I can tell is that it is developed with Rails and that it won&amp;#8217;t be open source, but rather it would optimally be offered as a service, which after all is what&lt;br /&gt;
the word &amp;#8220;app&amp;#8221; on the web means these days. Open source projects could however use it for free, sort of in the spirit of GitHub.&lt;/p&gt;
&lt;p&gt;It will also most likely be separately targeted to larger companies.&lt;/p&gt;
&lt;h4&gt;Can you give me more technical details about the way keyword search is performed? Are you indexing/tagging documentation beforehand?&lt;/h4&gt;
&lt;p&gt;There will probably be a blog post on the &lt;a href="http://blog.nodeta.fi"&gt;Nodeta blog&lt;/a&gt; about the search and how it works after the first release comes out.&lt;/p&gt;
&lt;h4&gt;What about the social side of it: you&amp;#8217;re hoping people will contribute with notes, which will then be collected and integrated in the documentation correct? Do you have any moderation or anti-spam precaution?&lt;/h4&gt;
&lt;p&gt;The quality of notes is judged in a social way. Notes can be thanked by other users and notes that get many thanks are showed in a more prominent way. Registration will be required in order to post notes and the registration will feature a captcha.&lt;/p&gt;
&lt;h4&gt;Will contributors be credited somehow? Who can contribute and at what level?&lt;/h4&gt;
&lt;p&gt;Anybody can post notes and good notes get thanks and thus so do their posters. Users that get lots of thanks will be later asked to become core users that can alter the extended documentation (not in the first&lt;br /&gt;
release.)&lt;/p&gt;
&lt;h4&gt;You want to blow out competition and that you don&amp;#8217;t want to fail: sounds a good plan! How is Rails-Docs different from other similar apps?&lt;/h4&gt;
&lt;p&gt;We think that our app is the first that is serious about making things happen. We think about users first and above all at this stage our search feature is frankly unparallelled.&lt;/p&gt;
&lt;h4&gt;Do you have DHH&amp;#8217;s seal of approval? Will you? Is there any copyright issue with your domain name?&lt;/h4&gt;
&lt;p&gt;Time will tell what &lt;span class="caps"&gt;DHH&lt;/span&gt; thinks. We did contact him just a few days ago to ask what his thoughts about all this are and are waiting for his comments. I doubt there is any wrinkles with copyright as Rails-doc itself is a completely non-profit project.&lt;/p&gt;
&lt;h4&gt;What about doing something similar for the whole Ruby language? Ruby docs may also be easier, in a way&amp;#8230;&lt;/h4&gt;
&lt;p&gt;It is possible that we might do just that but right now it&amp;#8217;s all about Rails.&lt;/p&gt;
&lt;h3&gt;The Bottom Line&lt;/h3&gt;
&lt;p&gt;Rails-Doc.org is definitely an interesting project, which has all the potential to become a powerful, Rails-powered service. Sure, it&amp;#8217;s not open source and this can be a bit of a letdown for some: but after all people flocked to GitHub when it opened, didn&amp;#8217;t they?&lt;/p&gt;
&lt;p&gt;The search capabilities of Rails-Doc.org are definitely a very important step forward in making Rails documentation more accessible and easier to use, but the killer feature is definitely the possibility to add notes, if used wisely.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll be watching this project closely and I&amp;#8217;ll pay particular attention on what happens to the community&amp;#8217;s contributions: will it really be useful? Will it really help creating documentation patches to Rails core? Only time will tell, of course.&lt;/p&gt;</description>
      <pubDate>Thu, 19 Jun 2008 05:30:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/rails-doc-first-look/</guid>
      <link>http://www.h3rald.com/articles/rails-doc-first-look/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/rails-doc-first-look/#comments</comments>
      <category>rails</category>
      <category>ruby</category>
      <category>writing</category>
      <category>review</category>
    </item>
    <item>
      <title>Book Review: Design Patterns in Ruby</title>
      <description>&lt;p&gt;I finally got my hands on a shiny new copy of &lt;em&gt;Design Patterns in Ruby&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/em&gt;. The book itself is not brand new and it was already widely praised by many different people online, so I wanted to take a look for myself.&lt;/p&gt;
&lt;p&gt;To my surprise, the book is a hardcover edition, which makes it look more professional and more durable than the average programming book&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;. It&amp;#8217;s also smaller and shorter than the average programming book&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; (340 pages), which makes it much easier to carry around and less intimidating to read. It&amp;#8217;s also &lt;em&gt;not&lt;/em&gt; meant to be a reference book, so it is actually pleasant an easy to read all in one go, as you&amp;#8217;ll soon find out.&lt;/p&gt;
&lt;p&gt;What is it about? &amp;mdash; well, design patters in the Ruby language of course. But it&amp;#8217;s not the usual brainwash of programming theory you would expect by a typical book on patters, it has &lt;em&gt;plenty&lt;/em&gt; of examples of real code. When I say &lt;em&gt;real code&lt;/em&gt; I don&amp;#8217;t mean the usual Dog/Cat/Horse/&amp;lt;insert animal here&amp;gt; classes or juke-box simulations which don&amp;#8217;t work at all etc. etc., I mean actual snippets from well known Ruby applications, like RubyGems, FXRuby and, of course, Rails.&lt;br /&gt;
OK well, there&amp;#8217;s an exception perhaps: Russ &lt;em&gt;did&lt;/em&gt; include a few wild life simulations (ponds with frogs and similar), but it&amp;#8217;s only for your own good, and for the sake of tradition.&lt;/p&gt;
&lt;p&gt;Anyhow, let&amp;#8217;s start from the beginning&amp;#8230;&lt;/p&gt;
&lt;h3&gt;Part I: Patters and Ruby&lt;/h3&gt;
&lt;p&gt;The first part of the book serves as a general introduction to the other two parts. If you know the basics of both design patterns and Ruby, you can safely skip this as you won&amp;#8217;t find anything of overwhelming interest here.&lt;/p&gt;
&lt;p&gt;Personally I really liked &lt;strong&gt;Chapter 1&lt;/strong&gt; though, &amp;#8220;Building better Programs with Patterns&amp;#8221;, in which Russ does a great job in summarizing the original GoF book&lt;sup class="footnote" id="fnr3"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt; into four points:&lt;/p&gt;
&lt;p style="float:right;"&gt;&lt;img src="/files/design_patterns_in_ruby.jpg" alt="" /&gt;&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;em&gt;Separate our the things that change from those that stay the same.&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Program to an interface, not an implementation.&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Prefer composition over inheritance.&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Delegate, delegate, delegate.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, although it does not come from the Design Patterns book but from building real systems, the author adds the &lt;span class="caps"&gt;YAGNI&lt;/span&gt; (You Ain&amp;#8217;t Gonna Need It) principle&lt;sup class="footnote" id="fnr4"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt; as a reminder to resist the temptation of implementing things which &lt;em&gt;may&lt;/em&gt; be needed &lt;em&gt;later on&lt;/em&gt;, even if they are not needed right now.&lt;br /&gt;
The chapter ends with an outline of the patterns which will be presented throughout the book: 14 out of the original 23 patterns by the Gand of Four will be discussed in Part II and 3 bonus &amp;#8220;Ruby-only&amp;#8221; patterns will be examined in Part &lt;span class="caps"&gt;III&lt;/span&gt;, as a special treat.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Chapter 2&lt;/strong&gt; (&lt;em&gt;Getting started with Ruby&lt;/em&gt;) feels perhaps a bit out of place. As others pointed out&lt;sup class="footnote" id="fnr5"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;, why does a book on advanced Ruby programming techniques include a 35-page-long introduction on the Ruby language? The answer was given by Russ himself in an interview&lt;sup class="footnote" id="fnr6"&gt;&lt;a href="#fn6"&gt;6&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;The reason that I included the introductory chapter about Ruby in there was to make the book accessible to folks with little or no Ruby background.&lt;br /&gt;
Now honestly, I don&#8217;t think that you could come to my book with no background in Ruby and walk away from it an expert Ruby programmer &amp;mdash; it&#8217;s not really that kind of introductory book.&lt;br /&gt;
But I do think that someone with experience in other languages could read my book and come away knowing about Ruby, understanding what all the shouting is about.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I admit, I skipped this chapter during my first reading because I was eager to move on to the main part of the book, but I did read it afterwards (I had to write this review after all!). It&amp;#8217;s quite a nice introduction aimed at the average .&lt;span class="caps"&gt;NET&lt;/span&gt;/Java developer: Russ provides a step-by-step presentation of the main features of the language while holding the reader by hand when something weird or scary comes about:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The slightly strange-looking syntax in this code is actually a tip-off something deep and important: In Ruby, everythng &amp;mdash; and I mean &lt;em&gt;everything&lt;/em&gt; &amp;mdash; is an object.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Of course Chapter 2 won&amp;#8217;t turn you into a Ruby guru, but it definitely fulfills one of the author&amp;#8217;s goals: bringing developers of other languages closer to Ruby, and give them a tiny taste of how Ruby can be &lt;em&gt;wickedly powerful&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Part II: Patterns in Ruby&lt;/h3&gt;
&lt;p&gt;Part II constitutes the bulk of the book, describing 14 GoF patterns in 220 pages. The patterns covered are the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Template Method&lt;/li&gt;
	&lt;li&gt;Strategy&lt;/li&gt;
	&lt;li&gt;Observer&lt;/li&gt;
	&lt;li&gt;Composite&lt;/li&gt;
	&lt;li&gt;Iterator&lt;/li&gt;
	&lt;li&gt;Command&lt;/li&gt;
	&lt;li&gt;Adapter&lt;/li&gt;
	&lt;li&gt;Proxy&lt;/li&gt;
	&lt;li&gt;Decorator&lt;/li&gt;
	&lt;li&gt;Singleton&lt;/li&gt;
	&lt;li&gt;Factory Method&lt;/li&gt;
	&lt;li&gt;Abstract Factory Method&lt;/li&gt;
	&lt;li&gt;Builder&lt;/li&gt;
	&lt;li&gt;Interpreter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Why not covering all 23? Well, because to be honest, they are rarely used in Ruby. Furthermore, in some cases some of the ones examined in the book may feel a bit &lt;em&gt;unnatural&lt;/em&gt; to the average Rubyist: how many times did you ever think about using an External Iterator when &lt;code&gt;each&lt;/code&gt; is normally available as default internal iterator for any Array-like class?&lt;/p&gt;
&lt;p&gt;Each chapter in this part is devoted to a particular pattern and it is organized in more or less the same way, as outlined in the following sections.&lt;/p&gt;
&lt;h4&gt;Introduction and Personal Anecdotes&lt;/h4&gt;
&lt;p&gt;Most chapters start with a personal anecdote involving the author: it may be a memory related to his first job at the local grocery store (Chapter 8), or about the day he decided to buy his son a bike (Chapter 14):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;I remember the day we bought my son his first bike.&amp;#8221; [&amp;#8230;] I spent hours trying to pull together a minor junkiard of parts according to instructions that would have baffled the entire National Security Agency. As it turned out, picking the bike was the easy part: putting it together was the real challenge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This was used to introduce the Builder pattern, and how to use it to configure objects which include different logical parts.&lt;br /&gt;
Personally I find this technique particularly useful to introduce a particular problem from a different, more mundane prospective instead of starting off with an abstract theorethical description of the pattern itself. &lt;br /&gt;
The anecdote is then followed by the description of the actual programming problem for which the specific pattern will be used.&lt;/p&gt;
&lt;h4&gt;Description of the Pattern and Initial Implementation&lt;/h4&gt;
&lt;p&gt;An initial implementation of the pattern in Ruby will be provided more or less immediately after the introduction of each chapter, often accompanied by a simple &lt;span class="caps"&gt;UML&lt;/span&gt; diagram.&lt;br /&gt;
This implementation normally has quite a few conceptual flaws, which are then examined and corrected step-by-step the chapter to obtain a more &amp;#8220;Ruby-friendly&amp;#8221; solution.&lt;/p&gt;
&lt;h4&gt;A More Rubyfied Version of the Pattern&lt;/h4&gt;
&lt;p&gt;The final implementation of each pattern is often very different from the initial attempt, and it may contain quite a lot of Ruby-specific code. The author does an excellent job in suggesting pattern implementations which often use blocks, &lt;code&gt;Proc&lt;/code&gt; objects or method redefinitions when needed, to make the code more succint and more readable at the same time, as all Ruby code should be.&lt;/p&gt;
&lt;p&gt;By doing so, even people who are still learning Ruby will understand how to use some very useful Ruby idioms which can be a bit difficult to grasp otherwise.&lt;/p&gt;
&lt;h4&gt;Using and Abusing &amp;lt;Pattern&amp;gt;&lt;/h4&gt;
&lt;p&gt;Patterns are often overused and misused, and some people normally end up wondering if they should be used at all, after all. This section (present as a matter of fact in &lt;em&gt;every&lt;/em&gt; chapter of part II an &lt;span class="caps"&gt;III&lt;/span&gt;) examines the pitfalls of the pattern and the most common mistakes developer make when applying it.&lt;br /&gt;
It is by far the most useful section of each chapter, and that&amp;#8217;s what I&amp;#8217;ll be reading and re-reading every time I&amp;#8217;m thinking about using a particular pattern in my code. As a matter of fact, these sections make you realize that &lt;em&gt;every&lt;/em&gt; pattern has its own inherent flaws and dangers, and that it is far from being a Silver Bullet. Even when you&amp;#8217;re &lt;em&gt;supposed&lt;/em&gt; to use a pattern to accomplish something, be aware that &lt;em&gt;something nasty&lt;/em&gt; can happen unless you&amp;#8217;re extra careful: this, perhaps, is the true Golden Rule conveyed throughout the whole book.&lt;/p&gt;
&lt;h4&gt;&amp;lt;Pattern&amp;gt;s in the Wild&lt;/h4&gt;
&lt;p&gt;This is another very interesting section which is included in every chapter of part II and &lt;span class="caps"&gt;III&lt;/span&gt;. After describing what a pattern does, how it &lt;em&gt;can&lt;/em&gt; be used and how it &lt;em&gt;should&lt;/em&gt; be used, you&amp;#8217;ll finally find some interesting examples taken from real world applications.&lt;br /&gt;
By &amp;#8220;real world application&amp;#8221; I mean something like ActiveRecord&lt;sup class="footnote" id="fnr7"&gt;&lt;a href="#fn7"&gt;7&lt;/a&gt;&lt;/sup&gt; (Observer, Command, Adapter, &amp;#8230;), DRb&lt;sup class="footnote" id="fnr8"&gt;&lt;a href="#fn8"&gt;8&lt;/a&gt;&lt;/sup&gt; (Proxy) or FXRuby&lt;sup class="footnote" id="fnr9"&gt;&lt;a href="#fn9"&gt;9&lt;/a&gt;&lt;/sup&gt; (Composite), for example, i.e. important programs and libraries which are used in production environments.&lt;br /&gt;
Personally, I was really glad to find such examples in this book: it definitely helps you feeling design patterns as something more practical and useful than pure software architecture theories.&lt;/p&gt;
&lt;h4&gt;Wrapping it Up&lt;/h4&gt;
&lt;p&gt;&amp;#8220;Wrapping it Up&amp;#8221; is the title of the last section of each chapter of Part II and &lt;span class="caps"&gt;III&lt;/span&gt;. It&amp;#8217;s basically a summary of the whole chapter and thus a useful way to recap the most important concepts. I found this section particularly useful when using the book as a design pattern reference, after reading it for the first time: this section provides a quick and essential overview of each pattern &amp;#8212; and the most important DOs and DON&amp;#8217;Ts, too.&lt;/p&gt;
&lt;h3&gt;Part &lt;span class="caps"&gt;III&lt;/span&gt;: Patterns for Ruby&lt;/h3&gt;
&lt;p&gt;By the time you get to Part &lt;span class="caps"&gt;III&lt;/span&gt; you&amp;#8217;ll definitely feel that Ruby can do &lt;em&gt;more_. Some of the Ruby implementation of certain patterns described in the book make extensive use of blocks and Proc objects, and the @method&lt;/em&gt;missing@ method (although potentially dangerous unless extra care is taken) gives us a more immediate way to obtain delegation, for example when creating Proxies. &lt;br /&gt;
Also the fact that objects can be modified at runtime by adding and removing methods &amp;#8220;as needed&amp;#8221; seems quite an underused feature in traditional patterns, simply because those patterns were first conceived for languages which are very different from Ruby and are perhaps less &lt;em&gt;liberal&lt;/em&gt; than Ruby when it comes to dynamic features&lt;sup class="footnote" id="fnr10"&gt;&lt;a href="#fn10"&gt;10&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;These particular Ruby features can be used (and abused, of course) to implement more Ruby-esque patterns, such as the ones included in this part of the book:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Internal Domain-Specific Languages&lt;/li&gt;
	&lt;li&gt;Meta-Programming&lt;/li&gt;
	&lt;li&gt;Convention Over Configuration&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are just examples, of course some may complain because the Active Record or &lt;span class="caps"&gt;ORM&lt;/span&gt; pattern are missing, but this is understandable as it may be considered too specific compared to the others. &lt;br /&gt;
Each pattern is examined in detail, and I particularly like way the &lt;span class="caps"&gt;DSL&lt;/span&gt; pattern was described: Chapter 16 explains how to develop a simple but effective Ruby &lt;span class="caps"&gt;DSL&lt;/span&gt; from scratch for creating file backups. This can be particularly useful for people who never tried creating DSLs before, but also for developers who tried, but want to improve their skills.&lt;/p&gt;
&lt;p&gt;Chapter 18 (Convention Over Configuration) is sufficiently clear and detailed, perhaps even too much if you already know how Rails was developed (and all the hype which follwed).&lt;/p&gt;
&lt;p&gt;On the other hand, I was a bit disappointed by Chapter 17 (Meta-Programming). Maybe it&amp;#8217;s because I built up extremely high expectations about it while reading the rest of the book, but it just felt too short and not detailed enough for my liking. If I had to write such a chapter (which would have been actually very hard), I would have started from an excellent post by Ola Bini&lt;sup class="footnote" id="fnr11"&gt;&lt;a href="#fn11"&gt;11&lt;/a&gt;&lt;/sup&gt; which introduces &lt;em&gt;eleven&lt;/em&gt; meta-programming techniques, and built up content and examples from there. The only reason why &amp;#8212; I think &amp;#8212; Russ didn&amp;#8217;t do it in his book was length/balance constraint: a &lt;em&gt;properly detailed&lt;/em&gt; chapter about meta-programming in Ruby could easily take up over forty pages!&lt;/p&gt;
&lt;h3&gt;The Verdict&lt;/h3&gt;
&lt;p&gt;As I said in the beginning: this is not meant to be a complete, in-depth, reference book on everything you may want to know about design patterns in Ruby. That&amp;#8217;s why, as a matter of fact, you can actually read this book all the way through without getting utterly bored. Russ uses an informal, yet appropriate style to turn potentially complex, theorethical computer science principles into easy-to-understand, &lt;em&gt;useful&lt;/em&gt; tools which can truly improve the way you code.&lt;/p&gt;
&lt;p&gt;The whole book flows very very nicely. I actually recommend reading this book in sequence, without skipping chapters, because each pattern is described in a way that is somehow linked to the following ones, so that you can understand and learn about the pros and cons of each one in a more natural and useful way.&lt;/p&gt;
&lt;p&gt;OK, I would have loved to see Part &lt;span class="caps"&gt;III&lt;/span&gt; as long as Part II, probably, but overall I&amp;#8217;m very, very satisfied of what the book taught me. The only problem is that it also made me suddenly realize all the naive design mistakes I&amp;#8217;ve been making when coding in Ruby, so I&amp;#8217;ll now feel compelled to fix at least some of them&amp;#8230;&lt;/p&gt;
&lt;p&gt;Definitely a worthwhile read, I just hope to see more books like this, or even a second edition of this one soon!&lt;/p&gt;
&lt;h3&gt;Notes&lt;/h3&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://www.informit.com/store/product.aspx?isbn=0321490452"&gt;Design Patterns in Ruby&lt;/a&gt; by Russ Olsen, Addison Wesley Professional, 2007.&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;a href="#fnr2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; Think of &lt;a href="http://www.pragprog.com/titles/ruby"&gt;Programming Ruby: The Pragmatic Programmer&amp;#8217;s Guide, 2nd Ed.&lt;/a&gt; by Dave Thomas with Chad Fowler and Andy Hunt, Pragmatic Programmers, 2004.&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;a href="#fnr3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://www.informit.com/store/product.aspx?isbn=0201633612"&gt;Design Patterns: Elements of Reusable Object-Oriented Software&lt;/a&gt;, by By Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides (a.k.a. the &lt;em&gt;Gang of Four&lt;/em&gt;), Addison Wesley Professional, 1994.&lt;/p&gt;
&lt;p class="footnote" id="fn4"&gt;&lt;a href="#fnr4"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; For more information on the &lt;span class="caps"&gt;YAGNI&lt;/span&gt; principle, visit &lt;a href="http://www.xprogramming.com/Practices/PracNotNeed.html"&gt;You&amp;#8217;re &lt;span class="caps"&gt;NOT&lt;/span&gt; gonna need it&lt;/a&gt;, Ronald E Jeffries.&lt;/p&gt;
&lt;p class="footnote" id="fn5"&gt;&lt;a href="#fnr5"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; See &lt;a href="http://on-ruby.blogspot.com/2007/12/design-patterns-in-ruby-review.html"&gt;Design Patterns in Ruby, a review&lt;/a&gt;, &lt;em&gt;On Ruby&lt;/em&gt;blog.&lt;/p&gt;
&lt;p class="footnote" id="fn6"&gt;&lt;a href="#fnr6"&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt; See &lt;a href="http://on-ruby.blogspot.com/2008/01/russ-olsen-interview.html"&gt;Russ Olsen Interview&lt;/a&gt;, &lt;em&gt;On Ruby&lt;/em&gt;blog.&lt;/p&gt;
&lt;p class="footnote" id="fn7"&gt;&lt;a href="#fnr7"&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://ar.rubyonrails.com/"&gt;ActiveRecord&lt;/a&gt; is an implementation of the Object-Relational Mapping (&lt;span class="caps"&gt;ORM&lt;/span&gt;) pattern used by the Ruby on Rails framework.&lt;/p&gt;
&lt;p class="footnote" id="fn8"&gt;&lt;a href="#fnr8"&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt; Distributed Ruby, see &lt;a href="http://chadfowler.com/ruby/drb.html"&gt;Intro to DRb&lt;/a&gt; by Chad Fowler.&lt;/p&gt;
&lt;p class="footnote" id="fn9"&gt;&lt;a href="#fnr9"&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://www.fxruby.org/"&gt;FXRuby&lt;/a&gt;, a graphical toolkit written in Ruby.&lt;/p&gt;
&lt;p class="footnote" id="fn10"&gt;&lt;a href="#fnr10"&gt;&lt;sup&gt;10&lt;/sup&gt;&lt;/a&gt; This can be a good or bad thing depending on the way you look at it, and what you want to use the language for. The fact that Ruby is dynamically typed makes it easier to do things which are totally impossible in C++ or Java, but it also introduces a whole new set of potential dangers.&lt;/p&gt;
&lt;p class="footnote" id="fn11"&gt;&lt;a href="#fnr11"&gt;&lt;sup&gt;11&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://ola-bini.blogspot.com/2006/09/ruby-metaprogramming-techniques.html"&gt;Ruby Metaprogramming Techniques&lt;/a&gt;, Ola Bini: Programming Language Synchronicity.&lt;/p&gt;</description>
      <pubDate>Fri, 11 Apr 2008 03:41:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/design-patterns-in-ruby-review/</guid>
      <link>http://www.h3rald.com/articles/design-patterns-in-ruby-review/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/design-patterns-in-ruby-review/#comments</comments>
      <category>ruby</category>
      <category>review</category>
      <category>books</category>
    </item>
    <item>
      <title>New Release: RawLine 0.2.0</title>
      <description>&lt;p&gt;&lt;del&gt;InLine&lt;/del&gt; RawLine 0.2.0 is out!&lt;/p&gt;
&lt;p&gt;*Raw*Line is the new name for InLine, in case you didn&amp;#8217;t guess. The name was changed to avoid name collision problems with the RubyInline project.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s what&amp;#8217;s new:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Added /examples and /test directory to gem.&lt;/li&gt;
	&lt;li&gt;Escape codes can now be used in prompt.&lt;/li&gt;
	&lt;li&gt;It is now possible to use bind(key, &amp;amp;block) with a String as key, even if the corresponding escape sequence is not defined.&lt;/li&gt;
	&lt;li&gt;Added Editor#write_line(string) to print a any string (and &amp;#8220;hit return&amp;#8221;).&lt;/li&gt;
	&lt;li&gt;Library name changed to &amp;#8220;RawLine&amp;#8221; to avoid name collision issues (Bug &lt;a href="http://rubyforge.org/tracker/?func=detail&amp;amp;aid=18879&amp;amp;group_id=5622&amp;amp;atid=21788"&gt;18879&lt;/a&gt;).&lt;/li&gt;
	&lt;li&gt;Provided alternative implementation for left and right arrows if terminal&lt;br /&gt;
supports escape sequences (on Windows, it requires the Win32Console gem).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In particular, I decided to provide an &amp;#8220;optimized implementation&amp;#8221; for the left and right arrows using escape sequences rather than shameful hacks. This is now possible because the Win32Console gem now enables &lt;span class="caps"&gt;ANSI&lt;/span&gt; escape sequences on Windows as well (weehee!).&lt;/p&gt;
&lt;p&gt;So:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If you&amp;#8217;re on *nix all good, your terminal is smart and can understand escape sequences =&amp;gt; the new implementation will be used.&lt;/li&gt;
	&lt;li&gt;If you&amp;#8217;re on Windows and you installed Win32Console, your termnal is smart and can understand escape sequences =&amp;gt; the new implementation will be used.&lt;/li&gt;
	&lt;li&gt;If you&amp;#8217;re on Windows and you didn&amp;#8217;t install Win32Console, then your terminal is stupid and it doesn&amp;#8217;t understand escape sequences, so the old implementation will be used.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new implementation is significantly faster than the old one, on Windows at least, and the cursor now blinks properly when left or right arrows are pressed.&lt;/p&gt;
&lt;p&gt;I re-emplemented only cursor movement because I&amp;#8217;m still having some problems in getting the delete/insert escapes to work properly (or better: how I want them to work!).&lt;/p&gt;</description>
      <pubDate>Wed, 02 Apr 2008 03:33:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/rawline-020/</guid>
      <link>http://www.h3rald.com/articles/rawline-020/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/rawline-020/#comments</comments>
      <category>ruby</category>
      <category>programming</category>
      <category>opensource</category>
      <category>rawline</category>
    </item>
    <item>
      <title>InLine name change: what's your opinion?</title>
      <description>&lt;p&gt;I&amp;#8217;ve been kindly asked by the lead developer of &lt;a href="http://www.zenspider.com/ZSS/Products/RubyInline/"&gt;RubyInLine&lt;/a&gt; to change the name of my &lt;a href="http://rubyforge.org/projects/inline/"&gt;InLine&lt;/a&gt; project, due to potential confusion and conflicts.&lt;/p&gt;
&lt;p&gt;This makes sense, and I&amp;#8217;m ready to change the name of my project, although I&amp;#8217;m not that good at choosing original and &lt;em&gt;smart&lt;/em&gt; names, so well, any suggestion is more than welcome!&lt;/p&gt;
&lt;p&gt;I was thinking of something like:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;RawLine&lt;/li&gt;
	&lt;li&gt;EditLine&lt;/li&gt;
	&lt;li&gt;RawInput&lt;/li&gt;
	&lt;li&gt;RubyInput&lt;/li&gt;
	&lt;li&gt;RubyLine&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I personally think that &lt;strong&gt;RawLine&lt;/strong&gt; is probably the best option, but please, if have any better idea just speak up!&lt;/p&gt;
&lt;p&gt;P.S.: &amp;#8220;RedLine&amp;#8221; is taken, unfortunately, otherwise it would have been my first choice since the beginning.&lt;/p&gt;</description>
      <pubDate>Thu, 27 Mar 2008 05:30:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/inline-name-change/</guid>
      <link>http://www.h3rald.com/articles/inline-name-change/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/inline-name-change/#comments</comments>
      <category>ruby</category>
      <category>programming</category>
      <category>opensource</category>
      <category>rawline</category>
    </item>
    <item>
      <title>RawLine - a 100% Ruby solution for console inline editing</title>
      <description>&lt;p&gt;One of the many things I like about Ruby is its cross-platform nature: as a general rule, Ruby code runs on everything which supports Ruby, regardless of its architecture and platform (yes, there are quite a few exceptions, but let&amp;#8217;s accept this generalization for now).&lt;/p&gt;
&lt;p&gt;More specifically, I liked the fact that I could use the &lt;a href="http://tiswww.case.edu/php/chet/readline/rltop.html"&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; Readline library&lt;/a&gt; with Ruby seamlessly on both Windows and Linux.&lt;br /&gt;
Readline offers quite a lot of features which are useful for those people like me who enjoy creating command-line scripts, in a nutshell, it provides:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;File/Word completion&lt;/li&gt;
	&lt;li&gt;History support&lt;/li&gt;
	&lt;li&gt;Custom key bindings which can be modified via .inputrc&lt;/li&gt;
	&lt;li&gt;Emacs and Vi edit modes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Basically it makes your command-line interface fast and powerful, and that&amp;#8217;s not an overstatement. Ruby&amp;#8217;s own &lt;span class="caps"&gt;IRB&lt;/span&gt; can be enhanced by enabling readline and completion, and it works great &amp;#8212; at least on *nix systems.&lt;/p&gt;
&lt;p&gt;For some weird reason, some people had problems with Readline on Windows: in particular, things get nasty when you start editing long lines. Text gets garbled, the cursor goes up one or two lines and doesn&amp;#8217;t come back, and other similar leprechaun&amp;#8217;s tricks, which are not that funny after a while.&lt;/p&gt;
&lt;p&gt;Apparently there&amp;#8217;s no alternative to Readline in the Ruby world. If you wan&amp;#8217;t tab completion that&amp;#8217;s it, you&amp;#8217;re stuck. Would it be difficult to implement &lt;em&gt;some&lt;/em&gt; of Readline functionality natively in Ruby? Maybe, but the problem is that for some reason the Ruby Standard Library doesn&amp;#8217;t have low level methods to operate on keystrokes&amp;#8230;&lt;/p&gt;
&lt;p&gt;&amp;#8230;but luckily, the &lt;a href="http://highline.rubyforge.org/"&gt;HighLine&lt;/a&gt; gem does! James Edward Gray II keeps pointing out here and here that HighLine&amp;#8217;s own &lt;code&gt;get_character&lt;/code&gt; method does just that: it returns the corresponding character code(s) right when a key is pressed, unlike &lt;code&gt;IO#gets()&lt;/code&gt; which waits for the user to press &lt;span class="caps"&gt;ENTER&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Believe it or not, that tiny method can do wonders&amp;#8230;h2. Reverse-engineering escape codes&lt;/p&gt;
&lt;p&gt;So here&amp;#8217;s a little script which uses &lt;code&gt;get_character()&lt;/code&gt; in an endless loop, diligently printing the character codes corresponding to a keystroke:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#!/usr/local/bin/ruby -w&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;highline/system_extensions&amp;#39;&lt;/span&gt;

&lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;HighLine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SystemExtensions&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Press a key to view the corresponding ASCII code(s) (or CTRL-X to exit).&amp;quot;&lt;/span&gt;

&lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;

	&lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;=&amp;gt; &amp;quot;&lt;/span&gt;
	&lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_character&lt;/span&gt;
	&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;
	&lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="sc"&gt;?\C-x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Exiting...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chr&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; [&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;] (hex: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;
	
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;A pretty harmless little thing. Try to run it and press some keys, and see what you get:&lt;/p&gt;
&lt;div style="font-family: Monospace"&gt;
&lt;p&gt;Press a key to view the corresponding &lt;span class="caps"&gt;ASCII&lt;/span&gt; code(s) (or &lt;span class="caps"&gt;CTRL&lt;/span&gt;-X to exit).&lt;/p&gt;
&lt;p&gt;=&amp;gt; a &lt;sup class="footnote" id="fnr96"&gt;&lt;a href="#fn96"&gt;96&lt;/a&gt;&lt;/sup&gt; (hex: 61)&lt;/p&gt;
&lt;p&gt;=&amp;gt; 1 &lt;sup class="footnote" id="fnr49"&gt;&lt;a href="#fn49"&gt;49&lt;/a&gt;&lt;/sup&gt; (hex: 31)&lt;/p&gt;
&lt;p&gt;=&amp;gt; Q &lt;sup class="footnote" id="fnr81"&gt;&lt;a href="#fn81"&gt;81&lt;/a&gt;&lt;/sup&gt; (hex: 51)&lt;/p&gt;
&lt;p&gt;=&amp;gt; &amp;alpha; &lt;sup class="footnote" id="fnr224"&gt;&lt;a href="#fn224"&gt;224&lt;/a&gt;&lt;/sup&gt; (hex: e0)&lt;/p&gt;
&lt;p&gt;=&amp;gt; K &lt;sup class="footnote" id="fnr75"&gt;&lt;a href="#fn75"&gt;75&lt;/a&gt;&lt;/sup&gt; (hex: 4b)&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Hang on, what are the last two codes? &lt;em&gt;A left arrow key on Windows&lt;/em&gt;, apparently.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Welcome to the wonderful world of input escape sequences!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To cut a long story short, both Windows and *nix system &amp;#8220;terminals&amp;#8221; translate special keystrokes into sequences of two or more codes. This applies to things like &lt;span class="caps"&gt;DEL&lt;/span&gt;, &lt;span class="caps"&gt;INSERT&lt;/span&gt;, arrows, etc. etc.&lt;br /&gt;
For some ideas, check out:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://www.microsoft.com/whdc/device/input/Scancode.mspx"&gt;Windows Scancodes&lt;/a&gt; (Thanks &lt;a href="http://64.223.189.234/node/92"&gt;Huff&lt;/a&gt;)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.connectrf.com/Documents/vt220.html"&gt;VT220 Terminal Input Sequences&lt;/a&gt; (Thanks &lt;a href="http://www.grayproductions.net/"&gt;James&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let&amp;#8217;s now assume that we&amp;#8217;re smart and we can write a program which can parse keystroke properly, including handling different input escape sequences according to the OS, what can it be used for?&lt;br /&gt;
Well:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;For normal characters, just print them back to the screen (&lt;code&gt;get_character&lt;/code&gt; doesn&amp;#8217;t print anything, it &amp;#8220;steals&amp;#8221; the keystroke)&lt;/li&gt;
	&lt;li&gt;For special characters, do something nice!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We could setup &lt;span class="caps"&gt;TAB&lt;/span&gt; to auto-complete the current word according to an array of matches, or bind the up arrow to load the last line typed in by the user, for example, that&amp;#8217;s basically something Readline does, right?&lt;/p&gt;
&lt;h2&gt;RawLine: how it works and what it does&lt;/h2&gt;
&lt;p&gt;I created a small project on RubyForge called &lt;a href="http://rubyforge.org/projects/rawline/"&gt;RawLine&lt;/a&gt; (not to be confused with RubyInline, a completely different thing altogether, sorry about that) to play around with the possibilities offered by the &lt;code&gt;get_character&lt;/code&gt; method. The library is just a preview of things which can be done, but it&amp;#8217;s already usable, provided that you&amp;#8217;re brave enough to try it out, that is.&lt;/p&gt;
&lt;p&gt;The basic idea behind RawLine is to be able to parse keystrokes properly on different platforms and re-bind them to a set of predefined, cross-platform actions or a user-defined code block.&lt;/p&gt;
&lt;h3&gt;Basic line-editing operations&lt;/h3&gt;
&lt;p&gt;The first challenge was to re-invent the wheel, i.e. re-bind keystrokes to their typical actions: a left arrow moves the cursor left, a backspace deletes the character at the left of the cursor and so on. Yes, because &lt;code&gt;get_characters&lt;/code&gt; gives you the right character codes at the price of &lt;em&gt;cancelling their normal effects&lt;/em&gt;, which is a great thing, as you&amp;#8217;ll soon find out.&lt;/p&gt;
&lt;p&gt;Printing a character on the screen was one of the easiest tasks (at first). &lt;code&gt;IO#putc&lt;/code&gt; does the job pretty well: it prints a character out.&lt;br /&gt;
What about moving left? Easy: print a non-descructive backspace (\b) and hope it is really not destructive. I did some tests and it seems to do as it&amp;#8217;s told and move the cursor back by one position.&lt;/p&gt;
&lt;p&gt;Moving right was a little trickier: the easiest thing I found was to re-print the character under the cursor, which will then move the cursor forward (as naive as it may seem, it does the job!). If there&amp;#8217;s nothing under the cursor, then we must be at the end of the line and it shouldn&amp;#8217;t move anywhere, so there we go.&lt;/p&gt;
&lt;p&gt;What if I move left a bit and then start typing normal characters? Well, everything is rewritten of course: this will be our &amp;#8220;character replace mode&amp;#8221;. Unfortunately users don&amp;#8217;t like this behavior that much, so what I did was this:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Copy all characters from the one at the left of the cursor till the end of the line&lt;/li&gt;
	&lt;li&gt;Print the character to be inserted&lt;/li&gt;
	&lt;li&gt;Re-print the previously-copied characters&lt;/li&gt;
	&lt;li&gt;Move the cursor back at the right place&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Again, a primitive solution which works seamlessly on all platforms, and yes, it&amp;#8217;s fast enough that you don&amp;#8217;t notice the difference.&lt;/p&gt;
&lt;p&gt;As you may have guessed, this of course means that I always had to keep track of:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;The cursor position within the line&lt;/li&gt;
	&lt;li&gt;The text currently printed to the screen&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Backspace and delete were implemented in a similar way, you can figure it out yourself or look at the source code: I won&amp;#8217;t bore you any further!&lt;/p&gt;
&lt;h3&gt;History management&lt;/h3&gt;
&lt;p&gt;The next step was to implement a history for both the characters inputted by the user (to allow undoing and redoing operations) and for the whole lines. This was just an ordinary programming exercise: a simple buffer with some extra controls here and there, nothing too scary.&lt;/p&gt;
&lt;p&gt;So every &amp;#8220;modification&amp;#8221; to the current line being typed is saved in a line history buffer and all the lines entered are saved in another history buffer. All is left is to allow users to navigate through these buffers back and forth. &lt;br /&gt;
Nothing impossible: all I had to do was keeping track of the current element of the history being retrieved and then overwrite the current line with a new line stored in the buffer? How&amp;#8217;s this line overwriting done? Same old:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Move the cursor to the beginnig of the line&lt;/li&gt;
	&lt;li&gt;Print X spaces, where X is the line length, so that the characters are no longer displayed in the console&lt;/li&gt;
	&lt;li&gt;Move the cursor back to the beginning of the line&lt;/li&gt;
	&lt;li&gt;Print the new line.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Easy and naive, as usual. But again, it works well enough.&lt;/p&gt;
&lt;h3&gt;Word completion&lt;/h3&gt;
&lt;p&gt;The other challange was word completion. The current implementation can be summarized as follows:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;If &lt;span class="caps"&gt;TAB&lt;/span&gt; (or another character, if you wish) is pressed, call a user-defined &lt;code&gt;completion_proc&lt;/code&gt; method which returns an array and show the first element of the array (in this case I actually used a cyclic RawLine::HistoryBuffer, not an array)&lt;/li&gt;
	&lt;li&gt;If the user presses &lt;span class="caps"&gt;TAB&lt;/span&gt; again, show another match, and so &lt;em&gt;ad infinitum&lt;/em&gt; if the user keeps pressing &lt;span class="caps"&gt;TAB&lt;/span&gt;.&lt;/li&gt;
	&lt;li&gt;If the user presses another key, accept the default completion and move on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Obviously this means that:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;RawLine has to keep track of the current &amp;#8220;word&amp;#8221;. A word is everything separated by a user defined &lt;code&gt;word_separator&lt;/code&gt;, which can obviously modified at runtime, with care.&lt;/li&gt;
	&lt;li&gt;Regarding the &lt;code&gt;completion_proc&lt;/code&gt;, typically you may want to return only the elements matching the word which is currently being written, so that&amp;#8217;s given as default parameter for your proc. Exactly like with ReadLine, the only difference is that you can access other things like &lt;em&gt;the whole line&lt;/em&gt; and &lt;em&gt;the whole history&lt;/em&gt; in real time, which can be really handy at times!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here&amp;#8217;s a simple example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completion_proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
	&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;
		&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;select&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;update&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;delete&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;destroy&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;find_all&lt;/span&gt;	&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Regexp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;h3&gt;Custom key bindings&lt;/h3&gt;
&lt;p&gt;All these pretty things are obviously bound to some keystrokes. If the key corresponds to only one code, everything is fine, but because special keys typically aren&amp;#8217;t so it was necessary to implement a mechanism to track an escape key (e.g. 0xE0 and 0 on Windows and \e on Linux) and listen to further characters, in case a known sequence is found. Anyhow, the final result of the method used for character binding is the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;bind(key, &amp;amp;block)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Where key can be:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;A &lt;code&gt;Fixnum&lt;/code&gt; corresponding to a single character code&lt;/li&gt;
	&lt;li&gt;An &lt;code&gt;Array&lt;/code&gt; of one or more character codes&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;String&lt;/code&gt; corresponding to an escape sequence&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;Symbol&lt;/code&gt; corresponding to a known escape sequence or key&lt;/li&gt;
	&lt;li&gt;A &lt;code&gt;Hash&lt;/code&gt; to define a new key or escape sequences&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, in the end you can do things like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:left_arrow&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;move_left&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;\e&lt;/span&gt;&lt;span class="s2"&gt;test&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;overwrite_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Test!!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sc"&gt;?\C-z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;undo&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Which, for Rubyists, it&amp;#8217;s far sexier and more flexible than editing an .inputrc file.&lt;/p&gt;
&lt;h3&gt;How do I use it, anyway?&lt;/h3&gt;
&lt;p&gt;A code example is better than a thousand words, right? So here you are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;#!/usr/local/bin/ruby -w&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rubygems&amp;#39;&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;rawline&amp;#39;&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;*** Inline Editor Test Shell ***&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; * Press CTRL+X to exit&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; * Press CTRL+C to clear command history&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; * Press CTRL+D for line-related information&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot; * Press CTRL+E to view command history&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;editor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;RawLine&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;

&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ctrl_c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clear_history&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ctrl_d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug_line&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ctrl_e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show_history&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:ctrl_x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Exiting...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completion_proc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;lambda&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
	&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;word&lt;/span&gt;
		&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;select&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;update&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;delete&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;debug&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;destroy&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;find_all&lt;/span&gt;	&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Regexp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;escape&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;word&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="kp"&gt;loop&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
	&lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;You typed: [&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;editor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;=&amp;gt; &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chomp!&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;]&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This example can be found in examples/rawline_shell.rb within the RawLine source code or gem package.&lt;/p&gt;
&lt;h2&gt;Current status and availability&lt;/h2&gt;
&lt;p&gt;I currently &lt;a href="http://rubyforge.org/forum/forum.php?forum_id=22543"&gt;released&lt;/a&gt; RawLine 0.1.0 on &lt;a href="http://rubyforge.org/projects/rawline"&gt;SourceForge&lt;/a&gt;, and it can be installed via:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;gem install -r rawline&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The RDoc documentation is available &lt;a href="http://rawline.rubyforge.org/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Feel free to try it out. First of all try the &lt;code&gt;rawline_shell.rb&lt;/code&gt; example, and see if it works on your machine. If it doesn&amp;#8217;t than maybe you try re-binding some keys (use &lt;code&gt;key_tester.rb&lt;/code&gt; to &amp;#8220;reverse-engineer&amp;#8221; your terminal&amp;#8217;s input escape sequences), and let me know!&lt;/p&gt;
&lt;p&gt;Status information and limitations:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;It has been tested on Windows (XP, using the usual command prompt) and on Linux (ZenWalk, using &lt;span class="caps"&gt;XFCE&lt;/span&gt; Terminal).&lt;/li&gt;
	&lt;li&gt;It can handle lines no longer than the maximum terminal width &amp;#8211; 2. This is to ensure that the cursor never &amp;#8220;falls down&amp;#8221; to the next line.&lt;/li&gt;
	&lt;li&gt;On Windows, the cursor doesn&amp;#8217;t blink immedialy when moving left, but it moves, don&amp;#8217;t worry.&lt;/li&gt;
	&lt;li&gt;On Linux, you should really consider installing the &lt;a href="http://raa.ruby-lang.org/project/ruby-termios/"&gt;Termios&lt;/a&gt; library for a faster experience (otherwise &lt;code&gt;get_character&lt;/code&gt; won&amp;#8217;t parse characters correctly if you press and hold a key, and that, trust me, is a real mess!).&lt;/li&gt;
	&lt;li&gt;RawLine is very far from being a complete replacement for the ReadLine library, and it is currently in alpha stage.&lt;/li&gt;
	&lt;li&gt;Release 0.1.0 has been created after 2 weeks of sporadic coding during lunch breaks and week-ends.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For any ideas on where to go from here, comments and feedback, just reply below or send an email to my usual email address.&lt;/p&gt;</description>
      <pubDate>Mon, 10 Mar 2008 05:59:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/inline-introduction/</guid>
      <link>http://www.h3rald.com/articles/inline-introduction/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/inline-introduction/#comments</comments>
      <category>ruby</category>
      <category>programming</category>
      <category>opensource</category>
      <category>rawline</category>
    </item>
    <item>
      <title>Book Review: Writing Efficient Ruby Code</title>
      <description>&lt;p style="float:right;"&gt;&lt;img src="/files/efficient_ruby_shortcut.jpeg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;The second shortcut from Addison-Wesley Professional series I&amp;#8217;m going to review is called &lt;a href="http://www.informit.com/store/product.aspx?isbn=0321540034"&gt;Writing Efficient Ruby Code&lt;/a&gt;. A very promising title, especially considering that this book is only 50 pages long.&lt;/p&gt;
&lt;p&gt;As usual, this shortcut can be intended as a sort of programmer-friendly detailed cheatsheet: like the other ones in this series it sports a monitor-friendly landscape layout and does not go to deep into the details unless strictly necessary to understand a particular concept.&lt;/p&gt;
&lt;h3&gt;The Author&lt;/h3&gt;
&lt;p&gt;&lt;a href="http://railsexpress.de/blog/"&gt;Dr. Stefan Kaes&lt;/a&gt;, the author, contributed a lot to improve Ruby on Rails&amp;#8217; performance by refactoring portions of its core and try to &amp;#8220;get maximum speed out of performance-critical sections of code&amp;#8221;. This short but interesting shortcut groups together a lot of performance tweaks, tips and tricks but also some &amp;#8220;anti-patterns&amp;#8221; Kaes was able to identify through his career as programming teacher Ruby software consultant and key Rails contributor.&lt;/p&gt;
&lt;h3&gt;The Contents&lt;/h3&gt;
&lt;p&gt;Like with the previously-covered &lt;a href="/articles/mongrel-shortcut-review"&gt;Mongrel shortcut&lt;/a&gt;, &lt;em&gt;Writing Efficient Ruby Code&lt;/em&gt; always goes straight to the point when it comes to identify problems. The first one mentioned is of course that the &lt;em&gt;Ruby Interpreter is Slow&lt;/em&gt;, most people are aware of that, due to their direct experience or because this argument is normally used by non-Rubyists to argue the language&amp;#8217;s usability in commercial projects. What you may not know is why that is so, and that&amp;#8217;s where the first part of this book comes into play.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;Ruby is a highly dynamic language: Almost all language entities are first-class citizens in that they can be created, changed, and destroyed at runtime. This comprises classes, modules, methods, constants, and class and instance variables. Only local variables are second-class citizens in Ruby: Whether a name refers to a local variable is determined at parse time.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This makes Ruby extremely flexible, but also more complex. Whever you use a name to refer to an object, Ruby has to search for the object it refers to, and this costs in terms of processing time.&lt;/p&gt;
&lt;p&gt;As a matter of fact, one of the most recurring tips in the book to improve code performance is the following:&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;strong&gt;Method calls are expensive, use variables directly when possible.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Keep this in mind: &lt;code&gt;self.something&lt;/code&gt; is &lt;em&gt;not&lt;/em&gt; the same as &lt;code&gt;@something&lt;/code&gt;. The end result is the same, but the first way costs more in terms of performance because Ruby has to look up the method name.&lt;br /&gt;
Similarly, &lt;strong&gt;local variables &lt;em&gt;should&lt;/em&gt; be introduced as a way to &amp;#8220;cache&amp;#8221; the result of method calls&lt;/strong&gt;. Often you may feel &amp;#8220;guilty&amp;#8221; to introduce a new variable and keep calling the same method over and over: this should definitely be avoided.&lt;/p&gt;
&lt;p&gt;Other useful tips include, for example:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Use syntax constructs (e.g. assignments) as expressinons. Use evaluation precedences.&lt;/li&gt;
	&lt;li&gt;Use interpolated strings &lt;code&gt;"... #{string_variable}"&lt;/code&gt; (there&amp;#8217;s also no performance difference if constant strings are used between &lt;code&gt;"&lt;/code&gt; or &lt;code&gt;'&lt;/code&gt;)&lt;/li&gt;
	&lt;li&gt;Use operators which update the data structure without copying it (when possible). Use &lt;code&gt;update&lt;/code&gt; or &lt;code&gt;merge&lt;/code&gt; to update hashes.&lt;/li&gt;
	&lt;li&gt;Iterating using &lt;code&gt;for a in  A&lt;/code&gt; is slightly faster than performing the same iteration using &lt;code&gt;each&lt;/code&gt;, (it is the opposite in Ruby 1.9 though)&lt;/li&gt;
	&lt;li&gt;do not use &lt;code&gt;return&lt;/code&gt; unless you have to&lt;/li&gt;
	&lt;li&gt;test in order of expected case frequency&lt;/li&gt;
	&lt;li&gt;Use parallel assignment (&lt;code&gt;a, b = 5, 6&lt;/code&gt;) where applicable&lt;/li&gt;
	&lt;li&gt;If a module gets included in only one other class (or module), it&#8217;s preferable to open the class instead.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I deliberately chose not to elaborate any further on the tips listed above because otherwise I&amp;#8217;ll give a big chunk of the contents of the book itself. If you know Ruby enough, you may already know why such reccommendations make sense, but if you don&amp;#8217;t, &lt;em&gt;Writing Efficient Ruby Code&lt;/em&gt; can be a short but very interesting read.&lt;/p&gt;
&lt;h3&gt;The Good&lt;/h3&gt;
&lt;p&gt;For each of the 30 &amp;#8220;coding patterns&amp;#8221; (and consequent anti-patterns) described in the book, the author does a great job explaining the reasons of doing something in a particular way, also through examples and benchmarks, where possible.&lt;/p&gt;
&lt;p&gt;Furthermore, this &lt;em&gt;shortcut&lt;/em&gt; can really be useful to grasp a few difference between Ruby 1.8.5, 1.8.6 and 1.9 in terms of performance: not all the patters apply to all Ruby implementations, and when that&amp;#8217;s the case it is clearly stated.&lt;/p&gt;
&lt;h3&gt;The Bad&lt;/h3&gt;
&lt;p&gt;My only complaint about the book is probably the lack of details and more &amp;#8220;specialized&amp;#8221; patterns. Everything (except for a few Rails-specific tips) normally apply to Ruby &lt;em&gt;as a whole&lt;/em&gt;, without going deeply to analyze specific libraries or third-party gems. As a result, once you get the general idea, some of the patters may seem pretty obvious or a logic consequence of others.&lt;/p&gt;
&lt;p&gt;It is also true that this is meant to be a &lt;em&gt;shortcut&lt;/em&gt;, not a comprehensive analysis on code optimization techniques which can be applied to specific cases: something like this would require much more than 50 pages!&lt;/p&gt;
&lt;h3&gt;The Bottom Line&lt;/h3&gt;
&lt;p&gt;Read it, re-read a few bits of it to make sure you grasp the most important concepts, and keep its table of contents in front of you as a reminder when refactoring your code!&lt;/p&gt;</description>
      <pubDate>Mon, 21 Jan 2008 04:47:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/efficient-ruby-code-shortcut-review/</guid>
      <link>http://www.h3rald.com/articles/efficient-ruby-code-shortcut-review/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/efficient-ruby-code-shortcut-review/#comments</comments>
      <category>ruby</category>
      <category>review</category>
      <category>books</category>
    </item>
    <item>
      <title>Announcement: RedBook v0.5.0 released</title>
      <description>&lt;p&gt;This new beta release of RedBook introduces quite a few changes when it comes to configuration and setup. Here&amp;#8217;s some highlights&amp;#8230;h3. Regexp changes&lt;/p&gt;
&lt;p&gt;It is now necessary to enter &amp;#8220;proper&amp;#8221; regular expressions for &lt;code&gt;:select&lt;/code&gt;. Proper means between slashes, like the following:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;/Work Day/&lt;/li&gt;
	&lt;li&gt;/mail/i&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I changed this in order to support case-insensitive searches using the &lt;code&gt;i&lt;/code&gt; switch. This makes queries much more powerful.&lt;/p&gt;
&lt;h3&gt;Variables&lt;/h3&gt;
&lt;p&gt;A new, interesting feature I decided to introduce in this release is &lt;em&gt;variables&lt;/em&gt;. For now you define them inside your rbconfig.yml file, like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;:var_monday_morning: &amp;quot;monday at 8 am&amp;quot;

:var_friday_evening: &amp;quot;friday at 8 pm&amp;quot;

:var_week_report: &amp;quot;:select :duration :from :%monday_morning :to :%friday_evening&amp;quot; 
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this way, every time you type in :%week_report in RedBook, it will expand to: &lt;code&gt;:select :duration :from monday at 8 am :to friday at 8 pm&lt;/code&gt;. By the way, completion is supported, so you&amp;#8217;ll only have to type in something like &lt;code&gt;:%we&lt;/code&gt; and hit &lt;tab&gt;.&lt;/p&gt;
&lt;p&gt;It is possible to define variables as &lt;code&gt;:var_&amp;lt;something&amp;gt;&lt;/code&gt; in the rbconfig.yml file and then used them inside RedBook as &lt;code&gt;:%&amp;lt;something&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;New Operations&lt;/h3&gt;
&lt;p&gt;Five new operations have been added:&lt;/p&gt;
&lt;h4&gt;:blank&lt;/h4&gt;
&lt;p&gt;This will blank your current log after asking you if you really want to do so.&lt;/p&gt;
&lt;h4&gt;:restore&lt;/h4&gt;
&lt;p&gt;This operation will overwrite your current log with the last saved backup. Like with the &lt;code&gt;:blank&lt;/code&gt; operation, you&amp;#8217;re asked if you really want to proceed or not.&lt;/p&gt;
&lt;h4&gt;:archive&lt;/h4&gt;
&lt;p&gt;By typing &lt;code&gt;:archive&lt;/code&gt;, the current log file will be archived to your &lt;code&gt;:archives_folder:&lt;/code&gt; directory specified in the rbconfig.yml file (similarly, it is now possible to specify a :backups_folder: for your logs&amp;#8217; backup files).&lt;/p&gt;
&lt;h4&gt;:dataset&lt;/h4&gt;
&lt;p&gt;A simple operation to display the messages inthe current dataset.&lt;/p&gt;
&lt;h4&gt;:dump&lt;/h4&gt;
&lt;p&gt;This operation will dump the output of the last &lt;code&gt;:select&lt;/code&gt; operation to a text file. Useful for saving the average, total time and duration of a set of activities.&lt;/p&gt;
&lt;h3&gt;Portable edition&lt;/h3&gt;
&lt;p&gt;Some Windows users will definitely love this. I finally found an easy way to run RedBook confined within the current directory, by using a simple &lt;code&gt;start.bat&lt;/code&gt; batch file to set the &lt;span&gt;&lt;span class="caps"&gt;INPUTRC&lt;/span&gt;&lt;/span&gt; and &lt;span&gt;&lt;span class="caps"&gt;HOME&lt;/span&gt;&lt;/span&gt; variables temporarily to the path to the .inputrc file and the directory of RedBook executable. This makes RedBook 100% portable and suitable to be used on &lt;span class="caps"&gt;USB&lt;/span&gt; sticks &amp;amp;similar.&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;strong&gt;&lt;a href="http://redbook.googlecode.com/files/RedBook-0.5_Win32-portable.zip"&gt;Get RedBook Portable&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;New Development Page&lt;/h3&gt;
&lt;p&gt;I decided to move the primary RedBook repository from &lt;a href="http://www.assembla.org"&gt;Assembla&lt;/a&gt; to Google Code. Why? Well, nothing wrong with Assembla per se, I still think it&amp;#8217;s an excellent free service to host your public &lt;em&gt;and private&lt;/em&gt; projects, but Google Code is faster and offers only the features I need:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Public &lt;span class="caps"&gt;SVN&lt;/span&gt; repository access&lt;/li&gt;
	&lt;li&gt;Simple-to-use issue tracker&lt;/li&gt;
	&lt;li&gt;Very nicely developed downloads section, with download counts, and &amp;#8220;normal&amp;#8221; filenames.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So here&amp;#8217;s the new RedBook Development Home:&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;strong&gt;&lt;a href="http://code.google.com/p/redbook/"&gt;http://code.google.com/p/redbook/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Additionally I also setup a &lt;a href="http://groups.google.com/group/redbook-support/"&gt;RedBook Support Google Group&lt;/a&gt;, so if you have any question concerning the program, you know where to go!&lt;/p&gt;</description>
      <pubDate>Sun, 16 Dec 2007 07:07:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/redbook-050-released/</guid>
      <link>http://www.h3rald.com/articles/redbook-050-released/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/redbook-050-released/#comments</comments>
      <category>opensource</category>
      <category>productivity</category>
      <category>redbook</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Book Review: Mongrel Digital Shortcut</title>
      <description>&lt;p&gt;If you ever considered about developing an deploying a Rails application in the last year or so, you must have heard of &lt;a href="http://mongrel.rubyforge.org/index.html"&gt;Mongrel&lt;/a&gt; before. If you didn&amp;#8217;t, I&amp;#8217;d recommend you learn more about it because up to now it proved to be one of the few essential ingredients for deploying &lt;em&gt;scalable&lt;/em&gt; Rails applications.&lt;/p&gt;
&lt;p&gt;Mongrel is a creation of &lt;a href="http://www.zedshaw.com/"&gt;Zed Shaw&lt;/a&gt; who started writing a replacement for FastCGI to use with Rails, and ended up creating a brand new, &lt;span class="caps"&gt;HTTP&lt;/span&gt; web server who turned out to be one of the best things the Rails community ever saw happening.&lt;/p&gt;
&lt;p&gt;It was created to be simple to use and configure, nevertheless it &lt;em&gt;does&lt;/em&gt; require some skill to set it up and tune it. Documentation is there, along with plenty of blog posts, but there&amp;#8217;s also an interesting &lt;a href="http://www.informit.com/store/product.aspx?isbn=0321483502&amp;amp;rl=1"&gt;book&lt;/a&gt; from &lt;a href="http://www.awprofessional.com/"&gt;Addison Wesley Professional&lt;/a&gt; which is definetely worth a read.&lt;/p&gt;
&lt;p style="float:right;"&gt;&lt;img src="/files/mongrel_shortcut.jpeg" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8220;Mongrel: Serving, Deploying, and Extending Your Ruby Applications&amp;#8221; &amp;ndash; that&amp;#8217;s the title of the book. A &lt;em&gt;Digital Shortcut&lt;/em&gt;, 100-odd pages long, in &lt;em&gt;landscape&lt;/em&gt; format to make it easier to read on a computer, straight to the point with no added sugar for just 15$ (&lt;span class="caps"&gt;PDF&lt;/span&gt; only). I must say Addison Wesley got it right: the book&amp;#8217;s format is, as a matter of fact, &lt;em&gt;optimized for web developers&lt;/em&gt;, especially those who can&amp;#8217;t afford to read a 500-pages book covering everything about a subject just to find that one thing they don&amp;#8217;t know about.&lt;br /&gt;
This &lt;em&gt;shortcut&lt;/em&gt; can be seen, essentially, as an expanded cheatsheet which will teach you the basics about Mongrel and also give you plenty of advice on how to learn more about it.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s have a closer look at it.&lt;/p&gt;
&lt;h3&gt;Overview, Introduction &amp;amp; Getting Started&lt;/h3&gt;
&lt;p&gt;The first three &lt;del&gt;chapters&lt;/del&gt; sections (there are no chapters, just &lt;em&gt;sections&lt;/em&gt;) of the book are meant to be a gentle introduction to Mongrel and its world. The main author is &lt;a href="http://www.informit.com/authors/bio.aspx?a=0260912e-6ed8-4ed1-882a-c357e644feec"&gt;Matt Pelletier&lt;/a&gt;, but Zed Show&amp;#8217;s contributions are definitely one of the book&amp;#8217;s best selling points. &lt;br /&gt;
Zed&amp;#8217;s thoughts are scattered here and there in many &lt;em&gt;sidebars&lt;/em&gt; throughout the book (there&amp;#8217;s at least one in each section): you&amp;#8217;ll see an odd-looking face (Zed&amp;#8217;s self-caricature) with some text next to it; when you read it, you&amp;#8217;ll notice that they are &lt;em&gt;actually&lt;/em&gt; Zed&amp;#8217;s own thoughts, straight from his mind, with no editorial filter whatsoever in-between. &lt;br /&gt;
Be warned: the text included within the &lt;strong&gt;Zed Sez&lt;/strong&gt; sidebars is highly opinionated, that&amp;#8217;s precisely what Zed &lt;em&gt;feels&lt;/em&gt; to say about something, and he&amp;#8217;ll just say it: just the plain, simple thoughts of an experienced programmer. As the author explains in &lt;strong&gt;Section 1&lt;/strong&gt;: &lt;em&gt;&amp;#8220;[&amp;#8230;] You may not agree with everything he says, but you probably should.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Section 2&lt;/strong&gt; is a general introduction about Mongrel. It explains &lt;em&gt;what&lt;/em&gt; it is, &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt; it was made, and &lt;em&gt;how&lt;/em&gt; it works. There&amp;#8217;s nothing new to learn if you already used Mongrel before, probably, but it&amp;#8217;s definitely the first thing to show to someone who&amp;#8217;s new to Mongrel and its world, and possibly a bit skeptical about it. &lt;br /&gt;
The last subsection &lt;em&gt;&amp;#8220;What can Mongrel do for me&amp;#8221;&lt;/em&gt; is an attempt to &lt;del&gt;brainwash&lt;/del&gt; persuade you to fully embrace Mongrel and its philosophy, whether you are a developer, a sysadmin or even a manager: assertions like &lt;em&gt;&amp;#8220;Mongrel is pretty damned secure.&amp;#8221;&lt;/em&gt; and &lt;em&gt;&amp;#8220;Mongrel&amp;#8217;s license is capitalist-friendly.&amp;#8221;&lt;/em&gt; will definitaly make some of you (managers) happy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Section 3&lt;/strong&gt; is slightly more juicy than the previous one, as it explains how to install and use Mongrel. Basically that&amp;#8217;s what everyone who ever used it already knows, but it&amp;#8217;s still necessary for the book&amp;#8217;s consistency, after all. After reading this section, you&amp;#8217;ll probably have your first Mongrel up and running and serving your little Rails application&amp;#8217;s pages, and you&amp;#8217;ll begin to wonder why the hell you need to keep reading this book now that everything seems to work already&amp;#8230;&lt;/p&gt;
&lt;h3&gt;Section 4: Configurations&lt;/h3&gt;
&lt;p&gt;&amp;#8230;aka &amp;#8220;a truly useful Mongrel cheatsheet&amp;#8221;. This section dives deep(er) into Mongrel&amp;#8217;s configuration by explaining what each start parameter does in detail. The parameters are presented in tabular form in a very well-organized way. As you would expect from an high-quality cheatsheet.&lt;/p&gt;
&lt;p&gt;Then the author will explore a few commonly used deployment scenarios, in particular:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Standalone&lt;/strong&gt; &amp;ndash; The simplest configuration possible, with just one Mongrel instance serving both static and dynamic pages.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;mongrel&amp;#95;cluster&lt;/strong&gt; &amp;ndash; How to use &lt;em&gt;&amp;#8220;a pack of mongrels&amp;#8221;&lt;/em&gt; together to handle more traffic.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Behind a static web server&lt;/strong&gt; &amp;ndash; The most common (and most scalable) option, used to serve static content faster using a front-end server and use Mongrel only to handle Ruby pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Towards the end of the section, for the developer&amp;#8217;s delight, the author will discuss two common, useful scenarios where Mongrel can be used:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Apache 2 + mod_proxy_balancer + mongrel&amp;#95;cluster&lt;/strong&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Nginx + mongrel&amp;#95;cluster&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The difference here is that detailed instructions are provided on how to setup and configure each server, including example file sources. This can be particularly useful for the Nginx example, as most of the documentation for this fantastic, lightweight Mongrel fron-end is scattered around the web (or written in Russian in a &lt;a href="http://sysoev.ru/nginx/"&gt;well known place&lt;/a&gt;).&lt;/p&gt;
&lt;h3&gt;Section 5: Production Deployment&lt;/h3&gt;
&lt;p&gt;This section introduces one of the most important part of the life cycle of a Rails application: the deployment on a production server. The author is pretty honest about the whole subject:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;You will not do this in a day. If you are expecting to code until 1 minute before your deadline and then simply point and click and have an instant server then you need to take some kind of&lt;br /&gt;
medication because you are violently hallucinating. You will need at least a week of 8 hours days to make sure your first deployment works and to have the time to do it right.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sounds terribly true. Especially for larger projects demanding good performance under heavy traffic. Scared? Probably, if you never deployed a Rails application &amp;#8220;properly&amp;#8221; before, but at least the book comes to the rescue by providing an overview of what you need to perform a deployment and why it is such a complex and delicate process.&lt;/p&gt;
&lt;p&gt;Not only this, but also a &amp;#8220;Best Practices Rubric&amp;#8221; is also provided for the developer&amp;#8217;s own private enjoyement. It&amp;#8217;s written as a list of questions like:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;11. Do you have a shared location where you can document the deployment, such as a Wiki or &lt;span class="caps"&gt;CMS&lt;/span&gt;?&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;12. Do you know how to use httperf or ab and know what the statistics mean?&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;After these 13 questions, the author provides the key to give a meaning to your answers:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;For each question you answer with &amp;#8220;NO&amp;#8221;, add 10 hours to your time estimate for completion. This may seem unrealistic, since saying &amp;#8220;NO&amp;#8221; to everything means it&amp;#8217;ll take 190 hours (about one&lt;br /&gt;
month), but this estimate is actually low according to most first deployment experiences.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you answered &amp;#8220;NO&amp;#8221; too many times to these questions, you may want to read on through the next subsection which states 17 &amp;#8220;worst practices&amp;#8221;: an invaluable read for beginners!&lt;/p&gt;
&lt;p&gt;But after all this section is not only about stating the obvious (&amp;#8230;right?): a full example scenario is describedand examined throughly to give you an idea of how a deployment &lt;em&gt;should&lt;/em&gt; be made, using three different machines:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;One for Apache (as a front-end to Mongrel)&lt;/li&gt;
	&lt;li&gt;One for the Mongrel cluster and the Rails application&lt;/li&gt;
	&lt;li&gt;One for the database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Maybe something you&amp;#8217;ll never do if you just want to run your grandma&amp;#8217;s site on Rails, but certainly something you may want to start looking at if your grandma becomes really popular and your small server gets grounded by several thousands of visitors per day.&lt;/p&gt;
&lt;p&gt;The last part of the section will give you a brief introduction on monitoring your applications and on which tools you should be using, although it does not discuss the subject in detail at all, it&amp;#8217;s just meant to point you to the right direction.&lt;/p&gt;
&lt;h3&gt;Section 6: Extending Mongrel&lt;/h3&gt;
&lt;p&gt;This section digs deeper into the software code internals and describes &lt;em&gt;how to teach new tricks to your Mongrel&lt;/em&gt;, i.e. how to extend its functionality.&lt;/p&gt;
&lt;p&gt;Before you begin, though, don&amp;#8217;t forget what Zed himself has to say about Mongrel&amp;#8217;s simplicity:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;I&amp;#8217;ve always had a different aesthetic sense when I write my software. I value simplicity and directness and try to write software that follows this approach. I jokingly call it the Shibumi School of Software Structure. All I do is apply this rule: When given two possible designs with equal end results, pick the simpler one. I then ruthlessly strip the solution down to its finest elements, but no more.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mongrel&amp;#8217;s architecture is not that complex, and this section is sufficient to get you started by providing an overview of the main classes involved (HttpServer, HttpRequest, HttpResponse, HttpHandler, URIClassifier), and how they work together.&lt;br /&gt;
Note that the book won&amp;#8217;t describe anything about the APIs of these classes. but after all, the project&amp;#8217;s &lt;a href="http://mongrel.rubyforge.org/rdoc/files/README.html"&gt;RDoc documentation&lt;/a&gt; should cover all the details you need.&lt;/p&gt;
&lt;p&gt;The rest of the section focuses on how to extend Mongrel, by:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Writing custom handlers in Ruby&lt;/li&gt;
	&lt;li&gt;Creating custom filters to perform security checks, clean up requests and preliminary file processing&lt;/li&gt;
	&lt;li&gt;Creating plugins and distributing them as rubygems&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Two working examples are also provided:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;An example handler to deflate content (if the browser supports deflate)&lt;/li&gt;
	&lt;li&gt;An example &amp;#8220;duck&amp;#8221; plugin, to make Mongrel quack like a duck when it&amp;#8217;s started (not the most useful thing in the world, but serves the purpose)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Debugging, Performance &amp;amp; Security&lt;/h3&gt;
&lt;p&gt;The last three sections deals with other important aspects concerning the deployment of your application, how to debug, how to improve performance and how to secure your application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Section 7&lt;/strong&gt; introduces two debugging modes:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Dash-Bee logging (-B)&lt;/li&gt;
	&lt;li&gt;USR1 logging (lighter)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And also gives you an idea on what to look for when debugging an application. Nothing too detailed, granted, but enough to make sure you are pointed in the right direction.&lt;/p&gt;
&lt;p&gt;Again, Zed&amp;#8217;s wisdom and wit are remarkable:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;These people&amp;#8217;s problem is they suffer from Potpourri Turd Syndrome&#8212;a belief that their you-know-what don&amp;#8217;t stink and smells like fine dew on freshly cut grass. Whenever there&amp;#8217;s a bug, they go&lt;br /&gt;
running like kids in a candy store to other people&amp;#8217;s code trying to find fault and just assume that it&amp;#8217;s nothing they wrote.&lt;br /&gt;
[&amp;#8230;]&lt;br /&gt;
When you run into a problem with your application, always assume it&amp;#8217;s your fault first. Mongrel&amp;#8217;s not perfect, but its code is minuscule compared to the size of Rails and most likely even your own appli-cation code. Mongrel also powers many large and medium deployments without any problems. If there&amp;#8217;s an error, the evidence already says it&amp;#8217;s in your code, so bite the bullet and start investigating it as if it&amp;#8217;s your problem.&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Similarly, &lt;strong&gt;Section 8&lt;/strong&gt; is a short but useful overview on performance tips and tricks and deployment tuning. The most useful thing is probably the checklist of the &amp;#8220;tuning process&amp;#8221;, which illustrates the simple steps to take to tune your application.&lt;/p&gt;
&lt;p&gt;Finally, &lt;strong&gt;Section 9&lt;/strong&gt; addresses some common security concerns and clarifies how Mongrel deals with them. The answer is normally &amp;#8220;Mongrel strictly does this&amp;#8221; or &amp;#8220;Mongrel doesn&amp;#8217;t support this feature&amp;#8221;. After all, you should have understood by now that Mongrel is an example of simplicity and that it deliberately does not aim to offer all the feature you&amp;#8217;d expect by a server like Apache:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;quot;As you probably see, Mongrel say, &amp;#8220;No&amp;#8221; in many places where most Web servers say, &amp;#8220;Yes, OK.&amp;#8221; Sometimes this is because no one using Mongrel has needed it yet, sometimes it&amp;#8217;s because there&amp;#8217;s a&lt;br /&gt;
better, simpler way to accomplish the same goal. Mongrel is a different kind of Web server, and frequently you can solve your problem with a different solution.&amp;quot;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;If Mongrel is opinionated software, this is definitely an opinionated book which fully embraces the project&amp;#8217;s philosopy of simplicity above everything else. It&amp;#8217;s an interesting read and it won&amp;#8217;t bore you to death by deliberately skipping long and potentially tedious subjects and adding interesting insights instead (like the Zed Sez sidebars). Perhaps it is a bit too direct towards certain people, who may get even get offended (as planned) by some of the author&amp;#8217;s assertions.&lt;/p&gt;
&lt;p&gt;Despite being a 100-pages book, this &lt;em&gt;shortcut&lt;/em&gt; covers pretty much everything you need to know &lt;strong&gt;about Mongrel&lt;/strong&gt;. It will &lt;em&gt;not&lt;/em&gt; teach you everything about deployment, security, performance tweaks and debugging though: as the authors often state throughout the book, a lot of (big) books are available on those subject, and it wouldn&amp;#8217;t make sense to even attempt to discuss them in this shortcut.&lt;/p&gt;
&lt;p&gt;Similarly, you won&amp;#8217;t find complex examples either, but that&amp;#8217;s acceptable because simple examples are often the only thing you need to grasp the basics of a concept or feature, and then use them as a &amp;#8220;scaffold&amp;#8221; for your own code.&lt;/p&gt;
&lt;p&gt;Globally, the book is well balanced and &lt;em&gt;optimized&lt;/em&gt; for its size: lightweight introductory sections at first, then the &amp;#8220;real juice&amp;#8221; in the middle, and a few overview sections on advanced topics towards the end. You can read it easily in a few hours, perhaps less, and whenever you need to look something up in a hurry it will be fairly easy to locate.&lt;/p&gt;
&lt;p&gt;A good read, and a &lt;em&gt;must&lt;/em&gt; for everyone who wants to learn more about Mongrel or Rails deployment.&lt;/p&gt;</description>
      <pubDate>Sat, 15 Dec 2007 02:42:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/mongrel-shortcut-review/</guid>
      <link>http://www.h3rald.com/articles/mongrel-shortcut-review/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/mongrel-shortcut-review/#comments</comments>
      <category>review</category>
      <category>books</category>
      <category>rails</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Announcement: RedBook v0.4.0 released</title>
      <description>&lt;p&gt;I&amp;#8217;m pleased to announce a new release of the RedBook daily logging and time tracking script. This release introduces two new operations, four stats-related directives and a brand new Windows Installer able to setup RedBook in a blink, with (almost) no configuration at all.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s have a closer look&amp;#8230;h2. New Operations&lt;/p&gt;
&lt;p&gt;Suppose that you just logged a message and you noticed one of these two things happened:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You didn&amp;#8217;t really wanted to log it&lt;/li&gt;
	&lt;li&gt;You made a silly typo in the message or in the tags&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What can you do about it? Up to RedBook 0.3, the only solution was to open the &lt;span class="caps"&gt;YAML&lt;/span&gt; file and correct the mistake manually. From now on there&amp;#8217;s also another simpler way to operate in such situations: using the :update and :delete operations!&lt;/p&gt;
&lt;h3&gt;:update&lt;/h3&gt;
&lt;p&gt;This operation can be used to update the message and or the tags of a previously-logged activity. The usage is simple: load a dataset first, and then execute an &lt;code&gt;:update&lt;/code&gt; command like:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:update 4 :message My updated message :with new_tag1 new_tag2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will update the 4th message of the dataset modifying its message and tags. Of course you can update either of the two things or both; the timestamp of the activity will not be changed.&lt;/p&gt;
&lt;h3&gt;:delete&lt;/h3&gt;
&lt;p&gt;The delete operation can be used to completely delete a message from the log. Just load a dataset using a &lt;code&gt;:select&lt;/code&gt; operation and then execute a &lt;code&gt;:delete&lt;/code&gt; command, e.g.:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;:delete 1&lt;/code&gt; &lt;em&gt;(will delete the first activity)&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:delete 4 2 7 9&lt;/code&gt; &lt;em&gt;(will delete activity #2, #4, #7 and #9)&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;:delete&lt;/code&gt; &lt;em&gt;(will delete the entire dataset)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A confirmation message will appear before deleting the message(s).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;IMPORTANT&lt;/span&gt;&lt;/strong&gt;&lt;br /&gt;
&lt;em&gt;Due to the architecture of the application, whenever an &lt;code&gt;:update&lt;/code&gt; or &lt;code&gt;:delete&lt;/code&gt; occurs the log file will be reloaded in memory and completely overwritten. This doesn&amp;#8217;t cause problems, although for big log files (10,000+ activities) this may take a few seconds.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Statistics&lt;/h2&gt;
&lt;p&gt;Another important new feature introduced by this release is &lt;em&gt;time tracking&lt;/em&gt;. It was actually already there, kind of: the &lt;code&gt;:calc&lt;/code&gt; operation was already able to calculate the time elapsed between two activities&amp;#8230; however, this is not really practical.&lt;/p&gt;
&lt;p&gt;Since last release, it is possible to log the completion of an activity using the &lt;code&gt;:finish&lt;/code&gt; command. This will basically re-log the same activity prepending &lt;em&gt;[&lt;span class="caps"&gt;COMPLETED&lt;/span&gt;]&lt;/em&gt; to its message.&lt;br /&gt;
If you started using the &lt;code&gt;:finish&lt;/code&gt; command to complete your activities, RedBook can now calculate the following stats for you:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Count the number of messages in a dataset&lt;/li&gt;
	&lt;li&gt;Calculate the average time spent for the completed activities in a dataset&lt;/li&gt;
	&lt;li&gt;Calculate the total time spent for the completed activities in a dataset&lt;/li&gt;
	&lt;li&gt;Calculate the duration of each completed activity in a dataset&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each of these calculations is performed by adding special directive to a &lt;code&gt;:select&lt;/code&gt; command, as explained in the following sections.&lt;/p&gt;
&lt;h3&gt;:count&lt;/h3&gt;
&lt;p&gt;This directive can be added to a &lt;code&gt;:select&lt;/code&gt; command to return just the number of message of the loaded dataset. &lt;br /&gt;
In other words, executing the following:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:select :count :with mail !work&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8230;will return the number of activities tagged with &lt;em&gt;mail&lt;/em&gt; but not with &lt;em&gt;personal&lt;/em&gt;, without listing all the activities.&lt;/p&gt;
&lt;h3&gt;:avg&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;:avg&lt;/code&gt; directive can be used to calculate the average time spent on activities matching certain criteria, for example:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:select Status Meeting :avg :with meeting&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8230;will return the average time spent on activities whose messages matches &lt;em&gt;/Status Meeting/&lt;/em&gt; and are tagged with &lt;em&gt;meeting&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;:total&lt;/h3&gt;
&lt;p&gt;Similarly, &lt;code&gt;:total&lt;/code&gt; can be used to return the total time spent on activities matching certain criteria, e.g.:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:select :total :with mail work&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8230;will return the total time spent on activities tagged with &lt;em&gt;mail&lt;/em&gt; and &lt;em&gt;work&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;:duration&lt;/h3&gt;
&lt;p&gt;Lastly, &lt;code&gt;:duration&lt;/code&gt; will print each completed task along with its duration. The syntax is similar to the others:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;:select :duration :with break&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will print each completed activity tagged with &lt;em&gt;break&lt;/em&gt; along with its duration.&lt;/p&gt;
&lt;h3&gt;:nodiff and _concurrent&lt;/h3&gt;
&lt;p&gt;The logic behind the above-mentioned directives may seem trivial to implement, but it is not. The fun part was telling RedBook to subtract the duration of each sub-activity contained in another activity&amp;#8230; a feature I considered necessary for time tracking purpose. However, if you start your work day with a &lt;em&gt;Working Day&lt;/em&gt; activity and you complete that activity using the &lt;code&gt;:finish&lt;/code&gt; command, when calculating the duration of the working day RedBook will subtract the duration of &lt;em&gt;all the completed sub-activities&lt;/em&gt; from the duration of &lt;em&gt;Working Day&lt;/em&gt;. This is not OK, so I added the directive &lt;code&gt;:nodiff&lt;/code&gt; which can be used to prevent RedBook from calculating the difference between the parent activity&amp;#8217;s duration and the duration of each of its child activity.&lt;/p&gt;
&lt;p&gt;What if you&amp;#8217;re doing two things at once? use the special &lt;code&gt;_concurrent&lt;/code&gt; tag, and that activity will be considered symultaneous to its parent activity for time tracking purposes.&lt;/p&gt;
&lt;h2&gt;Activity Status Filters&lt;/h2&gt;
&lt;p&gt;RedBook is now fully aware of the &amp;#8220;status&amp;#8221; of each activity, so it is possible to display only activities in a certain status using the following directives:&lt;/p&gt;
&lt;h3&gt;:plain&lt;/h3&gt;
&lt;p&gt;Executing &lt;code&gt;:select :plain :from today&lt;/code&gt; will return all the activities logged today, omitting their completions (if any), i.e. any activity beginning with &lt;em&gt;[&lt;span class="caps"&gt;COMPLETED&lt;/span&gt;]&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;:pending&lt;/h3&gt;
&lt;p&gt;Executing &lt;code&gt;:select :pending :from today&lt;/code&gt; will return all the activities logged today which have not been completed yet. Again, this was not too trivial to implement, but it seems to work (it also smart enough to detect if the same activity has been relogged etc. etc.).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;WARNING&lt;/span&gt;:&lt;/strong&gt; &lt;br /&gt;
&lt;em&gt;Using this directive with a large dataset may cause RedBook to take some time before delivering the result, due to the amount of iterations to perform. Use with care.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;:completed&lt;/h3&gt;
&lt;p&gt;Executing &lt;code&gt;:select :completed :from today&lt;/code&gt; will return all the activities logged today which have been completed.&lt;/p&gt;
&lt;h2&gt;Windows Installer&lt;/h2&gt;
&lt;p&gt;I decided to spend some time (half an hour) and create a proper setup file for Windows using InnoSetup. The setup will take care of almost everything for you, so you have no excuse not to try RedBook because it&amp;#8217;s not user-friendly to install!&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href="http://redbook.h3rald.com"&gt;manual&lt;/a&gt; for more details.&lt;/p&gt;
&lt;h2&gt;RubyForge Project&lt;/h2&gt;
&lt;p&gt;Finally, I registered a new &lt;a href="http://rubyforge.org/projects/redbook/"&gt;RubyForge Project&lt;/a&gt; for RedBook, which include a public &lt;span class="caps"&gt;SVN&lt;/span&gt; repository updated every week (Assembla doesn&amp;#8217;t allow anonymous checkouts, unfortunately).&lt;br /&gt;
This project will also host the official RedBook Gem, scheduled for the 1.0 release.&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;strong&gt;&lt;a href="http://www.assembla.com/spaces/files/redbook"&gt;&lt;span class="caps"&gt;DOWNLOAD&lt;/span&gt;&lt;/a&gt; | &lt;a href="http://redbook.h3rald.com/"&gt;&lt;span class="caps"&gt;MANUAL&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
      <pubDate>Wed, 28 Nov 2007 07:34:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/redbook-040-released/</guid>
      <link>http://www.h3rald.com/articles/redbook-040-released/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/redbook-040-released/#comments</comments>
      <category>opensource</category>
      <category>productivity</category>
      <category>redbook</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Announcement: RedBook v0.3.0 released</title>
      <description>&lt;p&gt;It&amp;#8217;s time for a new beta release of RedBook. This was actually going to be a fairly modest release in terms of features, but I actually ended up implementing a lot more than expected, even things which were planned for the first production release 1.0. So, let&amp;#8217;s see what&amp;#8217;s new&lt;/p&gt;
&lt;h3&gt;New operation names &lt;em&gt;(which break compatibility with previous versions)&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;I had a look at the names I choose for the operations and I noticed that they were either not intuitive enough or too verbose. So I decided to change a fair few of them (thus breaking compatibility with previous versions, but after all that&amp;#8217;s what beta releases are for, right?):&lt;/p&gt;
&lt;table&gt;
	&lt;tr&gt;
		&lt;th&gt;&lt;span class="caps"&gt;OLD&lt;/span&gt; &lt;/th&gt;
		&lt;th&gt;&lt;span class="caps"&gt;NEW&lt;/span&gt; &lt;/th&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; :complete &lt;/td&gt;
		&lt;td&gt; :finish &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; :load &lt;/td&gt;
		&lt;td&gt; :select &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; :load_config &lt;/td&gt;
		&lt;td&gt; :config &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; :load_log &lt;/td&gt;
		&lt;td&gt; :refresh &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; :timecalc &lt;/td&gt;
		&lt;td&gt; :calc &lt;/td&gt;
	&lt;/tr&gt;
	&lt;tr&gt;
		&lt;td&gt; :stop &lt;/td&gt;
		&lt;td&gt; :quit &lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;
&lt;h3&gt;New Manual/Home Page&lt;/h3&gt;
&lt;p&gt;A while ago I discovered &lt;a href="http://www.tiddlywiki.com/"&gt;TiddlyWiki&lt;/a&gt;, but as a matter of fact I never used it for anything practical. From last week though, I started using it a work for taking notes and create short memos, and then I thought of using it to replace RedBook&amp;#8217;s standard &lt;span class="caps"&gt;README&lt;/span&gt; file (which was made in a hurry and was kinda cryptical). Now a brand new &amp;#8220;manual.html&amp;#8221; ships with RedBook &amp;#8212; 308 KB (30 of actual docs and 278 of Javascript/&lt;span class="caps"&gt;HTML&lt;/span&gt;/&lt;span class="caps"&gt;CSS&lt;/span&gt; magic) with everything you need to know about it. Additionally, an online version is available at the following address:&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;strong&gt;&lt;a href="http://redbook.h3rald.com"&gt;redbook.h3rald.com&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Removed Win32::Console Library&lt;/h3&gt;
&lt;p&gt;OK this is not good news for people (like me) who use RedBook on Windows, but I promise you&amp;#8217;ll forgive me when you read about the other new features below. I discovered by chance that the Win32::Console library (which was used to get colors working on Windows) seems not to handle international characters properly and also seems to be conflicting in some way with the Readline library I decided to include (see below). I don&amp;#8217;t know whether this is a problem of the actual library or just of the gem used to pack it.&lt;/p&gt;
&lt;h3&gt;rbconfig.yml&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;config.yml&lt;/code&gt; file has been renamed to &lt;code&gt;rbconfig.yml&lt;/code&gt;. Additionally, if you place a file with this name in your $&lt;span class="caps"&gt;HOME&lt;/span&gt; directory it will override the one in your RedBook folder (This was done in preparation for the RedBook RubyGem).&lt;/p&gt;
&lt;h3&gt;New operations&lt;/h3&gt;
&lt;p&gt;The following new operations are available:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://redbook.h3rald.com/#%3Arelog"&gt;:relog&lt;/a&gt; &amp;#8212; Re-logs a previously-logged message (keeping the same tags and updating the timestamp)&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://redbook.h3rald.com/#%3Aclear"&gt;:clear&lt;/a&gt; &amp;#8212; Clears the screen.&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://redbook.h3rald.com/#%3Aruby"&gt;:ruby&lt;/a&gt; &amp;#8212; Evaluates arbitrary Ruby code outputting the result (use with care&amp;#8230;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Auto-completion&lt;/h3&gt;
&lt;p&gt;Some Mac users originally complained that the backspace key wasn&amp;#8217;t working in RedBook (and it didn&amp;#8217;t in Linux either). Fortunately the solution to this was easy enough: include the &lt;span class="caps"&gt;GNU&lt;/span&gt; &lt;a href="http://tiswww.case.edu/php/chet/readline/rltop.html"&gt;Readline&lt;/a&gt; library. &lt;br /&gt;
Readline is now being used in RedBook to:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Provide basic (Emacs-style) bindings&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Auto-completion&lt;/strong&gt; for keywords &lt;em&gt;and tags&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;Allow the user to automatically customize key bindings via an &lt;a href="http://redbook.h3rald.com/#.inputrc"&gt;.inputrc&lt;/a&gt; file placed in their $&lt;span class="caps"&gt;HOME&lt;/span&gt; directory (on Windows you&amp;#8217;ll have to define a &lt;span&gt;&lt;span class="caps"&gt;HOME&lt;/span&gt;&lt;/span&gt; environment variable pointing to a directory of your choice). An example .inputrc file is distributed with RedBook with some specific key bindings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Support for international characters&lt;/h3&gt;
&lt;p&gt;Finally, I decided to implement another feature which was originally planned for the 1.0 release: international characters support. This is possible using the Iconv Ruby extension (requires &lt;a href="http://www.gnu.org/software/libiconv/"&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; libiconv&lt;/a&gt;) which can convert strings between different character sets. The character sets needs to be configured via the &lt;a href="http://redbook.h3rald.com/#rbconfig.yml"&gt;rbconfig.yml&lt;/a&gt; file.&lt;/p&gt;
&lt;p&gt;For more information, check out the &lt;a href="http://redbook.h3rald.com/#ChangeLog"&gt;ChangeLog&lt;/a&gt;&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;strong&gt;&lt;a href="http://www.assembla.com/spaces/files/bWE7NkzCqr3k25abIlDkbG"&gt;Download RedBook&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 25 Oct 2007 05:18:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/redbook-030-released/</guid>
      <link>http://www.h3rald.com/articles/redbook-030-released/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/redbook-030-released/#comments</comments>
      <category>redbook</category>
      <category>ruby</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Announcement: RedBook v0.2.0 released</title>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&amp;#8220;Release Early, Release Often&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&amp;#8212; Eric S. Raymond, &lt;a href="http://www.catb.org/~esr/writings/cathedral-bazaar/cathedral-bazaar/ar01s04.html"&gt;The Cathedral and the Bazaar&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, time for another (early) release of &lt;a href="http://www.assembla.com/space/redbook"&gt;RedBook&lt;/a&gt;. There are quite a few new features which are worth examining, in particular:&lt;/p&gt;
&lt;h3&gt;Regexp search for messages&lt;/h3&gt;
&lt;p&gt;This was actually already available before, just if you inputted a search string which was not a regexp, you&amp;#8217;d get an unhandled exception (more or less). This exception is now handled propertly so you get a pretty message instead, if an error occurs when parsing the search string.&lt;/p&gt;
&lt;h3&gt;Log Backup&lt;/h3&gt;
&lt;p&gt;A new &lt;strong&gt;&amp;#58;backup&lt;/strong&gt; keyword is available to quickly backup your log file. Here&amp;#8217;s what it does:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Loads all messages silently&lt;/li&gt;
	&lt;li&gt;Writes them to a file in the same directory as the original log file named &amp;lt;log-alias&amp;gt;.bkp.yml.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Handy, especially if there was a similar keyword to restore the last backup, which is planned for &lt;a href="http://www.assembla.com/spaces/milestones/index/bWE7NkzCqr3k25abIlDkbG?spaces_tool_id=ceS8UazCqr3k25abIlDkbG"&gt;later on&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Support for multiple log files&lt;/h3&gt;
&lt;p&gt;This is perhaps the most important feature introduced by this release. It is now possible to configure more than one log file by adding any number of &lt;strong&gt;&amp;#58;data_&amp;lt;alias&amp;gt;&amp;#58;&lt;/strong&gt; settings inside your config.yml file, where alias is the name of your log file. So, for example, if your config.yml file contains the following:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#58;data_test&amp;#58; &amp;#8220;testlog.yml&amp;#8221;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can load the &amp;#8220;test&amp;#8221; log by typing&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#58;use test&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;(&amp;#58;use is a shorthand for &amp;#58;load_log). Similarly, another new keyword &lt;strong&gt;&amp;#58;dest&lt;/strong&gt; has been introduced to be able to log a message to a different log file without loading it into memory, like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#58;log This message will be saved to testlog.yml &amp;#58;dest test&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Finally, a &lt;strong&gt;&amp;#58;refresh&lt;/strong&gt; keyword has been introduced as an alias to reloading the current log.&lt;/p&gt;
&lt;h3&gt;(Almost) automatic log of completed activities&lt;/h3&gt;
&lt;p&gt;Right when I was coding the &lt;strong&gt;&amp;#58;timecalc&lt;/strong&gt; operation, I thought it would be nice to be able to log the start and end of a task without having to type it twice. Now this is possible using the &lt;strong&gt;&amp;#58;complete&lt;/strong&gt; keyword:&lt;/p&gt;
&lt;p&gt;&amp;#58;log Testing feature X in product Y&lt;/p&gt;
&lt;p&gt;&amp;#58;complete&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#58;complete&lt;/strong&gt; will re-log the last message prepended with [&lt;span class="caps"&gt;COMPLETED&lt;/span&gt;]:&lt;/p&gt;
4 Mon Oct 08 2007 &amp;#8211; 10:47:45 AM Testing feature X in product Y
5 Mon Oct 08 2007 &amp;#8211; 10:54:31 AM [&lt;span class="caps"&gt;COMPLETED&lt;/span&gt;] Testing feature X in product Y
&lt;p&gt;What if I start another task before completing the first one? No problem, it is sufficient to load the last activities using a &lt;strong&gt;&amp;#58;load&lt;/strong&gt; command and then issuing &lt;strong&gt;&amp;#58;complete &amp;lt;number&amp;gt;&lt;/strong&gt; where &amp;lt;number&amp;gt; is the index of the loaded activity. &lt;br /&gt;
This nifty little feature will become more and more important when (starting from release 0.4) I&amp;#8217;ll implement more time tracking functions, and it will be possible to track completed tasks in a specific timeframe and/or marked with a specific tag.&lt;/p&gt;
&lt;h3&gt;Easy integration with launchers like Launchy and QuickSilver&lt;/h3&gt;
&lt;p&gt;To conclude, as someone pointed out that it would be cool to use RedBook from launchers like Launchy or Quicksilver, I made another standalone script (redbooklet.rb or redbooklet.exe) which is just able to parse a log command and write a message to the specified log file.&lt;br /&gt;
To use it with Launchy, for example, all you have to do is the following:&lt;/p&gt;
&lt;ol&gt;
	&lt;li&gt;Create a shortcut to redbooklet.exe (or to a way to execute the corresponding ruby script) named &amp;#8220;log&amp;#8221;.&lt;/li&gt;
	&lt;li&gt;Copy the &amp;#8220;log&amp;#8221; shortcut anywhere in your start menu&lt;/li&gt;
	&lt;li&gt;Bring up launchy (ALT+SPACE) and type in &amp;#8220;log&amp;#8221;&lt;/li&gt;
	&lt;li&gt;Hit tab&lt;/li&gt;
	&lt;li&gt;Type in your log message, optionally with the any &amp;#58;tags or &amp;#58;dest keywords.&lt;/li&gt;
	&lt;li&gt;The message will be logged to your default log file or to the log you specified using the &amp;#58;dest keyword. If an error occurs, it will appear in a command line window for 15 seconds before the program is closed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That&amp;#8217;s all folks! As usual, if you have any comment or suggestion feel free to reply to this post or email me. For a list of the planned features and releases, check out the &lt;a href="http://www.assembla.com/spaces/milestones/index/bWE7NkzCqr3k25abIlDkbG?spaces_tool_id=ceS8UazCqr3k25abIlDkbG"&gt;Milestones&lt;/a&gt; page.&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;strong&gt;&lt;a href="http://www.assembla.com/spaces/files/bWE7NkzCqr3k25abIlDkbG"&gt;&lt;span class="caps"&gt;DOWNLOAD&lt;/span&gt; &lt;span class="caps"&gt;HERE&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;</description>
      <pubDate>Mon, 08 Oct 2007 03:05:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/redbook-020-released/</guid>
      <link>http://www.h3rald.com/articles/redbook-020-released/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/redbook-020-released/#comments</comments>
      <category>redbook</category>
      <category>ruby</category>
      <category>productivity</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Book Review: Humble Little Ruby Book</title>
      <description>&lt;p&gt;After reading the very first paragraph of Mr. Neighborly&amp;#8217;s &lt;a href="http://www.humblelittlerubybook.com/"&gt;Humble Little Ruby Book&lt;/a&gt; (&lt;span class="caps"&gt;HLRB&lt;/span&gt; for short, from now on) it was very clear to me that it was going to be quite an unconventional read:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;Yes, there is a Chapter 0.  There is a little bit of introductory stuff we need to talk about before &lt;br /&gt;
we set you loose on Ruby.  You wouldn&amp;#8217;t want to get psyched about a new gadget, get it home, &lt;br /&gt;
and then figure out you need batteries, a grapefruit, and the ability to speak three  languages to &lt;br /&gt;
even open the box would you?&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That reminded me immediately of &lt;a href="http://poignantguide.net/ruby/"&gt;Why&amp;#8217;s Poignant Guide to Ruby&lt;/a&gt;. without a doubt. I don&amp;#8217;t know how it is possible that two witty, crazy, and very inventive guys grew fond of the same programming language. Anyhow, to reassure a few of you, you won&amp;#8217;t find any foxes or chunky bacon cartoons in &lt;span class="caps"&gt;HLRB&lt;/span&gt;, just some very well made (although still pretty unconventional) diagrams like this one:&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/hlrb_diagram.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Got the picture? Good. Let&amp;#8217;s move on&amp;#8230;h3. Chapter 0: What&amp;#8217;chu talkin&amp;#8217; &amp;#8217;bout, mister?&lt;/p&gt;
&lt;p&gt;Chapter 0 is like an introduction to the book &lt;em&gt;and&lt;/em&gt; a place to put all the boring stuff you have to talk about in a book about a programming language:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;What is Ruby?&lt;/li&gt;
	&lt;li&gt;Installation procedure (on Windows, Mac OS X and Linux)&lt;/li&gt;
	&lt;li&gt;Hello, World!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Yes, you can skip this one safely without losing too much, unless of course you still need to install Ruby on your machine.&lt;/p&gt;
&lt;h3&gt;Chapter 1: Welcome to Ruby.&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;This  section  aims  to  introduce  the  syntactic  sugar  and  linguistic  misfortunes  of  Ruby  in  the &lt;br /&gt;
quickest manner that will still allow  for a full  education on the subject.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As the first two lines of this chapter say, it&amp;#8217;s time to learn the basics of Ruby. You&amp;#8217;ll be quickly guided through strings, numbers, collections and variables. Every section with tons of code examples for your to play with. You won&amp;#8217;t find a full list of all the 876 methods of the String class, but you&amp;#8217;ll certainly learn the 10 most common ones at least (numbers are random, so no, don&amp;#8217;t count them). &lt;br /&gt;
Sure, yes, right, whatever&amp;#8230; &lt;em&gt;if you really want&lt;/em&gt; you can skip this chapter too, but if you are already a Ruby Guru there&amp;#8217;s probably no need for you to read books about Ruby, right? Beginners need to read this chapter. It&amp;#8217;s compulsory, really, and pretty enjoyable, too.&lt;/p&gt;
&lt;h3&gt;Chapter 2: Break it down now!&lt;/h3&gt;
&lt;p&gt;Or &amp;#8220;learn how to segment your code&amp;#8221; using methods, and&amp;#8230; blocks &amp;amp; &lt;code&gt;Proc&lt;/code&gt; objects! Gosh. Our poor newbies will probably have a heart attack if they never heard about blocks and closures before. I almost got scared myself, because this is normally regarded as a pretty tough topic. Despite, at page 25 of the book you&amp;#8217;ll have to face your fears and dive into it. You&amp;#8217;ll survive, anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Purist Warning:&lt;/strong&gt; Please be aware that sometimes the author may decide to use certain terms and construct which may not sound 100% right to your ears. Just move on, beginners will understand more things like &lt;em&gt;&amp;#8220;Think of Proc objects as blocks that are pushed into variables.&amp;#8221;&lt;/em&gt; than anything else, guaranteed.&lt;/p&gt;
&lt;p&gt;After this section you&amp;#8217;ll finally be introduced to Ruby classes. Now, this can piss someone off, no doubt. Ruby is a &lt;em&gt;fully OO language&lt;/em&gt;, so people &lt;em&gt;must&lt;/em&gt; learn about classes before anything else. I must admit I was a bit confused by the ordering of the topics at first, but if someone comes from a non-OO background he&amp;#8217;ll probably find this particular order more suitable. &lt;br /&gt;
This section will cover class and object basics in Ruby like defining classes, instantiating objects, access control, methods, attributes, scope, duck typing. Finally, you&amp;#8217;ll briefly look into modules as well.&lt;/p&gt;
&lt;h3&gt;Chapter 3: Hustle and flow (control)&lt;/h3&gt;
&lt;p&gt;Finally, the author will deal with flow control. So things like &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;case&lt;/code&gt;, conditional operators, loops and statement modifiers. In my opinion this section is truly excellent: it introduces all the control structures in a very simple and crystal clear way, often using flowcharts. A great chance even for absolute beginners to understand these basic but powerful concepts.&lt;br /&gt;
Towards the end of the chapter, you&amp;#8217;ll also learn how exceptions work: a clever way to tell people &amp;#8220;you have to learn how to use exceptions from the very beginning&amp;#8221;. Really nicely done.&lt;/p&gt;
&lt;h3&gt;Chapter 4: The system beneath&amp;#8230;&lt;/h3&gt;
&lt;p&gt;Here comes the juicy stuff. Up to now you learnt the usual boring things you need to know when learning a new programming language, now finally you learn how to do &lt;em&gt;real things&lt;/em&gt;. The chapter is full of complete and meaningful code snippets which will answer nearly all the questions you may have (at this time):&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;How do I read and write to a file?&lt;/li&gt;
	&lt;li&gt;How do I handle threads and processes?&lt;/li&gt;
	&lt;li&gt;How do command-line parameters and environment variables work?&lt;/li&gt;
	&lt;li&gt;How can I perform specific Windows-only operations, like reading and writing to the Registry? What about &lt;span class="caps"&gt;OLE&lt;/span&gt; automation?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some of the big books out there will not spend too much time talking about Windows-only libraries, but I found &lt;span class="caps"&gt;HLRB&lt;/span&gt; gives quite a comprehensive introduction about them.&lt;/p&gt;
&lt;h3&gt;Chapter 5: Looking beyond home&lt;/h3&gt;
&lt;p&gt;More juicy stuff. If you are looking for a tutorial to learn the basics about networking, from from sockets to &lt;span class="caps"&gt;FTP&lt;/span&gt; to &lt;span class="caps"&gt;POP&lt;/span&gt; and web services, look no further: this chapter does a very remarkable job introducing various network-related libraries, with the usual well written code examples.&lt;br /&gt;
If that&amp;#8217;s still not enough, you&amp;#8217;ll also have a chance to explore the wonderful world of distributed Ruby and of databases. Granted, this chapter won&amp;#8217;t tell you about the 1567 methods available in ActiveRecord (buy a copy of &lt;a href="http://www.pragmaticprogrammer.com/title/rails/"&gt;Agile Web Development with Rails&lt;/a&gt; for this), but will tell you enough to get started.&lt;/p&gt;
&lt;h3&gt;Chapter 6: It&amp;#8217;s a Library!&lt;/h3&gt;
&lt;p&gt;The final chapter will go more in depth on some more advanced topics, like:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Strings&lt;/li&gt;
	&lt;li&gt;Regexp&lt;/li&gt;
	&lt;li&gt;Date &amp;amp; Time&lt;/li&gt;
	&lt;li&gt;Hashing and Cryptography&lt;/li&gt;
	&lt;li&gt;Unit Testing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Everything with more and more useful code snippets.&lt;/p&gt;
&lt;h3&gt;The Appendices&lt;/h3&gt;
&lt;p&gt;Last but not least, a &lt;span class="caps"&gt;HUGE&lt;/span&gt; collection of links and resources to learn more about Ruby, and a quick digression on C/C++ extensions&amp;#8230; not much, but enough to wet your appetite.&lt;/p&gt;
&lt;h3&gt;The bottom line&lt;/h3&gt;
&lt;p&gt;&lt;span class="caps"&gt;HLRB&lt;/span&gt; is not &lt;em&gt;the only&lt;/em&gt; book you need to read about Ruby. It&amp;#8217;s better to make this clear otherwise I&amp;#8217;ll be hunted forever by Dave Thomas, Chad Fowler, &lt;span class="caps"&gt;DHH&lt;/span&gt; and all the other excellent Ruby hackers who also wrote very successful books (which I bought as well). &lt;span class="caps"&gt;HLRB&lt;/span&gt; is &lt;span class="caps"&gt;LITTLE&lt;/span&gt; and &lt;span class="caps"&gt;HUMBLE&lt;/span&gt;, after all: it doesn&amp;#8217;t aim at becoming the official Ruby Bible anytime soon (although a bird told me it may get updated &lt;em&gt;someday&lt;/em&gt; and include more stuff), but it is still a worthwhile reading.&lt;/p&gt;
&lt;p&gt;And of course I came to the very end of this review without mentioning the most important thing: this little wonder is free. All you need is to register to InfoQ (for free) and grab your &lt;a href="http://www.infoq.com/minibooks/ruby/"&gt;free copy&lt;/a&gt;. If you want you can buy a printed copy for just $9.95, if you feel in a good mood (please do).&lt;/p&gt;
&lt;p&gt;The most obvious strengths of this book are the abundance of code examples and very useful working snippets, and the unconventional style which makes it very readable and not boring at all. If I were to name some of its weaknesses (but only if you force me to), I&amp;#8217;d say some parts should be expanded and more info on other libraries should be provided&amp;#8230; but you never know what the future will bring us!&lt;/p&gt;
&lt;p&gt;Well done, &lt;a href="http://www.jeremymcanally.com/"&gt;Mr. Neighborly&lt;/a&gt;!&lt;/p&gt;</description>
      <pubDate>Wed, 03 Oct 2007 03:53:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/hlrb-review/</guid>
      <link>http://www.h3rald.com/articles/hlrb-review/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/hlrb-review/#comments</comments>
      <category>ruby</category>
      <category>review</category>
      <category>books</category>
    </item>
    <item>
      <title>RedBook - A simple Ruby program for your daily logging needs</title>
      <description>&lt;p&gt;Logging your daily activities is important. If you don&amp;#8217;t believe me you&amp;#8217;d better check at least these three posts on LifeHacker, which feature different scripts and applications:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href="http://lifehacker.com/software/top/geek-to-live--quick+log-your-work-day-189772.php"&gt;QuickLogger&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://lifehacker.com/software/windows/log-your-workday-from-the-system-tray-with-life-logger-285602.php"&gt;Life Logger&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://lifehacker.com/software/featured-windows-download/log-your-workday-with-quicklogger-2-302932.php"&gt;QuickLogger 2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I had a look at each one of them, and I believe they are quite useful, although I didn&amp;#8217;t really find what I was looking for. Why? Well, for example:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;I don&amp;#8217;t believe a &lt;span class="caps"&gt;GUI&lt;/span&gt; is necessary &amp;#8212; you&amp;#8217;d better off with just a shortcut key or command to run from Launchy or QuickSilver, that&amp;#8217;s much faster.&lt;/li&gt;
	&lt;li&gt;They just log timestamped messages on a file, there&amp;#8217;s no real way to search through them and display them except by using a test editor&lt;/li&gt;
	&lt;li&gt;They are Windows only &amp;#8212; not that it matters for me, but others may not be happy about it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That&amp;#8217;s why I thought I&amp;#8217;d roll out my own: meet &lt;a href="http://www.assembla.com/space/redbook"&gt;RedBook&lt;/a&gt;.&lt;br /&gt;
Let me say it&amp;#8217;s nothing fancy: I&amp;#8217;m not a full-time programmer but I do like playing with Ruby during my lunch breaks at work, so that&amp;#8217;s why RedBook is just a humble, tiny Ruby script. This automatically makes it cross-platform: you can install Ruby very easily on Linux &amp;amp; alikes, Mac OS X and Windows. Furthermore, if you are on Windows and for some weird reason you don&amp;#8217;t want to install Ruby, you can just try out the packed &lt;span class="caps"&gt;EXE&lt;/span&gt; file (made with RubyScript2Exe) &amp;#8212; it&amp;#8217;s about 2MB, but you won&amp;#8217;t need anything else.&lt;/p&gt;
&lt;h3&gt;How It Works&lt;/h3&gt;
&lt;p&gt;The program uses two &lt;span class="caps"&gt;YAML&lt;/span&gt; files, one for configuration, which must reside in the same directory as redbook.rb (or redboo.exe) and one for the log itself, which you can place anywhere, provided that you edit the configuration file accordingly. For information on how to install RedBook and how to configure it, you can check the manual.html (powered by &lt;a href="http://www.tiddlywiki.com"&gt;TiddlyWiki&lt;/a&gt;) file provided with the program or &lt;a href="http://redbook.h3rald.com"&gt;browse it online&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;When started, RedBook will load both the configuration file (config.yml) and &lt;em&gt;the whole log file&lt;/em&gt; into memory &amp;#8212; it&amp;#8217;s not a big deal, considering that they are only text files after all. I did a test with a log of quite a few MBs, and it was fine.&lt;/p&gt;
&lt;p&gt;You can then start input commands right away, following a few sample rules. RedBook has a (very) rudimentary parser which is able to detect keywords, i.e. alphabetic strings prepended with a colon. RedBook commands look like this:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;&amp;#58;log&lt;/strong&gt; This message will be logger &lt;strong&gt;&amp;#58;tags&lt;/strong&gt; tag1 tag2&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&amp;#58;select&lt;/strong&gt; &lt;strong&gt;&amp;#58;last&lt;/strong&gt; 15 &lt;strong&gt;&amp;#58;since&lt;/strong&gt; January&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;&amp;#58;save&lt;/strong&gt; /home/h3rald/backup.yml&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If everything goes OK, RedBook will reply with some sort of response, an acknowledgement, a list of messages, etc.&lt;/p&gt;
&lt;p&gt;Simple.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s basically what the program can do:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Log any message to the main log file. Messages can be tagged with one or more tags and will be automatically timestamped.&lt;/li&gt;
	&lt;li&gt;Load/display a list of logged messages on the screen. It is possible to filter messages by specifying a time span, a string to search in the message text, or a list of tags.&lt;/li&gt;
	&lt;li&gt;Dump loaded messages to a &lt;span class="caps"&gt;TXT&lt;/span&gt;, &lt;span class="caps"&gt;CSV&lt;/span&gt; or &lt;span class="caps"&gt;YAML&lt;/span&gt; file (you can even backup your log saving it to another &lt;span class="caps"&gt;YAML&lt;/span&gt; file in this way).&lt;/li&gt;
	&lt;li&gt;Calculate the time elapsed between two or more tasks. Time will be displayed in years, months, weeks, days, hours, minutes and/or seconds as necessary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How? Here&amp;#8217;s a short tutorial&amp;#8230;&lt;/p&gt;
&lt;h3&gt;A Quick RedBook Tutorial&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s assume you are able to run RedBook on your system by now (if you can&amp;#8217;t find some of the gems which are required for it, you can download them packed in a &lt;span class="caps"&gt;ZIP&lt;/span&gt; file from &lt;a href="http://www.assembla.com/spaces/files/redbook"&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s what happens when you start the program:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: 'Bitstream Vera Sans Mono', Monaco, 'Courier New'; font-size: 10px"&gt;&lt;br /&gt;
&lt;del&gt;-&lt;/del&gt;&lt;br /&gt;
RedBook v0.1 &amp;#8211; Copyright &amp;#169; 2007, Fabio Cevasco&lt;br /&gt;
&lt;del&gt;-&lt;/del&gt;&lt;br /&gt;
   &lt;span style="color:blue"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Loading config file&amp;#8230;&lt;br /&gt;
   &lt;span style="color:green"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Config file loaded.&lt;br /&gt;
   &lt;span style="color:blue"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Loading log file&amp;#8230;&lt;br /&gt;
   &lt;span style="color:green"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Log file loaded.&lt;br /&gt;
   &lt;span style="color:blue"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Ready.&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt;&lt;br /&gt;
&lt;/code&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Good. Let&amp;#8217;s start logging something then. Just use the &lt;strong&gt;&amp;#58;log&lt;/strong&gt; keyword, followed by a message, and then you can also add the &lt;strong&gt;&amp;#58;tags&lt;/strong&gt; keyword followed by space-separated tags, like this:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: 'Bitstream Vera Sans Mono', Monaco, 'Courier New'; font-size: 10px"&gt;&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt; &amp;#58;log My first message &amp;#58;tags test&lt;br /&gt;
   &lt;span style="color:green"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Logged.&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt; &amp;#58;log This is another message&lt;br /&gt;
   &lt;span style="color:green"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Logged.&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt; &amp;#58;log This is another message &amp;#58;tags test another_test&lt;br /&gt;
   &lt;span style="color:green"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Logged.&lt;br /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Try waiting a few seconds between each message. These three messages will be appended to the log file. You could open it in an editor, but it&amp;#8217;s normally easier to display them directly inside RedBook, like this:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: 'Bitstream Vera Sans Mono', Monaco, 'Courier New'; font-size: 10px"&gt;&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt; &amp;#58;select&lt;br /&gt;
 &lt;span style="color:yellow"&gt;1&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:09:32 PM&lt;/span&gt; My first message &lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;br /&gt;
 &lt;span style="color:yellow"&gt;2&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:10:51 PM&lt;/span&gt; This is another message&lt;br /&gt;
 &lt;span style="color:yellow"&gt;3&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:11:45 PM&lt;/span&gt; This is another message &lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;another_test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;br /&gt;
   &lt;span style="color:green"&gt;&amp;gt;&amp;gt;&lt;/span&gt; 3 messages loaded.&lt;br /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Easy. What if you have hundreds of messages? Well, the &amp;#58;select operation can take an optional search string, or you can tell RedBook to load only those messages tagged with one or more specific tags, like this:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: 'Bitstream Vera Sans Mono', Monaco, 'Courier New'; font-size: 10px"&gt;&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt; &amp;#58;select &amp;#58;tags test&lt;br /&gt;
 &lt;span style="color:yellow"&gt;1&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:09:32 PM&lt;/span&gt; My first message &lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;br /&gt;
  &lt;span style="color:yellow"&gt;3&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:11:45 PM&lt;/span&gt; This is another message &lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;another_test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;br /&gt;
    &lt;span style="color:green"&gt;&amp;gt;&amp;gt;&lt;/span&gt; 2 messages loaded.&lt;br /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Or you can use the &amp;#58;from and/or &amp;#58;to keywords to specify a certain time frame, like this:&lt;/p&gt;
&lt;p&gt;&amp;#58;select &amp;#58;tags test &lt;strong&gt;&amp;#58;from ten minutes ago&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;#58;select &lt;strong&gt;&amp;#58;from last week &amp;#58;to 2 days ago&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;RedBook includes a very nice &amp;#8220;natural language date/time parser&amp;#8221;, &lt;a href="http://chronic.rubyforge.org/"&gt;Chronic&lt;/a&gt; which is able to convert sentences like the following into Ruby Time objects:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;6 in the morning&lt;/li&gt;
	&lt;li&gt;friday 1pm&lt;/li&gt;
	&lt;li&gt;sat 7 in the evening&lt;/li&gt;
	&lt;li&gt;today&lt;/li&gt;
	&lt;li&gt;yesterday at 4:00&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;#8217;s not perfect (and it&amp;#8217;s in pre-alpha as well), but it does the job, for what I can see, and it makes it very easy and fast to specify timeframes.&lt;/p&gt;
&lt;p&gt;After executing a &amp;#58;select command, two other operations can be performed on the loaded messages: &lt;strong&gt;&amp;#58;calc&lt;/strong&gt; and &lt;strong&gt;&amp;#58;save&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&amp;#58;calc calculates the exact amount of time elapsed between two or more tasks. Do you remember the numbers on the far left of each message? Think them as temporary IDs for the actual messages, and you can use them to select specific tasks when executing the &amp;#58;calc operation:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: 'Bitstream Vera Sans Mono', Monaco, 'Courier New'; font-size: 10px"&gt;&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt; &amp;#58;calc 1 3&lt;br /&gt;
 &lt;span style="color:yellow"&gt;1&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:09:32 PM&lt;/span&gt; My first message &lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;br /&gt;
      &lt;del&gt;-&lt;/del&gt; 2 minutes and 13 seconds.&lt;br /&gt;
       &lt;span style="color:yellow"&gt;3&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:11:45 PM&lt;/span&gt; This is another message &lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;another_test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Similarly, if no IDs are specified, &amp;#58;calc calculates the time difference between each message and the previous:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: 'Bitstream Vera Sans Mono', Monaco, 'Courier New'; font-size: 10px"&gt;&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt; &amp;#58;calc&lt;br /&gt;
 &lt;span style="color:yellow"&gt;1&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:09:32 PM&lt;/span&gt; My first message &lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;
      &lt;del&gt;-&lt;/del&gt; 1 minute and 19 seconds.&lt;br /&gt;      &lt;br /&gt;
 &lt;span style="color:yellow"&gt;2&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:10:51 PM&lt;/span&gt; This is another message&lt;br /&gt; &lt;br /&gt;
      &lt;del&gt;-&lt;/del&gt; 54 seconds.&lt;br /&gt;      &lt;br /&gt;
 &lt;span style="color:yellow"&gt;3&lt;/span&gt; &lt;span style="color:blue"&gt;Sat Sep 29 2007 &amp;#8211; 09:11:45 PM&lt;/span&gt; This is another message &lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;span style="color:cyan"&gt;[&lt;/span&gt;&lt;span style="color:yellow"&gt;another_test&lt;/span&gt;&lt;span style="color:cyan"&gt;]&lt;/span&gt;&lt;br /&gt;
 &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Finally, you can save loaded messages to a &lt;span class="caps"&gt;TXT&lt;/span&gt;, &lt;span class="caps"&gt;YAML&lt;/span&gt; or &lt;span class="caps"&gt;CSV&lt;/span&gt; file, as follows:&lt;/p&gt;
&lt;p&gt;&lt;span style="font-family: 'Bitstream Vera Sans Mono', Monaco, 'Courier New'; font-size: 10px"&gt;&lt;br /&gt;
&lt;span style="color:red"&gt;Red&lt;/span&gt;Book &amp;gt;&amp;gt; &amp;#58;save log.txt&lt;br /&gt;
   &lt;span style="color:blue"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Saving&amp;#8230;&lt;br /&gt;
   &lt;span style="color:green"&gt;&amp;gt;&amp;gt;&lt;/span&gt; Saved dataset to &amp;#8220;log.txt&amp;#8221;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
h&lt;br /&gt;
If you want to backup your log, you can load all messages and then save them to a &lt;span class="caps"&gt;YAML&lt;/span&gt; file. Maybe in this case you want to append the &lt;strong&gt;&amp;#58;silent&lt;/strong&gt; keyword to the &amp;#58;select command, so that messages won&amp;#8217;t be displayed on the screen.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;RedBook is just a simple program: it suits my needs for now, but of course there&amp;#8217;s roo for improvement. If you have some useful suggestions, or you want to contribute in some way, feel free to contact me!&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;a href="http://redbook.h3rald.com"&gt;Home Page&lt;/a&gt; | &lt;a href="http://code.google.com/p/redbook/"&gt;Development&lt;/a&gt; | &lt;a href="http://code.google.com/p/redbook/downloads/list"&gt;Download&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sat, 29 Sep 2007 12:05:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/redbook/</guid>
      <link>http://www.h3rald.com/articles/redbook/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/redbook/#comments</comments>
      <category>ruby</category>
      <category>productivity</category>
      <category>software</category>
      <category>tools</category>
      <category>redbook</category>
    </item>
    <item>
      <title>Introducing RedBook (and the new Code section)</title>
      <description>&lt;p&gt;I&amp;#8217;m somehow pleased to announce the opening of a new section on this site. Nothing too big actually, it&amp;#8217;s just a &lt;a href="/code/"&gt;page&lt;/a&gt; with a few (one for now) brief descriptions of open source programs and scripts I made and I&amp;#8217;d like to share with my readers.&lt;/p&gt;
&lt;p&gt;Don&amp;#8217;t expect fancy stuff: (luckily) I don&amp;#8217;t code for a living, I code for pleasure and I code small things. Lately I&amp;#8217;ve been trying to write a small Ruby program able to log my daily activities and also display them in a pleasant enough way, so I started using my lunch breaks at work more constructively and I came up with &lt;a href="/code/"&gt;RedBook&lt;/a&gt; an interactive command-line program written in Ruby.&lt;/p&gt;
&lt;p&gt;Main features:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Log timestamped and &lt;em&gt;tagged&lt;/em&gt; messages to a single &lt;span class="caps"&gt;YAML&lt;/span&gt; file&lt;/li&gt;
	&lt;li&gt;Load and display messages containing a certain string, or certain tags or within a time frame.&lt;/li&gt;
	&lt;li&gt;Calculate the time elapsed between two or more tasks.&lt;/li&gt;
	&lt;li&gt;Export loaded messages to &lt;span class="caps"&gt;YAML&lt;/span&gt;, &lt;span class="caps"&gt;TXT&lt;/span&gt; or &lt;span class="caps"&gt;CSV&lt;/span&gt; format.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All done via command line via simple commands:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#58;log&lt;/strong&gt; This is a test message &lt;strong&gt;&amp;#58;tags&lt;/strong&gt; test&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#58;load&lt;/strong&gt; &lt;strong&gt;&amp;#58;last&lt;/strong&gt; 30 &lt;strong&gt;&amp;#58;from&lt;/strong&gt; last week&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#58;timecalc&lt;/strong&gt; 2 5&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;#58;save&lt;/strong&gt; test.txt&lt;/p&gt;
&lt;p&gt;Thanks to the wonderful &lt;a href="http://chronic.rubyforge.org/"&gt;Chronic&lt;/a&gt; library, you can specify your time frames using natural language expressions like &amp;#8220;8 in the morning&amp;#8221;, &amp;#8220;this tuesday&amp;#8221;, &amp;#8220;last month&amp;#8221; and so on&amp;#8230;&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a screenshot showing RedBook in action:&lt;/p&gt;
&lt;p&gt;&lt;img src="/files/redbook.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;RedBook is of course free, open source software licensed under the terms of the &lt;span class="caps"&gt;BSD&lt;/span&gt; license. It can be installed on any machine able to run Ruby and there&amp;#8217;s also an &lt;span class="caps"&gt;EXE&lt;/span&gt; version for the lazy windows folks who don&amp;#8217;t want to install Ruby, packed with &lt;a href="http://www.erikveenstra.nl/rubyscript2exe/index.html"&gt;RubyScript2Exe&lt;/a&gt;. A more in-depth article explaining how RedBook works &lt;del&gt;will hopefully be completed soon&lt;/del&gt; is available &lt;a href="http://www.h3rald.com/articles/redbook"&gt;:here&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sat, 29 Sep 2007 00:12:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/introducing-redbook/</guid>
      <link>http://www.h3rald.com/articles/introducing-redbook/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/introducing-redbook/#comments</comments>
      <category>ruby</category>
      <category>productivity</category>
      <category>software</category>
      <category>tools</category>
      <category>redbook</category>
    </item>
    <item>
      <title>Simply On Rails - Part 4: Quick and Easy Default Data Migrations</title>
      <description>&lt;p&gt;In the &lt;a href="http://www.h3rald.com/blog/simply-on-rails-3-shared-controller"&gt;last post&lt;/a&gt; of this series I tried to find a &lt;acronym title="Don&amp;#39;t Repeat Yourself"&gt;&lt;span class="caps"&gt;DRY&lt;/span&gt;&lt;/acronym&gt; solution to deal with tables storing &amp;#8220;ancillary&amp;#8221; data, i.e. names of user roles, predefined categories, page state names and other similar things.&lt;br /&gt;
I personally chose to put this kind of data to make my application more dynamic, although I could have decided to use ENUMs or simply ordinary varchar fields &amp;#8212; that would have been easier, but less flexible. For now, I&amp;#8217;m sticking with my original choice.&lt;/p&gt;
&lt;p&gt;The data in these tables is kind of a prerequisite for the application to run: I must be able to have a status to assign to a user when creating it, and the same applies to roles. Sure, I could spend 20 minutes populating these tables manually, but it would be nice if there was a less tedious way, wouldn&amp;#8217;t it?&lt;/p&gt;
&lt;p&gt;There is indeed. The inspiration came from a technique described in the book (which I highly recommend) &lt;em&gt;Agile Web Development With Rails&lt;/em&gt;, in which the author outlines how it would be possible to use Rails&amp;#8217; fixtures and migrations to load data in the database automatically from &lt;span class="caps"&gt;YAML&lt;/span&gt; files. &lt;br /&gt;
All you have to do is create a migration to load the specified &lt;span class="caps"&gt;YAML&lt;/span&gt; files and you&amp;#8217;re all set.&lt;/p&gt;
&lt;p&gt;I wanted to take a little step further, allowing the migration to load data from &lt;em&gt;all &lt;span class="caps"&gt;YAML&lt;/span&gt; files in a specific directory&lt;/em&gt;, automatically.Let&amp;#8217;s start creating the &lt;span class="caps"&gt;YAML&lt;/span&gt; files then and place them all in one directory of the application like &lt;code&gt;/db/migrate/defaults&lt;/code&gt;. Here&amp;#8217;s the one I used for user roles, for example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="l-Scalar-Plain"&gt;visitor&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;1&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Visitor&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;level&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;0&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;user&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;2&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;User&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;level&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;10&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;contributor&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;3&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Contributor&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;level&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;20&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;provider&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;4&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Provider&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;level&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;50&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;operator&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;5&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Operator&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;level&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;100&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;administrator&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;6&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Administrator&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;level&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;500&lt;/span&gt;

&lt;span class="l-Scalar-Plain"&gt;webmaster&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;id&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;7&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;name&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;Webmaster&lt;/span&gt;
&lt;span class="err"&gt;	&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;level&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;1000&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The important thing to remember is to provide a unique string to identify each record, before specifying each fiels. The other files look similar, so I won&amp;#8217;t bother listing them here.&lt;/p&gt;
&lt;p&gt;And here&amp;#8217;s the simple code for the migration:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;active_record/fixtures&amp;#39;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LoadDefaults&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Migration&lt;/span&gt;

	&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;up&lt;/span&gt;
		&lt;span class="n"&gt;down&lt;/span&gt;
		&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_models&lt;/span&gt;
		&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;   
			&lt;span class="no"&gt;Fixtures&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_fixtures&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_directory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
		&lt;span class="k"&gt;end&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;

	&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;down&lt;/span&gt;
		&lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_models&lt;/span&gt;
		&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
			&lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;singularize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capitalize&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.delete_all&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
		&lt;span class="k"&gt;end&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;

	&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_directory&lt;/span&gt;
		&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;__FILE__&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;defaults&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;

	&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_models&lt;/span&gt;
		&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;glob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;default_directory&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/*.yml&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;[]&lt;/span&gt;
		&lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blank?&lt;/span&gt;
			&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;.yml&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
			&lt;span class="n"&gt;names&lt;/span&gt;
		&lt;span class="k"&gt;else&lt;/span&gt;
			&lt;span class="o"&gt;[]&lt;/span&gt;
		&lt;span class="k"&gt;end&lt;/span&gt;
	&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Basically the migration will look in a directory named &amp;#8220;defaults&amp;#8221; for some &lt;span class="caps"&gt;YAML&lt;/span&gt; files named after a particular database table, and it will attempt to load all the records defined in each one of them. &lt;br /&gt;
The &lt;code&gt;down&lt;/code&gt; method of the migration &lt;em&gt;deletes all the data in the specified tables&lt;/em&gt;, so use with care&amp;#8230;&lt;/p&gt;</description>
      <pubDate>Sat, 15 Sep 2007 11:10:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/simply-on-rails-4-default-data-migrations/</guid>
      <link>http://www.h3rald.com/articles/simply-on-rails-4-default-data-migrations/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/simply-on-rails-4-default-data-migrations/#comments</comments>
      <category>rails</category>
      <category>ruby</category>
      <category>databases</category>
    </item>
    <item>
      <title>10 Reasons to Learn Ruby</title>
      <description>&lt;h3&gt;Preamble&lt;/h3&gt;
&lt;p&gt;I discovered Ruby fairly recently, through the excellent Ruby on Rails framework&lt;sup class="footnote" id="fnr1"&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Although I don&amp;#8217;t consider myself a Ruby expert by any means, I read the PickAxe&lt;sup class="footnote" id="fnr2"&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt;, I&amp;#8217;ve coded a few utilities for my personal use in Ruby and I&amp;#8217;m currently developing with Rails during my free time.&lt;/p&gt;
&lt;p&gt;Ruby is currently my programming language of choice; I started off with Turbo Pascal in high school, discovered C and C++ at university, did my thesis in Java and learned &lt;span class="caps"&gt;PHP&lt;/span&gt; from scratch because I wanted to learn how to make websites quickly and easily. I guess I feel compelled to code sometimes, more as a form of entertainment than anything else.  Rather dissatisfied with what I tried language-wise, I was determined to start learning either Python or Ruby. I chose the latter because I didn&amp;#8217;t want incorrect indentation to break my code&lt;sup class="footnote" id="fnr3"&gt;&lt;a href="#fn3"&gt;3&lt;/a&gt;&lt;/sup&gt;, and here I am, heaping praise upon it.&lt;/p&gt;
&lt;p&gt;There are plenty&lt;sup class="footnote" id="fnr4"&gt;&lt;a href="#fn4"&gt;4&lt;/a&gt;&lt;/sup&gt; of introductions, tutorials, articles and essays of different sorts which aim to guide the novice and advise the guru on how to get the most out of Ruby. This article, however, is not one of them.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s more of a modest, humble, and incomplete list of a few reasons which may (or may not) entice you to use Ruby or at least play with it a bit. A word of caution: if you are using another programming language for work or whatever, don&amp;#8217;t complain to me if you don&amp;#8217;t want to use it anymore &amp;#8211; that&amp;#8217;s exactly what happened to me, but luckily, it didn&amp;#8217;t matter.  Ruby is a very beautiful and elegant language, but like all things of this sort, it may well poison your mind and corrupt your soul&amp;#8230;&lt;/p&gt;
&lt;p&gt;You have been warned.&lt;br /&gt;
h3. Why learn Ruby?&lt;/p&gt;
&lt;h4&gt;#1 &amp;#8211; You get all the treats without the tricks&lt;/h4&gt;
&lt;p&gt;Ruby borrows from all the best programming languages out there, from smalltalk to Java, Perl to Python&lt;sup class="footnote" id="fnr5"&gt;&lt;a href="#fn5"&gt;5&lt;/a&gt;&lt;/sup&gt;. Basically, here&amp;#8217;s the features and functionalities Ruby gives you which you may have seen elsewhere:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;em&gt;Exceptions:&lt;/em&gt; Believe it or not, exceptions are one of the most important things to master when developing any kind of application. PHP4 programmers probably won&amp;#8217;t know anything about them and they&amp;#8217;ll tell you to just print stuff on the screen or use their &amp;#8220;extremely advanced&amp;#8221; class for error handling. Please, ignore them. Fortunately for all of us, Ruby comes with try/catch (or better, begin/rescue) blocks and a series of predefined, extensible Exceptions to handle errors properly.&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Namespaces:&lt;/em&gt; Ruby modules make excellent and easy-to-use namespaces, for the joy of Java and C++ enthusiasts.&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Built-in Regular Expressions:&lt;/em&gt; For all the Perl monkeys, you can put something between slashes and it will become a regular expression, ready to be matched with a =~ operator.&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Overloadable operators:&lt;/em&gt; Ruby lets you define operators like +, -, etc., for any of your classes.&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Packages:&lt;/em&gt; Called &amp;#8220;gems&amp;#8221;, they really are solid and precious indeed&amp;#8230;and they work! Packages support dependencies, and they can be either cross-platform or platform-dependent.&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Interactive Shell:&lt;/em&gt; the Interactive Ruby Shell can be used to test Ruby code instantly, similar to the Python console.&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Unit Testing&lt;/em&gt;: The &lt;code&gt;Test::Unit&lt;/code&gt; module makes things so easy that you really don&amp;#8217;t have any excuse not to test your code.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;#2 &amp;#8211; You&amp;#8217;ll love the little things&lt;/h4&gt;
&lt;p&gt;Ruby is elegant. Why&amp;#8217;s that? Because it doesn&amp;#8217;t focus on making code &lt;em&gt;concise&lt;/em&gt; so much as &lt;em&gt;readable and usable&lt;/em&gt;. Here are some tips to help you out:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You can use both &lt;em&gt;if&lt;/em&gt; and &lt;em&gt;unless&lt;/em&gt; in condition statements. Of course you can just use &lt;em&gt;if&lt;/em&gt; and negate the condition, but &lt;em&gt;unless&lt;/em&gt; can be less error-prone at times. Furthermore, you can use both operators as conditional modifiers, after a statement rather than before: &lt;em&gt;order.new unless order.exists&lt;/em&gt;.&lt;/li&gt;
	&lt;li&gt;You can use question marks and exclamation marks at the end of your methods. Although no convention is enforced, ? is added if the method should return true or false, while ! is used to clarify that the method does something forcefully, like destroying a database record, chopping off the last character of a string, etc.&lt;/li&gt;
	&lt;li&gt;You can use the &lt;em&gt;alias&lt;/em&gt; directives to create an alias for a method already defined. In this way you can have an &lt;em&gt;exist&lt;/em&gt; and an &lt;em&gt;exists&lt;/em&gt; method at no additional cost or repetition.&lt;/li&gt;
	&lt;li&gt;You can use the &lt;em&gt;attr_reader&lt;/em&gt;, &lt;em&gt;attr_writer&lt;/em&gt; or &lt;em&gt;attr_accessor&lt;/em&gt; directives to automatically generate getter and setter methods for specified class members.&lt;/li&gt;
	&lt;li&gt;Some naming conventions are enforced for your own sanity: constants, classes and modules are capitalized, methods and members must start with a lowercase letter; global variables are prepended by a $, instance variables by &lt;code&gt;@&lt;/code&gt; and class variables by &lt;code&gt;@@&lt;/code&gt;; etc.&lt;/li&gt;
	&lt;li&gt;Parentheses are optional in method calls.  You can therefore write &lt;em&gt;File.open(&amp;#8220;/home/h3rald/test.txt&amp;#8221;)&lt;/em&gt; or simply &lt;em&gt;File.open &amp;#8220;/home/h3rald/test.txt&amp;#8221;&lt;/em&gt;, which is particularly handy with methods that don&amp;#8217;t take parameters.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;#3 &amp;#8211; You won&amp;#8217;t ever use a semicolon again&lt;/h4&gt;
&lt;p&gt;You want to add another instruction? Just go on the next line. Hit &lt;return&gt; and you&amp;#8217;re done. In Ruby, like in Python, newlines matter and you don&amp;#8217;t have to remember to end your instructions with a semicolon. Unfortunately this means that you won&amp;#8217;t be able to write your whole program in a single line of code, like the C++ folks&amp;#8230; that&amp;#8217;s too bad, isn&amp;#8217;t it?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;:&lt;/strong&gt; Indeed you &lt;span class="caps"&gt;CAN&lt;/span&gt; use semicolons as line delimiters in Ruby as well, the point, however, is that you don&amp;#8217;t have to.&lt;/p&gt;
&lt;h4&gt;#4 &amp;#8211; Everything is an object, as it should be&lt;/h4&gt;
&lt;p&gt;When I studied Java they taught me that everything is an object.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;- &amp;#8220;So 14 and 374346.678 are objects then?&amp;#8221;&lt;/em&gt;&lt;br /&gt;
&lt;em&gt;- &amp;#8220;No, silly, they are numbers!&amp;#8221;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;In Ruby, numbers, strings, Boolean values &lt;em&gt;et al&lt;/em&gt; are objects. Really. This means you&amp;#8217;ll write things like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="s2"&gt;&amp;quot;YOU SHOULDN&amp;#39;T ALWAYS USE CAPITALS&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;downcase&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; outputs &amp;quot;you shouldn&amp;#39;t always use capitals&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;abs&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; outputs 12&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;instead of something like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c1"&gt;# PHP Code&lt;/span&gt;

&lt;span class="n"&gt;strtolower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;YOU SHOULDN&amp;#39;T ALWAYS USE CAPITALS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You save time, you save brackets, and it just makes more sense.&lt;/p&gt;
&lt;h4&gt;#5 &amp;#8211; Everything has a value&lt;/h4&gt;
&lt;p&gt;Or &amp;#8220;you&amp;#8217;ll hardly ever use return to return values&amp;#8221;. In a nutshell, all Ruby instructions return a value, even variable assignments, so you don&amp;#8217;t really need to use the &amp;#8220;return&amp;#8221; keyword at the end of a method; the value of the last assignment or &lt;em&gt;any&lt;/em&gt; other expression will always be returned.&lt;/p&gt;
&lt;h4&gt;#6 &amp;#8211; You can alter your environment in any way you like&lt;/h4&gt;
&lt;p&gt;The first time I saw this, it really freaked me out. Imagine a typical programming situation: you start using a system class or a class written by someone else and you notice that you&amp;#8217;d like to have an additional method. At this point you have a few ways to handle this in ordinary programming languages:&lt;br /&gt;
s&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;You modify the developer&amp;#8217;s source code, if you have access to it. This is normally not a good idea, and you shouldn&amp;#8217;t do it.&lt;/li&gt;
	&lt;li&gt;You derive a new class from the original one, and you implement the new method there. This is a good idea, but it could be overkill for just one method, and you may have to update some of your other code accordingly.&lt;/li&gt;
	&lt;li&gt;You give up, and you just create the method outside the class, somewhere else. This can be done, but it is not very elegant and goes against Object Oriented Programming.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In Ruby, you can simply add the method to the original class, without having to hack the original source code, and even for system classes! You want to have a method to automatically convert a measurement from meters to feet? You can simply extend the Numeric class as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Numeric&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;feet&lt;/span&gt;
	&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2808399&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;From now on, all your numbers will have a &lt;em&gt;feet&lt;/em&gt; method, which can be used just like any other method that was originally defined for the class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;feet&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; Returns 16.4041995&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Basically, Ruby classes are never closed and can be modified at any time from anywhere. Use with care, of course.&lt;/p&gt;
&lt;h4&gt;#7 You won&amp;#8217;t get unicorns from birds and horses, but you&amp;#8217;ll still get donkeys if you want&lt;/h4&gt;
&lt;p&gt;I distinctly remember my C++ professor at university using animals to illustrate key object-oriented concepts like classes and inheritance. Weird things came in when she tried to explain multiple inheritance to inherit a class Pegasus from a class Bird and a class Horse. It had methods like &amp;#8220;fly&amp;#8221; and &amp;#8220;neigh&amp;#8221;&amp;#8230; crazy stuff, anyhow, Ruby does not offer multiple inheritance. &lt;br /&gt;
This seems to be the trend, after all, and of course it&amp;#8217;s up to tastes. I don&amp;#8217;t quite fancy multiple inheritances, as they may lead to unpredictable things. Nevertheless, it is possible to create &amp;#8220;mix-ins&amp;#8221; using Ruby modules, so that members and methods defined in a module will be added to a particular class if the module is included in it.&lt;/p&gt;
&lt;h4&gt;#8 You don&amp;#8217;t really need &lt;span class="caps"&gt;XML&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span class="caps"&gt;XML&lt;/span&gt; is a nice, general-purpose markup language which can be processed by every programming language and used everywhere. Unfortunately, it can also be quite verbose to write, very difficult to parse, and let&amp;#8217;s be honest, it&amp;#8217;s not really readable at first glance in many cases, unlike the following code snippet:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="l-Scalar-Plain"&gt;regexp&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;!ruby&lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;/regexp /a-zA-Z/&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;number&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;4.7&lt;/span&gt;
&lt;span class="l-Scalar-Plain"&gt;string&lt;/span&gt;&lt;span class="p-Indicator"&gt;:&lt;/span&gt; &lt;span class="l-Scalar-Plain"&gt;a string&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This is definitely easier and more readable than &lt;span class="caps"&gt;XML&lt;/span&gt;, isn&amp;#8217;t it? Welcome to &lt;span class="caps"&gt;YAML&lt;/span&gt;, Ruby&amp;#8217;s favorite markup (but not really&lt;sup class="footnote" id="fnr6"&gt;&lt;a href="#fn6"&gt;6&lt;/a&gt;&lt;/sup&gt;) language, which can be used to represent any Ruby object in a simple, clear and yet complete way. &lt;br /&gt;
Ruby &lt;em&gt;can&lt;/em&gt; parse &lt;span class="caps"&gt;XML&lt;/span&gt;, but YAML&amp;#8217;s simplicity convinced a lot of developers to use it as an alternative to &lt;span class="caps"&gt;XML&lt;/span&gt; for configuration files, for example (Rails does this).&lt;br /&gt;
The code snipped presented before was obtained by executing the following line of Ruby code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;string&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;a string&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;number&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;regexp&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="sr"&gt;/a-zA-Z/&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_yaml&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;em&gt;to_yaml&lt;/em&gt; method is defined for the Object class, which is the father of all of the other classes, and thus it is available in all Ruby objects. This means that you can convert anything into &lt;span class="caps"&gt;YAML&lt;/span&gt; &lt;em&gt;and&lt;/em&gt; re-convert anything back into Ruby objects, with total transparency for the developer. So much for parsing, huh?&lt;/p&gt;
&lt;h4&gt;#9 Lambda is much more than a Greek letter&lt;/h4&gt;
&lt;p&gt;Ruby borrows some magic from Lisp and Perl with Proc objects and blocks. Procs are _&amp;quot;blocks of code that have been bound to a set of local variables. Once bound, the code may be called in different contexts and still access those variables.&amp;quot; _&lt;sup class="footnote" id="fnr7"&gt;&lt;a href="#fn7"&gt;7&lt;/a&gt;&lt;/sup&gt; Consider the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;gen_times&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
	 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;Proc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="k"&gt;end&lt;/span&gt;

   &lt;span class="n"&gt;times3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gen_times&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="n"&gt;times5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gen_times&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="n"&gt;times3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;               &lt;span class="c1"&gt;#=&amp;gt; 36&lt;/span&gt;
   &lt;span class="n"&gt;times5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                &lt;span class="c1"&gt;#=&amp;gt; 25&lt;/span&gt;
   &lt;span class="n"&gt;times3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;   &lt;span class="c1"&gt;#=&amp;gt; 60&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;I could have used the &lt;em&gt;lambda&lt;/em&gt; method instead of &lt;em&gt;Proc.new&lt;/em&gt; and gotten the same result. This should ring a bell for people who know Perl and Python (or Lisp)&lt;sup class="footnote" id="fnr8"&gt;&lt;a href="#fn8"&gt;8&lt;/a&gt;&lt;/sup&gt;.  You can do the same thing in &lt;span class="caps"&gt;PHP&lt;/span&gt; as well, but most people don&amp;#8217;t really use the function.&lt;sup class="footnote" id="fnr9"&gt;&lt;a href="#fn9"&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Additionally, Ruby makes extensive use of blocks, sort of &amp;#8220;unborn Procs&amp;#8221;&lt;sup class="footnote" id="fnr10"&gt;&lt;a href="#fn10"&gt;10&lt;/a&gt;&lt;/sup&gt;, for example, to iterate the contents of an object and execute some code, like the &lt;em&gt;each&lt;/em&gt; method available for the Array class:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="o"&gt;].&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;#=&amp;gt; outputs each element multiplied by 2 in a new line. &lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Should the code in the block exceed one line, you&amp;#8217;re advised (but not required) to include the block within &lt;em&gt;do &amp;#8230; end&lt;/em&gt; instead of using braces. Ruby folks don&amp;#8217;t like braces much, really.&lt;/p&gt;
&lt;h4&gt;#10 &amp;#8211; You can go on Rails&lt;/h4&gt;
&lt;p&gt;Last but not least, you can always use Ruby on Rails for developing web applications. Deployment may not be as easy as it is with &lt;span class="caps"&gt;PHP&lt;/span&gt;, but Rails was built in Ruby because Ruby has features no other language can offer.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Time&amp;#8217;s up. You&amp;#8217;ve probably made up your mind about Ruby already, and you are either playing with it already, or you&amp;#8217;re totally ignoring it.  However, the next time you&amp;#8217;re frustrated because your code looks ugly and you think you could have done the same thing with half the code you got, don&amp;#8217;t blame me!&lt;/p&gt;
&lt;h3&gt;Notes&lt;/h3&gt;
&lt;p class="footnote" id="fn1"&gt;&lt;a href="#fnr1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://www.rubyonrails.org"&gt;Ruby on Rails&lt;/a&gt;, &lt;span class="caps"&gt;MVC&lt;/span&gt; Web Development Framework.&lt;/p&gt;
&lt;p class="footnote" id="fn2"&gt;&lt;a href="#fnr2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; &lt;a href="http://www.pragmaticprogrammer.com/title/ruby/index.html" title="2nd Ed."&gt;Programming Ruby&lt;/a&gt;, by Dave Thomas &amp;amp; others, Pragmatic Programmers, 2004&lt;/p&gt;
&lt;p class="footnote" id="fn3"&gt;&lt;a href="#fnr3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; Not entirely correct, but sort of. For more information on Python&amp;#8217;s indentation rules and myths, read &lt;a href="http://www.secnetix.de/~olli/Python/block_indentation.hawk"&gt;Python: Myths about Indentation&lt;/a&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn4"&gt;&lt;a href="#fnr4"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; For a list of Ruby tutorials, refer to the &lt;a href="http://www.ruby-lang.org/en/documentation/"&gt;Documentation&lt;/a&gt; section of the Official Ruby Website.&lt;/p&gt;
&lt;p class="footnote" id="fn5"&gt;&lt;a href="#fnr5"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; For more information on Ruby, and in particular on the similarities and differences with other languages, refer to &lt;a href="http://www.ruby-lang.org/en/documentation/ruby-from-other-languages/"&gt;Ruby from Other Languages&lt;/a&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn6"&gt;&lt;a href="#fnr6"&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt; &lt;span class="caps"&gt;YAML&lt;/span&gt; is Not a Markup Language.&lt;/p&gt;
&lt;p class="footnote" id="fn7"&gt;&lt;a href="#fnr7"&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt; Definition and example taken from the official Ruby documentation for class &lt;a href="http://www.ruby-doc.org/core/classes/Proc.html"&gt;Proc&lt;/a&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn8"&gt;&lt;a href="#fnr8"&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt; For some example on lambda functions in Python, see &lt;a href="http://www.secnetix.de/~olli/Python/lambda_functions.hawk"&gt;Python: Lambda Functions&lt;/a&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn9"&gt;&lt;a href="#fnr9"&gt;&lt;sup&gt;9&lt;/sup&gt;&lt;/a&gt; For examples of &amp;#8220;lambda functions&amp;#8221; in &lt;span class="caps"&gt;PHP&lt;/span&gt; using create_function(), see &lt;a href="http://www.webmasterworld.com/forum88/7414.htm"&gt;this&lt;/a&gt;.&lt;/p&gt;
&lt;p class="footnote" id="fn10"&gt;&lt;a href="#fnr10"&gt;&lt;sup&gt;10&lt;/sup&gt;&lt;/a&gt; For more detailed information on Ruby&amp;#8217;s Procs, blocks etc. refer to &lt;a href="http://eli.thegreenplace.net/2006/04/18/understanding-ruby-blocks-procs-and-methods"&gt;Understanding Ruby blocks, Procs and methods&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Wed, 05 Sep 2007 10:40:00 -0000</pubDate>
      <guid>http://www.h3rald.com/articles/10-reasons-to-learn-ruby/</guid>
      <link>http://www.h3rald.com/articles/10-reasons-to-learn-ruby/</link>
      <author>h3rald@h3rald.com</author>
      <comments>http://www.h3rald.com/articles/10-reasons-to-learn-ruby/#comments</comments>
      <category>ruby</category>
    </item>
  </channel>
</rss>
