Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Simple model layer that let's you query text documents as if they were a database.

branch: master
README.md

Document Mapper

Build Status

Document mapper is an object mapper for plain text documents. The documents look like the ones used in jekyll, toto or Serious. They consist of a preambel written in YAML (also called YAML front matter), and some content in the format you prefer, e.g. Textile. This enables you to write documents in your favorite editor and access the content and metadata in your Ruby scripts.

Step-by-step tutorial

Documents look somehow like this. The part between the ---s is the YAML front matter. After the second ---, there is one blank line, followed by the content of the file. All items in the YAML front matter and the content are accessible by Document Mapper.

---
id: 1
title: Ruby is great
tags: [programming, software]
number_of_foos: 42
status: published
---

I like Ruby.

In order to access the values in the front matter, you have to create a class that includes DocumentMapper.

require 'document_mapper'
class MyDocument
  include DocumentMapper::Document
end

Initializing single documents

doc = MyDocument.from_file('./documents/document-file.textile')

Accessing the attributes of single documents

doc.title                    # => "Ruby is great"
doc.tags                     # => ["programming", "software"]
doc.content                  # => "I like Ruby."

Date recognition

You can either set the date of a document in the YAML front matter, or you can use the file name, if you want to. A file named 2010-08-07-test-document-file.textile will return a date like this:

doc.date                     # => #<Date: 2010-08-07 (4910833/2,0,2299161)>
doc.date.to_s                # => "2010-08-07"
doc.year                     # => 2010
doc.month                    # => 08
doc.day                      # => 07

Working with directories

As an example let's assume we have a directory called "documents" containing the following files:

documents/
|-foo.textile
|-bar.textile

In order to work with a whole directory of files, we have to use the @directory@ method:

require 'document_mapper'
class MyDocument
  include DocumentMapper::Document
  self.directory = 'documents'
end

Now we can receive all available documents or filter like that:

MyDocument.all
MyDocument.first
MyDocument.last
MyDocument.limit(2)
MyDocument.offset(2)
MyDocument.where(:title => 'Some title').first
MyDocument.where(:status => 'published').all
MyDocument.where(:year => 2010).all

Not all of the documents in the directory need to have all of the attributes. You can add single attributes to single documents, and the queries will only return those documents where the attributes match.

The document queries do support more operators than just equality. The following operators are available:

MyDocument.where(:year.gt => 2010)        # year > 2010
MyDocument.where(:year.gte => 2010)       # year >= 2010
MyDocument.where(:year.in => [2010,2011]) # year one of [2010,2011]
MyDocument.where(:tags.include => 'ruby') # 'ruby' is included in tags = ['ruby', 'rails', ...]
MyDocument.where(:year.lt => 2010)        # year < 2010
MyDocument.where(:year.lte => 2010)       # year <= 2010

While retrieving documents, you can also define the way the documents should be ordered. By default, the documents will be returned in the order they were loaded from the file system, which usually means by file name ascending. If you define an ordering, the documents that don't own the ordering attribute will be excluded.

MyDocument.order_by(:title => :asc).all  # Order by title attribute, ascending
MyDocument.order_by(:title).all          # Same as order_by(:title => :asc)
MyDocument.order_by(:title => :desc).all # Order by title attribute, descending

Chaining

Chaining works with all available query methods, e.g.:

MyDocument.where(:status => 'published').where(:title => 'Some title').limit(2).all

Reloading

If any of the files change, you must manually reload them:

MyDocument.reload

Author

Written by Ralph von der Heyden. Don't hesitate to contact me if you have any further questions.

Follow me on Twitter

Something went wrong with that request. Please try again.