'Ruby' 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.