├── AUTHORS ├── ChangeLog ├── LICENSE ├── README.md ├── bin └── motyl └── examples ├── assets └── robots.txt ├── motyl.conf ├── pages ├── archives.md ├── archives.yaml ├── index.md └── index.yaml └── posts ├── hello-world.md └── hello-world.yaml /AUTHORS: -------------------------------------------------------------------------------- 1 | Motyl is developed by: 2 | 3 | Frederic Cambus 4 | 5 | Site: https://www.cambus.net 6 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Motyl 1.0.3 (2022-07-28) 2 | 3 | - Fix an off-by-one error, we want 20 posts in the Atom feed 4 | - Raise the default to 30 posts in the Atom feed 5 | - Remove unused feedItems directive from motyl.conf 6 | - Add Motyl ASCii logo header (Thanks H7!) 7 | - Add SPDX short license identifier in source file 8 | 9 | 10 | 11 | Motyl 1.0.2 (2019-05-07) 12 | 13 | - Add require 'date', which allows Motyl to run with Ruby 2.5+ 14 | 15 | 16 | 17 | Motyl 1.0.1 (2018-10-18) 18 | 19 | - Enforce UTF-8 character encoding 20 | - Lint code and wrap lines longer than 80 characters 21 | 22 | 23 | 24 | Motyl 1.0.0 (2018-04-28) 25 | 26 | - Initial release 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016-2022, Frederic Cambus 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in the 12 | documentation and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 18 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | 3 | ::::::::::::::::::: 4 | ::: _______ :: ________ ____. ______. .____. 5 | ::: .\ _ \____.\ _. /.\ |_\\ |----| | 6 | ::: | | . | \| | _/--- | | |_ 7 | ::: | |\_| | : | | \___ | \ 8 | ::: | | |____|________|_____ | //____/|______/ H7 9 | - - ::: -`----' --- ... ----------- `----' ---------------- -- - 10 | ::: ::: 11 | ::::::::::::::::::: 12 | 13 | ``` 14 | 15 | ## Description 16 | 17 | Motyl is an opinionated blog-aware static site generator written in Ruby. 18 | It uses Mustache as templating system, and all content is written in Markdown. 19 | 20 | For the record, motyl means butterfly in Polish. 21 | 22 | ## Features 23 | 24 | - Small and easy to understand codebase 25 | - Minimal dependencies (only three gems) 26 | - Pages and posts written in Markdown 27 | - Templates are logic-less and use Mustache 28 | - Support for multiple categories per post 29 | - Syntax highlighting (using Rouge) 30 | - Customizable URLs (constructed from filename) 31 | - Atom feed generator 32 | 33 | ## Requirements 34 | 35 | ### Ruby modules 36 | 37 | Motyl requires the following Ruby modules: 38 | 39 | - kramdown 40 | - mustache 41 | - rouge 42 | 43 | Installing dependencies via gem: 44 | 45 | gem install kramdown mustache rouge 46 | 47 | Alternatively, those modules can be installed directly via the operating 48 | system's package manager. 49 | 50 | ## Configuration 51 | 52 | The 'examples' directory contains a sample site which can be used as a 53 | starting point. 54 | 55 | ### Installing a theme 56 | 57 | Clone the [Chrysalide](https://github.com/fcambus/chrysalide) theme repository 58 | and place it in the `themes` directory. 59 | 60 | ## Usage 61 | 62 | Simply run `motyl` to build the site, it will generate posts and pages into 63 | the `public` directory, and will also copy static assets. 64 | 65 | ## License 66 | 67 | Motyl is released under the BSD 2-Clause license. See `LICENSE` file 68 | for details. 69 | 70 | ## Author 71 | 72 | Motyl is developed by Frederic Cambus. 73 | 74 | - Site: https://www.cambus.net 75 | 76 | ## Resources 77 | 78 | GitHub: https://github.com/fcambus/motyl 79 | -------------------------------------------------------------------------------- /bin/motyl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # 4 | # Motyl 1.0.3 5 | # Copyright (c) 2016-2022, Frederic Cambus 6 | # https://github.com/fcambus/motyl 7 | # 8 | # Created: 2016-02-16 9 | # Last Updated: 2022-07-28 10 | # 11 | # Motyl is released under the BSD 2-Clause license. 12 | # See LICENSE file for details. 13 | # 14 | # SPDX-License-Identifier: BSD-2-Clause 15 | # 16 | 17 | require 'date' 18 | require 'fileutils' 19 | require 'kramdown' 20 | require 'mustache' 21 | require 'yaml' 22 | 23 | # Enforce UTF-8 character encoding 24 | Encoding.default_internal = Encoding::UTF_8 25 | Encoding.default_external = Encoding::UTF_8 26 | 27 | # Load and process Markdown file 28 | def markdown(path) 29 | Kramdown::Document.new( 30 | File.read(path), 31 | smart_quotes: %w[apos apos quot quot], 32 | syntax_highlighter: 'rouge' 33 | ).to_html 34 | end 35 | 36 | # Display status message 37 | def status(message) 38 | puts('[' + Time.now.strftime('%X') + '] ' + message) 39 | end 40 | 41 | # Loading configuration 42 | data = { 43 | 'version' => 'Motyl 1.0.3', 44 | 'updated' => Time.now.strftime('%Y-%m-%dT%XZ'), 45 | 'site' => YAML.load_file('motyl.conf'), 46 | 'posts' => [], 47 | 'categories' => {} 48 | } 49 | 50 | theme = 'themes/' + data['site']['theme'] + '/' 51 | 52 | # Loading templates 53 | templates = { 54 | 'categories' => File.read(theme + 'templates/categories.mustache'), 55 | 'atom' => File.read(theme + 'templates/atom.mustache'), 56 | 'pages' => File.read(theme + 'templates/page.mustache'), 57 | 'posts' => File.read(theme + 'templates/post.mustache') 58 | } 59 | 60 | Mustache.template_path = theme + 'templates/' 61 | 62 | def render(directory, templates, data) 63 | Dir.foreach(directory) do |file| 64 | next if ['.', '..'].include?(file) 65 | 66 | extension = File.extname(file) 67 | 68 | if extension == '.md' 69 | basename = File.basename(file, extension) 70 | data['page'] = YAML.load_file(directory + '/' + basename + '.yaml') 71 | data['page']['content'] = Mustache.render( 72 | markdown(directory + '/' + file), 73 | data 74 | ) 75 | data['page']['url'] ||= basename + '/' 76 | 77 | status('Rendering ' + data['page']['url']) 78 | 79 | if directory == 'posts' 80 | data['page']['datetime'] = 81 | DateTime.parse(data['page']['date']).strftime('%Y-%m-%dT%XZ') 82 | 83 | data['posts'].push(data['page']) 84 | 85 | data['page']['categoryDisplay'] = [] 86 | 87 | # Populate category table 88 | data['page']['categories'].each do |category| 89 | data['categories'][category] ||= [] 90 | data['categories'][category].push(data['page']) 91 | data['page']['categoryDisplay'].push( 92 | 'category' => category, 93 | 'url' => data['site']['categoryMap'][category] 94 | ) 95 | end 96 | end 97 | 98 | FileUtils.mkdir_p('public/' + data['page']['url']) 99 | File.write('public/' + data['page']['url'] + 'index.html', 100 | Mustache.render(templates[directory], data)) 101 | 102 | data['page'] = {} 103 | end 104 | end 105 | end 106 | 107 | # Render posts 108 | FileUtils.rm_rf('public') 109 | render('posts', templates, data) 110 | 111 | # Sort post archives 112 | data['posts'].sort! { |a, b| b['date'] <=> a['date'] } 113 | 114 | # Renger pages 115 | render('pages', templates, data) 116 | 117 | # Feed 118 | data['feed'] = data['posts'][0..29] 119 | 120 | File.write('public/atom.xml', Mustache.render(templates['atom'], data)) 121 | status('Rendering atom.xml') 122 | data['page'] = {} 123 | 124 | # Categories 125 | data['categories'].keys.each do |category| 126 | category_url = data['site']['categoryMap'][category] + '/' 127 | 128 | data['categories'][category].sort! { |a, b| b['date'] <=> a['date'] } 129 | data['page']['title'] = category 130 | data['page']['url'] = 'categories/' + category_url 131 | data['posts'] = data['categories'][category] 132 | 133 | FileUtils.mkdir_p('public/categories/' + category_url) 134 | File.write('public/categories/' + category_url + 'index.html', 135 | Mustache.render(templates['categories'], data)) 136 | status('Rendering ' + category_url) 137 | end 138 | 139 | # Copy static assets 140 | status('Copying assets and static files') 141 | FileUtils.cp_r(Dir.glob(theme + 'assets/*'), 'public') 142 | FileUtils.cp_r(Dir.glob('assets/*'), 'public') 143 | -------------------------------------------------------------------------------- /examples/assets/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | -------------------------------------------------------------------------------- /examples/motyl.conf: -------------------------------------------------------------------------------- 1 | lang: en 2 | title: Motyl 3 | name: Motyl 4 | description: Motyl, an opinionated blog-aware static site generator written in Ruby. 5 | keywords: static, site, generator, ssg, motyl, ruby 6 | author: Frederic Cambus 7 | copyright: '2016-2022' 8 | url: https://github.com/fcambus/motyl 9 | theme: chrysalide 10 | pages: 11 | - title: Home 12 | url: / 13 | - title: '· Archives' 14 | url: /archives/ 15 | - title: '· RSS' 16 | url: /atom.xml 17 | categoryMap: 18 | News: news 19 | Miscellaneous: miscellaneous 20 | Ruby: ruby 21 | -------------------------------------------------------------------------------- /examples/pages/archives.md: -------------------------------------------------------------------------------- 1 | {{#posts}} 2 |

