Introducing Marley, the blog engine without textareas
<textarea> and store your writings in a relational database somewhere. Not Marley. Marley assumes you like to write in your text editor, store text as plain-text files, keep things versioned with Git and publish stuff by auto-syncing content with Git post-receive hooks in remote repository.
An introduction
Writing your own weblog software is presumably the dumbest thing you could do. Why do such thing, when there's so much open-source blog engines or hosted service to choose from, right? Well, there may be at least two reasons for doing it. Head over to the source code of Marley at Github if you're impatient or read on for some background.
First, flexibility and/or extendability. As recently stated by Adam Wiggins, blogging software seems to be in sorry state. The famed „feature bloat“ isn't the big problem. Worse is, that blogging software, once pioneering quite a few concepts (syndication, XML-RPC, ...) seems to be caught in an endless loop. Every package or service implements more or less the same features in a more or less same interface. And maybe you have other ideas how to manage content on your blog or how should it work.
Secondly, and this is far more important point, as developers, we often underestimate the need to practice our skills aside the „regular work“. It is essential to have some playground where one could try out ideas and programming techniques, experiment with libraries or code maybe too risky for the contracted stuff, try to simplify the installation as much as possible ... I think that such exploratory programming is essential for one's skillset to grow and directly impacts the quality of code written „during the day“.
And this is where Sinatra, web micro-framework for Ruby, takes the stage. Working on a Sinatra-based applications has been the most satisfiying experience for me lately. Rails? Rails is awesome! Rails is just plain fucking awesome, just to stress the point. But this „oh shit this is plain fucking awesome“ sentiment wears down a bit when you code Rails applications day after day. Coding in Rails is about having a specific mindset. It's about coding as little as possible and trying to „think along“ the framework, coding by using subtle touches of Rails' DSL. It's also about speed. You want or need to do things quickly, making use of plugins and gems, searching for them and constantly making decisions about other people's code. And it's about responsibility, first of all: you want to abstract from your „style“ as much as possible, using Ruby and Rails idioms to make it easier for any future developer who may take over the project.
Coding an application in Sinatra is different. You're free to do anything. And that doesn't mean using Datamapper/Sequel/{INSERT YOUR FAVORITE ORM HERE} instead of ActiveRecord or jQuery instead of Prototype. (Which is bandied about as „choice“, surprisingly.) It means you can design the application on a luscious green meadow. You can play with sophisticated toys from the Design Patterns department or just shove fifty lines of ad-hoc code inside a method. You can come up with absolutely elegant use of blocks. You can explore the Ruby language, your willingness to learn, your skillset. It's your choice.
But you don't want to have to be setting up infrastructure. You just want to sit down and play. Sinatra is absolutely the easiest way to put a Ruby-based application online. (Or to be more precise, probably the easiest way to put an interface on any idea expressable in Ruby.) Sinatra is a tiny domain-specific language, sitting on top of Rack interface to web server. It comes with support for all the HTTP methods, so you can be a true restafari. And when we say „easy“, we mean this easy:
# application.rb
require 'rubygems'
require 'sinatra'
get "/" do
"Hello, it's #{Time.now} at the server"
end
Which you run by:
$ ruby application.rb
But let's reserve Sinatra for another article, shall we? You can peruse a list of Sinatra applications or browse the open-source Sinatra book [Github source] in the meantime.
Why another blog engine in Sinatra
So. Why build another minimal blog engine in Ruby when everybody and their sister is already doing so? Short answer: because I needed something else then a <textarea> dumping content into relational database. I still remember the hassle when publishing and specifically updating anything on my previous, Mephisto based blog (in Czech). (Writing anything worth reading is quite a hassle in itself.) I like to write just anything in Textmate, formatted in Markdown, using keyboard shortcuts for formatting, inserting links, etc. So partial reason why my previous blog died was maybe the hassle from shuffling text via clipboard between Textmate and Mephisto.
Also, I like to store my writing in plain-text, locally. I like it to be backed up by TimeMachine or versioned by Git. And I want the publishing/updating part to be as invisible and painless as possible. I just want to mirror the articles on the web, is all!
How does Marley work, then? What it depends on? What it assumes?
First, it stores articles in subdirectories on your local/remote computer. It parses various properties to get things like date published, title, perex, etc. It stores comments in SQLite flat-file database, with ActiveRecord as an interface. (Why ActiveRecord? Well, if you have a host with Ruby, you very probably have Rails there and thus ActiveRecord.) It uses Markdown for formatting and RDiscount for translating it to HTML. Standard stuff. Not interesting, thanks.
It differs quite a lot in the synchronizing/publishing/updating part of the game. When you have your content in a remote repository, you could publish things just by git push-ing to it. Post-receive hooks will take care of it. Marley features special URL hook to sync the content on the server to remote articles repository -- Github in particular makes setting these hooks very easy. For setting this up (and it is not as straightforward as one would like), the application provides you with some Capistrano task.
Installation & Setup
Marley tries really hard to be as easy to set up as possible. I know the pain of trying out some open-source application and dealing with multistep configs and sorting out dependencies.
For the application to run, you have to install or update following Rubygems:
sudo gem install sinatra rack thin activerecord sqlite3-ruby rdiscount builder capistrano
You have to edit the configuration file in config/config.example.yml and rename it to config/config.yml. You can leave it as it is, and it will work.
Then install the application with this Rake task:
rake app:install
(As you can see in the source, it creates necessary directories, database for comments and inserts sample article and comment.)
After this step just load the standard Sinatra URL in your browser and you should be done:
http://localhost:4567
Create some directories in the content directory, put some text files in there, post comments. It should work.
For deployment on the server, you should edit the config/deploy.example.rb file for Capistrano. You have to provide it with your SSH username, repository containing the application (could be Marley's public URL, of course), deploy path, server IPs, etc. Pretty standard Capistrano stuff. Rename the file to config/deploy.rb and run:
cap deploy:setup
cap deploy:cold
which sets up whole infrastructure, clones the application from repository and starts Thin web server on port 4500. (Of course, you need to front Thin with Apache/Nginx/etc to run it for a domain. See the example virtual host configuration for Apache2.)
Synchronizing content
You already know that Marley assumes you like to write in your favorite text editor, using Markdown, previewing on the fly, and synchronizing when you’re ready to publish something, right? But how to transfer everything to the server to amaze and entertain the world?
Of course, you can be hardcore and write articles over SSH in Vim directly on the server for "just-in-time-publication" when you hit :w. Or you can store everything locally and be scp-ing or rsync-ing it, but you probably wouldn't publish stuff too often...
If you store your content in a Git repository (and you should!), you can setup remote hooks which will synchronize your content after you git push anything.
One way is to transfer your local data directory to the server as a Git repo, cloning it there and then add a post-receive hook to it. This is how I do it, publishing by running git push sync when I update or add some content. It is very fast, very convenient.
Of course, you can setup the repo with content on Github (and you should!), which provides you with absolutely easiest way to setup a post-receive hook: after every push into a Github repo, it calls an URL you specify. It works the same for private and public repos. This is where Marley's /sync URL comes into play. It does almost nothing, just cd-s to the data directory and git pull-s anything you don't have, but... you probably couldn't publish stuff easier. The URL is authorized by a token set in config/config.yml file. OMG! Not secure! Could be overheard in the internets! Of course it could. If you are worried by this, you shouldn't use it. Marley takes reasonable measures against someone trying to flood the app and your repo with these requests, but nothing is bullet proof and until Github implements some way to authorize/sign what's sent to post-receive URLs, there's probably not much to be done.
You can set up any of these ways by running a Capistrano task:
cap sync:setup
After you choose which one you would like, the task walks you through the rest. Try it out afterwards by pushing to the added sync remote repo in your content directory. The setup process is quite intricate, so there's a chance it explodes in your terminal. Drop a line in comments below or at the Github wiki if it should!
Drop a line below or write an e-mail about what you like and don't like about Marley!
Join the discussion