'Open Source' Articles

Maruku is obsolete

, ,

A few weeks ago I finally released Maruku 0.7.0 after a short beta that revealed no serious issues. This was the first release in four years of the venerable Ruby Markdown library. I inherited Maruku over a year ago and I’m very proud of the work I’ve put into it during that year. I’m glad that I was able to fix many of its bugs and update it to work in a modern Ruby environment. However, I want to recommend that, if you have a choice, you should choose a different Markdown library instead of Maruku.

When Natalie Weizenbaum handed Maruku over to me, my interest in the library stemmed from its use in Middleman, and my desire to default to a pure-Ruby Markdown processor in the name of compatibility and ease of installation. The two options were Maruku and Kramdown. Maruku was the default Markdown engine for the popular Jekyll site generator, but was old and unmaintained. It also used the problematic GPLv2 license, which made its use from non-GPL projects questionable. Kramdown was inarguably a better written library, with active maintenance, but under the even-more-problematic GPLv3 license. The GPLv3 is outright forbidden in many corporate environments because of its tricky patent licensing clauses, plus it has all the issues of GPLv2 on top. I emailed Thomas Leitner, Kramdown’s maintainer, about changing the license to a more permissive license like the MIT license (used widely in the Ruby community) but he declined to change it, so I set to work on Maruku.

As I explained in my initial blog post, my plan was to fix up Maruku’s bugs and relicense it under the MIT license and release that as version 0.7.0. I did that, and then the plan was to release 1.0.0:

I’m thinking about a new API and internals that are much more friendly to extension and customization, deprecating odd features and moving most everything but the core Markdown-to-HTML bits into separate libraries that plug in to Maruku, and general non-backwards-compatible overhauls. […] Overall, my goal for Maruku is to make it the default Markdown engine for Ruby, with a focus on compatibility (across platforms, Rubies, and with other Markdown interpreters), extensibility, and ease of contribution.

However, in March of 2013, Mr. Leitner decided to relicense Kramdown under the MIT license starting with version 1.0.0. I continued to work on finishing Maruku 0.7.0, but I knew then that for people looking for a capable, flexible, well-written pure-Ruby Markdown library, Kramdown was now the correct choice. All of the things I wanted to do in Maruku for 1.0.0 were in fact already done in Kramdown – better code organization, better modularity and extensibility, good documentation, a better parser, and improved performance. Soon after Kramdown 1.0.0 was released, I switched Middleman to depend on it instead of Maruku.

I will continue to maintain Maruku and make bugfixes, because it’s the right thing to do. That said, I’m not sure I can justify doing much work on the 1.0.0 milestone knowing that, given the choice, I would use Kramdown or Redcarpet over Maruku. My recommendation to the Ruby community, and Ruby library authors, is the same: use a different Markdown library, or better yet abstract away the choice via Tilt. Please feel free to continue to send pull requests and issues to the Maruku repository, I’ll still be there.

Maruku 0.7.0.beta1 released

, ,

I’ve just pushed Maruku 0.7.0.beta1 to RubyGems.org. This is the first real release of Maruku in over 4 years. I released version 0.6.1 exactly one year ago, but that included only a single fix on top of the 0.6.0 code (for Ruby 1.9+ compatibility).

Last year, I said in “I own Maruku now”:

My present plan is to work towards releasing Maruku 0.7.0 (with a beta beforehand) as a bugfix release including the Nokogiri changes. I’ll fix whatever bugs I can without drastically changing the code, document in tests everything I can’t fix easily, and make sure there aren’t any more regressions from the previous release. I’d actually rather minimize or remove the usage of Nokogiri in the library, simply so that Maruku can have fewer dependencies, but that may not be an attainable goal. Maruku 0.7.0 will also drop support for Rubies older than 1.8.7.

It took far longer than I thought, but that goal has finally been completed, including the removal of Nokogiri as a hard dependency. There have been 447 commits by 15 contributors - I made about half of those, followed by Jacques Distler and Natalie Weizenbaum in roughly equal measure. Ignoring whitespace changes, 405 files were changed, with 8,745 insertions, and 21,439 deletions. I always consider it a good sign when more code is deleted than added. Maruku now has pretty good test coverage and tests are green in Travis CI for Ruby 2.0.0, 1.9.3, 1.9.2, 1.8.7, JRuby, and Rubinius. You can see all the changes in the CHANGELOG.

Maruku 0.7.0 should be viewed as a fixed version of Maruku 0.6.0. While its behavior has changed because of bugfixes, the interface is the same, and there have been no major removals or additions with the exception of support for fenced code blocks (familiar from GitHub Flavored Markdown) which can now be enabled via the :fenced_code_blocks option.