{{{title}}}

3 | 4 | 5 | {{#categoryDisplay}} 6 | · {{category}} 7 | {{/categoryDisplay}} 8 | 9 | {{/posts}} 10 | -------------------------------------------------------------------------------- /examples/pages/archives.yaml: -------------------------------------------------------------------------------- 1 | title: 'Archives' 2 | description: '' 3 | keywords: '' 4 | -------------------------------------------------------------------------------- /examples/pages/index.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Motyl is an opinionated blog-aware static site generator written in Ruby. 4 | It uses Mustache as templating system, and all content is written in Markdown. 5 | 6 | For the record, motyl means butterfly in Polish. 7 | 8 | ## Features 9 | 10 | - Small and easy to understand codebase 11 | - Minimal dependencies (only three gems) 12 | - Pages and posts written in Markdown 13 | - Templates are logic-less and use Mustache 14 | - Support for multiple categories per post 15 | - Syntax highlighting (using Rouge) 16 | - Customizable URLs (constructed from filename) 17 | - Atom feed generator 18 | 19 | ## Requirements 20 | 21 | ### Ruby modules 22 | 23 | Motyl requires the following Ruby modules: 24 | 25 | - kramdown 26 | - mustache 27 | - rouge 28 | 29 | Installing dependencies via gem: 30 | 31 | gem install kramdown mustache rouge 32 | 33 | Alternatively, those modules can be installed directly via the operating 34 | system's package manager. 35 | 36 | ## Configuration 37 | 38 | The 'examples' directory contains a sample site which can be used as a 39 | starting point. 40 | 41 | ### Installing a theme 42 | 43 | Clone the [Chrysalide](https://github.com/fcambus/chrysalide) theme repository 44 | and place it in the `themes` directory. 45 | 46 | ## Usage 47 | 48 | Simply run `motyl` to build the site, it will generate posts and pages into 49 | the `public` directory, and will also copy static assets. 50 | 51 | ## License 52 | 53 | Motyl is released under the BSD 2-Clause license. See `LICENSE` file 54 | for details. 55 | 56 | ## Author 57 | 58 | Motyl is developed by Frederic Cambus. 59 | 60 | - Site: https://www.cambus.net 61 | 62 | ## Resources 63 | 64 | GitHub: https://github.com/fcambus/motyl 65 | -------------------------------------------------------------------------------- /examples/pages/index.yaml: -------------------------------------------------------------------------------- 1 | title: Home 2 | description: '' 3 | keywords: '' 4 | url: '/' 5 | -------------------------------------------------------------------------------- /examples/posts/hello-world.md: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 2 | 3 | Motyl supports fenced code blocks. 4 | 5 | Here is an example showing a shell script: 6 | 7 | ~~~ bash 8 | #!/bin/sh 9 | echo "Hello World!" 10 | ~~~ 11 | 12 | Another example showing C code: 13 | 14 | ~~~ c 15 | #include 16 | 17 | int main() { 18 | printf("Hello World!\n"); 19 | 20 | return 0; 21 | } 22 | ~~~ 23 | 24 | -------------------------------------------------------------------------------- /examples/posts/hello-world.yaml: -------------------------------------------------------------------------------- 1 | title: Hello World! 2 | date: 2016-06-28 18:17 3 | description: This is a sample post for Motyl. 4 | keywords: motyl, ruby 5 | categories: 6 | - News 7 | - Ruby 8 | --------------------------------------------------------------------------------