README.md

# Archivist

Archivist is a straightforward blogging utility for generating article content
at compile time from version-controlled article and image files. It is built to
be used in conjunction with the [Arcdown plaintext article parser library](https://github.com/functionhaus/arcdown).

Archivist is inspired by the general approach of Cẩm Huỳnh's great
[Nabo](https://github.com/qcam/nabo) library with some key differences:

* Archivist articles are formatted in `Arcdown` format by default, allowing
for more robust articles and article features.

* Archivist allows articles to be organized into nested *topic* directories for
better organization. Topic directory and sub-directory naming will be translated
into a hierarchical system-wide topic and sub-topic structure.

* Archivist currently doesn't parse article content as markdown, but will add
optional content parsing in future versions (like 0.3.x).

* Archivist adds default attributes for author names and email addresses, as
well as sorting content by author.

* Archivist exposes its article sorting mechanism as an anonymous function,
allowing users to implement custom article-sorting strategies at compile-time.

* Archivist allows you to set a `created_at` and `published_at` timestamps to
give you greater control over content and how it's used.

* Archivist allows you to *tag* your articles however you'd like, and provides
functions for sorting and collecting all tags used across your archive.

* Archivist generates lists of tags, topics, and authors at compile-time, giving
you more flexibility in your content's front-end presentation without having to
perform additional parsing at runtime.

## Installation

The package can be installed by adding `archivist` to your list of
dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:archivist, "~> 0.2"}
  ]
end
```

## Usage

The heart of Archivist is the `Archive` module, which acts as a repository for
exposing query functions for articles, slugs, topics, etc. You can create an
Archive out of any Elixir module by using `Archivist.Archive` like this:

```elixir
defmodule MyApp.Archive
  use Archivist.Archive
end

# the alias is just a nicety here and isn't required by any means
alias MyApp.Archive

Archive.articles()
Archive.topics()
Archive.tags()
Archive.slugs()
Archive.authors()
```

Archivist version 0.2.x expects you to create your article content directory at
`priv/archive/articles` at the root of your elixir library, like this:

`priv/archive/articles/journey_to_the_center_of_the_earth.ad`

If you'd like to customize any of your archive's behavior, you can define any of
the following options when it is used in the target archive directory. The values
shown are the defaults:

```elixir
defmodule MyApp.Archive
  use Archivist.Archive
    archive_dir: "priv/archive",
    content_dir: "articles",
    content_pattern: "**/*.ad",
    image_dir: "images",
    image_pattern: "**/*.{jpg,gif,png}",
    article_sorter: &(Map.get(&1, :published_at) >= Map.get(&2, :published_at))
end
```

Archivist will read any files with the `.ad` extension in your content directory
or in any of its subdirectories, and parse the content of those files with the
parser you've selected (Arcdown by default)

If you'd like to store your archive somewhere besides `priv/archive` you can
assign a custom path to your archive like this:

```elixir
defmodule MyApp.Archive
  use Archivist.Archive, archive_dir: "assets/images",
end
```

#### Usage notes for Version 0.1.x
Archivist version 0.1.x expects you to create your article content directory at
`priv/articles` at the root of your elixir library, like this:

`priv/articles/journey_to_the_center_of_the_earth.ad`

The following options are availble in Version 0.1.x. Values shown are defaults:

```elixir
defmodule MyApp.Archive
  use Archivist.Archive
    content_dir: "priv/articles",
    content_pattern: "**/*.ad",
    image_dir: "priv/images",
    image_pattern: "**/*.{jpg,gif,png}",
    article_sorter: &(Map.get(&1, :published_at) >= Map.get(&2, :published_at))
```

## Arcdown

Arcdown supports the following features for articles:

* Article Content
* Article Summary
* Topics
* Sub-Topics
* Tags
* Published Datetime
* Creation Datetime
* Author Name
* Author Email
* Article Slug

Here is an example article written in *Arcdown (.ad)* format:

```
The Day the Earth Stood Still <the-day-the-earth-stood-still>
by Julian Blaustein <julian@blaustein.com>

Filed under: Films > Sci-Fi > Classic

Created @ 10:24pm on 1/20/2019
Published @ 10:20pm on 1/20/2019

* Sci-Fi
* Horror
* Thrillers
* Aliens

Summary:
A sci-fi classic about a flying saucer landing in Washington, D.C.

---

The Day the Earth Stood Still (a.k.a. Farewell to the Master and Journey to the
World) is a 1951 American black-and-white science fiction film from 20th Century
Fox, produced by Julian Blaustein and directed by Robert Wise.
```

`0.1.x` versions of Archivist will parse and return article content as
`Archivist.Article` structs. The parsing output of the above article example
would look like this:

```elixir
%Archivist.Article{
  author: "Julian Blaustein",
  content: "The Day the Earth Stood Still (a.k.a. Farewell to the Master and Journey to the\nWorld) is a 1951 American black-and-white science fiction film from 20th Century\nFox, produced by Julian Blaustein and directed by Robert Wise.\n",
  created_at: #DateTime<2019-01-20 22:24:00Z>,
  email: "julian@blaustein.com",
  published_at: #DateTime<2019-04-02 04:30:00Z>,
  slug: "the-day-the-earth-stood-still",
  summary: "A sci-fi classic about a flying saucer landing in Washington, D.C.",
  tags: [:sci_fi, :horror, :thrillers, :aliens],
  title: "The Day the Earth Stood Still",
  topics: ["Films", "Sci-Fi", "Classic"]
}
```

## Development Notes

A quick review of the `Archivist.Archive` implementation would reveal additional
options that aren't otherwise mentioned in this README:

```elixir
defmodule MyApp.Archive
  use Archivist.Archive
    content_parser: Earmark,
    article_parser: Arcdown,
    application: nil
end
```

These options are currently placeholders for future functionality but do not
serve any purpose to the user for the time being. Some notes on forthcoming
features:

* While `Earmark` is included with Archivist, functionality for parsing content
as Earmark has not yet been added. Future versions (like 0.3.x) will add
something like a `parsed_content` attribute to the parsed articles flag, which
will contain content parsed as Earmark. Setting this value to `nil` will cause
the article parser not to parse the content at compile-time.

* The intent of the `application` flag is to be able to define an OTP app as the
target for the archive, allowing for the archived data to be called from a
besides the one in which `Archivist.Archive` is used. **Please note that this
functionality is currently not working and should not be used until further
notice in this README.**

* Also note that that swapping out the content and article parsers
with different modules currently is not supported. `ContentParser` and
`ArticleParser` behaviors will be implemented in future versions (likely 0.3.x)
and will support implementing custom parsers for these elements.

Please find additional information about known issues and planned features for
Archivist in the [issues tracker](https://github.com/functionhaus/archivist/issues).

## Todo

Issues and Todo enhancements are managed at the official
[Archivist issues tracker](https://github.com/functionhaus/archivist/issues) on GitHub.

## Availability

Source code is available at the official
[Archivist repository](https://github.com/functionhaus/arcdown)
on the [FunctionHaus GitHub Organization](https://github.com/functionhaus)

## License

Archivist source code is released under Apache 2 License.
Check LICENSE file for more information.

&copy; 2017 FunctionHaus, LLC