At this point, what I need is for Rubyists that use Maruku to try out the new version and file issues for any bugs they find. If everything’s OK for a few weeks, I’ll release 0.7.0 final, at which point I can start working on Maruku 1.0.0, which will hopefully be a more major change.

I’ve got some more things to say about the future of Maruku, but I’ll hold off on that until 0.7.0 is completely out the door. In the meantime, please give it a try!

I own Maruku now

, ,

So it turns out that I own Maruku now. Let’s start at the beginning.

Maruku is a Markdown interpreter written in Ruby. It’s one of many Markdown interpreters available to Ruby programmers, but it’s notable in that it is written only in Ruby, without relying on compiled C libraries or anything like that. This makes it nice as a default option for dealing with Markdown files, because it will run on any platform and on any flavor of Ruby.

My interest in Maruku stemmed from working on Middleman and trying to get it working in JRuby and on Windows. Ruby libraries that require compiling C code are problematic on Windows (a platform not exactly favored by Rubyists), and are even harder to get working with JRuby, which (some tricks aside) won’t load Ruby libraries that rely on C extensions. Middleman uses Tilt to allow users to choose which Markdown engine they want, but we chose Maruku as the default to provide easy setup and testing under JRuby and on Windows.

Unfortunately, Maruku had been abandoned at this point, and for several years at that. Maintainership had been transfered from Andrea Censi, the original author, to Natalie Weizenbaum, who did a bunch of cleanup. Natalie ended up getting busy with other important projects, and didn’t release a new version of the gem or working much on Maruku after that. Issues piled up, Maruku wasn’t updated to work with Bundler or Ruby 1.9, and generally began to rot.

During this period, Jacques Distler continued to enhance the library in his own fork, most notably replacing the use of Ruby’s built in REXML library with Nokogiri, which not only provided a speed boost, but fixed a lot of bugs having to do with REXML’s quirks. Jacques continued to fix bugs reported in the main Maruku issue tracker on his own fork, but nobody was around to merge them into the main repository or release a new version of Maruku.

In early May 2012 I heard news that Natalie had chosen a new maintainer for Haml to carry on the project now that she didn’t have time for it. I tweeted what I didn’t intend to be a snarky message to her asking if she was considering a similar move for Maruku. She responded quickly, asking if I was volunteering, and I agreed to manage issues for the project, and just like that I had commit access to the repository. Unfortunately, I couldn’t just jump in, because I needed to get permission from my employer to contribute to the project. This took almost three months, and I felt like a jerk the whole time for not doing anything for Maruku after being given responsibility for it. The approval came right as I was was preparing for a long trip to Africa, and so I wasn’t able to jump right on it, but after I got back I started dusting off the code and getting things into shape. I started bugging Natalie to switch options for me in GitHub (like enabling Travis CI builds), and she simply moved the repository to my account and gave me full control of everything.

Right away I was able to release Maruku 6.0.1, which includes only a single fix since the previous release – an annoying warning that appeared when running under Ruby 1.9. Since then, I’ve been chipping away at Maruku as much as I can, starting with merging Jacques’ fixes, and then turning my attention towards correcting the tests, which often asserted results that weren’t actually correct. After that, I’ve been mostly working on getting the corrected tests to pass again, especially in JRuby. While Jacques’ change to Nokogiri is a boon to speed and accuracy, it resulted in a handful of regressions under JRuby, many of which traced down to bugs in Nokogiri itself (which have all been fixed quickly by the Nokogiri maintainers). Only a few days ago, I finally got the tests running green in MRI, JRuby, and Rubinius. I had to skip certain tests that are exposing actual bugs in Maruku, but at least I now have a basis for improving the code without accidentally breaking one of the existing tests.

My present plan is to work towards releasing Maruku 0.7.0 (with a beta beforehand) as a bugfix release including the Nokogiri changes. I’ll fix whatever bugs I can without drastically changing the code, document in tests everything I can’t fix easily, and make sure there aren’t any more regressions from the previous release. I’d actually rather minimize or remove the usage of Nokogiri in the library, simply so that Maruku can have fewer dependencies, but that may not be an attainable goal. Maruku 0.7.0 will also drop support for Rubies older than 1.8.7.

Looking forward, I want to release Maruku 1.0.0, with some more drastic changes. I’m thinking about a new API and internals that are much more friendly to extension and customization, deprecating odd features and moving most everything but the core Markdown-to-HTML bits into separate libraries that plug in to Maruku, and general non-backwards-compatible overhauls. I’m also hoping that, with the original authors’ and major contributors’ support, I can relicense Maruku under the MIT license instead of GPLv2, to make it easier for Maruku to be used in more situations. Overall, my goal for Maruku is to make it the default Markdown engine for Ruby, with a focus on compatibility (across platforms, Rubies, and with other Markdown interpreters), extensibility, and ease of contribution.

For everyone who has reported bugs in Maruku, thank you for your patience. For everyone interested in the future of Maruku, feel free to watch the repository on GitHub to see the commits flowing, or subscribe to the gem on RubyGems.org to be notified of new releases. When the beta for the next release comes out, I’ll be excited to have people take it for a spin and let me know what’s still broken.

Middleman 3.0

,

For the last 8 months or so, I’ve been contributing to Thomas Reynolds’ open source project Middleman. Middleman is a Ruby framework for building static websites using all the nice tools (Haml, Sass, Compass, CoffeeScript, partials, layouts, etc.) that we’re used to from the Ruby on Rails world, and then some. This website is built with Middleman, and I think it’s the best way to put together a site that doesn’t need dynamic content. Since I started working on Middleman in November 2011, I’ve been contributing to the as-yet-unreleased version 3.0, which overhauls almost every part of the framework. Today, after many betas and release candidates, Middleman 3.0 is finally released and ready for general use, and I’m really proud of what I’ve been able to help build.

Middleman Logo

I’ve been building web sites for myself since the early 90s, before I even had an internet connection at home (I could see some primitive sites on Mosaic on my father’s university network). Early on I was inspired by HyperCard and Quicktime VR and I wanted to make my own browseable worlds, but I didn’t have a Mac (nor did I know what I was doing). Starting with Notepad and early Netscape, I started building sites full of spinning animated GIFs, blinking text, and bad Star Wars fanfiction. As time went on and I learned more bout how to actually build websites, the duplication of common elements like menus, headers, and footers became too much to manage. Around the same time I discovered how to make dynamic websites backed by a database, using ASP. For my static websites, I just used ASP includes and functions to encapsulate these common elements and do a little templating. With the release of .NET, I switched to writing sites, static and dynamic, in ASP.NET. Far too long after, I realized that hosting websites on Windows was a terrible idea, and I switched to using PHP to handle light templating duty. For dynamic, database-driven sites I switched to using Ruby on Rails, and I fell in love with its powerful templating and layout system, the Ruby language, Haml, Sass, and all the rest. However, the gulf between my Rails projects and my cheesy PHP sites was huge – all my tools were missing, and I still needed PHP available to host sites even though they were essentially static.

My first attempt to reconcile the two worlds was a Ruby static site generator called Staticmatic. Staticmatic had Haml built in, and worked mostly like Rails. I had just finished moving my site over to it when the developer discontinued the project. In its place, he recommended Middleman. However, as I started transitioning my site to Middleman, I found a few bugs, and wishing to be a good open source citizen, I included new tests with my bug reports. Thomas Reynolds, the project’s creator, encouraged me to keep contributing, and even gave me commit access to the GitHub repository very early on (at which point I broke the build on my first commit). From that point I started fixing more and more bugs, and then eventually answering issue reports, and finally adding new features and helping to overhaul large parts of the project. I’d contributed to open source projects before, but just with a bugfix here and there. Middleman has been my first real contribution, with ongoing effort and a real sense of ownership in the project.

My contributions have focused mainly in three areas. First, I’ve helped to get the new Sitemap feature working. I liked the way similar frameworks like Nanoc had a way to access a view of all the pages in a site in code, to help with automatically generating navigation. Middleman’s sitemap goes beyond that, providing a way to inspect all the files in a project, (including virtual pages), and even add to the list via extensions.

The next area I worked on is the blogging extension. I like the way Jekyll handles static blogging, but I wanted my blog to be just one part of my whole site – Jekyll is a little too focused on blog-only sites. I basically rewrote the fledgling blog extension that Thomas had started, and I’m really proud of the result. It not only handles basic blogging, but also generates tag and date pages, supports next/previous article links, and is extremely customizable. I moved my blog over from Wordpress (no more security vulnerabilities, yay!) and it’s been great.

The last place I focused was on website performance. I’ve always been interested in how to build very fast websites, and I wanted Middleman to support best practices around caching and compression. To that end, I built an extension that appends content-based hashes to asset filenames so you can give them long cache expiration times, and another extension that will pre-gzip your files to take load off your web server and deliver smaller payloads.

Beyond that I’ve fixed a lot of bugs, sped things up, written a lot of documentation, and added a lot of little features. I’m really happy that 3.0 is finally out there for people to use, and I hope more people will choose to contribute. And I’m looking forward to all the new stuff we’re going to add for 3.1!